]> git.pld-linux.org Git - packages/lighttpd.git/blob - lighttpd-branch.diff
- svn 1277
[packages/lighttpd.git] / lighttpd-branch.diff
1 --- ../lighttpd-1.4.11/NEWS     2006-03-09 19:34:33.000000000 +0200
2 +++ lighttpd-1.5.0/NEWS 2006-07-16 00:26:05.000000000 +0300
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.5.0/configure.in 2006-09-07 00:57:05.000000000 +0300
29 @@ -1,7 +1,7 @@
30  #                                               -*- Autoconf -*-
31  # Process this file with autoconf to produce a configure script.
32  AC_PREREQ(2.57)
33 -AC_INIT(lighttpd, 1.4.11, jan@kneschke.de)
34 +AC_INIT(lighttpd, 1.5.0, 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.5.0/cygwin/lighttpd.README       2006-09-07 01:00:40.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.5.0-<REL>-src.tar.bz2
299 +    if you use setup to install this src package, it will be
300 +        unpacked under /usr/src automatically
301 +  cd /usr/src
302 +  ./lighttpd-1.5.0-<REL>.sh all
303 +
304 +This will create:
305 +  /usr/src/lighttpd-1.5.0-<REL>.tar.bz2
306 +  /usr/src/lighttpd-1.5.0-<REL>-src.tar.bz2
307 +
308 +Or use './lighttpd-1.5.0-<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.5.0/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.5.0/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.5.0/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.5.0/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.5.0/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.5.0/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.5.0/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.5.0/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.5.0/lighttpd.spec        2006-09-07 01:00:40.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.5.0
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.5.0/openwrt/control      2006-09-07 01:00:41.000000000 +0300
787 @@ -1,8 +1,8 @@
788  Package: lighttpd
789 -Version: 1.4.11
790 +Version: 1.5.0
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.5.0.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.5.0/openwrt/lighttpd.mk  2006-09-07 01:00:41.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.5.0
806  LIGHTTPD_TARGET=.built
807  LIGHTTPD_DIR=$(BUILD_DIR)/$(LIGHTTPD)
808  LIGHTTPD_IPK=$(BUILD_DIR)/$(LIGHTTPD)_mipsel.ipk
809 --- ../lighttpd-1.4.11/src/Makefile.am  2006-03-07 14:20:20.000000000 +0200
810 +++ lighttpd-1.5.0/src/Makefile.am      2006-09-07 00:57:05.000000000 +0300
811 @@ -16,11 +16,26 @@
812  else
813  configparser.y: lemon
814  mod_ssi_exprparser.y: lemon
815 +http_resp_parser.y: lemon
816 +http_req_parser.y: lemon
817 +http_req_range_parser.y: lemon
818  
819  configparser.c configparser.h: configparser.y
820         rm -f configparser.h
821         $(LEMON) -q $(srcdir)/configparser.y $(srcdir)/lempar.c
822  
823 +http_resp_parser.c http_resp_parser.h: http_resp_parser.y
824 +       rm -f http_resp_parser.h
825 +       $(LEMON) -q $(srcdir)/http_resp_parser.y $(srcdir)/lempar.c
826 +
827 +http_req_parser.c http_req_parser.h: http_req_parser.y
828 +       rm -f http_req_parser.h
829 +       $(LEMON) -q $(srcdir)/http_req_parser.y $(srcdir)/lempar.c
830 +
831 +http_req_range_parser.c http_req_range_parser.h: http_req_range_parser.y
832 +       rm -f http_req_parser.h
833 +       $(LEMON) -q $(srcdir)/http_req_range_parser.y $(srcdir)/lempar.c
834 +
835  mod_ssi_exprparser.c mod_ssi_exprparser.h: mod_ssi_exprparser.y 
836         rm -f mod_ssi_exprparser.h
837         $(LEMON) -q $(srcdir)/mod_ssi_exprparser.y $(srcdir)/lempar.c
838 @@ -28,10 +43,13 @@
839  
840  configfile.c: configparser.h
841  mod_ssi_expr.c: mod_ssi_exprparser.h
842 +http_resp.c: http_resp_parser.h
843 +http_req.c: http_req_parser.h
844 +http_req_range.c: http_req_range_parser.h
845  
846  common_src=buffer.c log.c \
847        keyvalue.c chunk.c  \
848 -      http_chunk.c stream.c fdevent.c \
849 +      stream.c fdevent.c \
850        stat_cache.c plugin.c joblist.c etag.c array.c \
851        data_string.c data_count.c data_array.c \
852        data_integer.c md5.c data_fastcgi.c \
853 @@ -40,13 +58,16 @@
854        fdevent_solaris_devpoll.c fdevent_freebsd_kqueue.c \
855        data_config.c bitset.c \
856        inet_ntop_cache.c crc32.c \
857 -      connections-glue.c \
858 -      configfile-glue.c \
859 +      connections-glue.c iosocket.c \
860 +      configfile-glue.c status_counter.c \
861        http-header-glue.c \
862        network_write.c network_linux_sendfile.c \
863        network_freebsd_sendfile.c network_writev.c \
864        network_solaris_sendfilev.c network_openssl.c \
865 -      splaytree.c 
866 +      splaytree.c \
867 +      http_resp.c http_resp_parser.c \
868 +      http_req.c http_req_parser.c \
869 +      http_req_range.c http_req_range_parser.c 
870        
871  src = server.c response.c connections.c network.c \
872        configfile.c configparser.c request.c proc_open.c
873 @@ -75,6 +96,11 @@
874  mod_flv_streaming_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
875  mod_flv_streaming_la_LIBADD = $(common_libadd)
876  
877 +lib_LTLIBRARIES += mod_uploadprogress.la
878 +mod_uploadprogress_la_SOURCES = mod_uploadprogress.c 
879 +mod_uploadprogress_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
880 +mod_uploadprogress_la_LIBADD = $(common_libadd)
881 +
882  lib_LTLIBRARIES += mod_evasive.la
883  mod_evasive_la_SOURCES = mod_evasive.c
884  mod_evasive_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
885 @@ -82,9 +108,9 @@
886  
887  lib_LTLIBRARIES += mod_webdav.la
888  mod_webdav_la_SOURCES = mod_webdav.c
889 -mod_webdav_la_CFLAGS = $(AM_CFLAGS) $(XML_CFLAGS) $(SQLITE_CFLAGS)
890 +mod_webdav_la_CFLAGS = $(AM_CFLAGS) $(XML_CFLAGS) $(SQLITE_CFLAGS) 
891  mod_webdav_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
892 -mod_webdav_la_LIBADD = $(common_libadd) $(XML_LIBS) $(SQLITE_LIBS)
893 +mod_webdav_la_LIBADD = $(common_libadd) $(XML_LIBS) $(SQLITE_LIBS) $(UUID_LIB)
894  
895  lib_LTLIBRARIES += mod_cml.la
896  mod_cml_la_SOURCES = mod_cml.c mod_cml_lua.c mod_cml_funcs.c
897 @@ -103,6 +129,11 @@
898  mod_mysql_vhost_la_LIBADD = $(MYSQL_LIBS) $(common_libadd)
899  mod_mysql_vhost_la_CPPFLAGS = $(MYSQL_INCLUDE)
900  
901 +lib_LTLIBRARIES += mod_sql_vhost_core.la
902 +mod_sql_vhost_core_la_SOURCES = mod_sql_vhost_core.c
903 +mod_sql_vhost_core_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
904 +mod_sql_vhost_core_la_LIBADD = $(common_libadd)
905 +
906  lib_LTLIBRARIES += mod_cgi.la
907  mod_cgi_la_SOURCES = mod_cgi.c 
908  mod_cgi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
909 @@ -158,6 +189,15 @@
910  mod_proxy_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
911  mod_proxy_la_LIBADD = $(common_libadd)
912  
913 +lib_LTLIBRARIES += mod_proxy_core.la
914 +mod_proxy_core_la_SOURCES = mod_proxy_core.c mod_proxy_core_pool.c \
915 +                           mod_proxy_core_backend.c mod_proxy_core_address.c \
916 +                           mod_proxy_core_backlog.c mod_proxy_core_rewrites.c \
917 +                           mod_proxy_backend_http.c mod_proxy_backend_fastcgi.c
918 +mod_proxy_core_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
919 +mod_proxy_core_la_LIBADD = $(common_libadd) $(PCRE_LIB)
920 +
921 +
922  lib_LTLIBRARIES += mod_ssi.la
923  mod_ssi_la_SOURCES = mod_ssi_exprparser.c mod_ssi_expr.c mod_ssi.c 
924  mod_ssi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
925 @@ -231,7 +271,7 @@
926  
927  hdr = server.h buffer.h network.h log.h keyvalue.h \
928        response.h request.h fastcgi.h chunk.h \
929 -      settings.h http_chunk.h http_auth_digest.h \
930 +      settings.h http_auth_digest.h \
931        md5.h http_auth.h stream.h \
932        fdevent.h connections.h base.h stat_cache.h \
933        plugin.h mod_auth.h \
934 @@ -240,7 +280,25 @@
935        mod_ssi.h mod_ssi_expr.h inet_ntop_cache.h \
936        configparser.h mod_ssi_exprparser.h \
937        sys-mmap.h sys-socket.h mod_cml.h mod_cml_funcs.h \
938 -      splaytree.h proc_open.h
939 +      splaytree.h proc_open.h mod_sql_vhost_core.h \
940 +      sys-files.h sys-process.h sys-strings.h  \
941 +      iosocket.h array-static.h \
942 +      mod_proxy_core_address.h \
943 +      mod_proxy_core_backend.h \
944 +      mod_proxy_core_backlog.h \
945 +      mod_proxy_core.h  \
946 +      mod_proxy_core_pool.h \
947 +      mod_proxy_core_rewrites.h \
948 +      mod_proxy_backend_http.h \
949 +      mod_proxy_backend_fastcgi.h \
950 +      status_counter.h \
951 +      http_req.h \
952 +      http_req_parser.h \
953 +      http_req_range.h \
954 +      http_req_range_parser.h \
955 +      http_resp.h \
956 +      http_resp_parser.h \
957 +      http_parser.h
958  
959  DEFS= @DEFS@ -DLIBRARY_DIR="\"$(libdir)\""
960  
961 @@ -267,4 +325,10 @@
962  #ajp_SOURCES = ajp.c
963  
964  noinst_HEADERS   = $(hdr)
965 -EXTRA_DIST = mod_skeleton.c configparser.y mod_ssi_exprparser.y lempar.c
966 +EXTRA_DIST = mod_skeleton.c \
967 +            configparser.y \
968 +            mod_ssi_exprparser.y \
969 +            lempar.c  \
970 +            http_resp_parser.y \
971 +            http_req_parser.y \
972 +            http_req_range_parser.y 
973 --- ../lighttpd-1.4.11/src/array-static.h       1970-01-01 03:00:00.000000000 +0300
974 +++ lighttpd-1.5.0/src/array-static.h   2006-07-18 13:03:40.000000000 +0300
975 @@ -0,0 +1,33 @@
976 +#ifndef _ARRAY_STATIC_H_
977 +#define _ARRAY_STATIC_H_
978 +
979 +/* define a generic array of <type>
980 + * */
981 +
982 +#define ARRAY_STATIC_DEF(name, type, extra) \
983 +typedef struct { \
984 +       type **ptr; \
985 +       size_t used; \
986 +       size_t size; \
987 +       extra\
988 +} name
989 +
990 +/* all append operations need a 'resize' for the +1 */
991 +
992 +#define ARRAY_STATIC_PREPARE_APPEND(a) \
993 +        if (a->size == 0) { \
994 +               a->size = 16; \
995 +               a->ptr = malloc(a->size * sizeof(*(a->ptr))); \
996 +       } else if (a->size == a->used) { \
997 +               a->size += 16; \
998 +               a->ptr = realloc(a->ptr, a->size * sizeof(*(a->ptr))); \
999 +       }
1000 +       
1001 +#define FOREACH(array, element, func) \
1002 +do { size_t _i; for (_i = 0; _i < array->used; _i++) { void *element = array->ptr[_i]; func; } } while(0);
1003 +
1004 +#define STRUCT_INIT(type, var) \
1005 +       type *var;\
1006 +       var = calloc(1, sizeof(*var))
1007 +
1008 +#endif
1009 --- ../lighttpd-1.4.11/src/array.c      2005-11-18 13:58:32.000000000 +0200
1010 +++ lighttpd-1.5.0/src/array.c  2006-07-16 00:26:03.000000000 +0300
1011 @@ -11,12 +11,12 @@
1012  
1013  array *array_init(void) {
1014         array *a;
1015 -       
1016 +
1017         a = calloc(1, sizeof(*a));
1018         assert(a);
1019 -       
1020 +
1021         a->next_power_of_2 = 1;
1022 -       
1023 +
1024         return a;
1025  }
1026  
1027 @@ -43,29 +43,29 @@
1028  void array_free(array *a) {
1029         size_t i;
1030         if (!a) return;
1031 -       
1032 +
1033         if (!a->is_weakref) {
1034                 for (i = 0; i < a->size; i++) {
1035                         if (a->data[i]) a->data[i]->free(a->data[i]);
1036                 }
1037         }
1038 -       
1039 +
1040         if (a->data) free(a->data);
1041         if (a->sorted) free(a->sorted);
1042 -       
1043 +
1044         free(a);
1045  }
1046  
1047  void array_reset(array *a) {
1048         size_t i;
1049         if (!a) return;
1050 -       
1051 +
1052         if (!a->is_weakref) {
1053                 for (i = 0; i < a->used; i++) {
1054                         a->data[i]->reset(a->data[i]);
1055                 }
1056         }
1057 -       
1058 +
1059         a->used = 0;
1060  }
1061  
1062 @@ -84,20 +84,20 @@
1063  static int array_get_index(array *a, const char *key, size_t keylen, int *rndx) {
1064         int ndx = -1;
1065         int i, pos = 0;
1066 -       
1067 +
1068         if (key == NULL) return -1;
1069 -       
1070 +
1071         /* try to find the string */
1072         for (i = pos = a->next_power_of_2 / 2; ; i >>= 1) {
1073                 int cmp;
1074 -               
1075 +
1076                 if (pos < 0) {
1077                         pos += i;
1078                 } else if (pos >= (int)a->used) {
1079                         pos -= i;
1080                 } else {
1081                         cmp = buffer_caseless_compare(key, keylen, a->data[a->sorted[pos]]->key->ptr, a->data[a->sorted[pos]]->key->used);
1082 -                       
1083 +
1084                         if (cmp == 0) {
1085                                 /* found */
1086                                 ndx = a->sorted[pos];
1087 @@ -110,46 +110,46 @@
1088                 }
1089                 if (i == 0) break;
1090         }
1091 -       
1092 +
1093         if (rndx) *rndx = pos;
1094 -       
1095 +
1096         return ndx;
1097  }
1098  
1099  data_unset *array_get_element(array *a, const char *key) {
1100         int ndx;
1101 -       
1102 +
1103         if (-1 != (ndx = array_get_index(a, key, strlen(key) + 1, NULL))) {
1104                 /* found, leave here */
1105 -               
1106 +
1107                 return a->data[ndx];
1108 -       } 
1109 -       
1110 +       }
1111 +
1112         return NULL;
1113  }
1114  
1115  data_unset *array_get_unused_element(array *a, data_type_t t) {
1116         data_unset *ds = NULL;
1117 -       
1118 +
1119         UNUSED(t);
1120  
1121         if (a->size == 0) return NULL;
1122 -       
1123 +
1124         if (a->used == a->size) return NULL;
1125  
1126         if (a->data[a->used]) {
1127                 ds = a->data[a->used];
1128 -               
1129 +
1130                 a->data[a->used] = NULL;
1131         }
1132 -       
1133 +
1134         return ds;
1135  }
1136  
1137  /* replace or insert data, return the old one with the same key */
1138  data_unset *array_replace(array *a, data_unset *du) {
1139         int ndx;
1140 -       
1141 +
1142         if (-1 == (ndx = array_get_index(a, du->key->ptr, du->key->used, NULL))) {
1143                 array_insert_unique(a, du);
1144                 return NULL;
1145 @@ -164,13 +164,13 @@
1146         int ndx = -1;
1147         int pos = 0;
1148         size_t j;
1149 -       
1150 -       /* generate unique index if neccesary */
1151 +
1152 +       /* generate unique index if necessary */
1153         if (str->key->used == 0 || str->is_index_key) {
1154                 buffer_copy_long(str->key, a->unique_ndx++);
1155                 str->is_index_key = 1;
1156         }
1157 -       
1158 +
1159         /* try to find the string */
1160         if (-1 != (ndx = array_get_index(a, str->key->ptr, str->key->used, &pos))) {
1161                 /* found, leave here */
1162 @@ -181,14 +181,14 @@
1163                 }
1164                 return 0;
1165         }
1166 -       
1167 +
1168         /* insert */
1169 -       
1170 +
1171         if (a->used+1 > INT_MAX) {
1172                 /* we can't handle more then INT_MAX entries: see array_get_index() */
1173                 return -1;
1174         }
1175 -       
1176 +
1177         if (a->size == 0) {
1178                 a->size   = 16;
1179                 a->data   = malloc(sizeof(*a->data)     * a->size);
1180 @@ -204,27 +204,27 @@
1181                 assert(a->sorted);
1182                 for (j = a->used; j < a->size; j++) a->data[j] = NULL;
1183         }
1184 -       
1185 +
1186         ndx = (int) a->used;
1187 -       
1188 +
1189         a->data[a->used++] = str;
1190 -       
1191 +
1192         if (pos != ndx &&
1193 -           ((pos < 0) || 
1194 +           ((pos < 0) ||
1195              buffer_caseless_compare(str->key->ptr, str->key->used, a->data[a->sorted[pos]]->key->ptr, a->data[a->sorted[pos]]->key->used) > 0)) {
1196                 pos++;
1197 -       } 
1198 -       
1199 -       /* move everything on step to the right */
1200 +       }
1201 +
1202 +       /* move everything one step to the right */
1203         if (pos != ndx) {
1204                 memmove(a->sorted + (pos + 1), a->sorted + (pos), (ndx - pos) * sizeof(*a->sorted));
1205         }
1206 -       
1207 +
1208         /* insert */
1209         a->sorted[pos] = ndx;
1210 -       
1211 +
1212         if (a->next_power_of_2 == (size_t)ndx) a->next_power_of_2 <<= 1;
1213 -       
1214 +
1215         return 0;
1216  }
1217  
1218 @@ -254,7 +254,7 @@
1219         size_t i;
1220         size_t maxlen;
1221         int oneline = 1;
1222 -       
1223 +
1224         if (a->used > 5) {
1225                 oneline = 0;
1226         }
1227 @@ -314,7 +314,7 @@
1228         }
1229         array_print_indent(depth);
1230         fprintf(stderr, ")");
1231 -       
1232 +
1233         return 0;
1234  }
1235  
1236 @@ -323,47 +323,47 @@
1237         array *a;
1238         data_string *ds;
1239         data_count *dc;
1240 -       
1241 +
1242         UNUSED(argc);
1243         UNUSED(argv);
1244  
1245         a = array_init();
1246 -       
1247 +
1248         ds = data_string_init();
1249         buffer_copy_string(ds->key, "abc");
1250         buffer_copy_string(ds->value, "alfrag");
1251 -       
1252 +
1253         array_insert_unique(a, (data_unset *)ds);
1254 -       
1255 +
1256         ds = data_string_init();
1257         buffer_copy_string(ds->key, "abc");
1258         buffer_copy_string(ds->value, "hameplman");
1259 -       
1260 +
1261         array_insert_unique(a, (data_unset *)ds);
1262 -       
1263 +
1264         ds = data_string_init();
1265         buffer_copy_string(ds->key, "123");
1266         buffer_copy_string(ds->value, "alfrag");
1267 -       
1268 +
1269         array_insert_unique(a, (data_unset *)ds);
1270 -       
1271 +
1272         dc = data_count_init();
1273         buffer_copy_string(dc->key, "def");
1274 -       
1275 +
1276         array_insert_unique(a, (data_unset *)dc);
1277 -       
1278 +
1279         dc = data_count_init();
1280         buffer_copy_string(dc->key, "def");
1281 -       
1282 +
1283         array_insert_unique(a, (data_unset *)dc);
1284 -       
1285 +
1286         array_print(a, 0);
1287 -       
1288 +
1289         array_free(a);
1290 -       
1291 +
1292         fprintf(stderr, "%d\n",
1293                buffer_caseless_compare(CONST_STR_LEN("Content-Type"), CONST_STR_LEN("Content-type")));
1294 -       
1295 +
1296         return 0;
1297  }
1298  #endif
1299 --- ../lighttpd-1.4.11/src/array.h      2005-09-23 21:24:18.000000000 +0300
1300 +++ lighttpd-1.5.0/src/array.h  2006-09-07 00:57:05.000000000 +0300
1301 @@ -16,7 +16,7 @@
1302  #define DATA_UNSET \
1303         data_type_t type; \
1304         buffer *key; \
1305 -       int is_index_key; /* 1 if key is a array index (autogenerated keys) */ \
1306 +       int is_index_key; /* 1 if key is an array index (auto-generated keys) */ \
1307         struct data_unset *(*copy)(const struct data_unset *src); \
1308         void (* free)(struct data_unset *p); \
1309         void (* reset)(struct data_unset *p); \
1310 @@ -29,21 +29,21 @@
1311  
1312  typedef struct {
1313         data_unset  **data;
1314 -       
1315 +
1316         size_t *sorted;
1317 -       
1318 +
1319         size_t used;
1320         size_t size;
1321 -       
1322 +
1323         size_t unique_ndx;
1324 -       
1325 +
1326         size_t next_power_of_2;
1327         int is_weakref; /* data is weakref, don't bother the data */
1328  } array;
1329  
1330  typedef struct {
1331         DATA_UNSET;
1332 -       
1333 +
1334         int count;
1335  } data_count;
1336  
1337 @@ -51,7 +51,7 @@
1338  
1339  typedef struct {
1340         DATA_UNSET;
1341 -       
1342 +
1343         buffer *value;
1344  } data_string;
1345  
1346 @@ -60,21 +60,39 @@
1347  
1348  typedef struct {
1349         DATA_UNSET;
1350 -       
1351 +
1352         array *value;
1353  } data_array;
1354  
1355  data_array *data_array_init(void);
1356  
1357 -typedef enum { CONFIG_COND_UNSET, CONFIG_COND_EQ, CONFIG_COND_MATCH, CONFIG_COND_NE, CONFIG_COND_NOMATCH } config_cond_t;
1358 +/**
1359 + * possible compare ops in the configfile parser
1360 + */
1361 +typedef enum { 
1362 +       CONFIG_COND_UNSET, 
1363 +       CONFIG_COND_EQ,      /** == */
1364 +       CONFIG_COND_MATCH,   /** =~ */
1365 +       CONFIG_COND_NE,      /** != */
1366 +       CONFIG_COND_NOMATCH  /** !~ */
1367 +} config_cond_t;
1368  
1369 -#define PATCHES NULL, "SERVERsocket", "HTTPurl", "HTTPhost", "HTTPreferer", "HTTPuseragent", "HTTPcookie", "HTTPremoteip"
1370 +/**
1371 + * possible fields to match against
1372 + */
1373  typedef enum {
1374         COMP_UNSET,
1375 -       COMP_SERVER_SOCKET, COMP_HTTP_URL, COMP_HTTP_HOST, COMP_HTTP_REFERER, COMP_HTTP_USERAGENT, COMP_HTTP_COOKIE, COMP_HTTP_REMOTEIP
1376 +       COMP_SERVER_SOCKET, 
1377 +       COMP_HTTP_URL, 
1378 +       COMP_HTTP_HOST, 
1379 +       COMP_HTTP_REFERER, 
1380 +       COMP_HTTP_USERAGENT, 
1381 +       COMP_HTTP_COOKIE, 
1382 +       COMP_HTTP_REMOTEIP,
1383 +       COMP_HTTP_QUERYSTRING
1384  } comp_key_t;
1385  
1386 -/* $HTTP["host"] ==    "incremental.home.kneschke.de" { ... } 
1387 +/* $HTTP["host"] ==    "incremental.home.kneschke.de" { ... }
1388   * for print:   comp_key      op    string
1389   * for compare: comp          cond  string/regex
1390   */
1391 @@ -82,15 +100,15 @@
1392  typedef struct _data_config data_config;
1393  struct _data_config {
1394         DATA_UNSET;
1395 -       
1396 +
1397         array *value;
1398 -       
1399 +
1400         buffer *comp_key;
1401         comp_key_t comp;
1402 -       
1403 +
1404         config_cond_t cond;
1405         buffer *op;
1406 -       
1407 +
1408         int context_ndx; /* more or less like an id */
1409         array *childs;
1410         /* nested */
1411 @@ -98,7 +116,7 @@
1412         /* for chaining only */
1413         data_config *prev;
1414         data_config *next;
1415 -       
1416 +
1417         buffer *string;
1418  #ifdef HAVE_PCRE_H
1419         pcre   *regex;
1420 @@ -110,7 +128,7 @@
1421  
1422  typedef struct {
1423         DATA_UNSET;
1424 -       
1425 +
1426         int value;
1427  } data_integer;
1428  
1429 @@ -120,13 +138,13 @@
1430         DATA_UNSET;
1431  
1432         buffer *host;
1433 -       
1434 +
1435         unsigned short port;
1436  
1437         time_t disable_ts;
1438         int is_disabled;
1439         size_t balance;
1440 -               
1441 +
1442         int usage; /* fair-balancing needs the no. of connections active on this host */
1443         int last_used_ndx; /* round robin */
1444  } data_fastcgi;
1445 --- ../lighttpd-1.4.11/src/base.h       2006-01-11 16:51:04.000000000 +0200
1446 +++ lighttpd-1.5.0/src/base.h   2006-09-07 00:57:05.000000000 +0300
1447 @@ -2,7 +2,6 @@
1448  #define _BASE_H_
1449  
1450  #include <sys/types.h>
1451 -#include <sys/time.h>
1452  #include <sys/stat.h>
1453  
1454  #ifdef HAVE_CONFIG_H
1455 @@ -25,11 +24,11 @@
1456  #include "fdevent.h"
1457  #include "sys-socket.h"
1458  #include "splaytree.h"
1459 -
1460 +#include "http_req.h"
1461  
1462  #if defined HAVE_LIBSSL && defined HAVE_OPENSSL_SSL_H
1463  # define USE_OPENSSL
1464 -# include <openssl/ssl.h> 
1465 +# include <openssl/ssl.h>
1466  #endif
1467  
1468  #ifdef HAVE_FAM_H
1469 @@ -40,10 +39,6 @@
1470  # define O_BINARY 0
1471  #endif
1472  
1473 -#ifndef O_LARGEFILE
1474 -# define O_LARGEFILE 0
1475 -#endif
1476 -
1477  #ifndef SIZE_MAX
1478  # ifdef SIZE_T_MAX
1479  #  define SIZE_MAX SIZE_T_MAX
1480 @@ -70,7 +65,8 @@
1481  
1482  /* solaris and NetBSD 1.3.x again */
1483  #if (!defined(HAVE_STDINT_H)) && (!defined(HAVE_INTTYPES_H)) && (!defined(uint32_t))
1484 -# define uint32_t u_int32_t
1485 +/* # define uint32_t u_int32_t */
1486 +typedef unsigned __int32 uint32_t;
1487  #endif
1488  
1489  
1490 @@ -80,24 +76,25 @@
1491  
1492  #include "settings.h"
1493  
1494 -typedef enum { T_CONFIG_UNSET, 
1495 -               T_CONFIG_STRING, 
1496 -               T_CONFIG_SHORT, 
1497 -               T_CONFIG_BOOLEAN, 
1498 -               T_CONFIG_ARRAY, 
1499 -               T_CONFIG_LOCAL, 
1500 -               T_CONFIG_DEPRECATED
1501 +typedef enum { T_CONFIG_UNSET,
1502 +               T_CONFIG_STRING,
1503 +               T_CONFIG_SHORT,
1504 +               T_CONFIG_BOOLEAN,
1505 +               T_CONFIG_ARRAY,
1506 +               T_CONFIG_LOCAL,
1507 +               T_CONFIG_DEPRECATED,
1508 +               T_CONFIG_UNSUPPORTED
1509  } config_values_type_t;
1510  
1511 -typedef enum { T_CONFIG_SCOPE_UNSET, 
1512 -               T_CONFIG_SCOPE_SERVER, 
1513 +typedef enum { T_CONFIG_SCOPE_UNSET,
1514 +               T_CONFIG_SCOPE_SERVER,
1515                 T_CONFIG_SCOPE_CONNECTION
1516  } config_scope_type_t;
1517  
1518  typedef struct {
1519         const char *key;
1520         void *destination;
1521 -       
1522 +
1523         config_values_type_t type;
1524         config_scope_type_t scope;
1525  } config_values_t;
1526 @@ -118,64 +115,38 @@
1527         short factor;
1528  } fcgi_connections;
1529  
1530 -
1531 -typedef union {
1532 -#ifdef HAVE_IPV6
1533 -       struct sockaddr_in6 ipv6;
1534 -#endif
1535 -       struct sockaddr_in ipv4;
1536 -#ifdef HAVE_SYS_UN_H
1537 -       struct sockaddr_un un;
1538 -#endif
1539 -       struct sockaddr plain;
1540 -} sock_addr;
1541 -
1542 -/* fcgi_response_header contains ... */
1543 -#define HTTP_STATUS         BV(0)
1544 -#define HTTP_CONNECTION     BV(1)
1545 -#define HTTP_CONTENT_LENGTH BV(2)
1546 -#define HTTP_DATE           BV(3)
1547 -#define HTTP_LOCATION       BV(4)
1548 -
1549  typedef struct {
1550         /** HEADER */
1551         /* the request-line */
1552         buffer *request;
1553         buffer *uri;
1554 -       
1555 +
1556         buffer *orig_uri;
1557 -       
1558 +
1559         http_method_t  http_method;
1560         http_version_t http_version;
1561 -       
1562 -       buffer *request_line;
1563 -       
1564 -       /* strings to the header */
1565 -       buffer *http_host; /* not alloced */
1566 -       const char   *http_range;
1567 -       const char   *http_content_type;
1568 -       const char   *http_if_modified_since;
1569 -       const char   *http_if_none_match;
1570 -       
1571 +
1572 +       buffer *http_host;
1573 +
1574         array  *headers;
1575 -       
1576 +
1577         /* CONTENT */
1578 -       size_t content_length; /* returned by strtoul() */
1579 -       
1580 +       off_t   content_length; /* returned by strtoul() */
1581 +
1582         /* internal representation */
1583         int     accept_encoding;
1584 -       
1585 +
1586         /* internal */
1587         buffer *pathinfo;
1588  } request;
1589  
1590  typedef struct {
1591         off_t   content_length;
1592 -       int     keep_alive;               /* used by  the subrequests in proxy, cgi and fcgi to say the subrequest was keep-alive or not */
1593 -       
1594 +       int     keep_alive;               /* used by the subrequests in proxy, cgi and fcgi to say whether the subrequest was keep-alive or not */
1595 +
1596         array  *headers;
1597 -       
1598 -       enum { 
1599 +
1600 +       enum {
1601                 HTTP_TRANSFER_ENCODING_IDENTITY, HTTP_TRANSFER_ENCODING_CHUNKED
1602         } transfer_encoding;
1603  } response;
1604 @@ -191,21 +162,25 @@
1605  typedef struct {
1606         buffer *path;
1607         buffer *basedir; /* path = "(basedir)(.*)" */
1608 -       
1609 +
1610         buffer *doc_root; /* path = doc_root + rel_path */
1611         buffer *rel_path;
1612 -       
1613 +
1614         buffer *etag;
1615  } physical;
1616  
1617  typedef struct {
1618         buffer *name;
1619         buffer *etag;
1620 -       
1621 +
1622         struct stat st;
1623 -       
1624 +
1625         time_t stat_ts;
1626 -       
1627 +
1628 +#ifdef HAVE_LSTAT
1629 +       char is_symlink;
1630 +#endif
1631 +
1632  #ifdef HAVE_FAM_H
1633         int    dir_version;
1634         int    dir_ndx;
1635 @@ -215,20 +190,20 @@
1636  } stat_cache_entry;
1637  
1638  typedef struct {
1639 -       splay_tree *files; /* the nodes of the tree are stat_cache_entry's */
1640 -       
1641 +       splay_tree *files; /* the nodes of the tree are stat_cache_entries */
1642 +
1643         buffer *dir_name; /* for building the dirname from the filename */
1644  #ifdef HAVE_FAM_H
1645         splay_tree *dirs; /* the nodes of the tree are fam_dir_entry */
1646  
1647         FAMConnection *fam;
1648 -       int    fam_fcce_ndx;
1649 +       iosocket *sock;
1650  #endif
1651  } stat_cache;
1652  
1653  typedef struct {
1654         array *mimetypes;
1655 -       
1656 +
1657         /* virtual-servers */
1658         buffer *document_root;
1659         buffer *server_name;
1660 @@ -236,7 +211,7 @@
1661         buffer *server_tag;
1662         buffer *dirlist_encoding;
1663         buffer *errorfile_prefix;
1664 -       
1665 +
1666         unsigned short max_keep_alive_requests;
1667         unsigned short max_keep_alive_idle;
1668         unsigned short max_read_idle;
1669 @@ -244,16 +219,17 @@
1670         unsigned short use_xattr;
1671         unsigned short follow_symlink;
1672         unsigned short range_requests;
1673 -       
1674 +
1675         /* debug */
1676 -       
1677 +
1678         unsigned short log_file_not_found;
1679         unsigned short log_request_header;
1680         unsigned short log_request_handling;
1681         unsigned short log_response_header;
1682         unsigned short log_condition_handling;
1683 -       
1684 -       
1685 +       unsigned short log_condition_cache_handling;
1686 +
1687 +
1688         /* server wide */
1689         buffer *ssl_pemfile;
1690         buffer *ssl_ca_file;
1691 @@ -268,22 +244,22 @@
1692         /* configside */
1693         unsigned short global_kbytes_per_second; /*  */
1694  
1695 -       off_t  global_bytes_per_second_cnt; 
1696 +       off_t  global_bytes_per_second_cnt;
1697         /* server-wide traffic-shaper
1698 -        * 
1699 +        *
1700          * each context has the counter which is inited once
1701 -        * a second by the global_kbytes_per_second config-var
1702 +        * per second by the global_kbytes_per_second config-var
1703          *
1704          * as soon as global_kbytes_per_second gets below 0
1705          * the connected conns are "offline" a little bit
1706          *
1707          * the problem:
1708 -        * we somehow have to loose our "we are writable" signal 
1709 +        * we somehow have to lose our "we are writable" signal
1710          * on the way.
1711 -        * 
1712 +        *
1713          */
1714         off_t *global_bytes_per_second_cnt_ptr; /*  */
1715 -       
1716 +
1717  #ifdef USE_OPENSSL
1718         SSL_CTX *ssl_ctx;
1719  #endif
1720 @@ -291,18 +267,19 @@
1721  
1722  /* the order of the items should be the same as they are processed
1723   * read before write as we use this later */
1724 -typedef enum { 
1725 -       CON_STATE_CONNECT, 
1726 -       CON_STATE_REQUEST_START, 
1727 -       CON_STATE_READ, 
1728 -       CON_STATE_REQUEST_END, 
1729 -       CON_STATE_READ_POST, 
1730 -       CON_STATE_HANDLE_REQUEST, 
1731 -       CON_STATE_RESPONSE_START, 
1732 -       CON_STATE_WRITE, 
1733 -       CON_STATE_RESPONSE_END, 
1734 -       CON_STATE_ERROR, 
1735 -       CON_STATE_CLOSE 
1736 +typedef enum {
1737 +       CON_STATE_CONNECT,         /** we are wait for a connect */
1738 +       CON_STATE_REQUEST_START,   /** after the connect, the request is initialized, keep-alive starts here again */
1739 +       CON_STATE_READ_REQUEST_HEADER,   /** loop in the read-request-header until the full header is received */
1740 +       CON_STATE_VALIDATE_REQUEST_HEADER,   /** validate the request-header */
1741 +       CON_STATE_HANDLE_REQUEST_HEADER, /** find a handler for the request */
1742 +       CON_STATE_READ_REQUEST_CONTENT,  /** forward the request content to the handler */
1743 +       CON_STATE_HANDLE_RESPONSE_HEADER, /** the backend bounces the response back to the client */
1744 +       CON_STATE_WRITE_RESPONSE_HEADER,
1745 +       CON_STATE_WRITE_RESPONSE_CONTENT,
1746 +       CON_STATE_RESPONSE_END,
1747 +       CON_STATE_ERROR,
1748 +       CON_STATE_CLOSE
1749  } connection_state_t;
1750  
1751  typedef enum { COND_RESULT_UNSET, COND_RESULT_FALSE, COND_RESULT_TRUE } cond_result_t;
1752 @@ -315,91 +292,87 @@
1753  
1754  typedef struct {
1755         connection_state_t state;
1756 -       
1757 +
1758         /* timestamps */
1759         time_t read_idle_ts;
1760         time_t close_timeout_ts;
1761         time_t write_request_ts;
1762 -       
1763 +
1764         time_t connection_start;
1765         time_t request_start;
1766 -       
1767 +
1768         struct timeval start_tv;
1769 -       
1770 +
1771         size_t request_count;        /* number of requests handled in this connection */
1772         size_t loops_per_request;    /* to catch endless loops in a single request
1773 -                                     * 
1774 +                                     *
1775                                       * used by mod_rewrite, mod_fastcgi, ... and others
1776                                       * this is self-protection
1777                                       */
1778 -       
1779 -       int fd;                      /* the FD for this connection */
1780 -       int fde_ndx;                 /* index for the fdevent-handler */
1781 +
1782 +       iosocket *sock;
1783         int ndx;                     /* reverse mapping to server->connection[ndx] */
1784 -       
1785 +
1786         /* fd states */
1787         int is_readable;
1788         int is_writable;
1789 -       
1790 -       int     keep_alive;           /* only request.c can enable it, all other just disable */
1791 -       
1792 +
1793 +       int     keep_alive;          /* only request.c can enable it, all others just disable */
1794 +
1795         int file_started;
1796 -       int file_finished;
1797 -       
1798 -       chunkqueue *write_queue;      /* a large queue for low-level write ( HTTP response ) [ file, mem ] */
1799 -       chunkqueue *read_queue;       /* a small queue for low-level read ( HTTP request ) [ mem ] */
1800 -       chunkqueue *request_content_queue; /* takes request-content into tempfile if necessary [ tempfile, mem ]*/
1801 -       
1802 +
1803 +       chunkqueue *send;            /* the response-content without encoding */
1804 +       chunkqueue *recv;            /* the request-content, without encoding */
1805 +
1806 +       chunkqueue *send_raw;        /* the full response (HTTP-Header + compression + chunking ) */
1807 +       chunkqueue *recv_raw;        /* the full request (HTTP-Header + chunking ) */
1808 +
1809         int traffic_limit_reached;
1810 -       
1811 +
1812         off_t bytes_written;          /* used by mod_accesslog, mod_rrd */
1813         off_t bytes_written_cur_second; /* used by mod_accesslog, mod_rrd */
1814         off_t bytes_read;             /* used by mod_accesslog, mod_rrd */
1815         off_t bytes_header;
1816 -       
1817 +
1818         int http_status;
1819 -       
1820 +
1821         sock_addr dst_addr;
1822         buffer *dst_addr_buf;
1823  
1824         /* request */
1825         buffer *parse_request;
1826 -       unsigned int parsed_response; /* bitfield which contains the important header-fields of the parsed response header */
1827 -       
1828 +
1829 +       http_req *http_req;
1830         request  request;
1831         request_uri uri;
1832 -       physical physical; 
1833 +       physical physical;
1834         response response;
1835 -       
1836 +
1837         size_t header_len;
1838 -       
1839 +
1840         buffer *authed_user;
1841         array  *environment; /* used to pass lighttpd internal stuff to the FastCGI/CGI apps, setenv does that */
1842 -       
1843 +
1844         /* response */
1845         int    got_response;
1846 -       
1847 +
1848         int    in_joblist;
1849 -       
1850 +
1851         connection_type mode;
1852 -       
1853 +
1854         void **plugin_ctx;           /* plugin connection specific config */
1855 -       
1856 +
1857         specific_config conf;        /* global connection specific config */
1858         cond_cache_t *cond_cache;
1859 -       
1860 +
1861         buffer *server_name;
1862 -       
1863 +
1864         /* error-handler */
1865         buffer *error_handler;
1866         int error_handler_saved_status;
1867         int in_error_handler;
1868 -       
1869 +
1870         void *srv_socket;   /* reference to the server-socket (typecast to server_socket) */
1871 -       
1872 -#ifdef USE_OPENSSL
1873 -       SSL *ssl;
1874 -#endif
1875  } connection;
1876  
1877  typedef struct {
1878 @@ -439,55 +412,63 @@
1879         size_t size;
1880  } buffer_plugin;
1881  
1882 +typedef enum {
1883 +    NETWORK_STATUS_UNSET,
1884 +    NETWORK_STATUS_SUCCESS,
1885 +    NETWORK_STATUS_FATAL_ERROR,
1886 +    NETWORK_STATUS_CONNECTION_CLOSE,
1887 +    NETWORK_STATUS_WAIT_FOR_EVENT,
1888 +    NETWORK_STATUS_INTERRUPTED
1889 +} network_status_t;
1890 +
1891  typedef struct {
1892         unsigned short port;
1893         buffer *bindhost;
1894 -       
1895 -       buffer *errorlog_file;
1896 -       unsigned short errorlog_use_syslog;
1897 -       
1898 +
1899         unsigned short dont_daemonize;
1900         buffer *changeroot;
1901         buffer *username;
1902         buffer *groupname;
1903 -       
1904 +
1905         buffer *pid_file;
1906 -       
1907 +
1908         buffer *event_handler;
1909 -       
1910 +
1911         buffer *modules_dir;
1912         buffer *network_backend;
1913         array *modules;
1914         array *upload_tempdirs;
1915 -       
1916 +
1917         unsigned short max_worker;
1918         unsigned short max_fds;
1919         unsigned short max_conns;
1920         unsigned short max_request_size;
1921 -       
1922 +
1923         unsigned short log_request_header_on_error;
1924         unsigned short log_state_handling;
1925 -       
1926 -       enum { STAT_CACHE_ENGINE_UNSET, 
1927 -                       STAT_CACHE_ENGINE_NONE, 
1928 -                       STAT_CACHE_ENGINE_SIMPLE, 
1929 -                       STAT_CACHE_ENGINE_FAM 
1930 +
1931 +       enum { STAT_CACHE_ENGINE_UNSET,
1932 +                       STAT_CACHE_ENGINE_NONE,
1933 +                       STAT_CACHE_ENGINE_SIMPLE,
1934 +                       STAT_CACHE_ENGINE_FAM
1935         } stat_cache_engine;
1936         unsigned short enable_cores;
1937 +
1938 +       buffer *errorlog_file;
1939 +       unsigned short errorlog_use_syslog;
1940  } server_config;
1941  
1942  typedef struct {
1943         sock_addr addr;
1944 -       int       fd;
1945 -       int       fde_ndx;
1946 -       
1947 +       iosocket *sock;
1948 +
1949         buffer *ssl_pemfile;
1950         buffer *ssl_ca_file;
1951         unsigned short use_ipv6;
1952         unsigned short is_ssl;
1953 -       
1954 +
1955         buffer *srv_token;
1956 -       
1957 +
1958  #ifdef USE_OPENSSL
1959         SSL_CTX *ssl_ctx;
1960  #endif
1961 @@ -495,37 +476,32 @@
1962  
1963  typedef struct {
1964         server_socket **ptr;
1965 -       
1966 +
1967         size_t size;
1968         size_t used;
1969  } server_socket_array;
1970  
1971  typedef struct server {
1972         server_socket_array srv_sockets;
1973 -       
1974 -       /* the errorlog */
1975 -       int errorlog_fd;
1976 -       enum { ERRORLOG_STDERR, ERRORLOG_FILE, ERRORLOG_SYSLOG } errorlog_mode;
1977 -       buffer *errorlog_buf;
1978 -       
1979 +
1980         fdevents *ev, *ev_ins;
1981 -       
1982 +
1983         buffer_plugin plugins;
1984         void *plugin_slots;
1985 -       
1986 +
1987         /* counters */
1988         int con_opened;
1989         int con_read;
1990         int con_written;
1991         int con_closed;
1992 -       
1993 +
1994         int ssl_is_init;
1995 -       
1996 +
1997         int max_fds;    /* max possible fds */
1998         int cur_fds;    /* currently used fds */
1999         int want_fds;   /* waiting fds */
2000         int sockets_disabled;
2001 -       
2002 +
2003         size_t max_conns;
2004  
2005         /* buffers */
2006 @@ -533,13 +509,13 @@
2007         buffer *response_header;
2008         buffer *response_range;
2009         buffer *tmp_buf;
2010 -       
2011 +
2012         buffer *tmp_chunk_len;
2013 -       
2014 +
2015         buffer *empty_string; /* is necessary for cond_match */
2016  
2017         buffer *cond_check_buf;
2018 -       
2019 +
2020         /* caches */
2021  #ifdef HAVE_IPV6
2022         inet_ntop_cache_type inet_ntop_cache[INET_NTOP_CACHE_MAX];
2023 @@ -547,59 +523,47 @@
2024         mtime_cache_type mtime_cache[FILE_CACHE_MAX];
2025  
2026         array *split_vals;
2027 -       
2028 +
2029         /* Timestamps */
2030         time_t cur_ts;
2031         time_t last_generated_date_ts;
2032         time_t last_generated_debug_ts;
2033         time_t startup_ts;
2034 -       
2035 +
2036         buffer *ts_debug_str;
2037         buffer *ts_date_str;
2038 -       
2039 +
2040         /* config-file */
2041         array *config;
2042         array *config_touched;
2043 -       
2044 +
2045         array *config_context;
2046         specific_config **config_storage;
2047 -       
2048 +
2049         server_config  srvconf;
2050 -       
2051 -       int config_deprecated;
2052 -       
2053 +
2054 +       short unsigned config_deprecated;
2055 +       short unsigned config_unsupported;
2056 +
2057         connections *conns;
2058         connections *joblist;
2059         connections *fdwaitqueue;
2060 -       
2061 +
2062         stat_cache  *stat_cache;
2063  
2064 -       /**
2065 -        * The status array can carry all the status information you want
2066 -        * the key to the array is <module-prefix>.<name>
2067 -        * and the values are counters
2068 -        *
2069 -        * example:
2070 -        *   fastcgi.backends        = 10
2071 -        *   fastcgi.active-backends = 6
2072 -        *   fastcgi.backend.<key>.load = 24
2073 -        *   fastcgi.backend.<key>....
2074 -        *
2075 -        *   fastcgi.backend.<key>.disconnects = ...
2076 -        */
2077 -       array *status;
2078 -       
2079         fdevent_handler_t event_handler;
2080  
2081 -       int (* network_backend_write)(struct server *srv, connection *con, int fd, chunkqueue *cq);
2082 -       int (* network_backend_read)(struct server *srv, connection *con, int fd, chunkqueue *cq);
2083 +       network_status_t (* network_backend_write)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
2084 +       network_status_t (* network_backend_read)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
2085  #ifdef USE_OPENSSL
2086 -       int (* network_ssl_backend_write)(struct server *srv, connection *con, SSL *ssl, chunkqueue *cq);
2087 -       int (* network_ssl_backend_read)(struct server *srv, connection *con, SSL *ssl, chunkqueue *cq);
2088 +       network_status_t (* network_ssl_backend_write)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
2089 +       network_status_t (* network_ssl_backend_read)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
2090  #endif
2091  
2092 +#ifdef HAVE_PWD_H
2093         uid_t uid;
2094         gid_t gid;
2095 +#endif
2096  } server;
2097  
2098  
2099 --- ../lighttpd-1.4.11/src/bitset.c     2005-08-22 01:54:12.000000000 +0300
2100 +++ lighttpd-1.5.0/src/bitset.c 2006-07-18 13:03:40.000000000 +0300
2101 @@ -6,6 +6,7 @@
2102  
2103  #include "bitset.h"
2104  #include "buffer.h"
2105 +#include "log.h"
2106  
2107  #define BITSET_BITS \
2108         ( CHAR_BIT * sizeof(size_t) )
2109 --- ../lighttpd-1.4.11/src/buffer.c     2006-01-13 00:00:45.000000000 +0200
2110 +++ lighttpd-1.5.0/src/buffer.c 2006-07-18 13:03:40.000000000 +0300
2111 @@ -12,20 +12,20 @@
2112  
2113  
2114  /**
2115 - * init the buffer 
2116 - * 
2117 + * init the buffer
2118 + *
2119   */
2120  
2121  buffer* buffer_init(void) {
2122         buffer *b;
2123 -       
2124 +
2125         b = malloc(sizeof(*b));
2126         assert(b);
2127 -       
2128 +
2129         b->ptr = NULL;
2130         b->size = 0;
2131         b->used = 0;
2132 -       
2133 +
2134         return b;
2135  }
2136  
2137 @@ -36,8 +36,8 @@
2138  }
2139  
2140  /**
2141 - * free the buffer 
2142 - * 
2143 + * free the buffer
2144 + *
2145   */
2146  
2147  void buffer_free(buffer *b) {
2148 @@ -49,39 +49,39 @@
2149  
2150  void buffer_reset(buffer *b) {
2151         if (!b) return;
2152 -       
2153 +
2154         /* limit don't reuse buffer larger than ... bytes */
2155         if (b->size > BUFFER_MAX_REUSE_SIZE) {
2156                 free(b->ptr);
2157                 b->ptr = NULL;
2158                 b->size = 0;
2159         }
2160 -       
2161 +
2162         b->used = 0;
2163  }
2164  
2165  
2166  /**
2167 - * 
2168 - * allocate (if neccessary) enough space for 'size' bytes and 
2169 + *
2170 + * allocate (if necessary) enough space for 'size' bytes and
2171   * set the 'used' counter to 0
2172 - * 
2173 + *
2174   */
2175  
2176  #define BUFFER_PIECE_SIZE 64
2177  
2178  int buffer_prepare_copy(buffer *b, size_t size) {
2179         if (!b) return -1;
2180 -       
2181 -       if ((0 == b->size) || 
2182 +
2183 +       if ((0 == b->size) ||
2184             (size > b->size)) {
2185                 if (b->size) free(b->ptr);
2186 -               
2187 +
2188                 b->size = size;
2189 -               
2190 -               /* always allocate a multiply of BUFFER_PIECE_SIZE */
2191 +
2192 +               /* always allocate a multiple of BUFFER_PIECE_SIZE */
2193                 b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
2194 -               
2195 +
2196                 b->ptr = malloc(b->size);
2197                 assert(b->ptr);
2198         }
2199 @@ -90,30 +90,30 @@
2200  }
2201  
2202  /**
2203 - * 
2204 - * increase the internal buffer (if neccessary) to append another 'size' byte
2205 + *
2206 + * increase the internal buffer (if necessary) to append another 'size' byte
2207   * ->used isn't changed
2208 - * 
2209 + *
2210   */
2211  
2212  int buffer_prepare_append(buffer *b, size_t size) {
2213         if (!b) return -1;
2214 -       
2215 +
2216         if (0 == b->size) {
2217                 b->size = size;
2218 -               
2219 -               /* always allocate a multiply of BUFFER_PIECE_SIZE */
2220 +
2221 +               /* always allocate a multiple of BUFFER_PIECE_SIZE */
2222                 b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
2223 -               
2224 +
2225                 b->ptr = malloc(b->size);
2226                 b->used = 0;
2227                 assert(b->ptr);
2228         } else if (b->used + size > b->size) {
2229                 b->size += size;
2230 -               
2231 -               /* always allocate a multiply of BUFFER_PIECE_SIZE */
2232 +
2233 +               /* always allocate a multiple of BUFFER_PIECE_SIZE */
2234                 b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
2235 -               
2236 +
2237                 b->ptr = realloc(b->ptr, b->size);
2238                 assert(b->ptr);
2239         }
2240 @@ -122,7 +122,7 @@
2241  
2242  int buffer_copy_string(buffer *b, const char *s) {
2243         size_t s_len;
2244 -       
2245 +
2246         if (!s || !b) return -1;
2247  
2248         s_len = strlen(s) + 1;
2249 @@ -136,26 +136,26 @@
2250  
2251  int buffer_copy_string_len(buffer *b, const char *s, size_t s_len) {
2252         if (!s || !b) return -1;
2253 -#if 0  
2254 -       /* removed optimization as we have to keep the empty string 
2255 +#if 0
2256 +       /* removed optimization as we have to keep the empty string
2257          * in some cases for the config handling
2258 -        * 
2259 +        *
2260          * url.access-deny = ( "" )
2261          */
2262         if (s_len == 0) return 0;
2263 -#endif 
2264 +#endif
2265         buffer_prepare_copy(b, s_len + 1);
2266 -       
2267 +
2268         memcpy(b->ptr, s, s_len);
2269         b->ptr[s_len] = '\0';
2270         b->used = s_len + 1;
2271 -       
2272 +
2273         return 0;
2274  }
2275  
2276  int buffer_copy_string_buffer(buffer *b, const buffer *src) {
2277         if (!src) return -1;
2278 -       
2279 +
2280         if (src->used == 0) {
2281                 b->used = 0;
2282                 return 0;
2283 @@ -201,10 +201,10 @@
2284  
2285  /**
2286   * append a string to the end of the buffer
2287 - * 
2288 - * the resulting buffer is terminated with a '\0' 
2289 - * s is treated as a un-terminated string (a \0 is handled a normal character)
2290 - * 
2291 + *
2292 + * the resulting buffer is terminated with a '\0'
2293 + * s is treated as an un-terminated string (a \0 is handled as a normal character)
2294 + *
2295   * @param b a buffer
2296   * @param s the string
2297   * @param s_len size of the string (without the terminating \0)
2298 @@ -228,7 +228,7 @@
2299  int buffer_append_string_buffer(buffer *b, const buffer *src) {
2300         if (!src) return -1;
2301         if (src->used == 0) return 0;
2302 -       
2303 +
2304         return buffer_append_string_len(b, src->ptr, src->used - 1);
2305  }
2306  
2307 @@ -245,9 +245,9 @@
2308  
2309  int buffer_copy_memory(buffer *b, const char *s, size_t s_len) {
2310         if (!s || !b) return -1;
2311 -       
2312 +
2313         b->used = 0;
2314 -       
2315 +
2316         return buffer_append_memory(b, s, s_len);
2317  }
2318  
2319 @@ -402,46 +402,115 @@
2320  
2321  
2322  /**
2323 - * init the buffer 
2324 - * 
2325 + * init the ptr buffer
2326 + *
2327 + */
2328 +buffer_ptr *buffer_ptr_init(buffer_ptr_free_t freer)
2329 +{
2330 +       buffer_ptr *l = calloc(1, sizeof(buffer_ptr));
2331 +       l->free = freer;
2332 +
2333 +       return l;
2334 +}
2335 +
2336 +/**
2337 + * free the buffer_array
2338 + *
2339 + */
2340 +void buffer_ptr_free(buffer_ptr *l)
2341 +{
2342 +       if (NULL != l) {
2343 +               buffer_ptr_clear(l);
2344 +               free(l);
2345 +       }
2346 +}
2347 +
2348 +void buffer_ptr_clear(buffer_ptr *l)
2349 +{
2350 +       assert(NULL != l);
2351 +
2352 +       if (l->free && l->used) {
2353 +               size_t i;
2354 +               for (i = 0; i < l->used; i ++) {
2355 +                       l->free(l->ptr[i]);
2356 +               }
2357 +       }
2358 +
2359 +       if (l->ptr) {
2360 +               free(l->ptr);
2361 +               l->ptr = NULL;
2362 +       }
2363 +       l->used = 0;
2364 +       l->size = 0;
2365 +}
2366 +
2367 +void buffer_ptr_append(buffer_ptr* l, void *item)
2368 +{
2369 +       assert(NULL != l);
2370 +       if (l->ptr == NULL) {
2371 +               l->size = 16;
2372 +               l->ptr = (void **)malloc(sizeof(void *) * l->size);
2373 +       }
2374 +       else if (l->used == l->size) {
2375 +               l->size += 16;
2376 +               l->ptr = realloc(l->ptr, sizeof(void *) * l->size);
2377 +       }
2378 +       l->ptr[l->used++] = item;
2379 +}
2380 +
2381 +void *buffer_ptr_pop(buffer_ptr* l)
2382 +{
2383 +       assert(NULL != l && l->used > 0);
2384 +       return l->ptr[--l->used];
2385 +}
2386 +
2387 +void *buffer_ptr_top(buffer_ptr* l)
2388 +{
2389 +       assert(NULL != l && l->used > 0);
2390 +       return l->ptr[l->used-1];
2391 +}
2392 +
2393 +/**
2394 + * init the buffer
2395 + *
2396   */
2397  
2398  buffer_array* buffer_array_init(void) {
2399         buffer_array *b;
2400 -       
2401 +
2402         b = malloc(sizeof(*b));
2403 -       
2404 +
2405         assert(b);
2406         b->ptr = NULL;
2407         b->size = 0;
2408         b->used = 0;
2409 -       
2410 +
2411         return b;
2412  }
2413  
2414  void buffer_array_reset(buffer_array *b) {
2415         size_t i;
2416 -       
2417 +
2418         if (!b) return;
2419 -       
2420 +
2421         /* if they are too large, reduce them */
2422         for (i = 0; i < b->used; i++) {
2423                 buffer_reset(b->ptr[i]);
2424         }
2425 -       
2426 +
2427         b->used = 0;
2428  }
2429  
2430  
2431  /**
2432 - * free the buffer_array 
2433 - * 
2434 + * free the buffer_array
2435 + *
2436   */
2437  
2438  void buffer_array_free(buffer_array *b) {
2439         size_t i;
2440         if (!b) return;
2441 -       
2442 +
2443         for (i = 0; i < b->size; i++) {
2444                 if (b->ptr[i]) buffer_free(b->ptr[i]);
2445         }
2446 @@ -451,7 +520,7 @@
2447  
2448  buffer *buffer_array_append_get_buffer(buffer_array *b) {
2449         size_t i;
2450 -       
2451 +
2452         if (b->size == 0) {
2453                 b->size = 16;
2454                 b->ptr = malloc(sizeof(*b->ptr) * b->size);
2455 @@ -467,13 +536,13 @@
2456                         b->ptr[i] = NULL;
2457                 }
2458         }
2459 -       
2460 +
2461         if (b->ptr[b->used] == NULL) {
2462                 b->ptr[b->used] = buffer_init();
2463         }
2464 -       
2465 +
2466         b->ptr[b->used]->used = 0;
2467 -       
2468 +
2469         return b->ptr[b->used++];
2470  }
2471  
2472 @@ -482,23 +551,23 @@
2473         size_t i;
2474         if (len == 0) return NULL;
2475         if (needle == NULL) return NULL;
2476 -       
2477 +
2478         if (b->used < len) return NULL;
2479 -       
2480 +
2481         for(i = 0; i < b->used - len; i++) {
2482                 if (0 == memcmp(b->ptr + i, needle, len)) {
2483                         return b->ptr + i;
2484                 }
2485         }
2486 -       
2487 +
2488         return NULL;
2489  }
2490  
2491  buffer *buffer_init_string(const char *str) {
2492         buffer *b = buffer_init();
2493 -       
2494 +
2495         buffer_copy_string(b, str);
2496 -       
2497 +
2498         return b;
2499  }
2500  
2501 @@ -507,8 +576,8 @@
2502  }
2503  
2504  /**
2505 - * check if two buffer contain the same data
2506 - * 
2507 + * check if two buffers contain the same data
2508 + *
2509   * HISTORY: this function was pretty much optimized, but didn't handled
2510   * alignment properly.
2511   */
2512 @@ -517,105 +586,105 @@
2513         if (a->used != b->used) return 0;
2514         if (a->used == 0) return 1;
2515  
2516 -       return (0 == strcmp(a->ptr, b->ptr));
2517 +       return (0 == strncmp(a->ptr, b->ptr, a->used - 1));
2518  }
2519  
2520  int buffer_is_equal_string(buffer *a, const char *s, size_t b_len) {
2521         buffer b;
2522 -       
2523 +
2524         b.ptr = (char *)s;
2525         b.used = b_len + 1;
2526 -       
2527 +
2528         return buffer_is_equal(a, &b);
2529  }
2530  
2531  /* simple-assumption:
2532 - * 
2533 - * most parts are equal and doing a case conversion needs time
2534 - * 
2535 + *
2536 + * most parts are equal and doing a case conversion takes time
2537 + *
2538   */
2539  int buffer_caseless_compare(const char *a, size_t a_len, const char *b, size_t b_len) {
2540         size_t ndx = 0, max_ndx;
2541         size_t *al, *bl;
2542         size_t mask = sizeof(*al) - 1;
2543 -       
2544 +
2545         al = (size_t *)a;
2546         bl = (size_t *)b;
2547 -       
2548 -       /* is the alignment correct ? */
2549 +
2550 +       /* is the alignment correct? */
2551         if ( ((size_t)al & mask) == 0 &&
2552              ((size_t)bl & mask) == 0 ) {
2553 -               
2554 +
2555                 max_ndx = ((a_len < b_len) ? a_len : b_len) & ~mask;
2556 -               
2557 +
2558                 for (; ndx < max_ndx; ndx += sizeof(*al)) {
2559                         if (*al != *bl) break;
2560                         al++; bl++;
2561 -                       
2562 +
2563                 }
2564 -               
2565 +
2566         }
2567 -       
2568 +
2569         a = (char *)al;
2570         b = (char *)bl;
2571 -       
2572 +
2573         max_ndx = ((a_len < b_len) ? a_len : b_len);
2574 -       
2575 +
2576         for (; ndx < max_ndx; ndx++) {
2577                 char a1 = *a++, b1 = *b++;
2578 -               
2579 +
2580                 if (a1 != b1) {
2581                         if ((a1 >= 'A' && a1 <= 'Z') && (b1 >= 'a' && b1 <= 'z'))
2582                                 a1 |= 32;
2583                         else if ((a1 >= 'a' && a1 <= 'z') && (b1 >= 'A' && b1 <= 'Z'))
2584                                 b1 |= 32;
2585                         if ((a1 - b1) != 0) return (a1 - b1);
2586 -                       
2587 +
2588                 }
2589         }
2590 -       
2591 +
2592         return 0;
2593  }
2594  
2595  
2596  /**
2597   * check if the rightmost bytes of the string are equal.
2598 - * 
2599 - * 
2600 + *
2601 + *
2602   */
2603  
2604  int buffer_is_equal_right_len(buffer *b1, buffer *b2, size_t len) {
2605         /* no, len -> equal */
2606         if (len == 0) return 1;
2607 -       
2608 +
2609         /* len > 0, but empty buffers -> not equal */
2610         if (b1->used == 0 || b2->used == 0) return 0;
2611 -       
2612 +
2613         /* buffers too small -> not equal */
2614 -       if (b1->used - 1 < len || b1->used - 1 < len) return 0;
2615 -       
2616 -       if (0 == strncmp(b1->ptr + b1->used - 1 - len, 
2617 +       if (b1->used - 1 < len || b2->used - 1 < len) return 0;
2618 +
2619 +       if (0 == strncmp(b1->ptr + b1->used - 1 - len,
2620                          b2->ptr + b2->used - 1 - len, len)) {
2621                 return 1;
2622         }
2623 -       
2624 +
2625         return 0;
2626  }
2627  
2628  int buffer_copy_string_hex(buffer *b, const char *in, size_t in_len) {
2629         size_t i;
2630 -       
2631 +
2632         /* BO protection */
2633         if (in_len * 2 < in_len) return -1;
2634 -       
2635 +
2636         buffer_prepare_copy(b, in_len * 2 + 1);
2637 -       
2638 +
2639         for (i = 0; i < in_len; i++) {
2640                 b->ptr[b->used++] = hex_chars[(in[i] >> 4) & 0x0F];
2641                 b->ptr[b->used++] = hex_chars[in[i] & 0x0F];
2642         }
2643         b->ptr[b->used++] = '\0';
2644 -       
2645 +
2646         return 0;
2647  }
2648  
2649 @@ -624,7 +693,7 @@
2650         0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
2651         */
2652         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
2653 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */ 
2654 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
2655         1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1,  /*  20 -  2F space " # $ % & ' + , / */
2656         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,  /*  30 -  3F : ; = ? @ < > */
2657         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F */
2658 @@ -646,7 +715,7 @@
2659         0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
2660         */
2661         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
2662 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */ 
2663 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
2664         1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0,  /*  20 -  2F space " # $ % & ' + , / */
2665         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,  /*  30 -  3F : ; = ? @ < > */
2666         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F */
2667 @@ -668,7 +737,7 @@
2668         0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
2669         */
2670         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
2671 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */ 
2672 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
2673         0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  20 -  2F & */
2674         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0,  /*  30 -  3F < > */
2675         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F */
2676 @@ -690,7 +759,7 @@
2677         0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
2678         */
2679         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
2680 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */ 
2681 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
2682         0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  20 -  2F & */
2683         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0,  /*  30 -  3F < > */
2684         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F */
2685 @@ -712,12 +781,12 @@
2686         0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
2687         */
2688         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
2689 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */ 
2690 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  20 -  2F */ 
2691 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  30 -  3F */ 
2692 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  40 -  4F */ 
2693 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  50 -  5F */ 
2694 -       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  60 -  6F */ 
2695 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
2696 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  20 -  2F */
2697 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  30 -  3F */
2698 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  40 -  4F */
2699 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  50 -  5F */
2700 +       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  60 -  6F */
2701         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  70 -  7F */
2702         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  80 -  8F */
2703         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  90 -  9F */
2704 @@ -734,13 +803,12 @@
2705         unsigned char *ds, *d;
2706         size_t d_len, ndx;
2707         const char *map = NULL;
2708 -       
2709 +
2710         if (!s || !b) return -1;
2711 -       
2712 -       if (b->ptr[b->used - 1] != '\0') {
2713 -               SEGFAULT();
2714 -       }
2715 -       
2716 +       if (b->used == 0) return -1;
2717 +
2718 +       if (b->ptr[b->used - 1] != '\0') return -1;
2719 +
2720         if (s_len == 0) return 0;
2721  
2722         switch(encoding) {
2723 @@ -760,12 +828,12 @@
2724                 map = encoded_chars_hex;
2725                 break;
2726         case ENCODING_UNSET:
2727 -               break;
2728 +               return buffer_append_string_len(b, s, s_len);
2729         }
2730  
2731         assert(map != NULL);
2732 -       
2733 -       /* count to-be-encoded-characters */
2734 +
2735 +       /* count to-be-encoded characters */
2736         for (ds = (unsigned char *)s, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
2737                 if (map[*ds]) {
2738                         switch(encoding) {
2739 @@ -787,9 +855,9 @@
2740                         d_len ++;
2741                 }
2742         }
2743 -       
2744 +
2745         buffer_prepare_append(b, d_len);
2746 -       
2747 +
2748         for (ds = (unsigned char *)s, d = (unsigned char *)b->ptr + b->used - 1, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
2749                 if (map[*ds]) {
2750                         switch(encoding) {
2751 @@ -820,16 +888,16 @@
2752                 }
2753         }
2754  
2755 -       /* terminate buffer and calculate new length */ 
2756 +       /* terminate buffer and calculate new length */
2757         b->ptr[b->used + d_len - 1] = '\0';
2758 -       
2759 +
2760         b->used += d_len;
2761  
2762         return 0;
2763  }
2764  
2765  
2766 -/* decodes url-special-chars inplace.
2767 +/* decodes url-special chars in-place.
2768   * replaces non-printable characters with '_'
2769   */
2770  
2771 @@ -854,10 +922,10 @@
2772                                 low = hex2int(*(src + 2));
2773                                 if (low != 0xFF) {
2774                                         high = (high << 4) | low;
2775 -                                       
2776 -                                       /* map control-characters out */        
2777 +
2778 +                                       /* map out control characters */
2779                                         if (high < 32 || high == 127) high = '_';
2780 -                                       
2781 +
2782                                         *dst = high;
2783                                         src += 2;
2784                                 }
2785 @@ -891,7 +959,7 @@
2786   * /abc/./xyz       gets  /abc/xyz
2787   * /abc//xyz        gets  /abc/xyz
2788   *
2789 - * NOTE: src and dest can point to the same buffer, in which case,
2790 + * NOTE: src and dest can point to the same buffer, in which case
2791   *       the operation is performed in-place.
2792   */
2793  
2794 @@ -979,7 +1047,7 @@
2795  
2796  int light_isxdigit(int c) {
2797         if (light_isdigit(c)) return 1;
2798 -       
2799 +
2800         c |= 32;
2801         return (c >= 'a' && c <= 'f');
2802  }
2803 @@ -993,31 +1061,56 @@
2804         return light_isdigit(c) || light_isalpha(c);
2805  }
2806  
2807 +#undef BUFFER_CTYPE_FUNC
2808 +#define BUFFER_CTYPE_FUNC(type) \
2809 +       int buffer_is##type(buffer *b) { \
2810 +               size_t i, len; \
2811 +               if (b->used < 2) return 0; \
2812 +               /* strlen */ \
2813 +               len = b->used - 1; \
2814 +               /* c-string only */ \
2815 +               if (b->ptr[len] != '\0') { \
2816 +                       return 0; \
2817 +               } \
2818 +               /* check on the whole string */ \
2819 +               for (i = 0; i < len; i ++) { \
2820 +                       if (!light_is##type(b->ptr[i])) { \
2821 +                               return 0; \
2822 +                       } \
2823 +               } \
2824 +               return 1; \
2825 +       }
2826 +
2827 +BUFFER_CTYPE_FUNC(digit)
2828 +BUFFER_CTYPE_FUNC(xdigit)
2829 +BUFFER_CTYPE_FUNC(alpha)
2830 +BUFFER_CTYPE_FUNC(alnum)
2831 +
2832  int buffer_to_lower(buffer *b) {
2833         char *c;
2834 -       
2835 +
2836         if (b->used == 0) return 0;
2837 -       
2838 +
2839         for (c = b->ptr; *c; c++) {
2840                 if (*c >= 'A' && *c <= 'Z') {
2841                         *c |= 32;
2842                 }
2843         }
2844 -       
2845 +
2846         return 0;
2847  }
2848  
2849  
2850  int buffer_to_upper(buffer *b) {
2851         char *c;
2852 -       
2853 +
2854         if (b->used == 0) return 0;
2855 -       
2856 +
2857         for (c = b->ptr; *c; c++) {
2858                 if (*c >= 'a' && *c <= 'z') {
2859                         *c &= ~32;
2860                 }
2861         }
2862 -       
2863 +
2864         return 0;
2865  }
2866 --- ../lighttpd-1.4.11/src/buffer.h     2006-01-13 00:00:45.000000000 +0200
2867 +++ lighttpd-1.5.0/src/buffer.h 2006-07-18 13:03:40.000000000 +0300
2868 @@ -12,27 +12,43 @@
2869  
2870  typedef struct {
2871         char *ptr;
2872 -       
2873 +
2874         size_t used;
2875         size_t size;
2876  } buffer;
2877  
2878 +typedef void (*buffer_ptr_free_t)(void *p);
2879 +
2880 +typedef struct {
2881 +       void **ptr;
2882 +       size_t size;
2883 +       size_t used;
2884 +       buffer_ptr_free_t free;
2885 +} buffer_ptr;
2886 +
2887  typedef struct {
2888         buffer **ptr;
2889 -       
2890 +
2891         size_t used;
2892         size_t size;
2893  } buffer_array;
2894  
2895  typedef struct {
2896         char *ptr;
2897 -       
2898 -       size_t offset; /* input-pointer */
2899 -       
2900 -       size_t used;   /* output-pointer */
2901 +
2902 +       size_t offset; /* input pointer */
2903 +
2904 +       size_t used;   /* output pointer */
2905         size_t size;
2906  } read_buffer;
2907  
2908 +buffer_ptr *buffer_ptr_init(buffer_ptr_free_t freer);
2909 +void buffer_ptr_free(buffer_ptr *b);
2910 +void buffer_ptr_clear(buffer_ptr *b);
2911 +void buffer_ptr_append(buffer_ptr *b, void *item);
2912 +void *buffer_ptr_pop(buffer_ptr *b);
2913 +void *buffer_ptr_top(buffer_ptr *b);
2914 +
2915  buffer_array* buffer_array_init(void);
2916  void buffer_array_free(buffer_array *b);
2917  void buffer_array_reset(buffer_array *b);
2918 @@ -43,7 +59,7 @@
2919  buffer* buffer_init_string(const char *str);
2920  void buffer_free(buffer *b);
2921  void buffer_reset(buffer *b);
2922 -       
2923 +
2924  int buffer_prepare_copy(buffer *b, size_t size);
2925  int buffer_prepare_append(buffer *b, size_t size);
2926  
2927 @@ -85,9 +101,9 @@
2928  
2929  typedef enum {
2930         ENCODING_UNSET,
2931 -       ENCODING_REL_URI, /* for coding a rel-uri (/with space/and%percent) nicely as part of a href */
2932 -       ENCODING_REL_URI_PART, /* same as ENC_REL_URL plus coding / too as %2F */
2933 -       ENCODING_HTML,    /* & becomes &amp; and so on */
2934 +       ENCODING_REL_URI, /* for coding a rel-uri (/with space/and%percent) nicely as part of an href */
2935 +       ENCODING_REL_URI_PART, /* same as ENC_REL_URL plus encoding "/" as "%2F" */
2936 +       ENCODING_HTML,    /* "&" becomes "&amp;" and so on */
2937         ENCODING_MINIMAL_XML, /* minimal encoding for xml */
2938         ENCODING_HEX      /* encode string as hex */
2939  } buffer_encoding_t;
2940 @@ -111,20 +127,23 @@
2941  int light_isalpha(int c);
2942  int light_isalnum(int c);
2943  
2944 +#define BUFFER_CTYPE_FUNC(type) int buffer_is##type(buffer *b);
2945 +BUFFER_CTYPE_FUNC(digit)
2946 +BUFFER_CTYPE_FUNC(xdigit)
2947 +BUFFER_CTYPE_FUNC(alpha)
2948 +BUFFER_CTYPE_FUNC(alnum)
2949 +
2950 +#define BUF_STR(x) x->ptr
2951  #define BUFFER_APPEND_STRING_CONST(x, y) \
2952         buffer_append_string_len(x, y, sizeof(y) - 1)
2953  
2954  #define BUFFER_COPY_STRING_CONST(x, y) \
2955         buffer_copy_string_len(x, y, sizeof(y) - 1)
2956  
2957 -#define BUFFER_APPEND_SLASH(x) \
2958 -       if (x->used > 1 && x->ptr[x->used - 2] != '/') { BUFFER_APPEND_STRING_CONST(x, "/"); }
2959 -
2960  #define CONST_STR_LEN(x) x, x ? sizeof(x) - 1 : 0
2961 -#define CONST_BUF_LEN(x) x->ptr, x->used ? x->used - 1 : 0
2962 +#define CONST_BUF_LEN(x) BUF_STR(x), x->used ? x->used - 1 : 0
2963  
2964 -
2965 -#define SEGFAULT() do { fprintf(stderr, "%s.%d: aborted\n", __FILE__, __LINE__); abort(); } while(0)
2966 +       
2967  #define UNUSED(x) ( (void)(x) )
2968  
2969  #endif
2970 --- ../lighttpd-1.4.11/src/chunk.c      2005-11-18 15:18:19.000000000 +0200
2971 +++ lighttpd-1.5.0/src/chunk.c  2006-09-07 00:57:05.000000000 +0300
2972 @@ -1,16 +1,14 @@
2973  /**
2974   * the network chunk-API
2975 - * 
2976 - * 
2977 + *
2978 + *
2979   */
2980  
2981  #include <sys/types.h>
2982  #include <sys/stat.h>
2983 -#include <sys/mman.h>
2984  
2985  #include <stdlib.h>
2986  #include <fcntl.h>
2987 -#include <unistd.h>
2988  
2989  #include <stdio.h>
2990  #include <errno.h>
2991 @@ -18,36 +16,39 @@
2992  
2993  #include "chunk.h"
2994  
2995 +#include "sys-mmap.h"
2996 +#include "sys-files.h"
2997 +
2998  chunkqueue *chunkqueue_init(void) {
2999         chunkqueue *cq;
3000 -       
3001 +
3002         cq = calloc(1, sizeof(*cq));
3003 -       
3004 +
3005         cq->first = NULL;
3006         cq->last = NULL;
3007 -       
3008 +
3009         cq->unused = NULL;
3010 -       
3011 +
3012         return cq;
3013  }
3014  
3015  static chunk *chunk_init(void) {
3016         chunk *c;
3017 -       
3018 +
3019         c = calloc(1, sizeof(*c));
3020 -       
3021 +
3022         c->mem = buffer_init();
3023         c->file.name = buffer_init();
3024         c->file.fd = -1;
3025         c->file.mmap.start = MAP_FAILED;
3026         c->next = NULL;
3027 -       
3028 +
3029         return c;
3030  }
3031  
3032  static void chunk_free(chunk *c) {
3033         if (!c) return;
3034 -       
3035 +
3036         buffer_free(c->mem);
3037         buffer_free(c->file.name);
3038  
3039 @@ -56,13 +57,13 @@
3040  
3041  static void chunk_reset(chunk *c) {
3042         if (!c) return;
3043 -       
3044 +
3045         buffer_reset(c->mem);
3046  
3047         if (c->file.is_temp && !buffer_is_empty(c->file.name)) {
3048                 unlink(c->file.name->ptr);
3049         }
3050 -       
3051 +
3052         buffer_reset(c->file.name);
3053  
3054         if (c->file.fd != -1) {
3055 @@ -78,28 +79,28 @@
3056  
3057  void chunkqueue_free(chunkqueue *cq) {
3058         chunk *c, *pc;
3059 -       
3060 +
3061         if (!cq) return;
3062 -       
3063 +
3064         for (c = cq->first; c; ) {
3065                 pc = c;
3066                 c = c->next;
3067                 chunk_free(pc);
3068         }
3069 -       
3070 +
3071         for (c = cq->unused; c; ) {
3072                 pc = c;
3073                 c = c->next;
3074                 chunk_free(pc);
3075         }
3076 -       
3077 +
3078         free(cq);
3079  }
3080  
3081  static chunk *chunkqueue_get_unused_chunk(chunkqueue *cq) {
3082         chunk *c;
3083 -       
3084 -       /* check if we have a unused chunk */
3085 +
3086 +       /* check if we have an unused chunk */
3087         if (!cq->unused) {
3088                 c = chunk_init();
3089         } else {
3090 @@ -109,18 +110,18 @@
3091                 c->next = NULL;
3092                 cq->unused_chunks--;
3093         }
3094 -       
3095 +
3096         return c;
3097  }
3098  
3099  static int chunkqueue_prepend_chunk(chunkqueue *cq, chunk *c) {
3100         c->next = cq->first;
3101         cq->first = c;
3102 -       
3103 +
3104         if (cq->last == NULL) {
3105                 cq->last = c;
3106         }
3107 -       
3108 +
3109         return 0;
3110  }
3111  
3112 @@ -129,19 +130,19 @@
3113                 cq->last->next = c;
3114         }
3115         cq->last = c;
3116 -       
3117 +
3118         if (cq->first == NULL) {
3119                 cq->first = c;
3120         }
3121 -       
3122 +
3123         return 0;
3124  }
3125  
3126  void chunkqueue_reset(chunkqueue *cq) {
3127         chunk *c;
3128         /* move everything to the unused queue */
3129 -       
3130 -       /* mark all read written */ 
3131 +
3132 +       /* mark all read written */
3133         for (c = cq->first; c; c = c->next) {
3134                 switch(c->type) {
3135                 case MEM_CHUNK:
3136 @@ -150,7 +151,7 @@
3137                 case FILE_CHUNK:
3138                         c->offset = c->file.length;
3139                         break;
3140 -               default: 
3141 +               default:
3142                         break;
3143                 }
3144         }
3145 @@ -158,97 +159,98 @@
3146         chunkqueue_remove_finished_chunks(cq);
3147         cq->bytes_in = 0;
3148         cq->bytes_out = 0;
3149 +       cq->is_closed = 0;
3150  }
3151  
3152  int chunkqueue_append_file(chunkqueue *cq, buffer *fn, off_t offset, off_t len) {
3153         chunk *c;
3154 -       
3155 +
3156         if (len == 0) return 0;
3157 -       
3158 +
3159         c = chunkqueue_get_unused_chunk(cq);
3160 -       
3161 +
3162         c->type = FILE_CHUNK;
3163 -       
3164 +
3165         buffer_copy_string_buffer(c->file.name, fn);
3166         c->file.start = offset;
3167         c->file.length = len;
3168         c->offset = 0;
3169 -       
3170 +
3171         chunkqueue_append_chunk(cq, c);
3172 -       
3173 +
3174         return 0;
3175  }
3176  
3177  int chunkqueue_append_buffer(chunkqueue *cq, buffer *mem) {
3178         chunk *c;
3179 -       
3180 +
3181         if (mem->used == 0) return 0;
3182 -       
3183 +
3184         c = chunkqueue_get_unused_chunk(cq);
3185         c->type = MEM_CHUNK;
3186         c->offset = 0;
3187         buffer_copy_string_buffer(c->mem, mem);
3188 -       
3189 +
3190         chunkqueue_append_chunk(cq, c);
3191 -       
3192 +
3193         return 0;
3194  }
3195  
3196  int chunkqueue_prepend_buffer(chunkqueue *cq, buffer *mem) {
3197         chunk *c;
3198 -       
3199 +
3200         if (mem->used == 0) return 0;
3201 -       
3202 +
3203         c = chunkqueue_get_unused_chunk(cq);
3204         c->type = MEM_CHUNK;
3205         c->offset = 0;
3206         buffer_copy_string_buffer(c->mem, mem);
3207 -       
3208 +
3209         chunkqueue_prepend_chunk(cq, c);
3210 -       
3211 +
3212         return 0;
3213  }
3214  
3215  int chunkqueue_append_mem(chunkqueue *cq, const char * mem, size_t len) {
3216         chunk *c;
3217 -       
3218 +
3219         if (len == 0) return 0;
3220 -       
3221 +
3222         c = chunkqueue_get_unused_chunk(cq);
3223         c->type = MEM_CHUNK;
3224         c->offset = 0;
3225         buffer_copy_string_len(c->mem, mem, len - 1);
3226 -       
3227 +
3228         chunkqueue_append_chunk(cq, c);
3229 -       
3230 +
3231         return 0;
3232  }
3233  
3234  buffer * chunkqueue_get_prepend_buffer(chunkqueue *cq) {
3235         chunk *c;
3236 -       
3237 +
3238         c = chunkqueue_get_unused_chunk(cq);
3239 -       
3240 +
3241         c->type = MEM_CHUNK;
3242         c->offset = 0;
3243         buffer_reset(c->mem);
3244 -       
3245 +
3246         chunkqueue_prepend_chunk(cq, c);
3247 -       
3248 +
3249         return c->mem;
3250  }
3251  
3252  buffer *chunkqueue_get_append_buffer(chunkqueue *cq) {
3253         chunk *c;
3254 -       
3255 +
3256         c = chunkqueue_get_unused_chunk(cq);
3257 -       
3258 +
3259         c->type = MEM_CHUNK;
3260         c->offset = 0;
3261         buffer_reset(c->mem);
3262 -       
3263 +
3264         chunkqueue_append_chunk(cq, c);
3265 -       
3266 +
3267         return c->mem;
3268  }
3269  
3270 @@ -263,7 +265,7 @@
3271  chunk *chunkqueue_get_append_tempfile(chunkqueue *cq) {
3272         chunk *c;
3273         buffer *template = buffer_init_string("/var/tmp/lighttpd-upload-XXXXXX");
3274 -       
3275 +
3276         c = chunkqueue_get_unused_chunk(cq);
3277  
3278         c->type = FILE_CHUNK;
3279 @@ -273,12 +275,12 @@
3280                 size_t i;
3281  
3282                 /* we have several tempdirs, only if all of them fail we jump out */
3283 -               
3284 +
3285                 for (i = 0; i < cq->tempdirs->used; i++) {
3286                         data_string *ds = (data_string *)cq->tempdirs->data[i];
3287  
3288                         buffer_copy_string_buffer(template, ds->value);
3289 -                       BUFFER_APPEND_SLASH(template);
3290 +                       PATHNAME_APPEND_SLASH(template);
3291                         BUFFER_APPEND_STRING_CONST(template, "lighttpd-upload-XXXXXX");
3292  
3293                         if (-1 != (c->file.fd = mkstemp(template->ptr))) {
3294 @@ -300,7 +302,7 @@
3295         chunkqueue_append_chunk(cq, c);
3296  
3297         buffer_free(template);
3298 -       
3299 +
3300         return c;
3301  }
3302  
3303 @@ -308,7 +310,7 @@
3304  off_t chunkqueue_length(chunkqueue *cq) {
3305         off_t len = 0;
3306         chunk *c;
3307 -       
3308 +
3309         for (c = cq->first; c; c = c->next) {
3310                 switch (c->type) {
3311                 case MEM_CHUNK:
3312 @@ -321,14 +323,14 @@
3313                         break;
3314                 }
3315         }
3316 -       
3317 +
3318         return len;
3319  }
3320  
3321  off_t chunkqueue_written(chunkqueue *cq) {
3322         off_t len = 0;
3323         chunk *c;
3324 -       
3325 +
3326         for (c = cq->first; c; c = c->next) {
3327                 switch (c->type) {
3328                 case MEM_CHUNK:
3329 @@ -339,7 +341,7 @@
3330                         break;
3331                 }
3332         }
3333 -       
3334 +
3335         return len;
3336  }
3337  
3338 @@ -355,12 +357,13 @@
3339  
3340                 switch (c->type) {
3341                 case MEM_CHUNK:
3342 +                       if (c->mem->used == 0) is_finished = 1;
3343                         if (c->offset == (off_t)c->mem->used - 1) is_finished = 1;
3344                         break;
3345                 case FILE_CHUNK:
3346 -                       if (c->offset == c->file.length) is_finished = 1; 
3347 +                       if (c->offset == c->file.length) is_finished = 1;
3348                         break;
3349 -               default: 
3350 +               default:
3351                         break;
3352                 }
3353  
3354 @@ -383,3 +386,50 @@
3355  
3356         return 0;
3357  }
3358 +
3359 +void chunkqueue_print(chunkqueue *cq) {
3360 +       chunk *c;
3361 +
3362 +       for (c = cq->first; c; c = c->next) {
3363 +               fprintf(stderr, "(mem) %s", c->mem->ptr + c->offset);
3364 +       }
3365 +       fprintf(stderr, "\r\n");
3366 +}
3367 +
3368 +
3369 +/**
3370 + * remove the last chunk if it is empty
3371 + */
3372 +
3373 +void chunkqueue_remove_empty_last_chunk(chunkqueue *cq) {
3374 +       chunk *c;
3375 +       if (!cq->last) return;
3376 +       if (!cq->first) return;
3377 +
3378 +       if (cq->first == cq->last) {
3379 +               c = cq->first;
3380 +
3381 +               if (c->type != MEM_CHUNK) return;
3382 +               if (c->mem->used == 0) {
3383 +                       chunk_free(c);
3384 +                       cq->first = cq->last = NULL;
3385 +               }
3386 +               return;
3387 +       }
3388 +
3389 +       for (c = cq->first; c->next; c = c->next) {
3390 +               if (c->type != MEM_CHUNK) continue;
3391 +               if (c->mem->used != 0) continue;
3392 +
3393 +               if (c->next == cq->last) {
3394 +                       cq->last = c;
3395 +
3396 +                       chunk_free(c->next);
3397 +                       c->next = NULL;
3398 +
3399 +                       return;
3400 +               }
3401 +       }
3402 +}
3403 +
3404 +
3405 --- ../lighttpd-1.4.11/src/chunk.h      2005-11-01 09:32:21.000000000 +0200
3406 +++ lighttpd-1.5.0/src/chunk.h  2006-09-07 00:57:05.000000000 +0300
3407 @@ -6,7 +6,7 @@
3408  
3409  typedef struct chunk {
3410         enum { UNUSED_CHUNK, MEM_CHUNK, FILE_CHUNK } type;
3411 -       
3412 +
3413         buffer *mem; /* either the storage of the mem-chunk or the read-ahead buffer */
3414  
3415         struct {
3416 @@ -16,33 +16,35 @@
3417                 off_t  length; /* octets to send from the starting offset */
3418  
3419                 int    fd;
3420 -               struct { 
3421 +               struct {
3422                         char   *start; /* the start pointer of the mmap'ed area */
3423                         size_t length; /* size of the mmap'ed area */
3424 -                       off_t  offset; /* start is <n> octet away from the start of the file */
3425 +                       off_t  offset; /* start is <n> octets away from the start of the file */
3426                 } mmap;
3427  
3428 -               int is_temp; /* file is temporary and will be deleted if on cleanup */
3429 +               int is_temp; /* file is temporary and will be deleted on cleanup */
3430         } file;
3431 -       
3432 -       off_t  offset; /* octets sent from this chunk 
3433 -                         the size of the chunk is either 
3434 +
3435 +       off_t  offset; /* octets sent from this chunk
3436 +                         the size of the chunk is either
3437                           - mem-chunk: mem->used - 1
3438                           - file-chunk: file.length
3439                         */
3440 -       
3441 +
3442         struct chunk *next;
3443  } chunk;
3444  
3445  typedef struct {
3446         chunk *first;
3447         chunk *last;
3448 -       
3449 +
3450         chunk *unused;
3451         size_t unused_chunks;
3452  
3453         array *tempdirs;
3454  
3455 +       int is_closed;   /* the input to this CQ is closed */
3456 +
3457         off_t  bytes_in, bytes_out;
3458  } chunkqueue;
3459  
3460 @@ -56,6 +58,7 @@
3461  buffer * chunkqueue_get_append_buffer(chunkqueue *c);
3462  buffer * chunkqueue_get_prepend_buffer(chunkqueue *c);
3463  chunk * chunkqueue_get_append_tempfile(chunkqueue *cq);
3464 +void chunkqueue_remove_empty_last_chunk(chunkqueue *cq);
3465  
3466  int chunkqueue_remove_finished_chunks(chunkqueue *cq);
3467  
3468 @@ -66,4 +69,6 @@
3469  
3470  int chunkqueue_is_empty(chunkqueue *c);
3471  
3472 +void chunkqueue_print(chunkqueue *cq);
3473 +
3474  #endif
3475 --- ../lighttpd-1.4.11/src/configfile-glue.c    2006-03-03 20:14:56.000000000 +0200
3476 +++ lighttpd-1.5.0/src/configfile-glue.c        2006-09-07 00:57:05.000000000 +0300
3477 @@ -1,4 +1,5 @@
3478  #include <string.h>
3479 +#include <ctype.h>
3480  
3481  #include "base.h"
3482  #include "buffer.h"
3483 @@ -11,10 +12,10 @@
3484   * are the external interface of lighttpd. The functions
3485   * are used by the server itself and the plugins.
3486   *
3487 - * The main-goal is to have a small library in the end 
3488 - * which is linked against both and which will define 
3489 + * The main-goal is to have a small library in the end
3490 + * which is linked against both and which will define
3491   * the interface itself in the end.
3492 - * 
3493 + *
3494   */
3495  
3496  
3497 @@ -24,56 +25,60 @@
3498  int config_insert_values_internal(server *srv, array *ca, const config_values_t cv[]) {
3499         size_t i;
3500         data_unset *du;
3501 -       
3502 +
3503         for (i = 0; cv[i].key; i++) {
3504 -               
3505 +
3506                 if (NULL == (du = array_get_element(ca, cv[i].key))) {
3507                         /* no found */
3508 -                       
3509 +
3510                         continue;
3511                 }
3512 -               
3513 +
3514                 switch (cv[i].type) {
3515                 case T_CONFIG_ARRAY:
3516                         if (du->type == TYPE_ARRAY) {
3517                                 size_t j;
3518                                 data_array *da = (data_array *)du;
3519 -                               
3520 +
3521                                 for (j = 0; j < da->value->used; j++) {
3522                                         if (da->value->data[j]->type == TYPE_STRING) {
3523                                                 data_string *ds = data_string_init();
3524 -                                               
3525 +
3526                                                 buffer_copy_string_buffer(ds->value, ((data_string *)(da->value->data[j]))->value);
3527                                                 if (!da->is_index_key) {
3528                                                         /* the id's were generated automaticly, as we copy now we might have to renumber them
3529 -                                                        * this is used to prepend server.modules by mod_indexfiles as it has to be loaded 
3530 +                                                        * this is used to prepend server.modules by mod_indexfiles as it has to be loaded
3531                                                          * before mod_fastcgi and friends */
3532                                                         buffer_copy_string_buffer(ds->key, ((data_string *)(da->value->data[j]))->key);
3533                                                 }
3534 -                                               
3535 +
3536                                                 array_insert_unique(cv[i].destination, (data_unset *)ds);
3537                                         } else {
3538 -                                               log_error_write(srv, __FILE__, __LINE__, "sssd", 
3539 -                                                               "the key of and array can only be a string or a integer, variable:", 
3540 -                                                               cv[i].key, "type:", da->value->data[j]->type); 
3541 -                                               
3542 +                                               log_error_write(srv, __FILE__, __LINE__, "sssd",
3543 +                                                               "the key of and array can only be a string or a integer, variable:",
3544 +                                                               cv[i].key, "type:", da->value->data[j]->type);
3545 +
3546                                                 return -1;
3547                                         }
3548                                 }
3549                         } else {
3550                                 log_error_write(srv, __FILE__, __LINE__, "sss", "unexpected type for key: ", cv[i].key, "array of strings");
3551 -                               
3552 +
3553                                 return -1;
3554                         }
3555                         break;
3556                 case T_CONFIG_STRING:
3557                         if (du->type == TYPE_STRING) {
3558                                 data_string *ds = (data_string *)du;
3559 -                               
3560 +
3561                                 buffer_copy_string_buffer(cv[i].destination, ds->value);
3562 +                       } else if (du->type == TYPE_INTEGER) {
3563 +                               data_integer *di = (data_integer *)du;
3564 +
3565 +                               buffer_copy_long(cv[i].destination, di->value);
3566                         } else {
3567                                 log_error_write(srv, __FILE__, __LINE__, "ssss", "unexpected type for key: ", cv[i].key, "(string)", "\"...\"");
3568 -                               
3569 +
3570                                 return -1;
3571                         }
3572                         break;
3573 @@ -81,15 +86,20 @@
3574                         switch(du->type) {
3575                         case TYPE_INTEGER: {
3576                                 data_integer *di = (data_integer *)du;
3577 -                               
3578 +
3579                                 *((unsigned short *)(cv[i].destination)) = di->value;
3580                                 break;
3581                         }
3582                         case TYPE_STRING: {
3583                                 data_string *ds = (data_string *)du;
3584 -                                       
3585 +
3586 +                               if (buffer_isdigit(ds->value)) {
3587 +                                       *((unsigned short *)(cv[i].destination)) = strtol(ds->value->ptr, NULL, 10);
3588 +                                       break;
3589 +                               }
3590 +
3591                                 log_error_write(srv, __FILE__, __LINE__, "ssb", "get a string but expected a short:", cv[i].key, ds->value);
3592 -                               
3593 +
3594                                 return -1;
3595                         }
3596                         default:
3597 @@ -100,30 +110,36 @@
3598                 case T_CONFIG_BOOLEAN:
3599                         if (du->type == TYPE_STRING) {
3600                                 data_string *ds = (data_string *)du;
3601 -                               
3602 +
3603                                 if (buffer_is_equal_string(ds->value, CONST_STR_LEN("enable"))) {
3604                                         *((unsigned short *)(cv[i].destination)) = 1;
3605                                 } else if (buffer_is_equal_string(ds->value, CONST_STR_LEN("disable"))) {
3606                                         *((unsigned short *)(cv[i].destination)) = 0;
3607                                 } else {
3608                                         log_error_write(srv, __FILE__, __LINE__, "ssbs", "ERROR: unexpected value for key:", cv[i].key, ds->value, "(enable|disable)");
3609 -                                               
3610 +
3611                                         return -1;
3612                                 }
3613                         } else {
3614                                 log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: unexpected type for key:", cv[i].key, "(string)", "\"(enable|disable)\"");
3615 -                               
3616 +
3617                                 return -1;
3618                         }
3619                         break;
3620                 case T_CONFIG_LOCAL:
3621                 case T_CONFIG_UNSET:
3622                         break;
3623 +               case T_CONFIG_UNSUPPORTED:
3624 +                       log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: found unsupported key:", cv[i].key, "-", (char *)(cv[i].destination));
3625 +                       
3626 +                       srv->config_unsupported = 1;
3627 +                       
3628 +                       break;
3629                 case T_CONFIG_DEPRECATED:
3630                         log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: found deprecated key:", cv[i].key, "-", (char *)(cv[i].destination));
3631 -                       
3632 +
3633                         srv->config_deprecated = 1;
3634 -                       
3635 +
3636                         break;
3637                 }
3638         }
3639 @@ -133,25 +149,25 @@
3640  int config_insert_values_global(server *srv, array *ca, const config_values_t cv[]) {
3641         size_t i;
3642         data_unset *du;
3643 -       
3644 +
3645         for (i = 0; cv[i].key; i++) {
3646                 data_string *touched;
3647 -               
3648 +
3649                 if (NULL == (du = array_get_element(ca, cv[i].key))) {
3650                         /* no found */
3651 -                       
3652 +
3653                         continue;
3654                 }
3655 -               
3656 +
3657                 /* touched */
3658                 touched = data_string_init();
3659 -               
3660 +
3661                 buffer_copy_string(touched->value, "");
3662                 buffer_copy_string_buffer(touched->key, du->key);
3663 -               
3664 +
3665                 array_insert_unique(srv->config_touched, (data_unset *)touched);
3666         }
3667 -       
3668 +
3669         return config_insert_values_internal(srv, ca, cv);
3670  }
3671  
3672 @@ -191,25 +207,25 @@
3673         }
3674  
3675         /* pass the rules */
3676 -       
3677 +
3678         switch (dc->comp) {
3679         case COMP_HTTP_HOST: {
3680                 char *ck_colon = NULL, *val_colon = NULL;
3681 -               
3682 +
3683                 if (!buffer_is_empty(con->uri.authority)) {
3684 -               
3685 -                       /* 
3686 +
3687 +                       /*
3688                          * append server-port to the HTTP_POST if necessary
3689                          */
3690 -                       
3691 +
3692                         l = con->uri.authority;
3693 -                       
3694 +
3695                         switch(dc->cond) {
3696                         case CONFIG_COND_NE:
3697                         case CONFIG_COND_EQ:
3698                                 ck_colon = strchr(dc->string->ptr, ':');
3699                                 val_colon = strchr(l->ptr, ':');
3700 -                               
3701 +
3702                                 if (ck_colon == val_colon) {
3703                                         /* nothing to do with it */
3704                                         break;
3705 @@ -230,21 +246,21 @@
3706                                 break;
3707                         }
3708                 } else {
3709 -                       l = NULL;
3710 +                       l = srv->empty_string;
3711                 }
3712                 break;
3713         }
3714         case COMP_HTTP_REMOTEIP: {
3715                 char *nm_slash;
3716 -               /* handle remoteip limitations 
3717 -                * 
3718 +               /* handle remoteip limitations
3719 +                *
3720                  * "10.0.0.1" is provided for all comparisions
3721 -                * 
3722 +                *
3723                  * only for == and != we support
3724 -                * 
3725 +                *
3726                  * "10.0.0.1/24"
3727                  */
3728 -               
3729 +
3730                 if ((dc->cond == CONFIG_COND_EQ ||
3731                      dc->cond == CONFIG_COND_NE) &&
3732                     (con->dst_addr.plain.sa_family == AF_INET) &&
3733 @@ -253,41 +269,48 @@
3734                         long nm;
3735                         char *err;
3736                         struct in_addr val_inp;
3737 -                       
3738 +
3739 +                       if (con->conf.log_condition_handling) {
3740 +                               l = srv->empty_string;
3741 +
3742 +                               log_error_write(srv, __FILE__, __LINE__,  "bsbsb", dc->comp_key,
3743 +                                               "(", l, ") compare to", dc->string);
3744 +                       }
3745 +
3746                         if (*(nm_slash+1) == '\0') {
3747                                 log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: no number after / ", dc->string);
3748 -                                       
3749 +
3750                                 return COND_RESULT_FALSE;
3751                         }
3752 -                       
3753 +
3754                         nm_bits = strtol(nm_slash + 1, &err, 10);
3755 -                       
3756 +
3757                         if (*err) {
3758                                 log_error_write(srv, __FILE__, __LINE__, "sbs", "ERROR: non-digit found in netmask:", dc->string, *err);
3759 -                               
3760 +
3761                                 return COND_RESULT_FALSE;
3762                         }
3763 -                       
3764 +
3765                         /* take IP convert to the native */
3766                         buffer_copy_string_len(srv->cond_check_buf, dc->string->ptr, nm_slash - dc->string->ptr);
3767 -#ifdef __WIN32                 
3768 +#ifdef _WIN32
3769                         if (INADDR_NONE == (val_inp.s_addr = inet_addr(srv->cond_check_buf->ptr))) {
3770                                 log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf);
3771 -                               
3772 +
3773                                 return COND_RESULT_FALSE;
3774                         }
3775  
3776  #else
3777                         if (0 == inet_aton(srv->cond_check_buf->ptr, &val_inp)) {
3778                                 log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf);
3779 -                               
3780 +
3781                                 return COND_RESULT_FALSE;
3782                         }
3783  #endif
3784 -                       
3785 +
3786                         /* build netmask */
3787                         nm = htonl(~((1 << (32 - nm_bits)) - 1));
3788 -                       
3789 +
3790                         if ((val_inp.s_addr & nm) == (con->dst_addr.ipv4.sin_addr.s_addr & nm)) {
3791                                 return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
3792                         } else {
3793 @@ -302,13 +325,17 @@
3794                 l = con->uri.path;
3795                 break;
3796  
3797 +       case COMP_HTTP_QUERYSTRING:
3798 +               l = con->uri.query;
3799 +               break;
3800 +
3801         case COMP_SERVER_SOCKET:
3802                 l = srv_sock->srv_token;
3803                 break;
3804  
3805         case COMP_HTTP_REFERER: {
3806                 data_string *ds;
3807 -               
3808 +
3809                 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Referer"))) {
3810                         l = ds->value;
3811                 } else {
3812 @@ -338,7 +365,7 @@
3813         default:
3814                 return COND_RESULT_FALSE;
3815         }
3816 -       
3817 +
3818         if (NULL == l) {
3819                 if (con->conf.log_condition_handling) {
3820                         log_error_write(srv, __FILE__, __LINE__,  "bsbs", dc->comp_key,
3821 @@ -346,10 +373,10 @@
3822                 }
3823                 return COND_RESULT_FALSE;
3824         }
3825 -       
3826 +
3827         if (con->conf.log_condition_handling) {
3828                 log_error_write(srv, __FILE__, __LINE__,  "bsbsb", dc->comp_key,
3829 -                               "(", l, ") compare to ", dc->string);
3830 +                               "(", l, ") compare to", dc->string);
3831         }
3832         switch(dc->cond) {
3833         case CONFIG_COND_NE:
3834 @@ -365,13 +392,13 @@
3835         case CONFIG_COND_MATCH: {
3836                 cond_cache_t *cache = &con->cond_cache[dc->context_ndx];
3837                 int n;
3838 -               
3839 +
3840  #ifndef elementsof
3841  #define elementsof(x) (sizeof(x) / sizeof(x[0]))
3842  #endif
3843                 n = pcre_exec(dc->regex, dc->regex_study, l->ptr, l->used - 1, 0, 0,
3844                                 cache->matches, elementsof(cache->matches));
3845 -               
3846 +
3847                 cache->patterncount = n;
3848                 if (n > 0) {
3849                         cache->comp_value = l;
3850 @@ -387,7 +414,7 @@
3851                 /* no way */
3852                 break;
3853         }
3854 -       
3855 +
3856         return COND_RESULT_FALSE;
3857  }
3858  
3859 @@ -395,6 +422,9 @@
3860         cond_cache_t *caches = con->cond_cache;
3861  
3862         if (COND_RESULT_UNSET == caches[dc->context_ndx].result) {
3863 +               if (con->conf.log_condition_handling) {
3864 +                       log_error_write(srv, __FILE__, __LINE__,  "sds",  "=== start of", dc->context_ndx, "condition block ===");
3865 +               }
3866                 if (COND_RESULT_TRUE == (caches[dc->context_ndx].result = config_check_cond_nocache(srv, con, dc))) {
3867                         if (dc->next) {
3868                                 data_config *c;
3869 @@ -409,11 +439,11 @@
3870                 }
3871                 if (con->conf.log_condition_handling) {
3872                         log_error_write(srv, __FILE__, __LINE__, "dss", dc->context_ndx,
3873 -                                       "(uncached) result:",
3874 +                                       "result:",
3875                                         caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false");
3876                 }
3877         } else {
3878 -               if (con->conf.log_condition_handling) {
3879 +               if (con->conf.log_condition_cache_handling) {
3880                         log_error_write(srv, __FILE__, __LINE__, "dss", dc->context_ndx,
3881                                         "(cached) result:",
3882                                         caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false");
3883 @@ -422,10 +452,20 @@
3884         return caches[dc->context_ndx].result;
3885  }
3886  
3887 -int config_check_cond(server *srv, connection *con, data_config *dc) {
3888 -       if (con->conf.log_condition_handling) {
3889 -               log_error_write(srv, __FILE__, __LINE__,  "s",  "=== start of condition block ===");
3890 +void config_cond_cache_reset(server *srv, connection *con) {
3891 +#if COND_RESULT_UNSET
3892 +       size_t i;
3893 +
3894 +       for (i = srv->config_context->used - 1; i >= 0; i --) {
3895 +               con->cond_cache[i].result = COND_RESULT_UNSET;
3896 +               con->cond_cache[i].patterncount = 0;
3897         }
3898 +#else  
3899 +       memset(con->cond_cache, 0, sizeof(cond_cache_t) * srv->config_context->used);
3900 +#endif
3901 +}
3902 +
3903 +int config_check_cond(server *srv, connection *con, data_config *dc) {
3904         return (config_check_cond_cached(srv, con, dc) == COND_RESULT_TRUE);
3905  }
3906  
3907 @@ -443,3 +483,85 @@
3908         return 1;
3909  }
3910  
3911 +/* return <0 on error
3912 + * return 0-x if matched (and replaced)
3913 + */
3914 +int config_exec_pcre_keyvalue_buffer(connection *con, pcre_keyvalue_buffer *kvb, data_config *context, buffer *match_buf, buffer *result)
3915 +{
3916 +#ifdef HAVE_PCRE_H
3917 +       pcre *match;
3918 +       pcre_extra *extra;
3919 +       const char *pattern;
3920 +       size_t pattern_len;
3921 +       int n;
3922 +       size_t i;
3923 +       pcre_keyvalue *kv;
3924 +# define N 10
3925 +       int ovec[N * 3];
3926 +
3927 +       for (i = 0; i < kvb->used; i++) {
3928 +               kv = kvb->kv[i];
3929 +
3930 +               match       = kv->key;
3931 +               extra       = kv->key_extra;
3932 +               pattern     = kv->value->ptr;
3933 +               pattern_len = kv->value->used - 1;
3934 +
3935 +               if ((n = pcre_exec(match, extra, match_buf->ptr, match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
3936 +                       if (n != PCRE_ERROR_NOMATCH) {
3937 +                               return n;
3938 +                       }
3939 +               } else {
3940 +                       const char **list;
3941 +                       size_t start, end;
3942 +                       size_t k;
3943 +
3944 +                       /* it matched */
3945 +                       pcre_get_substring_list(match_buf->ptr, ovec, n, &list);
3946 +
3947 +                       /* search for $[0-9] */
3948 +
3949 +                       buffer_reset(result);
3950 +
3951 +                       start = 0; end = pattern_len;
3952 +                       for (k = 0; k < pattern_len; k++) {
3953 +                               if ((pattern[k] == '$' || pattern[k] == '%') &&
3954 +                                   isdigit((unsigned char)pattern[k + 1])) {
3955 +                                       /* got one */
3956 +
3957 +                                       size_t num = pattern[k + 1] - '0';
3958 +
3959 +                                       end = k;
3960 +
3961 +                                       buffer_append_string_len(result, pattern + start, end - start);
3962 +
3963 +                                       if (pattern[k] == '$') {
3964 +                                               /* n is always > 0 */
3965 +                                               if (num < (size_t)n) {
3966 +                                                       buffer_append_string(result, list[num]);
3967 +                                               }
3968 +                                       } else {
3969 +                                               config_append_cond_match_buffer(con, context, result, num);
3970 +                                       }
3971 +
3972 +                                       k++;
3973 +                                       start = k + 1;
3974 +                               }
3975 +                       }
3976 +
3977 +                       buffer_append_string_len(result, pattern + start, pattern_len - start);
3978 +
3979 +                       pcre_free(list);
3980 +
3981 +                       return i;
3982 +               }
3983 +       }
3984 +
3985 +       return PCRE_ERROR_NOMATCH;
3986 +#undef N
3987 +#else
3988 +       UNUSED(kvb);
3989 +       return -2;
3990 +#endif
3991 +}
3992 +
3993 --- ../lighttpd-1.4.11/src/configfile.c 2006-02-15 14:26:42.000000000 +0200
3994 +++ lighttpd-1.5.0/src/configfile.c     2006-09-07 00:57:05.000000000 +0300
3995 @@ -2,7 +2,6 @@
3996  
3997  #include <stdlib.h>
3998  #include <fcntl.h>
3999 -#include <unistd.h>
4000  #include <errno.h>
4001  #include <string.h>
4002  #include <stdio.h>
4003 @@ -13,21 +12,24 @@
4004  #include "log.h"
4005  #include "stream.h"
4006  #include "plugin.h"
4007 -#ifdef USE_LICENSE
4008 -#include "license.h"
4009 -#endif
4010 -
4011  #include "configparser.h"
4012  #include "configfile.h"
4013  #include "proc_open.h"
4014  
4015 +#include "sys-files.h"
4016 +#include "sys-process.h"
4017 +
4018 +#ifndef PATH_MAX
4019 +/* win32 */
4020 +#define PATH_MAX 64
4021 +#endif
4022  
4023  static int config_insert(server *srv) {
4024         size_t i;
4025         int ret = 0;
4026         buffer *stat_cache_string;
4027 -       
4028 -       config_values_t cv[] = { 
4029 +
4030 +       config_values_t cv[] = {
4031                 { "server.bind",                 NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 0 */
4032                 { "server.errorlog",             NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 1 */
4033                 { "server.errorfile-prefix",     NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 2 */
4034 @@ -38,7 +40,7 @@
4035                 { "server.tag",                  NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },  /* 7 */
4036                 { "server.use-ipv6",             NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
4037                 { "server.modules",              NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_SERVER },       /* 9 */
4038 -               
4039 +
4040                 { "server.event-handler",        NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 10 */
4041                 { "server.pid-file",             NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 11 */
4042                 { "server.max-request-size",     NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },   /* 12 */
4043 @@ -49,30 +51,37 @@
4044                 { "server.max-keep-alive-requests", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 17 */
4045                 { "server.name",                 NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },  /* 18 */
4046                 { "server.max-keep-alive-idle",  NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },   /* 19 */
4047 -               
4048 +
4049                 { "server.max-read-idle",        NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },   /* 20 */
4050                 { "server.max-write-idle",       NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },   /* 21 */
4051                 { "server.error-handler-404",    NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },  /* 22 */
4052                 { "server.max-fds",              NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER },       /* 23 */
4053 +#ifdef HAVE_LSTAT
4054                 { "server.follow-symlink",       NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 24 */
4055 +#else
4056 +               { "server.follow-symlink",
4057 +                 "Your system lacks lstat(). We cant differ symlinks from files."
4058 +                 "Please remove server.follow-symlinks from your config.",
4059 +                 T_CONFIG_UNSUPPORTED, T_CONFIG_SCOPE_UNSET }, /* 24 */
4060 +#endif
4061                 { "server.kbytes-per-second",    NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },   /* 25 */
4062                 { "connection.kbytes-per-second", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },  /* 26 */
4063                 { "mimetype.use-xattr",          NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 27 */
4064                 { "mimetype.assign",             NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },   /* 28 */
4065                 { "ssl.pemfile",                 NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 29 */
4066 -               
4067 +
4068                 { "ssl.engine",                  NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 30 */
4069 -               
4070 +
4071                 { "debug.log-file-not-found",    NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 31 */
4072                 { "debug.log-request-handling",  NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 32 */
4073                 { "debug.log-response-header",   NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 33 */
4074                 { "debug.log-request-header",    NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 34 */
4075 -               
4076 +
4077                 { "server.protocol-http11",      NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 35 */
4078                 { "debug.log-request-header-on-error", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 36 */
4079                 { "debug.log-state-handling",    NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 37 */
4080                 { "ssl.ca-file",                 NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },      /* 38 */
4081 -               
4082 +
4083                 { "server.errorlog-use-syslog",  NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },     /* 39 */
4084                 { "server.range-requests",       NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 40 */
4085                 { "server.stat-cache-engine",    NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },  /* 41 */
4086 @@ -80,7 +89,8 @@
4087                 { "server.network-backend",      NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },  /* 43 */
4088                 { "server.upload-dirs",          NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },   /* 44 */
4089                 { "server.core-files",           NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 45 */
4090 -               
4091 +               { "debug.log-condition-cache-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },    /* 46 */
4092 +
4093                 { "server.host",                 "use server.bind instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
4094                 { "server.docroot",              "use server.document-root instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
4095                 { "server.virtual-root",         "load mod_simple_vhost and use simple-vhost.server-root instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
4096 @@ -90,11 +100,11 @@
4097                 { "server.groupid",              "use server.groupname instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
4098                 { "server.use-keep-alive",       "use server.max-keep-alive-requests = 0 instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
4099                 { "server.force-lower-case-files",       "use server.force-lowercase-filenames instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
4100 -               
4101 +
4102                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
4103         };
4104  
4105 -       
4106 +
4107         /* 0 */
4108         cv[0].destination = srv->srvconf.bindhost;
4109         cv[1].destination = srv->srvconf.errorlog_file;
4110 @@ -102,33 +112,33 @@
4111         cv[4].destination = srv->srvconf.username;
4112         cv[5].destination = srv->srvconf.groupname;
4113         cv[6].destination = &(srv->srvconf.port);
4114 -       
4115 +
4116         cv[9].destination = srv->srvconf.modules;
4117         cv[10].destination = srv->srvconf.event_handler;
4118         cv[11].destination = srv->srvconf.pid_file;
4119 -       
4120 +
4121         cv[13].destination = &(srv->srvconf.max_worker);
4122         cv[23].destination = &(srv->srvconf.max_fds);
4123         cv[36].destination = &(srv->srvconf.log_request_header_on_error);
4124         cv[37].destination = &(srv->srvconf.log_state_handling);
4125 -       
4126 +
4127         cv[39].destination = &(srv->srvconf.errorlog_use_syslog);
4128 -       
4129 +
4130         stat_cache_string = buffer_init();
4131         cv[41].destination = stat_cache_string;
4132         cv[43].destination = srv->srvconf.network_backend;
4133         cv[44].destination = srv->srvconf.upload_tempdirs;
4134         cv[45].destination = &(srv->srvconf.enable_cores);
4135 -       
4136 +
4137         cv[42].destination = &(srv->srvconf.max_conns);
4138         cv[12].destination = &(srv->srvconf.max_request_size);
4139         srv->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
4140  
4141         assert(srv->config_storage);
4142 -       
4143 +
4144         for (i = 0; i < srv->config_context->used; i++) {
4145                 specific_config *s;
4146 -               
4147 +
4148                 s = calloc(1, sizeof(specific_config));
4149                 assert(s);
4150                 s->document_root = buffer_init();
4151 @@ -146,7 +156,9 @@
4152                 s->use_xattr     = 0;
4153                 s->is_ssl        = 0;
4154                 s->use_ipv6      = 0;
4155 +#ifdef HAVE_LSTAT
4156                 s->follow_symlink = 1;
4157 +#endif
4158                 s->kbytes_per_second = 0;
4159                 s->allow_http11  = 1;
4160                 s->range_requests = 1;
4161 @@ -154,24 +166,27 @@
4162                 s->global_kbytes_per_second = 0;
4163                 s->global_bytes_per_second_cnt = 0;
4164                 s->global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
4165 -               
4166 +
4167                 cv[2].destination = s->errorfile_prefix;
4168 -               
4169 +
4170                 cv[7].destination = s->server_tag;
4171                 cv[8].destination = &(s->use_ipv6);
4172 -               
4173 -               
4174 +
4175 +
4176                 /* 13 max-worker */
4177                 cv[14].destination = s->document_root;
4178                 cv[15].destination = &(s->force_lowercase_filenames);
4179                 cv[16].destination = &(s->log_condition_handling);
4180 +               cv[46].destination = &(s->log_condition_cache_handling);
4181                 cv[17].destination = &(s->max_keep_alive_requests);
4182                 cv[18].destination = s->server_name;
4183                 cv[19].destination = &(s->max_keep_alive_idle);
4184                 cv[20].destination = &(s->max_read_idle);
4185                 cv[21].destination = &(s->max_write_idle);
4186                 cv[22].destination = s->error_handler;
4187 +#ifdef HAVE_LSTAT
4188                 cv[24].destination = &(s->follow_symlink);
4189 +#endif
4190                 /* 23 -> max-fds */
4191                 cv[25].destination = &(s->global_kbytes_per_second);
4192                 cv[26].destination = &(s->kbytes_per_second);
4193 @@ -179,23 +194,23 @@
4194                 cv[28].destination = s->mimetypes;
4195                 cv[29].destination = s->ssl_pemfile;
4196                 cv[30].destination = &(s->is_ssl);
4197 -               
4198 +
4199                 cv[31].destination = &(s->log_file_not_found);
4200                 cv[32].destination = &(s->log_request_handling);
4201                 cv[33].destination = &(s->log_response_header);
4202                 cv[34].destination = &(s->log_request_header);
4203 -               
4204 +
4205                 cv[35].destination = &(s->allow_http11);
4206                 cv[38].destination = s->ssl_ca_file;
4207                 cv[40].destination = &(s->range_requests);
4208 -               
4209 +
4210                 srv->config_storage[i] = s;
4211 -       
4212 +
4213                 if (0 != (ret = config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv))) {
4214                         break;
4215                 }
4216         }
4217 -       
4218 +
4219         if (buffer_is_empty(stat_cache_string)) {
4220                 srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_SIMPLE;
4221         } else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("simple"))) {
4222 @@ -205,22 +220,22 @@
4223         } else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("disable"))) {
4224                 srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_NONE;
4225         } else {
4226 -               log_error_write(srv, __FILE__, __LINE__, "sb", 
4227 +               log_error_write(srv, __FILE__, __LINE__, "sb",
4228                                 "server.stat-cache-engine can be one of \"disable\", \"simple\", \"fam\", but not:", stat_cache_string);
4229                 ret = HANDLER_ERROR;
4230         }
4231 -       
4232 +
4233         buffer_free(stat_cache_string);
4234 -       
4235 +
4236         return ret;
4237 -                                                                
4238 -}
4239  
4240 +}
4241  
4242 -#define PATCH(x) con->conf.x = s->x
4243 +#define PATCH(x) \
4244 +       con->conf.x = s->x
4245  int config_setup_connection(server *srv, connection *con) {
4246         specific_config *s = srv->config_storage[0];
4247 -       
4248 +
4249         PATCH(allow_http11);
4250         PATCH(mimetypes);
4251         PATCH(document_root);
4252 @@ -231,25 +246,28 @@
4253         PATCH(use_xattr);
4254         PATCH(error_handler);
4255         PATCH(errorfile_prefix);
4256 +#ifdef HAVE_LSTAT
4257         PATCH(follow_symlink);
4258 +#endif
4259         PATCH(server_tag);
4260         PATCH(kbytes_per_second);
4261         PATCH(global_kbytes_per_second);
4262         PATCH(global_bytes_per_second_cnt);
4263 -       
4264 +
4265         con->conf.global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
4266         buffer_copy_string_buffer(con->server_name, s->server_name);
4267 -       
4268 +
4269         PATCH(log_request_header);
4270         PATCH(log_response_header);
4271         PATCH(log_request_handling);
4272         PATCH(log_condition_handling);
4273 +       PATCH(log_condition_cache_handling);
4274         PATCH(log_file_not_found);
4275 -       
4276 +
4277         PATCH(range_requests);
4278         PATCH(force_lowercase_filenames);
4279         PATCH(is_ssl);
4280 -       
4281 +
4282         PATCH(ssl_pemfile);
4283         PATCH(ssl_ca_file);
4284         return 0;
4285 @@ -257,22 +275,22 @@
4286  
4287  int config_patch_connection(server *srv, connection *con, comp_key_t comp) {
4288         size_t i, j;
4289 -       
4290 +
4291         /* skip the first, the global context */
4292         for (i = 1; i < srv->config_context->used; i++) {
4293                 data_config *dc = (data_config *)srv->config_context->data[i];
4294                 specific_config *s = srv->config_storage[i];
4295 -               
4296 +
4297                 /* not our stage */
4298                 if (comp != dc->comp) continue;
4299 -               
4300 +
4301                 /* condition didn't match */
4302                 if (!config_check_cond(srv, con, dc)) continue;
4303 -               
4304 +
4305                 /* merge config */
4306                 for (j = 0; j < dc->value->used; j++) {
4307                         data_unset *du = dc->value->data[j];
4308 -                       
4309 +
4310                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.document-root"))) {
4311                                 PATCH(document_root);
4312                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.range-requests"))) {
4313 @@ -299,8 +317,10 @@
4314                                 PATCH(ssl_ca_file);
4315                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.engine"))) {
4316                                 PATCH(is_ssl);
4317 +#ifdef HAVE_LSTAT
4318                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.follow-symlink"))) {
4319                                 PATCH(follow_symlink);
4320 +#endif
4321                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.name"))) {
4322                                 buffer_copy_string_buffer(con->server_name, s->server_name);
4323                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.tag"))) {
4324 @@ -315,11 +335,13 @@
4325                                 PATCH(log_response_header);
4326                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-condition-handling"))) {
4327                                 PATCH(log_condition_handling);
4328 +                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-condition-cache-handling"))) {
4329 +                               PATCH(log_condition_cache_handling);
4330                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-file-not-found"))) {
4331                                 PATCH(log_file_not_found);
4332                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.protocol-http11"))) {
4333                                 PATCH(allow_http11);
4334 -                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.force-lowercase-filenames"))) {  
4335 +                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.force-lowercase-filenames"))) {
4336                                 PATCH(force_lowercase_filenames);
4337                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.kbytes-per-second"))) {
4338                                 PATCH(global_kbytes_per_second);
4339 @@ -328,7 +350,7 @@
4340                         }
4341                 }
4342         }
4343 -       
4344 +
4345         return 0;
4346  }
4347  #undef PATCH
4348 @@ -336,15 +358,15 @@
4349  typedef struct {
4350         int foo;
4351         int bar;
4352 -       
4353 +
4354         const buffer *source;
4355         const char *input;
4356         size_t offset;
4357         size_t size;
4358 -       
4359 +
4360         int line_pos;
4361         int line;
4362 -       
4363 +
4364         int in_key;
4365         int in_brace;
4366         int in_cond;
4367 @@ -362,7 +384,7 @@
4368         }
4369  
4370         if (0 != stream_open(&(t->s), t->file)) {
4371 -               log_error_write(srv, __FILE__, __LINE__, "sbss", 
4372 +               log_error_write(srv, __FILE__, __LINE__, "sbss",
4373                                 "opening configfile ", t->file, "failed:", strerror(errno));
4374                 buffer_free(t->file);
4375                 return -1;
4376 @@ -373,7 +395,7 @@
4377         t->size = t->s.size;
4378         t->line = 1;
4379         t->line_pos = 1;
4380 -       
4381 +
4382         t->in_key = 1;
4383         t->in_brace = 0;
4384         t->in_cond = 0;
4385 @@ -401,7 +423,7 @@
4386  static int config_skip_comment(tokenizer_t *t) {
4387         int i;
4388         assert(t->input[t->offset] == '#');
4389 -       for (i = 1; t->input[t->offset + i] && 
4390 +       for (i = 1; t->input[t->offset + i] &&
4391              (t->input[t->offset + i] != '\n' && t->input[t->offset + i] != '\r');
4392              i++);
4393         t->offset += i;
4394 @@ -411,44 +433,44 @@
4395  static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *token) {
4396         int tid = 0;
4397         size_t i;
4398 -       
4399 +
4400         for (tid = 0; tid == 0 && t->offset < t->size && t->input[t->offset] ; ) {
4401                 char c = t->input[t->offset];
4402                 const char *start = NULL;
4403 -               
4404 +
4405                 switch (c) {
4406 -               case '=': 
4407 +               case '=':
4408                         if (t->in_brace) {
4409                                 if (t->input[t->offset + 1] == '>') {
4410                                         t->offset += 2;
4411 -                                       
4412 +
4413                                         buffer_copy_string(token, "=>");
4414 -                                       
4415 +
4416                                         tid = TK_ARRAY_ASSIGN;
4417                                 } else {
4418 -                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4419 +                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4420                                                         "source:", t->source,
4421 -                                                       "line:", t->line, "pos:", t->line_pos, 
4422 +                                                       "line:", t->line, "pos:", t->line_pos,
4423                                                         "use => for assignments in arrays");
4424                                         return -1;
4425                                 }
4426                         } else if (t->in_cond) {
4427                                 if (t->input[t->offset + 1] == '=') {
4428                                         t->offset += 2;
4429 -                                       
4430 +
4431                                         buffer_copy_string(token, "==");
4432 -                                       
4433 +
4434                                         tid = TK_EQ;
4435                                 } else if (t->input[t->offset + 1] == '~') {
4436                                         t->offset += 2;
4437 -                                       
4438 +
4439                                         buffer_copy_string(token, "=~");
4440 -                                       
4441 +
4442                                         tid = TK_MATCH;
4443                                 } else {
4444 -                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4445 +                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4446                                                         "source:", t->source,
4447 -                                                       "line:", t->line, "pos:", t->line_pos, 
4448 +                                                       "line:", t->line, "pos:", t->line_pos,
4449                                                         "only =~ and == are allowed in the condition");
4450                                         return -1;
4451                                 }
4452 @@ -456,51 +478,51 @@
4453                                 t->in_cond = 0;
4454                         } else if (t->in_key) {
4455                                 tid = TK_ASSIGN;
4456 -                               
4457 +
4458                                 buffer_copy_string_len(token, t->input + t->offset, 1);
4459 -                               
4460 +
4461                                 t->offset++;
4462                                 t->line_pos++;
4463                         } else {
4464 -                               log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4465 +                               log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4466                                                 "source:", t->source,
4467 -                                               "line:", t->line, "pos:", t->line_pos, 
4468 +                                               "line:", t->line, "pos:", t->line_pos,
4469                                                 "unexpected equal-sign: =");
4470                                 return -1;
4471                         }
4472 -                       
4473 +
4474                         break;
4475 -               case '!': 
4476 +               case '!':
4477                         if (t->in_cond) {
4478                                 if (t->input[t->offset + 1] == '=') {
4479                                         t->offset += 2;
4480 -                                       
4481 +
4482                                         buffer_copy_string(token, "!=");
4483 -                                       
4484 +
4485                                         tid = TK_NE;
4486                                 } else if (t->input[t->offset + 1] == '~') {
4487                                         t->offset += 2;
4488 -                                       
4489 +
4490                                         buffer_copy_string(token, "!~");
4491 -                                       
4492 +
4493                                         tid = TK_NOMATCH;
4494                                 } else {
4495 -                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4496 +                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4497                                                         "source:", t->source,
4498 -                                                       "line:", t->line, "pos:", t->line_pos, 
4499 +                                                       "line:", t->line, "pos:", t->line_pos,
4500                                                         "only !~ and != are allowed in the condition");
4501                                         return -1;
4502                                 }
4503                                 t->in_key = 1;
4504                                 t->in_cond = 0;
4505                         } else {
4506 -                               log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4507 +                               log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4508                                                 "source:", t->source,
4509 -                                               "line:", t->line, "pos:", t->line_pos, 
4510 +                                               "line:", t->line, "pos:", t->line_pos,
4511                                                 "unexpected exclamation-marks: !");
4512                                 return -1;
4513                         }
4514 -                       
4515 +
4516                         break;
4517                 case '\t':
4518                 case ' ':
4519 @@ -546,10 +568,10 @@
4520                 case ',':
4521                         if (t->in_brace > 0) {
4522                                 tid = TK_COMMA;
4523 -                               
4524 +
4525                                 buffer_copy_string(token, "(COMMA)");
4526                         }
4527 -                       
4528 +
4529                         t->offset++;
4530                         t->line_pos++;
4531                         break;
4532 @@ -557,70 +579,70 @@
4533                         /* search for the terminating " */
4534                         start = t->input + t->offset + 1;
4535                         buffer_copy_string(token, "");
4536 -                       
4537 +
4538                         for (i = 1; t->input[t->offset + i]; i++) {
4539                                 if (t->input[t->offset + i] == '\\' &&
4540                                     t->input[t->offset + i + 1] == '"') {
4541 -                                       
4542 +
4543                                         buffer_append_string_len(token, start, t->input + t->offset + i - start);
4544 -                                       
4545 +
4546                                         start = t->input + t->offset + i + 1;
4547 -                                       
4548 +
4549                                         /* skip the " */
4550                                         i++;
4551                                         continue;
4552                                 }
4553 -                               
4554 -                               
4555 +
4556 +
4557                                 if (t->input[t->offset + i] == '"') {
4558                                         tid = TK_STRING;
4559 -                               
4560 +
4561                                         buffer_append_string_len(token, start, t->input + t->offset + i - start);
4562 -                                       
4563 +
4564                                         break;
4565                                 }
4566                         }
4567  
4568                         if (t->input[t->offset + i] == '\0') {
4569                                 /* ERROR */
4570 -                               
4571 -                               log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4572 +
4573 +                               log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4574                                                 "source:", t->source,
4575 -                                               "line:", t->line, "pos:", t->line_pos, 
4576 +                                               "line:", t->line, "pos:", t->line_pos,
4577                                                 "missing closing quote");
4578 -                               
4579 +
4580                                 return -1;
4581                         }
4582 -                       
4583 +
4584                         t->offset += i + 1;
4585                         t->line_pos += i + 1;
4586 -                       
4587 +
4588                         break;
4589                 case '(':
4590                         t->offset++;
4591                         t->in_brace++;
4592 -                               
4593 +
4594                         tid = TK_LPARAN;
4595 -                               
4596 +
4597                         buffer_copy_string(token, "(");
4598                         break;
4599                 case ')':
4600                         t->offset++;
4601                         t->in_brace--;
4602 -                               
4603 +
4604                         tid = TK_RPARAN;
4605 -                               
4606 +
4607                         buffer_copy_string(token, ")");
4608                         break;
4609                 case '$':
4610                         t->offset++;
4611 -                               
4612 +
4613                         tid = TK_DOLLAR;
4614                         t->in_cond = 1;
4615                         t->in_key = 0;
4616 -                               
4617 +
4618                         buffer_copy_string(token, "$");
4619 -                       
4620 +
4621                         break;
4622  
4623                 case '+':
4624 @@ -637,115 +659,107 @@
4625  
4626                 case '{':
4627                         t->offset++;
4628 -                               
4629 +
4630                         tid = TK_LCURLY;
4631 -                               
4632 +
4633                         buffer_copy_string(token, "{");
4634 -                       
4635 +
4636                         break;
4637 -                       
4638 +
4639                 case '}':
4640                         t->offset++;
4641 -                               
4642 +
4643                         tid = TK_RCURLY;
4644 -                               
4645 +
4646                         buffer_copy_string(token, "}");
4647 -                       
4648 +
4649                         break;
4650  
4651                 case '[':
4652                         t->offset++;
4653 -                               
4654 +
4655                         tid = TK_LBRACKET;
4656 -                               
4657 +
4658                         buffer_copy_string(token, "[");
4659 -                       
4660 +
4661                         break;
4662 -                       
4663 +
4664                 case ']':
4665                         t->offset++;
4666 -                               
4667 +
4668                         tid = TK_RBRACKET;
4669 -                               
4670 +
4671                         buffer_copy_string(token, "]");
4672 -                       
4673 +
4674                         break;
4675                 case '#':
4676                         t->line_pos += config_skip_comment(t);
4677 -                       
4678 +
4679                         break;
4680                 default:
4681                         if (t->in_cond) {
4682 -                               for (i = 0; t->input[t->offset + i] && 
4683 +                               for (i = 0; t->input[t->offset + i] &&
4684                                      (isalpha((unsigned char)t->input[t->offset + i])
4685                                       ); i++);
4686 -                               
4687 +
4688                                 if (i && t->input[t->offset + i]) {
4689                                         tid = TK_SRVVARNAME;
4690                                         buffer_copy_string_len(token, t->input + t->offset, i);
4691 -                                       
4692 +
4693                                         t->offset += i;
4694                                         t->line_pos += i;
4695                                 } else {
4696                                         /* ERROR */
4697 -                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4698 +                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4699                                                         "source:", t->source,
4700 -                                                       "line:", t->line, "pos:", t->line_pos, 
4701 +                                                       "line:", t->line, "pos:", t->line_pos,
4702                                                         "invalid character in condition");
4703                                         return -1;
4704                                 }
4705                         } else if (isdigit((unsigned char)c)) {
4706                                 /* take all digits */
4707                                 for (i = 0; t->input[t->offset + i] && isdigit((unsigned char)t->input[t->offset + i]);  i++);
4708 -                               
4709 +
4710                                 /* was there it least a digit ? */
4711 -                               if (i && t->input[t->offset + i]) {
4712 +                               if (i) {
4713                                         tid = TK_INTEGER;
4714 -                                       
4715 +
4716                                         buffer_copy_string_len(token, t->input + t->offset, i);
4717 -                                       
4718 +
4719                                         t->offset += i;
4720                                         t->line_pos += i;
4721 -                               } else {
4722 -                                       /* ERROR */
4723 -                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4724 -                                                       "source:", t->source,
4725 -                                                       "line:", t->line, "pos:", t->line_pos, 
4726 -                                                       "unexpected EOF");
4727 -                                       
4728 -                                       return -1;
4729                                 }
4730                         } else {
4731                                 /* the key might consist of [-.0-9a-z] */
4732 -                               for (i = 0; t->input[t->offset + i] && 
4733 -                                    (isalnum((unsigned char)t->input[t->offset + i]) || 
4734 +                               for (i = 0; t->input[t->offset + i] &&
4735 +                                    (isalnum((unsigned char)t->input[t->offset + i]) ||
4736                                       t->input[t->offset + i] == '.' ||
4737                                       t->input[t->offset + i] == '_' || /* for env.* */
4738                                       t->input[t->offset + i] == '-'
4739                                       ); i++);
4740 -                               
4741 +
4742                                 if (i && t->input[t->offset + i]) {
4743                                         buffer_copy_string_len(token, t->input + t->offset, i);
4744 -                                       
4745 -                                       if (strcmp(token->ptr, "include") == 0) {
4746 +
4747 +                                       if (buffer_is_equal_string(token, CONST_STR_LEN("include"))) {
4748                                                 tid = TK_INCLUDE;
4749 -                                       } else if (strcmp(token->ptr, "include_shell") == 0) {
4750 +                                       } else if (buffer_is_equal_string(token, CONST_STR_LEN("include_shell"))) {
4751                                                 tid = TK_INCLUDE_SHELL;
4752 -                                       } else if (strcmp(token->ptr, "global") == 0) {
4753 +                                       } else if (buffer_is_equal_string(token, CONST_STR_LEN("global"))) {
4754                                                 tid = TK_GLOBAL;
4755 -                                       } else if (strcmp(token->ptr, "else") == 0) {
4756 +                                       } else if (buffer_is_equal_string(token, CONST_STR_LEN("else"))) {
4757                                                 tid = TK_ELSE;
4758                                         } else {
4759                                                 tid = TK_LKEY;
4760                                         }
4761 -                                       
4762 +
4763                                         t->offset += i;
4764                                         t->line_pos += i;
4765                                 } else {
4766                                         /* ERROR */
4767 -                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds", 
4768 +                                       log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4769                                                         "source:", t->source,
4770 -                                                       "line:", t->line, "pos:", t->line_pos, 
4771 +                                                       "line:", t->line, "pos:", t->line_pos,
4772                                                         "invalid character in variable name");
4773                                         return -1;
4774                                 }
4775 @@ -753,16 +767,16 @@
4776                         break;
4777                 }
4778         }
4779 -       
4780 +
4781         if (tid) {
4782                 *token_id = tid;
4783  #if 0
4784 -               log_error_write(srv, __FILE__, __LINE__, "sbsdsdbdd", 
4785 +               log_error_write(srv, __FILE__, __LINE__, "sbsdsdbdd",
4786                                 "source:", t->source,
4787                                 "line:", t->line, "pos:", t->line_pos,
4788                                 token, token->used - 1, tid);
4789  #endif
4790 -               
4791 +
4792                 return 1;
4793         } else if (t->offset < t->size) {
4794                 fprintf(stderr, "%s.%d: %d, %s\n",
4795 @@ -781,10 +795,11 @@
4796         pParser = configparserAlloc( malloc );
4797         lasttoken = buffer_init();
4798         token = buffer_init();
4799 +
4800         while((1 == (ret = config_tokenizer(srv, t, &token_id, token))) && context->ok) {
4801                 buffer_copy_string_buffer(lasttoken, token);
4802                 configparser(pParser, token_id, token, context);
4803 -               
4804 +
4805                 token = buffer_init();
4806         }
4807         buffer_free(token);
4808 @@ -797,14 +812,14 @@
4809                 }
4810         }
4811         configparserFree(pParser, free);
4812 -       
4813 +
4814         if (ret == -1) {
4815 -               log_error_write(srv, __FILE__, __LINE__, "sb", 
4816 +               log_error_write(srv, __FILE__, __LINE__, "sb",
4817                                 "configfile parser failed:", lasttoken);
4818         } else if (context->ok == 0) {
4819 -               log_error_write(srv, __FILE__, __LINE__, "sbsdsdsb", 
4820 +               log_error_write(srv, __FILE__, __LINE__, "sbsdsdsb",
4821                                 "source:", t->source,
4822 -                               "line:", t->line, "pos:", t->line_pos, 
4823 +                               "line:", t->line, "pos:", t->line_pos,
4824                                 "parser failed somehow near here:", lasttoken);
4825                 ret = -1;
4826         }
4827 @@ -821,7 +836,7 @@
4828         t->offset = 0;
4829         t->line = 1;
4830         t->line_pos = 1;
4831 -       
4832 +
4833         t->in_key = 1;
4834         t->in_brace = 0;
4835         t->in_cond = 0;
4836 @@ -844,7 +859,7 @@
4837         }
4838  
4839         if (0 != stream_open(&s, filename)) {
4840 -               log_error_write(srv, __FILE__, __LINE__, "sbss", 
4841 +               log_error_write(srv, __FILE__, __LINE__, "sbss",
4842                                 "opening configfile ", filename, "failed:", strerror(errno));
4843                 ret = -1;
4844         } else {
4845 @@ -866,7 +881,7 @@
4846         char oldpwd[PATH_MAX];
4847  
4848         if (NULL == getcwd(oldpwd, sizeof(oldpwd))) {
4849 -               log_error_write(srv, __FILE__, __LINE__, "s", 
4850 +               log_error_write(srv, __FILE__, __LINE__, "s",
4851                                 "cannot get cwd", strerror(errno));
4852                 return -1;
4853         }
4854 @@ -879,7 +894,7 @@
4855         }
4856  
4857         if (0 != proc_open_buffer(&proc, cmd, NULL, out, NULL)) {
4858 -               log_error_write(srv, __FILE__, __LINE__, "sbss", 
4859 +               log_error_write(srv, __FILE__, __LINE__, "sbss",
4860                                 "opening", source, "failed:", strerror(errno));
4861                 ret = -1;
4862         } else {
4863 @@ -896,13 +911,12 @@
4864  static void context_init(server *srv, config_t *context) {
4865         context->srv = srv;
4866         context->ok = 1;
4867 -       context->configs_stack = array_init();
4868 -       context->configs_stack->is_weakref = 1;
4869 +       context->configs_stack = buffer_ptr_init(NULL);
4870         context->basedir = buffer_init();
4871  }
4872  
4873  static void context_free(config_t *context) {
4874 -       array_free(context->configs_stack);
4875 +       buffer_ptr_free(context->configs_stack);
4876         buffer_free(context->basedir);
4877  }
4878  
4879 @@ -918,18 +932,15 @@
4880         context_init(srv, &context);
4881         context.all_configs = srv->config_context;
4882  
4883 -       pos = strrchr(fn,
4884 -#ifdef __WIN32
4885 -                       '\\'
4886 -#else
4887 -                       '/'
4888 -#endif
4889 -                       );
4890 +    /* use the current dir as basedir for all other includes
4891 +    */
4892 +       pos = strrchr(fn, DIR_SEPERATOR);
4893 +
4894         if (pos) {
4895                 buffer_copy_string_len(context.basedir, fn, pos - fn + 1);
4896                 fn = pos + 1;
4897         }
4898 -       
4899 +
4900         dc = data_config_init();
4901         buffer_copy_string(dc->key, "global");
4902  
4903 @@ -944,7 +955,7 @@
4904         dpid->value = getpid();
4905         buffer_copy_string(dpid->key, "var.PID");
4906         array_insert_unique(srv->config, (data_unset *)dpid);
4907 -       
4908 +
4909         dcwd = data_string_init();
4910         buffer_prepare_copy(dcwd->value, 1024);
4911         if (NULL != getcwd(dcwd->value->ptr, dcwd->value->size - 1)) {
4912 @@ -968,7 +979,7 @@
4913         } else {
4914                 return -1;
4915         }
4916 -       
4917 +
4918         if (NULL != (modules = (data_array *)array_get_element(srv->config, "server.modules"))) {
4919                 data_string *ds;
4920                 data_array *prepends;
4921 @@ -1026,22 +1037,23 @@
4922                 buffer_copy_string(modules->key, "server.modules");
4923                 array_insert_unique(srv->config, (data_unset *)modules);
4924         }
4925 -       
4926 +
4927  
4928         if (0 != config_insert(srv)) {
4929                 return -1;
4930         }
4931 -       
4932 +
4933         return 0;
4934  }
4935  
4936 +
4937  int config_set_defaults(server *srv) {
4938         size_t i;
4939         specific_config *s = srv->config_storage[0];
4940         struct stat st1, st2;
4941 -       
4942 -       struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] = 
4943 -       { 
4944 +
4945 +       struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
4946 +       {
4947                 /* - poll is most reliable
4948                  * - select works everywhere
4949                  * - linux-* are experimental
4950 @@ -1067,20 +1079,21 @@
4951  #endif
4952                 { FDEVENT_HANDLER_UNSET,          NULL }
4953         };
4954 -       
4955  
4956 -       if (buffer_is_empty(s->document_root)) {  
4957 -               log_error_write(srv, __FILE__, __LINE__, "s",  
4958 -                               "a default document-root has to be set");  
4959 -               
4960 -               return -1;  
4961 -       }  
4962 -       
4963 +
4964 +       if (buffer_is_empty(s->document_root)) {
4965 +               log_error_write(srv, __FILE__, __LINE__, "s",
4966 +                               "a default document-root has to be set");
4967 +
4968 +               return -1;
4969 +       }
4970 +
4971         if (buffer_is_empty(srv->srvconf.changeroot)) {
4972 -               if (-1 == stat(s->document_root->ptr, &st1)) {  
4973 -                       log_error_write(srv, __FILE__, __LINE__, "sb",  
4974 +        pathname_unix2local(s->document_root);
4975 +               if (-1 == stat(s->document_root->ptr, &st1)) {
4976 +                       log_error_write(srv, __FILE__, __LINE__, "sbs",
4977                                         "base-docroot doesn't exist:",
4978 -                                       s->document_root);  
4979 +                                       s->document_root, strerror(errno));
4980                         return -1;
4981                 }
4982  
4983 @@ -1088,18 +1101,18 @@
4984                 buffer_copy_string_buffer(srv->tmp_buf, srv->srvconf.changeroot);
4985                 buffer_append_string_buffer(srv->tmp_buf, s->document_root);
4986  
4987 -               if (-1 == stat(srv->tmp_buf->ptr, &st1)) {  
4988 -                       log_error_write(srv, __FILE__, __LINE__, "sb",  
4989 +               if (-1 == stat(srv->tmp_buf->ptr, &st1)) {
4990 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
4991                                         "base-docroot doesn't exist:",
4992 -                                       srv->tmp_buf);  
4993 +                                       srv->tmp_buf);
4994                         return -1;
4995                 }
4996 -               
4997 +
4998         }
4999 -       
5000 -       buffer_copy_string_buffer(srv->tmp_buf, s->document_root);  
5001  
5002 -       buffer_to_lower(srv->tmp_buf);  
5003 +       buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
5004 +
5005 +       buffer_to_lower(srv->tmp_buf);
5006  
5007         if (0 == stat(srv->tmp_buf->ptr, &st1)) {
5008                 int is_lower = 0;
5009 @@ -1107,68 +1120,68 @@
5010                 is_lower = buffer_is_equal(srv->tmp_buf, s->document_root);
5011  
5012                 /* lower-case existed, check upper-case */
5013 -               buffer_copy_string_buffer(srv->tmp_buf, s->document_root);  
5014 +               buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
5015  
5016 -               buffer_to_upper(srv->tmp_buf);  
5017 +               buffer_to_upper(srv->tmp_buf);
5018  
5019                 /* we have to handle the special case that upper and lower-casing results in the same filename
5020                  * as in server.document-root = "/" or "/12345/" */
5021  
5022                 if (is_lower && buffer_is_equal(srv->tmp_buf, s->document_root)) {
5023 -                       /* lower-casing and upper-casing didn't result in  
5024 -                        * an other filename, no need to stat(), 
5025 +                       /* lower-casing and upper-casing didn't result in
5026 +                        * an other filename, no need to stat(),
5027                          * just assume it is case-sensitive. */
5028  
5029                         s->force_lowercase_filenames = 0;
5030 -               } else if (0 == stat(srv->tmp_buf->ptr, &st2)) {  
5031 +               } else if (0 == stat(srv->tmp_buf->ptr, &st2)) {
5032 +
5033 +                       /* upper case exists too, doesn't the FS handle this ? */
5034 +
5035 +                       /* upper and lower have the same inode -> case-insensitve FS */
5036 +
5037 +                       if (st1.st_ino == st2.st_ino) {
5038 +                               /* upper and lower have the same inode -> case-insensitve FS */
5039 +
5040 +                               s->force_lowercase_filenames = 1;
5041 +                       }
5042 +               }
5043 +       }
5044  
5045 -                       /* upper case exists too, doesn't the FS handle this ? */  
5046 -                       
5047 -                       /* upper and lower have the same inode -> case-insensitve FS */  
5048 -                       
5049 -                       if (st1.st_ino == st2.st_ino) {  
5050 -                               /* upper and lower have the same inode -> case-insensitve FS */  
5051 -                               
5052 -                               s->force_lowercase_filenames = 1;  
5053 -                       }  
5054 -               }  
5055 -       }  
5056 -       
5057         if (srv->srvconf.port == 0) {
5058                 srv->srvconf.port = s->is_ssl ? 443 : 80;
5059         }
5060 -       
5061 +
5062         if (srv->srvconf.event_handler->used == 0) {
5063                 /* choose a good default
5064 -                * 
5065 -                * the event_handler list is sorted by 'goodness' 
5066 +                *
5067 +                * the event_handler list is sorted by 'goodness'
5068                  * taking the first available should be the best solution
5069                  */
5070                 srv->event_handler = event_handlers[0].et;
5071 -               
5072 +
5073                 if (FDEVENT_HANDLER_UNSET == srv->event_handler) {
5074 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
5075 +                       log_error_write(srv, __FILE__, __LINE__, "s",
5076                                         "sorry, there is no event handler for this system");
5077 -                       
5078 +
5079                         return -1;
5080                 }
5081         } else {
5082                 /*
5083                  * User override
5084                  */
5085 -               
5086 +
5087                 for (i = 0; event_handlers[i].name; i++) {
5088                         if (0 == strcmp(event_handlers[i].name, srv->srvconf.event_handler->ptr)) {
5089                                 srv->event_handler = event_handlers[i].et;
5090                                 break;
5091                         }
5092                 }
5093 -               
5094 +
5095                 if (FDEVENT_HANDLER_UNSET == srv->event_handler) {
5096 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
5097 -                                       "the selected event-handler in unknown or not supported:", 
5098 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
5099 +                                       "the selected event-handler in unknown or not supported:",
5100                                         srv->srvconf.event_handler );
5101 -                       
5102 +
5103                         return -1;
5104                 }
5105         }
5106 @@ -1176,19 +1189,19 @@
5107         if (s->is_ssl) {
5108                 if (buffer_is_empty(s->ssl_pemfile)) {
5109                         /* PEM file is require */
5110 -                       
5111 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
5112 +
5113 +                       log_error_write(srv, __FILE__, __LINE__, "s",
5114                                         "ssl.pemfile has to be set");
5115                         return -1;
5116                 }
5117 -               
5118 +
5119  #ifndef USE_OPENSSL
5120 -               log_error_write(srv, __FILE__, __LINE__, "s", 
5121 +               log_error_write(srv, __FILE__, __LINE__, "s",
5122                                 "ssl support is missing, recompile with --with-openssl");
5123 -               
5124 +
5125                 return -1;
5126  #endif
5127         }
5128 -       
5129 +
5130         return 0;
5131  }
5132 --- ../lighttpd-1.4.11/src/configfile.h 2005-08-23 17:36:12.000000000 +0300
5133 +++ lighttpd-1.5.0/src/configfile.h     2006-09-07 00:57:05.000000000 +0300
5134 @@ -9,7 +9,7 @@
5135         server *srv;
5136         int     ok;
5137         array  *all_configs;
5138 -       array  *configs_stack; /* to parse nested block */
5139 +       buffer_ptr  *configs_stack; /* to parse nested block */
5140         data_config *current; /* current started with { */
5141         buffer *basedir;
5142  } config_t;
5143 @@ -20,5 +20,6 @@
5144  int config_parse_file(server *srv, config_t *context, const char *fn);
5145  int config_parse_cmd(server *srv, config_t *context, const char *cmd);
5146  data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2);
5147 +void config_cond_cache_reset(server *srv, connection *con);
5148  
5149  #endif
5150 --- ../lighttpd-1.4.11/src/configparser.c       2006-02-01 19:51:15.000000000 +0200
5151 +++ lighttpd-1.5.0/src/configparser.c   2006-09-07 00:57:07.000000000 +0300
5152 @@ -24,52 +24,34 @@
5153      dc->parent = ctx->current;
5154      array_insert_unique(dc->parent->childs, (data_unset *)dc);
5155    }
5156 -  array_insert_unique(ctx->configs_stack, (data_unset *)ctx->current);
5157 +  buffer_ptr_append(ctx->configs_stack, (void *)ctx->current);
5158    ctx->current = dc;
5159  }
5160  
5161  static data_config *configparser_pop(config_t *ctx) {
5162    data_config *old = ctx->current;
5163 -  ctx->current = (data_config *) array_pop(ctx->configs_stack);
5164 +  ctx->current = (data_config *) buffer_ptr_pop(ctx->configs_stack);
5165    return old;
5166  }
5167  
5168  /* return a copied variable */
5169  static data_unset *configparser_get_variable(config_t *ctx, const buffer *key) {
5170 -  if (strncmp(key->ptr, "env.", sizeof("env.") - 1) == 0) {
5171 -    char *env;
5172 -
5173 -    if (NULL != (env = getenv(key->ptr + 4))) {
5174 -      data_string *ds;
5175 -      ds = data_string_init();
5176 -      buffer_append_string(ds->value, env);
5177 -      return (data_unset *)ds;
5178 -    }
5179 -
5180 -    fprintf(stderr, "Undefined env variable: %s\n", key->ptr + 4);
5181 -    ctx->ok = 0;
5182 -
5183 -    return NULL;
5184 -  } else {
5185 -    data_unset *du;
5186 -    data_config *dc;
5187 +  data_unset *du;
5188 +  data_config *dc;
5189  
5190  #if 0
5191 -    fprintf(stderr, "get var %s\n", key->ptr);
5192 +  fprintf(stderr, "get var %s\n", key->ptr);
5193  #endif
5194 -    for (dc = ctx->current; dc; dc = dc->parent) {
5195 +  for (dc = ctx->current; dc; dc = dc->parent) {
5196  #if 0
5197 -      fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
5198 -      array_print(dc->value, 0);
5199 +    fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
5200 +    array_print(dc->value, 0);
5201  #endif
5202 -      if (NULL != (du = array_get_element(dc->value, key->ptr))) {
5203 -        return du->copy(du);
5204 -      }
5205 +    if (NULL != (du = array_get_element(dc->value, key->ptr))) {
5206 +      return du->copy(du);
5207      }
5208 -    fprintf(stderr, "Undefined config variable: %s\n", key->ptr);
5209 -    ctx->ok = 0;
5210 -    return NULL;
5211    }
5212 +  return NULL;
5213  }
5214  
5215  /* op1 is to be eat/return by this function, op1->key is not cared
5216 @@ -124,14 +106,14 @@
5217  }
5218  
5219  
5220 -#line 128 "configparser.c"
5221 +#line 110 "configparser.c"
5222  /* Next is all token values, in a form suitable for use by makeheaders.
5223  ** This section will be null unless lemon is run with the -m switch.
5224  */
5225 -/* 
5226 +/*
5227  ** These constants (all generated automatically by the parser generator)
5228  ** specify the various kinds of tokens (terminals) that the parser
5229 -** understands. 
5230 +** understands.
5231  **
5232  ** Each symbol here is a terminal symbol in the grammar.
5233  */
5234 @@ -148,7 +130,7 @@
5235  **                       and nonterminals.  "int" is used otherwise.
5236  **    YYNOCODE           is a number of type YYCODETYPE which corresponds
5237  **                       to no legal terminal or nonterminal number.  This
5238 -**                       number is used to fill in empty slots of the hash 
5239 +**                       number is used to fill in empty slots of the hash
5240  **                       table.
5241  **    YYFALLBACK         If defined, this indicates that one or more tokens
5242  **                       have fall-back values which should be used if the
5243 @@ -157,7 +139,7 @@
5244  **                       and nonterminal numbers.  "unsigned char" is
5245  **                       used if there are fewer than 250 rules and
5246  **                       states combined.  "int" is used otherwise.
5247 -**    configparserTOKENTYPE     is the data type used for minor tokens given 
5248 +**    configparserTOKENTYPE     is the data type used for minor tokens given
5249  **                       directly to the parser from the tokenizer.
5250  **    YYMINORTYPE        is the data type used for all minor tokens.
5251  **                       This is typically a union of many types, one of
5252 @@ -192,8 +174,8 @@
5253  #define configparserARG_PDECL ,config_t *ctx
5254  #define configparserARG_FETCH config_t *ctx = yypParser->ctx
5255  #define configparserARG_STORE yypParser->ctx = ctx
5256 -#define YYNSTATE 62
5257 -#define YYNRULE 39
5258 +#define YYNSTATE 63
5259 +#define YYNRULE 40
5260  #define YYERRORSYMBOL 26
5261  #define YYERRSYMDT yy95
5262  #define YY_NO_ACTION      (YYNSTATE+YYNRULE+2)
5263 @@ -203,7 +185,7 @@
5264  /* Next are that tables used to determine what action to take based on the
5265  ** current state and lookahead token.  These tables are used to implement
5266  ** functions that take a state number and lookahead value and return an
5267 -** action integer.  
5268 +** action integer.
5269  **
5270  ** Suppose the action integer is N.  Then the action is determined as
5271  ** follows
5272 @@ -228,7 +210,7 @@
5273  ** If the index value yy_shift_ofst[S]+X is out of range or if the value
5274  ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
5275  ** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
5276 -** and that yy_default[S] should be used instead.  
5277 +** and that yy_default[S] should be used instead.
5278  **
5279  ** The formula above is for computing the action when the lookahead is
5280  ** a terminal symbol.  If the lookahead is a non-terminal (as occurs after
5281 @@ -248,67 +230,69 @@
5282  **  yy_default[]       Default action for each state.
5283  */
5284  static YYACTIONTYPE yy_action[] = {
5285 - /*     0 */     2,    3,    4,    5,   13,   14,   62,   15,    7,   44,
5286 - /*    10 */    20,   86,   16,   45,   28,   48,   40,   10,   39,   25,
5287 - /*    20 */    22,   49,   45,    8,   15,  102,    1,   20,   28,   18,
5288 - /*    30 */    57,   59,   19,   25,   22,   39,   19,   61,   98,   45,
5289 - /*    40 */    20,    6,   23,   24,   26,   28,   35,   57,   59,   12,
5290 - /*    50 */    25,   22,   28,   27,   36,   87,   29,   25,   22,   33,
5291 - /*    60 */    15,   30,   31,   20,   28,   38,    9,   17,   37,   25,
5292 - /*    70 */    22,   39,   42,   43,   10,   45,   11,   53,   54,   55,
5293 - /*    80 */    56,   28,   52,   57,   59,   34,   25,   22,   28,   27,
5294 - /*    90 */    32,   88,   41,   25,   22,   33,   28,   48,   46,   28,
5295 - /*   100 */    48,   25,   22,   58,   25,   22,   60,   21,   19,   47,
5296 - /*   110 */    51,   50,   25,   22,   88,   88,   93,
5297 + /*     0 */     2,    3,    4,    5,   13,   14,   63,   15,    7,   45,
5298 + /*    10 */    20,   88,   16,   46,   28,   49,   41,   10,   40,   25,
5299 + /*    20 */    22,   50,   46,    8,   15,  104,    1,   20,   28,   18,
5300 + /*    30 */    58,   60,    6,   25,   22,   40,   47,   62,   11,   46,
5301 + /*    40 */    20,    9,   23,   24,   26,   29,   89,   58,   60,   10,
5302 + /*    50 */    17,   38,   28,   27,   37,   19,   30,   25,   22,   34,
5303 + /*    60 */    15,  100,   20,   20,   23,   24,   26,   12,   19,   31,
5304 + /*    70 */    32,   40,   19,   44,   43,   46,   95,   35,   90,   89,
5305 + /*    80 */    28,   49,   42,   58,   60,   25,   22,   59,   28,   27,
5306 + /*    90 */    33,   48,   52,   25,   22,   34,   28,   49,   51,   28,
5307 + /*   100 */    36,   25,   22,   61,   25,   22,   89,   28,   39,   89,
5308 + /*   110 */    89,   89,   25,   22,   54,   55,   56,   57,   89,   28,
5309 + /*   120 */    53,   21,   89,   89,   25,   22,   25,   22,
5310  };
5311  static YYCODETYPE yy_lookahead[] = {
5312   /*     0 */    29,   30,   31,   32,   33,   34,    0,    1,   44,   38,
5313   /*    10 */     4,   15,   41,   16,   35,   36,   45,   46,   12,   40,
5314   /*    20 */    41,   42,   16,   15,    1,   27,   28,    4,   35,   36,
5315 - /*    30 */    24,   25,    5,   40,   41,   12,    5,   14,   11,   16,
5316 - /*    40 */     4,    1,    6,    7,    8,   35,   36,   24,   25,   28,
5317 - /*    50 */    40,   41,   35,   36,   37,   15,   39,   40,   41,   42,
5318 - /*    60 */     1,    9,   10,    4,   35,   36,   38,    2,    3,   40,
5319 - /*    70 */    41,   12,   28,   14,   46,   16,   13,   20,   21,   22,
5320 - /*    80 */    23,   35,   36,   24,   25,   11,   40,   41,   35,   36,
5321 - /*    90 */    37,   13,   13,   40,   41,   42,   35,   36,   17,   35,
5322 - /*   100 */    36,   40,   41,   42,   40,   41,   42,   35,    5,   18,
5323 - /*   110 */    43,   19,   40,   41,   47,   47,   13,
5324 + /*    30 */    24,   25,    1,   40,   41,   12,   17,   14,   13,   16,
5325 + /*    40 */     4,   38,    6,    7,    8,    9,   15,   24,   25,   46,
5326 + /*    50 */     2,    3,   35,   36,   37,    5,   39,   40,   41,   42,
5327 + /*    60 */     1,   11,    4,    4,    6,    7,    8,   28,    5,    9,
5328 + /*    70 */    10,   12,    5,   14,   28,   16,   13,   11,   13,   47,
5329 + /*    80 */    35,   36,   13,   24,   25,   40,   41,   42,   35,   36,
5330 + /*    90 */    37,   18,   43,   40,   41,   42,   35,   36,   19,   35,
5331 + /*   100 */    36,   40,   41,   42,   40,   41,   47,   35,   36,   47,
5332 + /*   110 */    47,   47,   40,   41,   20,   21,   22,   23,   47,   35,
5333 + /*   120 */    36,   35,   47,   47,   40,   41,   40,   41,
5334  };
5335  #define YY_SHIFT_USE_DFLT (-5)
5336  static signed char yy_shift_ofst[] = {
5337 - /*     0 */    -5,    6,   -5,   -5,   -5,   40,   -4,    8,   -3,   -5,
5338 - /*    10 */    63,   -5,   23,   -5,   -5,   -5,   65,   36,   31,   36,
5339 - /*    20 */    -5,   -5,   -5,   -5,   -5,   -5,   36,   27,   -5,   52,
5340 - /*    30 */    -5,   36,   -5,   74,   36,   31,   -5,   36,   31,   78,
5341 - /*    40 */    79,   -5,   59,   -5,   -5,   81,   91,   36,   31,   92,
5342 - /*    50 */    57,   36,  103,   -5,   -5,   -5,   -5,   36,   -5,   36,
5343 - /*    60 */    -5,   -5,
5344 + /*     0 */    -5,    6,   -5,   -5,   -5,   31,   -4,    8,   -3,   -5,
5345 + /*    10 */    25,   -5,   23,   -5,   -5,   -5,   48,   58,   67,   58,
5346 + /*    20 */    -5,   -5,   -5,   -5,   -5,   -5,   36,   50,   -5,   -5,
5347 + /*    30 */    60,   -5,   58,   -5,   66,   58,   67,   -5,   58,   67,
5348 + /*    40 */    65,   69,   -5,   59,   -5,   -5,   19,   73,   58,   67,
5349 + /*    50 */    79,   94,   58,   63,   -5,   -5,   -5,   -5,   58,   -5,
5350 + /*    60 */    58,   -5,   -5,
5351  };
5352  #define YY_REDUCE_USE_DFLT (-37)
5353  static signed char yy_reduce_ofst[] = {
5354 - /*     0 */    -2,  -29,  -37,  -37,  -37,  -36,  -37,  -37,   28,  -37,
5355 - /*    10 */   -37,   21,  -29,  -37,  -37,  -37,  -37,   -7,  -37,   72,
5356 + /*     0 */    -2,  -29,  -37,  -37,  -37,  -36,  -37,  -37,    3,  -37,
5357 + /*    10 */   -37,   39,  -29,  -37,  -37,  -37,  -37,   -7,  -37,   86,
5358   /*    20 */   -37,  -37,  -37,  -37,  -37,  -37,   17,  -37,  -37,  -37,
5359 - /*    30 */   -37,   53,  -37,  -37,   10,  -37,  -37,   29,  -37,  -37,
5360 - /*    40 */   -37,   44,  -29,  -37,  -37,  -37,  -37,  -21,  -37,  -37,
5361 - /*    50 */    67,   46,  -37,  -37,  -37,  -37,  -37,   61,  -37,   64,
5362 - /*    60 */   -37,  -37,
5363 + /*    30 */   -37,  -37,   53,  -37,  -37,   64,  -37,  -37,   72,  -37,
5364 + /*    40 */   -37,  -37,   46,  -29,  -37,  -37,  -37,  -37,  -21,  -37,
5365 + /*    50 */   -37,   49,   84,  -37,  -37,  -37,  -37,  -37,   45,  -37,
5366 + /*    60 */    61,  -37,  -37,
5367  };
5368  static YYACTIONTYPE yy_default[] = {
5369 - /*     0 */    64,  101,   63,   65,   66,  101,   67,  101,  101,   90,
5370 - /*    10 */   101,   64,  101,   68,   69,   70,  101,  101,   71,  101,
5371 - /*    20 */    73,   74,   76,   77,   78,   79,  101,   84,   75,  101,
5372 - /*    30 */    80,   82,   81,  101,  101,   85,   83,  101,   72,  101,
5373 - /*    40 */   101,   64,  101,   89,   91,  101,  101,  101,   98,  101,
5374 - /*    50 */   101,  101,  101,   94,   95,   96,   97,  101,   99,  101,
5375 - /*    60 */   100,   92,
5376 + /*     0 */    65,  103,   64,   66,   67,  103,   68,  103,  103,   92,
5377 + /*    10 */   103,   65,  103,   69,   70,   71,  103,  103,   72,  103,
5378 + /*    20 */    74,   75,   77,   78,   79,   80,  103,   86,   76,   81,
5379 + /*    30 */   103,   82,   84,   83,  103,  103,   87,   85,  103,   73,
5380 + /*    40 */   103,  103,   65,  103,   91,   93,  103,  103,  103,  100,
5381 + /*    50 */   103,  103,  103,  103,   96,   97,   98,   99,  103,  101,
5382 + /*    60 */   103,  102,   94,
5383  };
5384  #define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0]))
5385  
5386  /* The next table maps tokens into fallback tokens.  If a construct
5387  ** like the following:
5388 -** 
5389 +**
5390  **      %fallback ID X Y Z.
5391  **
5392  ** appears in the grammer, then ID becomes a fallback token for X, Y,
5393 @@ -359,10 +343,10 @@
5394  #endif /* NDEBUG */
5395  
5396  #ifndef NDEBUG
5397 -/* 
5398 +/*
5399  ** Turn parser tracing on by giving a stream to which to write the trace
5400  ** and a prompt to preface each trace message.  Tracing is turned off
5401 -** by making either argument NULL 
5402 +** by making either argument NULL
5403  **
5404  ** Inputs:
5405  ** <ul>
5406 @@ -387,7 +371,7 @@
5407  #ifndef NDEBUG
5408  /* For tracing shifts, the names of all terminals and nonterminals
5409  ** are required.  The following table supplies these names */
5410 -static const char *yyTokenName[] = { 
5411 +static const char *yyTokenName[] = {
5412    "$",             "EOL",           "ASSIGN",        "APPEND",      
5413    "LKEY",          "PLUS",          "STRING",        "INTEGER",     
5414    "LPARAN",        "RPARAN",        "COMMA",         "ARRAY_ASSIGN",
5415 @@ -425,27 +409,28 @@
5416   /*  15 */ "value ::= STRING",
5417   /*  16 */ "value ::= INTEGER",
5418   /*  17 */ "value ::= array",
5419 - /*  18 */ "array ::= LPARAN aelements RPARAN",
5420 - /*  19 */ "aelements ::= aelements COMMA aelement",
5421 - /*  20 */ "aelements ::= aelements COMMA",
5422 - /*  21 */ "aelements ::= aelement",
5423 - /*  22 */ "aelement ::= expression",
5424 - /*  23 */ "aelement ::= stringop ARRAY_ASSIGN expression",
5425 - /*  24 */ "eols ::= EOL",
5426 - /*  25 */ "eols ::=",
5427 - /*  26 */ "globalstart ::= GLOBAL",
5428 - /*  27 */ "global ::= globalstart LCURLY metalines RCURLY",
5429 - /*  28 */ "condlines ::= condlines eols ELSE condline",
5430 - /*  29 */ "condlines ::= condline",
5431 - /*  30 */ "condline ::= context LCURLY metalines RCURLY",
5432 - /*  31 */ "context ::= DOLLAR SRVVARNAME LBRACKET stringop RBRACKET cond expression",
5433 - /*  32 */ "cond ::= EQ",
5434 - /*  33 */ "cond ::= MATCH",
5435 - /*  34 */ "cond ::= NE",
5436 - /*  35 */ "cond ::= NOMATCH",
5437 - /*  36 */ "stringop ::= expression",
5438 - /*  37 */ "include ::= INCLUDE stringop",
5439 - /*  38 */ "include_shell ::= INCLUDE_SHELL stringop",
5440 + /*  18 */ "array ::= LPARAN RPARAN",
5441 + /*  19 */ "array ::= LPARAN aelements RPARAN",
5442 + /*  20 */ "aelements ::= aelements COMMA aelement",
5443 + /*  21 */ "aelements ::= aelements COMMA",
5444 + /*  22 */ "aelements ::= aelement",
5445 + /*  23 */ "aelement ::= expression",
5446 + /*  24 */ "aelement ::= stringop ARRAY_ASSIGN expression",
5447 + /*  25 */ "eols ::= EOL",
5448 + /*  26 */ "eols ::=",
5449 + /*  27 */ "globalstart ::= GLOBAL",
5450 + /*  28 */ "global ::= globalstart LCURLY metalines RCURLY",
5451 + /*  29 */ "condlines ::= condlines eols ELSE condline",
5452 + /*  30 */ "condlines ::= condline",
5453 + /*  31 */ "condline ::= context LCURLY metalines RCURLY",
5454 + /*  32 */ "context ::= DOLLAR SRVVARNAME LBRACKET stringop RBRACKET cond expression",
5455 + /*  33 */ "cond ::= EQ",
5456 + /*  34 */ "cond ::= MATCH",
5457 + /*  35 */ "cond ::= NE",
5458 + /*  36 */ "cond ::= NOMATCH",
5459 + /*  37 */ "stringop ::= expression",
5460 + /*  38 */ "include ::= INCLUDE stringop",
5461 + /*  39 */ "include_shell ::= INCLUDE_SHELL stringop",
5462  };
5463  #endif /* NDEBUG */
5464  
5465 @@ -465,7 +450,7 @@
5466  #endif
5467  }
5468  
5469 -/* 
5470 +/*
5471  ** This function allocates a new parser.
5472  ** The only argument is a pointer to a function which works like
5473  ** malloc.
5474 @@ -496,7 +481,7 @@
5475      /* Here is inserted the actions which take place when a
5476      ** terminal or non-terminal is destroyed.  This can happen
5477      ** when the symbol is popped from the stack during a
5478 -    ** reduce or during error processing or when a parser is 
5479 +    ** reduce or during error processing or when a parser is
5480      ** being destroyed before it is finished parsing.
5481      **
5482      ** Note: during a reduce, the only symbols destroyed are those
5483 @@ -528,44 +513,44 @@
5484      case 23:
5485      case 24:
5486      case 25:
5487 -#line 160 "./configparser.y"
5488 +#line 143 "./configparser.y"
5489  { buffer_free((yypminor->yy0)); }
5490 -#line 533 "configparser.c"
5491 +#line 518 "configparser.c"
5492        break;
5493      case 35:
5494 -#line 151 "./configparser.y"
5495 +#line 134 "./configparser.y"
5496  { (yypminor->yy41)->free((yypminor->yy41)); }
5497 -#line 538 "configparser.c"
5498 +#line 523 "configparser.c"
5499        break;
5500      case 36:
5501 -#line 152 "./configparser.y"
5502 +#line 135 "./configparser.y"
5503  { (yypminor->yy41)->free((yypminor->yy41)); }
5504 -#line 543 "configparser.c"
5505 +#line 528 "configparser.c"
5506        break;
5507      case 37:
5508 -#line 153 "./configparser.y"
5509 +#line 136 "./configparser.y"
5510  { (yypminor->yy41)->free((yypminor->yy41)); }
5511 -#line 548 "configparser.c"
5512 +#line 533 "configparser.c"
5513        break;
5514      case 39:
5515 -#line 154 "./configparser.y"
5516 +#line 137 "./configparser.y"
5517  { array_free((yypminor->yy40)); }
5518 -#line 553 "configparser.c"
5519 +#line 538 "configparser.c"
5520        break;
5521      case 40:
5522 -#line 155 "./configparser.y"
5523 +#line 138 "./configparser.y"
5524  { array_free((yypminor->yy40)); }
5525 -#line 558 "configparser.c"
5526 +#line 543 "configparser.c"
5527        break;
5528      case 41:
5529 -#line 156 "./configparser.y"
5530 +#line 139 "./configparser.y"
5531  { buffer_free((yypminor->yy43)); }
5532 -#line 563 "configparser.c"
5533 +#line 548 "configparser.c"
5534        break;
5535      case 42:
5536 -#line 157 "./configparser.y"
5537 +#line 140 "./configparser.y"
5538  { buffer_free((yypminor->yy43)); }
5539 -#line 568 "configparser.c"
5540 +#line 553 "configparser.c"
5541        break;
5542      default:  break;   /* If no destructor action specified: do nothing */
5543    }
5544 @@ -597,7 +582,7 @@
5545    return yymajor;
5546  }
5547  
5548 -/* 
5549 +/*
5550  ** Deallocate and destroy a parser.  Destructors are all called for
5551  ** all stack elements before shutting the parser down.
5552  **
5553 @@ -633,7 +618,7 @@
5554  ){
5555    int i;
5556    int stateno = pParser->yystack[pParser->yyidx].stateno;
5557
5558 +
5559    /* if( pParser->yyidx<0 ) return YY_NO_ACTION;  */
5560    i = yy_shift_ofst[stateno];
5561    if( i==YY_SHIFT_USE_DFLT ){
5562 @@ -677,7 +662,7 @@
5563  ){
5564    int i;
5565    int stateno = pParser->yystack[pParser->yyidx].stateno;
5566
5567 +
5568    i = yy_reduce_ofst[stateno];
5569    if( i==YY_REDUCE_USE_DFLT ){
5570      return yy_default[stateno];
5571 @@ -759,6 +744,7 @@
5572    { 35, 1 },
5573    { 35, 1 },
5574    { 35, 1 },
5575 +  { 40, 2 },
5576    { 40, 3 },
5577    { 39, 3 },
5578    { 39, 2 },
5579 @@ -800,7 +786,7 @@
5580    configparserARG_FETCH;
5581    yymsp = &yypParser->yystack[yypParser->yyidx];
5582  #ifndef NDEBUG
5583 -  if( yyTraceFILE && yyruleno>=0 
5584 +  if( yyTraceFILE && yyruleno>=0
5585          && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
5586      fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
5587        yyRuleName[yyruleno]);
5588 @@ -832,9 +818,9 @@
5589          /* No destructor defined for global */
5590          break;
5591        case 5:
5592 -#line 134 "./configparser.y"
5593 +#line 116 "./configparser.y"
5594  { yymsp[-1].minor.yy78 = NULL; }
5595 -#line 837 "configparser.c"
5596 +#line 823 "configparser.c"
5597    yy_destructor(1,&yymsp[0].minor);
5598          break;
5599        case 6:
5600 @@ -847,10 +833,15 @@
5601    yy_destructor(1,&yymsp[0].minor);
5602          break;
5603        case 9:
5604 -#line 162 "./configparser.y"
5605 +#line 145 "./configparser.y"
5606  {
5607    buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
5608 -  if (NULL == array_get_element(ctx->current->value, yymsp[0].minor.yy41->key->ptr)) {
5609 +  if (strncmp(yymsp[-2].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
5610 +    fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
5611 +        ctx->current->context_ndx,
5612 +        ctx->current->key->ptr, yymsp[-2].minor.yy43->ptr);
5613 +    ctx->ok = 0;
5614 +  } else if (NULL == array_get_element(ctx->current->value, yymsp[0].minor.yy41->key->ptr)) {
5615      array_insert_unique(ctx->current->value, yymsp[0].minor.yy41);
5616      yymsp[0].minor.yy41 = NULL;
5617    } else {
5618 @@ -864,16 +855,21 @@
5619    buffer_free(yymsp[-2].minor.yy43);
5620    yymsp[-2].minor.yy43 = NULL;
5621  }
5622 -#line 867 "configparser.c"
5623 +#line 858 "configparser.c"
5624    yy_destructor(2,&yymsp[-1].minor);
5625          break;
5626        case 10:
5627 -#line 179 "./configparser.y"
5628 +#line 167 "./configparser.y"
5629  {
5630    array *vars = ctx->current->value;
5631    data_unset *du;
5632  
5633 -  if (NULL != (du = array_get_element(vars, yymsp[-2].minor.yy43->ptr))) {
5634 +  if (strncmp(yymsp[-2].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
5635 +    fprintf(stderr, "Appending env variable is not supported in conditional %d %s: %s\n",
5636 +        ctx->current->context_ndx,
5637 +        ctx->current->key->ptr, yymsp[-2].minor.yy43->ptr);
5638 +    ctx->ok = 0;
5639 +  } else if (NULL != (du = array_get_element(vars, yymsp[-2].minor.yy43->ptr))) {
5640      /* exists in current block */
5641      du = configparser_merge_data(du, yymsp[0].minor.yy41);
5642      if (NULL == du) {
5643 @@ -883,6 +879,7 @@
5644        buffer_copy_string_buffer(du->key, yymsp[-2].minor.yy43);
5645        array_replace(vars, du);
5646      }
5647 +    yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5648    } else if (NULL != (du = configparser_get_variable(ctx, yymsp[-2].minor.yy43))) {
5649      du = configparser_merge_data(du, yymsp[0].minor.yy41);
5650      if (NULL == du) {
5651 @@ -892,22 +889,20 @@
5652        buffer_copy_string_buffer(du->key, yymsp[-2].minor.yy43);
5653        array_insert_unique(ctx->current->value, du);
5654      }
5655 +    yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5656    } else {
5657 -    fprintf(stderr, "Undefined config variable in conditional %d %s: %s\n", 
5658 -            ctx->current->context_ndx,
5659 -            ctx->current->key->ptr, yymsp[-2].minor.yy43->ptr);
5660 -    ctx->ok = 0;
5661 +    buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
5662 +    array_insert_unique(ctx->current->value, yymsp[0].minor.yy41);
5663    }
5664    buffer_free(yymsp[-2].minor.yy43);
5665    yymsp[-2].minor.yy43 = NULL;
5666 -  yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5667    yymsp[0].minor.yy41 = NULL;
5668  }
5669 -#line 906 "configparser.c"
5670 +#line 901 "configparser.c"
5671    yy_destructor(3,&yymsp[-1].minor);
5672          break;
5673        case 11:
5674 -#line 214 "./configparser.y"
5675 +#line 206 "./configparser.y"
5676  {
5677    if (strchr(yymsp[0].minor.yy0->ptr, '.') == NULL) {
5678      yygotominor.yy43 = buffer_init_string("var.");
5679 @@ -919,10 +914,10 @@
5680      yymsp[0].minor.yy0 = NULL;
5681    }
5682  }
5683 -#line 922 "configparser.c"
5684 +#line 917 "configparser.c"
5685          break;
5686        case 12:
5687 -#line 226 "./configparser.y"
5688 +#line 218 "./configparser.y"
5689  {
5690    yygotominor.yy41 = configparser_merge_data(yymsp[-2].minor.yy41, yymsp[0].minor.yy41);
5691    if (NULL == yygotominor.yy41) {
5692 @@ -932,21 +927,38 @@
5693    yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5694    yymsp[0].minor.yy41 = NULL;
5695  }
5696 -#line 935 "configparser.c"
5697 +#line 930 "configparser.c"
5698    yy_destructor(5,&yymsp[-1].minor);
5699          break;
5700        case 13:
5701 -#line 236 "./configparser.y"
5702 +#line 228 "./configparser.y"
5703  {
5704    yygotominor.yy41 = yymsp[0].minor.yy41;
5705    yymsp[0].minor.yy41 = NULL;
5706  }
5707 -#line 944 "configparser.c"
5708 +#line 939 "configparser.c"
5709          break;
5710        case 14:
5711 -#line 241 "./configparser.y"
5712 +#line 233 "./configparser.y"
5713  {
5714 -  yygotominor.yy41 = configparser_get_variable(ctx, yymsp[0].minor.yy43);
5715 +  if (strncmp(yymsp[0].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
5716 +    char *env;
5717 +
5718 +    if (NULL != (env = getenv(yymsp[0].minor.yy43->ptr + 4))) {
5719 +      data_string *ds;
5720 +      ds = data_string_init();
5721 +      buffer_append_string(ds->value, env);
5722 +      yygotominor.yy41 = (data_unset *)ds;
5723 +    }
5724 +    else {
5725 +      yygotominor.yy41 = NULL;
5726 +      fprintf(stderr, "Undefined env variable: %s\n", yymsp[0].minor.yy43->ptr + 4);
5727 +      ctx->ok = 0;
5728 +    }
5729 +  } else if (NULL == (yygotominor.yy41 = configparser_get_variable(ctx, yymsp[0].minor.yy43))) {
5730 +    fprintf(stderr, "Undefined config variable: %s\n", yymsp[0].minor.yy43->ptr);
5731 +    ctx->ok = 0;
5732 +  }
5733    if (!yygotominor.yy41) {
5734      /* make a dummy so it won't crash */
5735      yygotominor.yy41 = (data_unset *)data_string_init();
5736 @@ -954,50 +966,59 @@
5737    buffer_free(yymsp[0].minor.yy43);
5738    yymsp[0].minor.yy43 = NULL;
5739  }
5740 -#line 957 "configparser.c"
5741 +#line 969 "configparser.c"
5742          break;
5743        case 15:
5744 -#line 251 "./configparser.y"
5745 +#line 260 "./configparser.y"
5746  {
5747    yygotominor.yy41 = (data_unset *)data_string_init();
5748    buffer_copy_string_buffer(((data_string *)(yygotominor.yy41))->value, yymsp[0].minor.yy0);
5749    buffer_free(yymsp[0].minor.yy0);
5750    yymsp[0].minor.yy0 = NULL;
5751  }
5752 -#line 967 "configparser.c"
5753 +#line 979 "configparser.c"
5754          break;
5755        case 16:
5756 -#line 258 "./configparser.y"
5757 +#line 267 "./configparser.y"
5758  {
5759    yygotominor.yy41 = (data_unset *)data_integer_init();
5760    ((data_integer *)(yygotominor.yy41))->value = strtol(yymsp[0].minor.yy0->ptr, NULL, 10);
5761    buffer_free(yymsp[0].minor.yy0);
5762    yymsp[0].minor.yy0 = NULL;
5763  }
5764 -#line 977 "configparser.c"
5765 +#line 989 "configparser.c"
5766          break;
5767        case 17:
5768 -#line 264 "./configparser.y"
5769 +#line 273 "./configparser.y"
5770  {
5771    yygotominor.yy41 = (data_unset *)data_array_init();
5772    array_free(((data_array *)(yygotominor.yy41))->value);
5773    ((data_array *)(yygotominor.yy41))->value = yymsp[0].minor.yy40;
5774    yymsp[0].minor.yy40 = NULL;
5775  }
5776 -#line 987 "configparser.c"
5777 +#line 999 "configparser.c"
5778          break;
5779        case 18:
5780 -#line 270 "./configparser.y"
5781 +#line 279 "./configparser.y"
5782 +{
5783 +  yygotominor.yy40 = array_init();
5784 +}
5785 +#line 1006 "configparser.c"
5786 +  yy_destructor(8,&yymsp[-1].minor);
5787 +  yy_destructor(9,&yymsp[0].minor);
5788 +        break;
5789 +      case 19:
5790 +#line 282 "./configparser.y"
5791  {
5792    yygotominor.yy40 = yymsp[-1].minor.yy40;
5793    yymsp[-1].minor.yy40 = NULL;
5794  }
5795 -#line 995 "configparser.c"
5796 +#line 1016 "configparser.c"
5797    yy_destructor(8,&yymsp[-2].minor);
5798    yy_destructor(9,&yymsp[0].minor);
5799          break;
5800 -      case 19:
5801 -#line 275 "./configparser.y"
5802 +      case 20:
5803 +#line 287 "./configparser.y"
5804  {
5805    if (buffer_is_empty(yymsp[0].minor.yy41->key) ||
5806        NULL == array_get_element(yymsp[-2].minor.yy40, yymsp[0].minor.yy41->key->ptr)) {
5807 @@ -1014,37 +1035,37 @@
5808    yygotominor.yy40 = yymsp[-2].minor.yy40;
5809    yymsp[-2].minor.yy40 = NULL;
5810  }
5811 -#line 1017 "configparser.c"
5812 +#line 1038 "configparser.c"
5813    yy_destructor(10,&yymsp[-1].minor);
5814          break;
5815 -      case 20:
5816 -#line 292 "./configparser.y"
5817 +      case 21:
5818 +#line 304 "./configparser.y"
5819  {
5820    yygotominor.yy40 = yymsp[-1].minor.yy40;
5821    yymsp[-1].minor.yy40 = NULL;
5822  }
5823 -#line 1026 "configparser.c"
5824 +#line 1047 "configparser.c"
5825    yy_destructor(10,&yymsp[0].minor);
5826          break;
5827 -      case 21:
5828 -#line 297 "./configparser.y"
5829 +      case 22:
5830 +#line 309 "./configparser.y"
5831  {
5832    yygotominor.yy40 = array_init();
5833    array_insert_unique(yygotominor.yy40, yymsp[0].minor.yy41);
5834    yymsp[0].minor.yy41 = NULL;
5835  }
5836 -#line 1036 "configparser.c"
5837 +#line 1057 "configparser.c"
5838          break;
5839 -      case 22:
5840 -#line 303 "./configparser.y"
5841 +      case 23:
5842 +#line 315 "./configparser.y"
5843  {
5844    yygotominor.yy41 = yymsp[0].minor.yy41;
5845    yymsp[0].minor.yy41 = NULL;
5846  }
5847 -#line 1044 "configparser.c"
5848 +#line 1065 "configparser.c"
5849          break;
5850 -      case 23:
5851 -#line 307 "./configparser.y"
5852 +      case 24:
5853 +#line 319 "./configparser.y"
5854  {
5855    buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
5856    buffer_free(yymsp[-2].minor.yy43);
5857 @@ -1053,27 +1074,27 @@
5858    yygotominor.yy41 = yymsp[0].minor.yy41;
5859    yymsp[0].minor.yy41 = NULL;
5860  }
5861 -#line 1056 "configparser.c"
5862 +#line 1077 "configparser.c"
5863    yy_destructor(11,&yymsp[-1].minor);
5864          break;
5865 -      case 24:
5866 -  yy_destructor(1,&yymsp[0].minor);
5867 -        break;
5868        case 25:
5869 +  yy_destructor(1,&yymsp[0].minor);
5870          break;
5871        case 26:
5872 -#line 319 "./configparser.y"
5873 +        break;
5874 +      case 27:
5875 +#line 331 "./configparser.y"
5876  {
5877    data_config *dc;
5878    dc = (data_config *)array_get_element(ctx->srv->config_context, "global");
5879    assert(dc);
5880    configparser_push(ctx, dc, 0);
5881  }
5882 -#line 1072 "configparser.c"
5883 +#line 1093 "configparser.c"
5884    yy_destructor(12,&yymsp[0].minor);
5885          break;
5886 -      case 27:
5887 -#line 326 "./configparser.y"
5888 +      case 28:
5889 +#line 338 "./configparser.y"
5890  {
5891    data_config *cur;
5892    
5893 @@ -1082,16 +1103,16 @@
5894  
5895    assert(cur && ctx->current);
5896  
5897 -  yygotominor.yy0 = cur;
5898 +  yygotominor.yy78 = cur;
5899  }
5900 -#line 1087 "configparser.c"
5901 +#line 1108 "configparser.c"
5902          /* No destructor defined for globalstart */
5903    yy_destructor(13,&yymsp[-2].minor);
5904          /* No destructor defined for metalines */
5905    yy_destructor(14,&yymsp[0].minor);
5906          break;
5907 -      case 28:
5908 -#line 337 "./configparser.y"
5909 +      case 29:
5910 +#line 349 "./configparser.y"
5911  {
5912    assert(yymsp[-3].minor.yy78->context_ndx < yymsp[0].minor.yy78->context_ndx);
5913    yymsp[0].minor.yy78->prev = yymsp[-3].minor.yy78;
5914 @@ -1100,20 +1121,20 @@
5915    yymsp[-3].minor.yy78 = NULL;
5916    yymsp[0].minor.yy78 = NULL;
5917  }
5918 -#line 1103 "configparser.c"
5919 +#line 1124 "configparser.c"
5920          /* No destructor defined for eols */
5921    yy_destructor(15,&yymsp[-1].minor);
5922          break;
5923 -      case 29:
5924 -#line 346 "./configparser.y"
5925 +      case 30:
5926 +#line 358 "./configparser.y"
5927  {
5928    yygotominor.yy78 = yymsp[0].minor.yy78;
5929    yymsp[0].minor.yy78 = NULL;
5930  }
5931 -#line 1113 "configparser.c"
5932 +#line 1134 "configparser.c"
5933          break;
5934 -      case 30:
5935 -#line 351 "./configparser.y"
5936 +      case 31:
5937 +#line 363 "./configparser.y"
5938  {
5939    data_config *cur;
5940    
5941 @@ -1124,14 +1145,14 @@
5942  
5943    yygotominor.yy78 = cur;
5944  }
5945 -#line 1127 "configparser.c"
5946 +#line 1148 "configparser.c"
5947          /* No destructor defined for context */
5948    yy_destructor(13,&yymsp[-2].minor);
5949          /* No destructor defined for metalines */
5950    yy_destructor(14,&yymsp[0].minor);
5951          break;
5952 -      case 31:
5953 -#line 362 "./configparser.y"
5954 +      case 32:
5955 +#line 374 "./configparser.y"
5956  {
5957    data_config *dc;
5958    buffer *b, *rvalue, *op;
5959 @@ -1183,6 +1204,7 @@
5960        { COMP_HTTP_USERAGENT,     CONST_STR_LEN("HTTP[\"useragent\"]"  ) },
5961        { COMP_HTTP_COOKIE,        CONST_STR_LEN("HTTP[\"cookie\"]"     ) },
5962        { COMP_HTTP_REMOTEIP,      CONST_STR_LEN("HTTP[\"remoteip\"]"   ) },
5963 +      { COMP_HTTP_QUERYSTRING,   CONST_STR_LEN("HTTP[\"querystring\"]") },
5964        { COMP_UNSET, NULL, 0 },
5965      };
5966      size_t i;
5967 @@ -1266,45 +1288,45 @@
5968    yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5969    yymsp[0].minor.yy41 = NULL;
5970  }
5971 -#line 1269 "configparser.c"
5972 +#line 1291 "configparser.c"
5973    yy_destructor(16,&yymsp[-6].minor);
5974    yy_destructor(18,&yymsp[-4].minor);
5975    yy_destructor(19,&yymsp[-2].minor);
5976          break;
5977 -      case 32:
5978 -#line 496 "./configparser.y"
5979 +      case 33:
5980 +#line 509 "./configparser.y"
5981  {
5982    yygotominor.yy27 = CONFIG_COND_EQ;
5983  }
5984 -#line 1279 "configparser.c"
5985 +#line 1301 "configparser.c"
5986    yy_destructor(20,&yymsp[0].minor);
5987          break;
5988 -      case 33:
5989 -#line 499 "./configparser.y"
5990 +      case 34:
5991 +#line 512 "./configparser.y"
5992  {
5993    yygotominor.yy27 = CONFIG_COND_MATCH;
5994  }
5995 -#line 1287 "configparser.c"
5996 +#line 1309 "configparser.c"
5997    yy_destructor(21,&yymsp[0].minor);
5998          break;
5999 -      case 34:
6000 -#line 502 "./configparser.y"
6001 +      case 35:
6002 +#line 515 "./configparser.y"
6003  {
6004    yygotominor.yy27 = CONFIG_COND_NE;
6005  }
6006 -#line 1295 "configparser.c"
6007 +#line 1317 "configparser.c"
6008    yy_destructor(22,&yymsp[0].minor);
6009          break;
6010 -      case 35:
6011 -#line 505 "./configparser.y"
6012 +      case 36:
6013 +#line 518 "./configparser.y"
6014  {
6015    yygotominor.yy27 = CONFIG_COND_NOMATCH;
6016  }
6017 -#line 1303 "configparser.c"
6018 +#line 1325 "configparser.c"
6019    yy_destructor(23,&yymsp[0].minor);
6020          break;
6021 -      case 36:
6022 -#line 509 "./configparser.y"
6023 +      case 37:
6024 +#line 522 "./configparser.y"
6025  {
6026    yygotominor.yy43 = NULL;
6027    if (ctx->ok) {
6028 @@ -1321,10 +1343,10 @@
6029    yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
6030    yymsp[0].minor.yy41 = NULL;
6031  }
6032 -#line 1324 "configparser.c"
6033 +#line 1346 "configparser.c"
6034          break;
6035 -      case 37:
6036 -#line 526 "./configparser.y"
6037 +      case 38:
6038 +#line 539 "./configparser.y"
6039  {
6040    if (ctx->ok) {
6041      if (0 != config_parse_file(ctx->srv, ctx, yymsp[0].minor.yy43->ptr)) {
6042 @@ -1334,11 +1356,11 @@
6043      yymsp[0].minor.yy43 = NULL;
6044    }
6045  }
6046 -#line 1337 "configparser.c"
6047 +#line 1359 "configparser.c"
6048    yy_destructor(24,&yymsp[-1].minor);
6049          break;
6050 -      case 38:
6051 -#line 536 "./configparser.y"
6052 +      case 39:
6053 +#line 549 "./configparser.y"
6054  {
6055    if (ctx->ok) {
6056      if (0 != config_parse_cmd(ctx->srv, ctx, yymsp[0].minor.yy43->ptr)) {
6057 @@ -1348,7 +1370,7 @@
6058      yymsp[0].minor.yy43 = NULL;
6059    }
6060  }
6061 -#line 1351 "configparser.c"
6062 +#line 1373 "configparser.c"
6063    yy_destructor(25,&yymsp[-1].minor);
6064          break;
6065    };
6066 @@ -1378,11 +1400,11 @@
6067    while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
6068    /* Here code is inserted which will be executed whenever the
6069    ** parser fails */
6070 -#line 125 "./configparser.y"
6071 +#line 107 "./configparser.y"
6072  
6073    ctx->ok = 0;
6074  
6075 -#line 1385 "configparser.c"
6076 +#line 1407 "configparser.c"
6077    configparserARG_STORE; /* Suppress warning about unused %extra_argument variable */
6078  }
6079  
6080 @@ -1489,7 +1511,7 @@
6081  #ifdef YYERRORSYMBOL
6082        /* A syntax error has occurred.
6083        ** The response to an error depends upon whether or not the
6084 -      ** grammar defines an error token "ERROR".  
6085 +      ** grammar defines an error token "ERROR".
6086        **
6087        ** This is what we do if the grammar does define ERROR:
6088        **
6089 --- ../lighttpd-1.4.11/src/configparser.y       2006-01-26 18:46:25.000000000 +0200
6090 +++ lighttpd-1.5.0/src/configparser.y   2006-09-07 00:57:05.000000000 +0300
6091 @@ -21,52 +21,34 @@
6092      dc->parent = ctx->current;
6093      array_insert_unique(dc->parent->childs, (data_unset *)dc);
6094    }
6095 -  array_insert_unique(ctx->configs_stack, (data_unset *)ctx->current);
6096 +  buffer_ptr_append(ctx->configs_stack, (void *)ctx->current);
6097    ctx->current = dc;
6098  }
6099  
6100  static data_config *configparser_pop(config_t *ctx) {
6101    data_config *old = ctx->current;
6102 -  ctx->current = (data_config *) array_pop(ctx->configs_stack);
6103 +  ctx->current = (data_config *) buffer_ptr_pop(ctx->configs_stack);
6104    return old;
6105  }
6106  
6107  /* return a copied variable */
6108  static data_unset *configparser_get_variable(config_t *ctx, const buffer *key) {
6109 -  if (strncmp(key->ptr, "env.", sizeof("env.") - 1) == 0) {
6110 -    char *env;
6111 -
6112 -    if (NULL != (env = getenv(key->ptr + 4))) {
6113 -      data_string *ds;
6114 -      ds = data_string_init();
6115 -      buffer_append_string(ds->value, env);
6116 -      return (data_unset *)ds;
6117 -    }
6118 -
6119 -    fprintf(stderr, "Undefined env variable: %s\n", key->ptr + 4);
6120 -    ctx->ok = 0;
6121 -
6122 -    return NULL;
6123 -  } else {
6124 -    data_unset *du;
6125 -    data_config *dc;
6126 +  data_unset *du;
6127 +  data_config *dc;
6128  
6129  #if 0
6130 -    fprintf(stderr, "get var %s\n", key->ptr);
6131 +  fprintf(stderr, "get var %s\n", key->ptr);
6132  #endif
6133 -    for (dc = ctx->current; dc; dc = dc->parent) {
6134 +  for (dc = ctx->current; dc; dc = dc->parent) {
6135  #if 0
6136 -      fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
6137 -      array_print(dc->value, 0);
6138 +    fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
6139 +    array_print(dc->value, 0);
6140  #endif
6141 -      if (NULL != (du = array_get_element(dc->value, key->ptr))) {
6142 -        return du->copy(du);
6143 -      }
6144 +    if (NULL != (du = array_get_element(dc->value, key->ptr))) {
6145 +      return du->copy(du);
6146      }
6147 -    fprintf(stderr, "Undefined config variable: %s\n", key->ptr);
6148 -    ctx->ok = 0;
6149 -    return NULL;
6150    }
6151 +  return NULL;
6152  }
6153  
6154  /* op1 is to be eat/return by this function, op1->key is not cared
6155 @@ -141,6 +123,7 @@
6156  %type       aelement               {data_unset *}
6157  %type       condline               {data_config *}
6158  %type       condlines              {data_config *}
6159 +%type       global                 {data_config *}
6160  %type       aelements              {array *}
6161  %type       array                  {array *}
6162  %type       key                    {buffer *}
6163 @@ -161,7 +144,12 @@
6164  
6165  varline ::= key(A) ASSIGN expression(B). {
6166    buffer_copy_string_buffer(B->key, A);
6167 -  if (NULL == array_get_element(ctx->current->value, B->key->ptr)) {
6168 +  if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
6169 +    fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
6170 +        ctx->current->context_ndx,
6171 +        ctx->current->key->ptr, A->ptr);
6172 +    ctx->ok = 0;
6173 +  } else if (NULL == array_get_element(ctx->current->value, B->key->ptr)) {
6174      array_insert_unique(ctx->current->value, B);
6175      B = NULL;
6176    } else {
6177 @@ -180,7 +168,12 @@
6178    array *vars = ctx->current->value;
6179    data_unset *du;
6180  
6181 -  if (NULL != (du = array_get_element(vars, A->ptr))) {
6182 +  if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
6183 +    fprintf(stderr, "Appending env variable is not supported in conditional %d %s: %s\n",
6184 +        ctx->current->context_ndx,
6185 +        ctx->current->key->ptr, A->ptr);
6186 +    ctx->ok = 0;
6187 +  } else if (NULL != (du = array_get_element(vars, A->ptr))) {
6188      /* exists in current block */
6189      du = configparser_merge_data(du, B);
6190      if (NULL == du) {
6191 @@ -190,6 +183,7 @@
6192        buffer_copy_string_buffer(du->key, A);
6193        array_replace(vars, du);
6194      }
6195 +    B->free(B);
6196    } else if (NULL != (du = configparser_get_variable(ctx, A))) {
6197      du = configparser_merge_data(du, B);
6198      if (NULL == du) {
6199 @@ -199,15 +193,13 @@
6200        buffer_copy_string_buffer(du->key, A);
6201        array_insert_unique(ctx->current->value, du);
6202      }
6203 +    B->free(B);
6204    } else {
6205 -    fprintf(stderr, "Undefined config variable in conditional %d %s: %s\n", 
6206 -            ctx->current->context_ndx,
6207 -            ctx->current->key->ptr, A->ptr);
6208 -    ctx->ok = 0;
6209 +    buffer_copy_string_buffer(B->key, A);
6210 +    array_insert_unique(ctx->current->value, B);
6211    }
6212    buffer_free(A);
6213    A = NULL;
6214 -  B->free(B);
6215    B = NULL;
6216  }
6217  
6218 @@ -239,7 +231,24 @@
6219  }
6220  
6221  value(A) ::= key(B). {
6222 -  A = configparser_get_variable(ctx, B);
6223 +  if (strncmp(B->ptr, "env.", sizeof("env.") - 1) == 0) {
6224 +    char *env;
6225 +
6226 +    if (NULL != (env = getenv(B->ptr + 4))) {
6227 +      data_string *ds;
6228 +      ds = data_string_init();
6229 +      buffer_append_string(ds->value, env);
6230 +      A = (data_unset *)ds;
6231 +    }
6232 +    else {
6233 +      A = NULL;
6234 +      fprintf(stderr, "Undefined env variable: %s\n", B->ptr + 4);
6235 +      ctx->ok = 0;
6236 +    }
6237 +  } else if (NULL == (A = configparser_get_variable(ctx, B))) {
6238 +    fprintf(stderr, "Undefined config variable: %s\n", B->ptr);
6239 +    ctx->ok = 0;
6240 +  }
6241    if (!A) {
6242      /* make a dummy so it won't crash */
6243      A = (data_unset *)data_string_init();
6244 @@ -267,6 +276,9 @@
6245    ((data_array *)(A))->value = B;
6246    B = NULL;
6247  }
6248 +array(A) ::= LPARAN RPARAN. {
6249 +  A = array_init();
6250 +}
6251  array(A) ::= LPARAN aelements(B) RPARAN. {
6252    A = B;
6253    B = NULL;
6254 @@ -410,6 +422,7 @@
6255        { COMP_HTTP_USERAGENT,     CONST_STR_LEN("HTTP[\"useragent\"]"  ) },
6256        { COMP_HTTP_COOKIE,        CONST_STR_LEN("HTTP[\"cookie\"]"     ) },
6257        { COMP_HTTP_REMOTEIP,      CONST_STR_LEN("HTTP[\"remoteip\"]"   ) },
6258 +      { COMP_HTTP_QUERYSTRING,   CONST_STR_LEN("HTTP[\"querystring\"]") },
6259        { COMP_UNSET, NULL, 0 },
6260      };
6261      size_t i;
6262 --- ../lighttpd-1.4.11/src/connections-glue.c   2005-09-12 10:04:23.000000000 +0300
6263 +++ lighttpd-1.5.0/src/connections-glue.c       2006-09-07 00:57:05.000000000 +0300
6264 @@ -3,42 +3,48 @@
6265  const char *connection_get_state(connection_state_t state) {
6266         switch (state) {
6267         case CON_STATE_CONNECT: return "connect";
6268 -       case CON_STATE_READ: return "read";
6269 -       case CON_STATE_READ_POST: return "readpost";
6270 -       case CON_STATE_WRITE: return "write";
6271 -       case CON_STATE_CLOSE: return "close";
6272 -       case CON_STATE_ERROR: return "error";
6273 -       case CON_STATE_HANDLE_REQUEST: return "handle-req";
6274 +
6275         case CON_STATE_REQUEST_START: return "req-start";
6276 -       case CON_STATE_REQUEST_END: return "req-end";
6277 -       case CON_STATE_RESPONSE_START: return "resp-start";
6278 +       case CON_STATE_READ_REQUEST_HEADER: return "read-header";
6279 +       case CON_STATE_HANDLE_REQUEST_HEADER: return "handle-req";
6280 +       case CON_STATE_READ_REQUEST_CONTENT: return "read-content";
6281 +
6282 +       case CON_STATE_HANDLE_RESPONSE_HEADER: return "resp-start";
6283 +       case CON_STATE_WRITE_RESPONSE_HEADER: return "write-header";
6284 +       case CON_STATE_WRITE_RESPONSE_CONTENT: return "write-content";
6285         case CON_STATE_RESPONSE_END: return "resp-end";
6286 -       default: return "(unknown)";    
6287 +
6288 +       case CON_STATE_CLOSE: return "close";
6289 +       case CON_STATE_ERROR: return "error";
6290 +       default: return "(unknown)";
6291         }
6292  }
6293  
6294  const char *connection_get_short_state(connection_state_t state) {
6295         switch (state) {
6296         case CON_STATE_CONNECT: return ".";
6297 -       case CON_STATE_READ: return "r";
6298 -       case CON_STATE_READ_POST: return "R";
6299 -       case CON_STATE_WRITE: return "W";
6300 -       case CON_STATE_CLOSE: return "C";
6301 -       case CON_STATE_ERROR: return "E";
6302 -       case CON_STATE_HANDLE_REQUEST: return "h";
6303         case CON_STATE_REQUEST_START: return "q";
6304 -       case CON_STATE_REQUEST_END: return "Q";
6305 -       case CON_STATE_RESPONSE_START: return "s";
6306 +
6307 +       case CON_STATE_READ_REQUEST_HEADER: return "r";
6308 +       case CON_STATE_HANDLE_REQUEST_HEADER: return "h";
6309 +       case CON_STATE_READ_REQUEST_CONTENT: return "R";
6310 +
6311 +       case CON_STATE_HANDLE_RESPONSE_HEADER: return "s";
6312 +       case CON_STATE_WRITE_RESPONSE_HEADER: return "w";
6313 +       case CON_STATE_WRITE_RESPONSE_CONTENT: return "W";
6314         case CON_STATE_RESPONSE_END: return "S";
6315 -       default: return "x";    
6316 +
6317 +       case CON_STATE_CLOSE: return "C";
6318 +       case CON_STATE_ERROR: return "E";
6319 +       default: return "x";
6320         }
6321  }
6322  
6323  int connection_set_state(server *srv, connection *con, connection_state_t state) {
6324         UNUSED(srv);
6325 -       
6326 +
6327         con->state = state;
6328 -       
6329 +
6330         return 0;
6331  }
6332  
6333 --- ../lighttpd-1.4.11/src/connections.c        2006-03-05 22:14:53.000000000 +0200
6334 +++ lighttpd-1.5.0/src/connections.c    2006-09-07 00:57:05.000000000 +0300
6335 @@ -2,7 +2,6 @@
6336  
6337  #include <stdlib.h>
6338  #include <stdio.h>
6339 -#include <unistd.h>
6340  #include <errno.h>
6341  #include <string.h>
6342  #include <fcntl.h>
6343 @@ -17,17 +16,18 @@
6344  #include "request.h"
6345  #include "response.h"
6346  #include "network.h"
6347 -#include "http_chunk.h"
6348  #include "stat_cache.h"
6349  #include "joblist.h"
6350  
6351  #include "plugin.h"
6352  
6353  #include "inet_ntop_cache.h"
6354 +#include "configfile.h"
6355 +#include "http_req.h"
6356  
6357  #ifdef USE_OPENSSL
6358 -# include <openssl/ssl.h> 
6359 -# include <openssl/err.h> 
6360 +# include <openssl/ssl.h>
6361 +# include <openssl/err.h>
6362  #endif
6363  
6364  #ifdef HAVE_SYS_FILIO_H
6365 @@ -35,15 +35,16 @@
6366  #endif
6367  
6368  #include "sys-socket.h"
6369 +#include "sys-files.h"
6370  
6371  typedef struct {
6372 -               PLUGIN_DATA;
6373 +       PLUGIN_DATA;
6374  } plugin_data;
6375  
6376  static connection *connections_get_new_connection(server *srv) {
6377         connections *conns = srv->conns;
6378         size_t i;
6379 -       
6380 +
6381         if (conns->size == 0) {
6382                 conns->size = 128;
6383                 conns->ptr = NULL;
6384 @@ -54,21 +55,14 @@
6385         } else if (conns->size == conns->used) {
6386                 conns->size += 128;
6387                 conns->ptr = realloc(conns->ptr, sizeof(*conns->ptr) * conns->size);
6388 -               
6389 +
6390                 for (i = conns->used; i < conns->size; i++) {
6391                         conns->ptr[i] = connection_init(srv);
6392                 }
6393         }
6394  
6395         connection_reset(srv, conns->ptr[conns->used]);
6396 -#if 0  
6397 -       fprintf(stderr, "%s.%d: add: ", __FILE__, __LINE__);
6398 -       for (i = 0; i < conns->used + 1; i++) {
6399 -               fprintf(stderr, "%d ", conns->ptr[i]->fd);
6400 -       }
6401 -       fprintf(stderr, "\n");
6402 -#endif 
6403 -       
6404 +
6405         conns->ptr[conns->used]->ndx = conns->used;
6406         return conns->ptr[conns->used++];
6407  }
6408 @@ -77,272 +71,127 @@
6409         size_t i;
6410         connections *conns = srv->conns;
6411         connection *temp;
6412 -       
6413 +
6414         if (con == NULL) return -1;
6415 -       
6416 +
6417         if (-1 == con->ndx) return -1;
6418 -       
6419 +
6420         i = con->ndx;
6421 -       
6422 +
6423         /* not last element */
6424 -       
6425 +
6426         if (i != conns->used - 1) {
6427                 temp = conns->ptr[i];
6428                 conns->ptr[i] = conns->ptr[conns->used - 1];
6429                 conns->ptr[conns->used - 1] = temp;
6430 -               
6431 +
6432                 conns->ptr[i]->ndx = i;
6433                 conns->ptr[conns->used - 1]->ndx = -1;
6434         }
6435 -       
6436 +
6437         conns->used--;
6438 -       
6439 +
6440         con->ndx = -1;
6441 -#if 0
6442 -       fprintf(stderr, "%s.%d: del: (%d)", __FILE__, __LINE__, conns->used);
6443 -       for (i = 0; i < conns->used; i++) {
6444 -               fprintf(stderr, "%d ", conns->ptr[i]->fd);
6445 -       }
6446 -       fprintf(stderr, "\n");
6447 -#endif 
6448 +
6449         return 0;
6450  }
6451  
6452  int connection_close(server *srv, connection *con) {
6453  #ifdef USE_OPENSSL
6454 -       server_socket *srv_sock = con->srv_socket;
6455 -#endif
6456 -       
6457 -#ifdef USE_OPENSSL
6458 -       if (srv_sock->is_ssl) {
6459 -               if (con->ssl) SSL_free(con->ssl);
6460 -               con->ssl = NULL;
6461 +       /* should be in iosocket_close() */
6462 +
6463 +       if (con->sock->ssl) {
6464 +               switch (SSL_shutdown(con->sock->ssl)) {
6465 +               case 1:
6466 +                       /* done */
6467 +                       break;
6468 +               case 0:
6469 +                       /* wait for fd-event
6470 +                        *
6471 +                        * FIXME: wait for fdevent and call SSL_shutdown again
6472 +                        *
6473 +                        */
6474 +
6475 +                       break;
6476 +               default:
6477 +                       ERROR("SSL_shutdown failed: %s", ERR_error_string(ERR_get_error(), NULL));
6478 +               }
6479 +
6480 +               SSL_free(con->sock->ssl);
6481 +               con->sock->ssl = NULL;
6482         }
6483  #endif
6484 -       
6485 -       fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
6486 -       fdevent_unregister(srv->ev, con->fd);
6487 -#ifdef __WIN32
6488 -       if (closesocket(con->fd)) {
6489 -               log_error_write(srv, __FILE__, __LINE__, "sds",
6490 -                               "(warning) close:", con->fd, strerror(errno));
6491 -       }
6492 -#else
6493 -       if (close(con->fd)) {
6494 +
6495 +       fdevent_event_del(srv->ev, con->sock);
6496 +       fdevent_unregister(srv->ev, con->sock);
6497 +
6498 +       if (closesocket(con->sock->fd)) {
6499                 log_error_write(srv, __FILE__, __LINE__, "sds",
6500 -                               "(warning) close:", con->fd, strerror(errno));
6501 +                               "(warning) close:", con->sock->fd, strerror(errno));
6502         }
6503 -#endif
6504 -       
6505 +
6506         srv->cur_fds--;
6507 -#if 0
6508 -       log_error_write(srv, __FILE__, __LINE__, "sd",
6509 -                       "closed()", con->fd);
6510 -#endif
6511 -       
6512 +
6513         connection_del(srv, con);
6514         connection_set_state(srv, con, CON_STATE_CONNECT);
6515 -       
6516 +
6517         return 0;
6518  }
6519  
6520  #if 0
6521  static void dump_packet(const unsigned char *data, size_t len) {
6522         size_t i, j;
6523 -       
6524 +
6525         if (len == 0) return;
6526 -       
6527 +
6528         for (i = 0; i < len; i++) {
6529                 if (i % 16 == 0) fprintf(stderr, "  ");
6530 -               
6531 +
6532                 fprintf(stderr, "%02x ", data[i]);
6533 -               
6534 +
6535                 if ((i + 1) % 16 == 0) {
6536                         fprintf(stderr, "  ");
6537                         for (j = 0; j <= i % 16; j++) {
6538                                 unsigned char c;
6539 -                               
6540 +
6541                                 if (i-15+j >= len) break;
6542 -                               
6543 +
6544                                 c = data[i-15+j];
6545 -                               
6546 +
6547                                 fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
6548                         }
6549 -                       
6550 +
6551                         fprintf(stderr, "\n");
6552                 }
6553         }
6554 -       
6555 +
6556         if (len % 16 != 0) {
6557                 for (j = i % 16; j < 16; j++) {
6558                         fprintf(stderr, "   ");
6559                 }
6560 -               
6561 +
6562                 fprintf(stderr, "  ");
6563                 for (j = i & ~0xf; j < len; j++) {
6564                         unsigned char c;
6565 -                       
6566 +
6567                         c = data[j];
6568                         fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
6569                 }
6570                 fprintf(stderr, "\n");
6571         }
6572  }
6573 -#endif 
6574 -
6575 -static int connection_handle_read(server *srv, connection *con) {
6576 -       int len;
6577 -       buffer *b;
6578 -       int toread;
6579 -#ifdef USE_OPENSSL
6580 -       server_socket *srv_sock = con->srv_socket;
6581 -#endif
6582 -
6583 -       b = chunkqueue_get_append_buffer(con->read_queue);
6584 -       buffer_prepare_copy(b, 4096);
6585 -
6586 -#ifdef USE_OPENSSL
6587 -       if (srv_sock->is_ssl) {
6588 -               len = SSL_read(con->ssl, b->ptr, b->size - 1);
6589 -       } else {
6590 -               if (ioctl(con->fd, FIONREAD, &toread)) {
6591 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
6592 -                                       "unexpected end-of-file:",
6593 -                                       con->fd);
6594 -                       return -1;
6595 -               }
6596 -               buffer_prepare_copy(b, toread);
6597 -
6598 -               len = read(con->fd, b->ptr, b->size - 1);
6599 -       }
6600 -#elif defined(__WIN32)
6601 -       len = recv(con->fd, b->ptr, b->size - 1, 0);
6602 -#else
6603 -       if (ioctl(con->fd, FIONREAD, &toread)) {
6604 -               log_error_write(srv, __FILE__, __LINE__, "sd", 
6605 -                               "unexpected end-of-file:",
6606 -                               con->fd);
6607 -               return -1;
6608 -       }
6609 -       buffer_prepare_copy(b, toread);
6610 -
6611 -       len = read(con->fd, b->ptr, b->size - 1);
6612  #endif
6613 -       
6614 -       if (len < 0) {
6615 -               con->is_readable = 0;
6616 -               
6617 -#ifdef USE_OPENSSL
6618 -               if (srv_sock->is_ssl) {
6619 -                       int r, ssl_err;
6620 -                       
6621 -                       switch ((r = SSL_get_error(con->ssl, len))) {
6622 -                       case SSL_ERROR_WANT_READ:
6623 -                               return 0;
6624 -                       case SSL_ERROR_SYSCALL:
6625 -                               /**
6626 -                                * man SSL_get_error()
6627 -                                * 
6628 -                                * SSL_ERROR_SYSCALL
6629 -                                *   Some I/O error occurred.  The OpenSSL error queue may contain more 
6630 -                                *   information on the error.  If the error queue is empty (i.e.
6631 -                                *   ERR_get_error() returns 0), ret can be used to find out more about 
6632 -                                *   the error: If ret == 0, an EOF was observed that violates the
6633 -                                *   protocol.  If ret == -1, the underlying BIO reported an I/O error 
6634 -                                *   (for socket I/O on Unix systems, consult errno for details).
6635 -                                *
6636 -                                */
6637 -                               while((ssl_err = ERR_get_error())) {
6638 -                                       /* get all errors from the error-queue */
6639 -                                       log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:", 
6640 -                                                       r, ERR_error_string(ssl_err, NULL));
6641 -                               }
6642  
6643 -                               switch(errno) {
6644 -                               default:
6645 -                                       log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:", 
6646 -                                                       len, r, errno,
6647 -                                                       strerror(errno));
6648 -                                       break;
6649 -                               }
6650 -                               
6651 -                               break;
6652 -                       case SSL_ERROR_ZERO_RETURN:
6653 -                               /* clean shutdown on the remote side */
6654 -                               
6655 -                               if (r == 0) {
6656 -                                       /* FIXME: later */
6657 -                               }
6658 -                               
6659 -                               /* fall thourgh */
6660 -                       default:
6661 -                               while((ssl_err = ERR_get_error())) {
6662 -                                       /* get all errors from the error-queue */
6663 -                                       log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:", 
6664 -                                                       r, ERR_error_string(ssl_err, NULL));
6665 -                               }
6666 -                               break;
6667 -                       }
6668 -               } else {
6669 -                       if (errno == EAGAIN) return 0;
6670 -                       if (errno == EINTR) {
6671 -                               /* we have been interrupted before we could read */
6672 -                               con->is_readable = 1;
6673 -                               return 0;
6674 -                       }
6675 -               
6676 -                       if (errno != ECONNRESET) {
6677 -                               /* expected for keep-alive */
6678 -                               log_error_write(srv, __FILE__, __LINE__, "ssd", "connection closed - read failed: ", strerror(errno), errno);
6679 -                       }
6680 -               }
6681 -#else
6682 -               if (errno == EAGAIN) return 0;
6683 -               if (errno == EINTR) {
6684 -                       /* we have been interrupted before we could read */
6685 -                       con->is_readable = 1;
6686 -                       return 0;
6687 -               }
6688 -               
6689 -               if (errno != ECONNRESET) {
6690 -                       /* expected for keep-alive */
6691 -                       log_error_write(srv, __FILE__, __LINE__, "ssd", "connection closed - read failed: ", strerror(errno), errno);
6692 -               }
6693 -#endif
6694 -               connection_set_state(srv, con, CON_STATE_ERROR);
6695 -               
6696 -               return -1;
6697 -       } else if (len == 0) {
6698 -               con->is_readable = 0;
6699 -               /* the other end close the connection -> KEEP-ALIVE */
6700 -
6701 -               /* pipelining */
6702 -
6703 -               return -2;
6704 -       } else if ((size_t)len < b->size - 1) {
6705 -               /* we got less then expected, wait for the next fd-event */
6706 -               
6707 -               con->is_readable = 0;
6708 -       }
6709 -       
6710 -       b->used = len;
6711 -       b->ptr[b->used++] = '\0';
6712 -       
6713 -       con->bytes_read += len;
6714 -#if 0
6715 -       dump_packet(b->ptr, len);
6716 -#endif
6717 -       
6718 -       return 0;
6719 -}
6720 +static int connection_handle_response_header(server *srv, connection *con) {
6721 +       data_string *cl;
6722  
6723 -static int connection_handle_write_prepare(server *srv, connection *con) {
6724         if (con->mode == DIRECT) {
6725                 /* static files */
6726                 switch(con->request.http_method) {
6727                 case HTTP_METHOD_GET:
6728                 case HTTP_METHOD_POST:
6729                 case HTTP_METHOD_HEAD:
6730 +                       /* webdav */
6731                 case HTTP_METHOD_PUT:
6732                 case HTTP_METHOD_MKCOL:
6733                 case HTTP_METHOD_DELETE:
6734 @@ -350,21 +199,25 @@
6735                 case HTTP_METHOD_MOVE:
6736                 case HTTP_METHOD_PROPFIND:
6737                 case HTTP_METHOD_PROPPATCH:
6738 +               case HTTP_METHOD_LOCK:
6739 +               case HTTP_METHOD_UNLOCK:
6740                         break;
6741                 case HTTP_METHOD_OPTIONS:
6742                         /*
6743                          * 400 is coming from the request-parser BEFORE uri.path is set
6744 -                        * 403 is from the response handler when noone else catched it 
6745 -                        * 
6746 +                        * 403 is from the response handler when noone else catched it
6747 +                        *
6748                          * */
6749                         if (con->uri.path->used &&
6750                             con->uri.path->ptr[0] != '*') {
6751                                 response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST"));
6752  
6753 +                               /* trash the content */
6754 +                               chunkqueue_reset(con->send);
6755 +
6756                                 con->http_status = 200;
6757 -                               con->file_finished = 1;
6758 +                               con->send->is_closed = 1;
6759  
6760 -                               chunkqueue_reset(con->write_queue);
6761                         }
6762                         break;
6763                 default:
6764 @@ -381,55 +234,61 @@
6765                         break;
6766                 }
6767         }
6768 -       
6769 +
6770         if (con->http_status == 0) {
6771 +               TRACE("%s", "no status, setting 403");
6772                 con->http_status = 403;
6773         }
6774 -       
6775 +
6776         switch(con->http_status) {
6777         case 400: /* class: header + custom body */
6778         case 401:
6779         case 403:
6780         case 404:
6781         case 408:
6782 +       case 409:
6783 +       case 410:
6784         case 411:
6785         case 416:
6786         case 423:
6787         case 500:
6788         case 501:
6789 +       case 502:
6790         case 503:
6791 -       case 505: 
6792 +       case 504:
6793 +       case 505:
6794 +       case 509:
6795                 if (con->mode != DIRECT) break;
6796 -               
6797 -               con->file_finished = 0;
6798 -               
6799 +
6800 +               con->send->is_closed = 0;
6801 +
6802                 buffer_reset(con->physical.path);
6803 -                               
6804 +
6805                 /* try to send static errorfile */
6806                 if (!buffer_is_empty(con->conf.errorfile_prefix)) {
6807                         stat_cache_entry *sce = NULL;
6808 -                       
6809 +
6810                         buffer_copy_string_buffer(con->physical.path, con->conf.errorfile_prefix);
6811                         buffer_append_string(con->physical.path, get_http_status_body_name(con->http_status));
6812 -                       
6813 +
6814                         if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
6815 -                               con->file_finished = 1;
6816 -                               
6817 -                               http_chunk_append_file(srv, con, con->physical.path, 0, sce->st.st_size);
6818 +                               con->send->is_closed = 1;
6819 +
6820 +                               chunkqueue_append_file(con->send, con->physical.path, 0, sce->st.st_size);
6821                                 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
6822                         }
6823                 }
6824 -               
6825 -               if (!con->file_finished) {                      
6826 +
6827 +               if (!con->send->is_closed) {
6828                         buffer *b;
6829 -                       
6830 +
6831                         buffer_reset(con->physical.path);
6832 -                       
6833 -                       con->file_finished = 1;
6834 -                       b = chunkqueue_get_append_buffer(con->write_queue);
6835 -                               
6836 +
6837 +                       con->send->is_closed = 1;
6838 +                       b = chunkqueue_get_append_buffer(con->send);
6839 +
6840                         /* build default error-page */
6841 -                       buffer_copy_string(b, 
6842 +                       buffer_copy_string(b,
6843                                            "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
6844                                            "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
6845                                            "         \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
6846 @@ -439,7 +298,7 @@
6847                         buffer_append_long(b, con->http_status);
6848                         buffer_append_string(b, " - ");
6849                         buffer_append_string(b, get_http_status_name(con->http_status));
6850 -                       
6851 +
6852                         buffer_append_string(b,
6853                                              "</title>\n"
6854                                              " </head>\n"
6855 @@ -448,12 +307,12 @@
6856                         buffer_append_long(b, con->http_status);
6857                         buffer_append_string(b, " - ");
6858                         buffer_append_string(b, get_http_status_name(con->http_status));
6859 -                       
6860 -                       buffer_append_string(b,"</h1>\n" 
6861 +
6862 +                       buffer_append_string(b,"</h1>\n"
6863                                              " </body>\n"
6864                                              "</html>\n"
6865                                              );
6866 -                       
6867 +
6868                         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
6869                 }
6870                 /* fall through */
6871 @@ -463,109 +322,69 @@
6872         case 301:
6873         case 302:
6874                 break;
6875 -               
6876 +
6877         case 206: /* write_queue is already prepared */
6878 -               con->file_finished = 1;
6879 -               
6880 +               con->send->is_closed = 1;
6881 +
6882                 break;
6883         case 205: /* class: header only */
6884         case 304:
6885         default:
6886                 /* disable chunked encoding again as we have no body */
6887                 con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
6888 -               chunkqueue_reset(con->write_queue);
6889 -               
6890 -               con->file_finished = 1;
6891 +               chunkqueue_reset(con->send);
6892 +
6893 +               con->send->is_closed = 1;
6894 +
6895                 break;
6896         }
6897 -       
6898  
6899 -       if (con->file_finished) {
6900 -               /* we have all the content and chunked encoding is not used, set a content-length */ 
6901 -               
6902 -               if ((!(con->parsed_response & HTTP_CONTENT_LENGTH)) && 
6903 -                   (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0) {
6904 -                       buffer_copy_off_t(srv->tmp_buf, chunkqueue_length(con->write_queue));
6905 -               
6906 +
6907 +       if (con->send->is_closed) {
6908 +               /* we have all the content and chunked encoding is not used, set a content-length */
6909 +
6910 +               if ((con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0 &&
6911 +                   NULL == (cl = (data_string *)array_get_element(con->response.headers, "Content-Length"))) {
6912 +                       buffer_copy_off_t(srv->tmp_buf, chunkqueue_length(con->send));
6913 +                       
6914                         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Length"), CONST_BUF_LEN(srv->tmp_buf));
6915                 }
6916         } else {
6917 -               /* disable keep-alive if size-info for the body is missing */
6918 -               if ((con->parsed_response & HTTP_CONTENT_LENGTH) &&
6919 -                   ((con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0)) {
6920 -                       con->keep_alive = 0;
6921 -               }
6922 -               
6923 -               if (0 == (con->parsed_response & HTTP_CONNECTION)) {
6924 -                       /* (f)cgi did'nt send Connection: header
6925 -                        *                          
6926 -                        * shall we ?
6927 -                        */
6928 -                       if (((con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0) &&
6929 -                           (con->parsed_response & HTTP_CONTENT_LENGTH) == 0) {
6930 -                               /* without content_length, no keep-alive */
6931 -                               
6932 -                               con->keep_alive = 0;
6933 -                       }
6934 -               } else {
6935 -                       /* a subrequest disable keep-alive although the client wanted it */
6936 -                       if (con->keep_alive && !con->response.keep_alive) {
6937 +               if (NULL == (cl = (data_string *)array_get_element(con->response.headers, "Content-Length"))) {
6938 +                       /* we don't know the size of the content yet 
6939 +                        * - either enable chunking 
6940 +                        * - or disable keep-alive  */
6941 +
6942 +                       if (con->request.http_version == HTTP_VERSION_1_1) {
6943 +                               /* enable chunk-encoding */
6944 +                               con->response.transfer_encoding |= HTTP_TRANSFER_ENCODING_CHUNKED;
6945 +                       } else  {
6946                                 con->keep_alive = 0;
6947 -                               
6948 -                               /* FIXME: we have to drop the Connection: Header from the subrequest */
6949                         }
6950                 }
6951         }
6952 -       
6953 +
6954         if (con->request.http_method == HTTP_METHOD_HEAD) {
6955 -               chunkqueue_reset(con->write_queue);
6956 +               con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
6957 +               chunkqueue_reset(con->send);
6958 +
6959 +               con->send->is_closed = 1;
6960         }
6961  
6962 -       http_response_write_header(srv, con);
6963 -               
6964 -       return 0;
6965 -}
6966 +       http_response_write_header(srv, con, con->send_raw);
6967  
6968 -static int connection_handle_write(server *srv, connection *con) {
6969 -       switch(network_write_chunkqueue(srv, con, con->write_queue)) {
6970 -       case 0:
6971 -               if (con->file_finished) {
6972 -                       connection_set_state(srv, con, CON_STATE_RESPONSE_END);
6973 -                       joblist_append(srv, con);
6974 -               }
6975 -               break;
6976 -       case -1: /* error on our side */
6977 -               log_error_write(srv, __FILE__, __LINE__, "sd",
6978 -                               "connection closed: write failed on fd", con->fd);
6979 -               connection_set_state(srv, con, CON_STATE_ERROR);
6980 -               joblist_append(srv, con);
6981 -               break;
6982 -       case -2: /* remote close */
6983 -               connection_set_state(srv, con, CON_STATE_ERROR);
6984 -               joblist_append(srv, con);
6985 -               break;
6986 -       case 1:
6987 -               con->is_writable = 0;
6988 -               
6989 -               /* not finished yet -> WRITE */
6990 -               break;
6991 -       }
6992 -       
6993         return 0;
6994  }
6995  
6996 -
6997 -
6998  connection *connection_init(server *srv) {
6999         connection *con;
7000 -       
7001 +
7002         UNUSED(srv);
7003  
7004         con = calloc(1, sizeof(*con));
7005 -               
7006 -       con->fd = 0;
7007 +
7008 +       con->sock = iosocket_init();
7009         con->ndx = -1;
7010 -       con->fde_ndx = -1;
7011         con->bytes_written = 0;
7012         con->bytes_read = 0;
7013         con->bytes_header = 0;
7014 @@ -573,91 +392,97 @@
7015  
7016  #define CLEAN(x) \
7017         con->x = buffer_init();
7018 -       
7019 +
7020         CLEAN(request.uri);
7021 -       CLEAN(request.request_line);
7022         CLEAN(request.request);
7023         CLEAN(request.pathinfo);
7024 -       
7025 +       CLEAN(request.http_host);
7026 +
7027         CLEAN(request.orig_uri);
7028 -       
7029 +
7030         CLEAN(uri.scheme);
7031         CLEAN(uri.authority);
7032         CLEAN(uri.path);
7033         CLEAN(uri.path_raw);
7034         CLEAN(uri.query);
7035 -       
7036 +
7037         CLEAN(physical.doc_root);
7038         CLEAN(physical.path);
7039         CLEAN(physical.basedir);
7040         CLEAN(physical.rel_path);
7041         CLEAN(physical.etag);
7042         CLEAN(parse_request);
7043 -       
7044 +
7045         CLEAN(authed_user);
7046         CLEAN(server_name);
7047         CLEAN(error_handler);
7048         CLEAN(dst_addr_buf);
7049 -       
7050 +
7051  #undef CLEAN
7052 -       con->write_queue = chunkqueue_init();
7053 -       con->read_queue = chunkqueue_init();
7054 -       con->request_content_queue = chunkqueue_init();
7055 -       chunkqueue_set_tempdirs(con->request_content_queue, srv->srvconf.upload_tempdirs);
7056 +       con->send = chunkqueue_init();
7057 +       con->recv = chunkqueue_init();
7058 +
7059 +       con->send_raw = chunkqueue_init();
7060 +       con->recv_raw = chunkqueue_init();
7061 +       chunkqueue_set_tempdirs(con->recv_raw, srv->srvconf.upload_tempdirs);
7062  
7063         con->request.headers      = array_init();
7064         con->response.headers     = array_init();
7065         con->environment     = array_init();
7066 -       
7067 +
7068 +       con->http_req = http_request_init();
7069 +
7070         /* init plugin specific connection structures */
7071 -       
7072 +
7073         con->plugin_ctx = calloc(1, (srv->plugins.used + 1) * sizeof(void *));
7074 -       
7075 +
7076         con->cond_cache = calloc(srv->config_context->used, sizeof(cond_cache_t));
7077         config_setup_connection(srv, con);
7078 -       
7079 +
7080         return con;
7081  }
7082  
7083  void connections_free(server *srv) {
7084         connections *conns = srv->conns;
7085 -       size_t i;       
7086 -       
7087 +       size_t i;
7088 +
7089         for (i = 0; i < conns->size; i++) {
7090                 connection *con = conns->ptr[i];
7091 -               
7092 +
7093                 connection_reset(srv, con);
7094 -               
7095 -               chunkqueue_free(con->write_queue);
7096 -               chunkqueue_free(con->read_queue);
7097 -               chunkqueue_free(con->request_content_queue);
7098 +               iosocket_free(con->sock);
7099 +
7100 +               chunkqueue_free(con->send);
7101 +               chunkqueue_free(con->recv);
7102 +               chunkqueue_free(con->send_raw);
7103 +               chunkqueue_free(con->recv_raw);
7104                 array_free(con->request.headers);
7105                 array_free(con->response.headers);
7106                 array_free(con->environment);
7107  
7108  #define CLEAN(x) \
7109         buffer_free(con->x);
7110 -               
7111 +
7112                 CLEAN(request.uri);
7113 -               CLEAN(request.request_line);
7114                 CLEAN(request.request);
7115                 CLEAN(request.pathinfo);
7116 -               
7117 +               CLEAN(request.http_host);
7118 +
7119                 CLEAN(request.orig_uri);
7120 -               
7121 +
7122                 CLEAN(uri.scheme);
7123                 CLEAN(uri.authority);
7124                 CLEAN(uri.path);
7125                 CLEAN(uri.path_raw);
7126                 CLEAN(uri.query);
7127 -               
7128 +
7129                 CLEAN(physical.doc_root);
7130                 CLEAN(physical.path);
7131                 CLEAN(physical.basedir);
7132                 CLEAN(physical.etag);
7133                 CLEAN(physical.rel_path);
7134                 CLEAN(parse_request);
7135 -               
7136 +
7137                 CLEAN(authed_user);
7138                 CLEAN(server_name);
7139                 CLEAN(error_handler);
7140 @@ -665,97 +490,88 @@
7141  #undef CLEAN
7142                 free(con->plugin_ctx);
7143                 free(con->cond_cache);
7144 -               
7145 +
7146 +               http_request_free(con->http_req);
7147 +
7148                 free(con);
7149         }
7150 -       
7151 +
7152         free(conns->ptr);
7153  }
7154  
7155  
7156  int connection_reset(server *srv, connection *con) {
7157         size_t i;
7158 -       
7159 +
7160         plugins_call_connection_reset(srv, con);
7161 -       
7162 +
7163         con->is_readable = 1;
7164         con->is_writable = 1;
7165         con->http_status = 0;
7166 -       con->file_finished = 0;
7167         con->file_started = 0;
7168         con->got_response = 0;
7169 -       
7170 -       con->parsed_response = 0;
7171 -       
7172 +
7173         con->bytes_written = 0;
7174         con->bytes_written_cur_second = 0;
7175         con->bytes_read = 0;
7176         con->bytes_header = 0;
7177         con->loops_per_request = 0;
7178 -       
7179 +
7180         con->request.http_method = HTTP_METHOD_UNSET;
7181         con->request.http_version = HTTP_VERSION_UNSET;
7182 -       
7183 -       con->request.http_if_modified_since = NULL;
7184 -       con->request.http_if_none_match = NULL;
7185 -       
7186 +       con->request.content_length = -1;
7187 +
7188         con->response.keep_alive = 0;
7189         con->response.content_length = -1;
7190         con->response.transfer_encoding = 0;
7191 -       
7192 +
7193         con->mode = DIRECT;
7194 -       
7195 +
7196  #define CLEAN(x) \
7197         if (con->x) buffer_reset(con->x);
7198 -       
7199 +
7200         CLEAN(request.uri);
7201 -       CLEAN(request.request_line);
7202         CLEAN(request.pathinfo);
7203         CLEAN(request.request);
7204 -       
7205 +       CLEAN(request.http_host);
7206 +
7207         CLEAN(request.orig_uri);
7208 -       
7209 +
7210         CLEAN(uri.scheme);
7211         CLEAN(uri.authority);
7212         CLEAN(uri.path);
7213         CLEAN(uri.path_raw);
7214         CLEAN(uri.query);
7215 -       
7216 +
7217         CLEAN(physical.doc_root);
7218         CLEAN(physical.path);
7219         CLEAN(physical.basedir);
7220         CLEAN(physical.rel_path);
7221         CLEAN(physical.etag);
7222 -       
7223 +
7224         CLEAN(parse_request);
7225 -       
7226 +
7227         CLEAN(authed_user);
7228         CLEAN(server_name);
7229         CLEAN(error_handler);
7230 -#undef CLEAN   
7231 -       
7232 -#define CLEAN(x) \
7233 -       if (con->x) con->x->used = 0;   
7234 -       
7235  #undef CLEAN
7236 -       
7237 +
7238  #define CLEAN(x) \
7239 -               con->request.x = NULL;
7240 -       
7241 -       CLEAN(http_host);
7242 -       CLEAN(http_range);
7243 -       CLEAN(http_content_type);
7244 +       if (con->x) con->x->used = 0;
7245 +
7246  #undef CLEAN
7247 -       con->request.content_length = 0;
7248 -       
7249 +
7250         array_reset(con->request.headers);
7251         array_reset(con->response.headers);
7252         array_reset(con->environment);
7253 -       
7254 -       chunkqueue_reset(con->write_queue);
7255 -       chunkqueue_reset(con->request_content_queue);
7256  
7257 -       /* the plugins should cleanup themself */       
7258 +       chunkqueue_reset(con->send);
7259 +       chunkqueue_reset(con->recv);
7260 +       chunkqueue_reset(con->send_raw);
7261 +
7262 +       http_request_reset(con->http_req);
7263 +
7264 +       /* the plugins should cleanup themself */
7265         for (i = 0; i < srv->plugins.used; i++) {
7266                 plugin *p = ((plugin **)(srv->plugins.ptr))[i];
7267                 plugin_data *pd = p->data;
7268 @@ -768,455 +584,270 @@
7269  
7270                 con->plugin_ctx[pd->id] = NULL;
7271         }
7272 -       
7273 -#if COND_RESULT_UNSET
7274 -       for (i = srv->config_context->used - 1; i >= 0; i --) {
7275 -               con->cond_cache[i].result = COND_RESULT_UNSET;
7276 -               con->cond_cache[i].patterncount = 0;
7277 -       }
7278 -#else
7279 -       memset(con->cond_cache, 0, sizeof(cond_cache_t) * srv->config_context->used);
7280 -#endif
7281 -       
7282 +
7283 +       config_cond_cache_reset(srv, con);
7284 +
7285         con->header_len = 0;
7286         con->in_error_handler = 0;
7287 -       
7288 +
7289         config_setup_connection(srv, con);
7290 -       
7291 +
7292         return 0;
7293  }
7294  
7295  /**
7296 - * 
7297 - * search for \r\n\r\n 
7298 - * 
7299 - * this is a special 32bit version which is using a sliding window for
7300 - * the comparisions 
7301 - * 
7302 - * how it works:
7303 - * 
7304 - * b:      'abcdefg'
7305 - * rnrn:   'cdef'
7306 - * 
7307 - * cmpbuf: abcd != cdef
7308 - * cmpbuf: bcde != cdef
7309 - * cmpbuf: cdef == cdef -> return &c
7310 - * 
7311 - * cmpbuf and rnrn are treated as 32bit uint and bit-ops are used to 
7312 - * maintain cmpbuf and rnrn
7313 - * 
7314 - */
7315 -
7316 -char *buffer_search_rnrn(buffer *b) {
7317 -       uint32_t cmpbuf, rnrn;
7318 -       char *cp;
7319 -       size_t i;
7320 -       
7321 -       if (b->used < 4) return NULL;
7322 -       
7323 -       rnrn = ('\r' << 24) | ('\n' << 16) |
7324 -               ('\r' << 8) | ('\n' << 0);
7325 -       
7326 -       cmpbuf = (b->ptr[0] << 24) | (b->ptr[1] << 16) |
7327 -               (b->ptr[2] << 8) | (b->ptr[3] << 0);
7328 -               
7329 -       cp = b->ptr + 4;
7330 -       for (i = 0; i < b->used - 4; i++) {
7331 -               if (cmpbuf == rnrn) return cp - 4;
7332 -                       
7333 -               cmpbuf = (cmpbuf << 8 | *(cp++)) & 0xffffffff;
7334 -       }
7335 -       
7336 -       return NULL;
7337 -}
7338 -/**
7339   * handle all header and content read
7340   *
7341   * we get called by the state-engine and by the fdevent-handler
7342   */
7343 -int connection_handle_read_state(server *srv, connection *con)  {
7344 -       int ostate = con->state;
7345 -       char *h_term = NULL;
7346 -       chunk *c;
7347 -       chunkqueue *cq = con->read_queue;
7348 -       chunkqueue *dst_cq = con->request_content_queue;
7349 -       
7350 -       if (con->is_readable) {
7351 -               con->read_idle_ts = srv->cur_ts;
7352 -       
7353 -               switch(connection_handle_read(srv, con)) {
7354 -               case -1:
7355 -                       return -1;
7356 -               case -2:
7357 -                       /* remote side closed the connection
7358 -                        * if we still have content, handle it, if not leave here */
7359 +handler_t connection_handle_read_request_header(server *srv, connection *con)  {
7360 +       /* let's see if we need more data later */
7361 +       fdevent_event_del(srv->ev, con->sock);
7362 +
7363 +       con->read_idle_ts = srv->cur_ts;  /* start a read-call() */
7364 +
7365 +       /* read from the network */ 
7366 +       switch (network_read(srv, con, con->sock, con->recv_raw)) {
7367 +       case NETWORK_STATUS_SUCCESS:
7368 +               /* we read everything from the socket, do we have a full header ? */
7369  
7370 -                       if (cq->first == cq->last &&
7371 -                           cq->first->mem->used == 0) {
7372 +               break;
7373 +       case NETWORK_STATUS_WAIT_FOR_EVENT:
7374 +               fdevent_event_add(srv->ev, con->sock, FDEVENT_IN);
7375 +               return HANDLER_WAIT_FOR_EVENT;
7376 +       case NETWORK_STATUS_CONNECTION_CLOSE:
7377 +               /* the connection went away before we got something back */
7378 +               connection_set_state(srv, con, CON_STATE_CLOSE);
7379  
7380 -                               /* conn-closed, leave here */
7381 -                               connection_set_state(srv, con, CON_STATE_ERROR);
7382 -                       }
7383 -               default:
7384 -                       break;
7385 -               }
7386 +               return HANDLER_GO_ON;
7387 +       default:
7388 +               ERROR("++ %s", "oops, something went wrong while reading");
7389 +               return HANDLER_ERROR;
7390         }
7391  
7392 -       /* the last chunk might be empty */
7393 -       for (c = cq->first; c;) {
7394 -               if (cq->first == c && c->mem->used == 0) {
7395 -                       /* the first node is empty */
7396 -                       /* ... and it is empty, move it to unused */
7397 -
7398 -                       cq->first = c->next;
7399 -                       if (cq->first == NULL) cq->last = NULL;
7400 -
7401 -                       c->next = cq->unused;
7402 -                       cq->unused = c;
7403 -                       cq->unused_chunks++;
7404 -
7405 -                       c = cq->first;
7406 -               } else if (c->next && c->next->mem->used == 0) {
7407 -                       chunk *fc;
7408 -                       /* next node is the last one */
7409 -                       /* ... and it is empty, move it to unused */
7410 -
7411 -                       fc = c->next;
7412 -                       c->next = fc->next;
7413 -
7414 -                       fc->next = cq->unused;
7415 -                       cq->unused = fc;
7416 -                       cq->unused_chunks++;
7417 -
7418 -                       /* the last node was empty */
7419 -                       if (c->next == NULL) {
7420 -                               cq->last = c;
7421 -                       } 
7422  
7423 -                       c = c->next;
7424 -               } else {
7425 -                       c = c->next;
7426 -               }
7427 +       switch (http_request_parse_cq(con->recv_raw, con->http_req)) {
7428 +       case PARSE_ERROR:
7429 +               con->http_status = 400; /* the header is broken */
7430 +
7431 +               chunkqueue_remove_finished_chunks(con->recv_raw);
7432 +
7433 +               return HANDLER_FINISHED;
7434 +       case PARSE_NEED_MORE:
7435 +               /* we need more */
7436 +               fdevent_event_add(srv->ev, con->sock, FDEVENT_IN);
7437 +
7438 +               return HANDLER_WAIT_FOR_EVENT;
7439 +       case PARSE_SUCCESS:
7440 +               chunkqueue_remove_finished_chunks(con->recv_raw);
7441 +               break;
7442 +       default:
7443 +               chunkqueue_remove_finished_chunks(con->recv_raw);
7444 +               TRACE("%s", "(error)");
7445 +               return HANDLER_ERROR;
7446         }
7447 +
7448 +       return HANDLER_GO_ON;
7449 +}
7450 +
7451 +/* decode the HTTP/1.1 chunk encoding */
7452 +
7453 +handler_t connection_handle_read_request_content(server *srv, connection *con)  {
7454 +       /* read data from the socket and push it to the backend */
7455 +
7456 +       chunkqueue *in = con->recv_raw;
7457 +       chunkqueue *out = con->recv; /* the pure content */
7458 +       chunk *c;
7459         
7460 -       /* nothing to handle */
7461 -       if (cq->first == NULL) return 0;
7462 +       /* let's see if we need more data later */
7463 +       fdevent_event_del(srv->ev, con->sock);
7464 +
7465 +       con->read_idle_ts = srv->cur_ts;  /* start a read-call() */
7466 +
7467 +       if (con->request.content_length == -1) return HANDLER_GO_ON;
7468 +
7469 +       /* if the content was short enough, it might be read already */
7470 +       if (in->first &&
7471 +           chunkqueue_length(in) - in->first->offset > 0) {
7472  
7473 -       switch(ostate) {
7474 -       case CON_STATE_READ:
7475 -               /* prepare con->request.request */
7476 -               c = cq->first;
7477 +               /*  
7478 +                * looks like the request-header also had some content for us
7479 +                */
7480                 
7481 -               /* check if we need the full package */
7482 -               if (con->request.request->used == 0) {
7483 -                       buffer b;
7484 -                       
7485 -                       b.ptr = c->mem->ptr + c->offset;
7486 -                       b.used = c->mem->used - c->offset;
7487 -                       
7488 -                       if (NULL != (h_term = buffer_search_rnrn(&b))) {
7489 -                               /* \r\n\r\n found
7490 -                                * - copy everything incl. the terminator to request.request
7491 -                                */
7492 -                               
7493 -                               buffer_copy_string_len(con->request.request, 
7494 -                                                      b.ptr, 
7495 -                                                      h_term - b.ptr + 4);
7496 -                               
7497 -                               /* the buffer has been read up to the terminator */
7498 -                               c->offset += h_term - b.ptr + 4;
7499 -                       } else {
7500 -                               /* not found, copy everything */
7501 -                               buffer_copy_string_len(con->request.request, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
7502 -                               c->offset = c->mem->used - 1;
7503 -                       }
7504 -               } else {
7505 -                       /* have to take care of overlapping header terminators */
7506 -                       
7507 -                       size_t l = con->request.request->used - 2;
7508 -                       char *s  = con->request.request->ptr;
7509 -                       buffer b;
7510 -                       
7511 -                       b.ptr = c->mem->ptr + c->offset;
7512 -                       b.used = c->mem->used - c->offset;
7513 -                       
7514 -                       if (con->request.request->used - 1 > 3 &&
7515 -                           c->mem->used > 1 &&
7516 -                           s[l-2] == '\r' &&
7517 -                           s[l-1] == '\n' &&
7518 -                           s[l-0] == '\r' &&
7519 -                           c->mem->ptr[0] == '\n') {
7520 -                               buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, 1);
7521 -                               c->offset += 1;
7522 -                               
7523 -                               h_term = con->request.request->ptr;
7524 -                       } else if (con->request.request->used - 1 > 2 &&
7525 -                                  c->mem->used > 2 &&
7526 -                                  s[l-1] == '\r' &&
7527 -                                  s[l-0] == '\n' &&
7528 -                                  c->mem->ptr[0] == '\r' &&
7529 -                                  c->mem->ptr[1] == '\n') {
7530 -                               buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, 2);
7531 -                               c->offset += 2;
7532 -                               
7533 -                               h_term = con->request.request->ptr;
7534 -                       } else if (con->request.request->used - 1 > 1 &&
7535 -                                  c->mem->used > 3 &&
7536 -                                  s[l-0] == '\r' &&
7537 -                                  c->mem->ptr[0] == '\n' &&
7538 -                                  c->mem->ptr[1] == '\r' &&
7539 -                                  c->mem->ptr[2] == '\n') {
7540 -                               buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, 3);
7541 -                               c->offset += 3;
7542 -                               
7543 -                               h_term = con->request.request->ptr;
7544 -                       } else if (NULL != (h_term = buffer_search_string_len(&b, "\r\n\r\n", 4))) {
7545 -                               /* \r\n\r\n found
7546 -                                * - copy everything incl. the terminator to request.request
7547 -                                */
7548 -                               
7549 -                               buffer_append_string_len(con->request.request, 
7550 -                                                      c->mem->ptr + c->offset, 
7551 -                                                      c->offset + h_term - b.ptr + 4);
7552 -                               
7553 -                               /* the buffer has been read up to the terminator */
7554 -                               c->offset += h_term - b.ptr + 4;
7555 -                       } else {
7556 -                               /* not found, copy everything */
7557 -                               buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
7558 -                               c->offset = c->mem->used - 1;
7559 -                       }
7560 +       } else {
7561 +               /* read from the network */ 
7562 +               switch (network_read(srv, con, con->sock, in)) {
7563 +               case NETWORK_STATUS_SUCCESS:
7564 +                       /* we have data */
7565 +                       break;
7566 +               case NETWORK_STATUS_WAIT_FOR_EVENT:
7567 +                       fdevent_event_add(srv->ev, con->sock, FDEVENT_IN);
7568 +                       TRACE("%s", "content-read: wait-for-event");
7569 +                       return HANDLER_WAIT_FOR_EVENT;
7570 +               case NETWORK_STATUS_CONNECTION_CLOSE:
7571 +                       /* the connection went away before we got something back */
7572 +                       connection_set_state(srv, con, CON_STATE_CLOSE);
7573 +
7574 +                       return HANDLER_GO_ON;
7575 +               default:
7576 +                       ERROR("++ %s", "oops, something went wrong while reading");
7577 +                       return HANDLER_ERROR;
7578                 }
7579 +       }
7580  
7581 -               /* con->request.request is setup up */
7582 -               if (h_term) {
7583 -                       connection_set_state(srv, con, CON_STATE_REQUEST_END);
7584 -               } else if (con->request.request->used > 64 * 1024) {
7585 -                       log_error_write(srv, __FILE__, __LINE__, "s", "oversized request-header -> sending Status 414");
7586 +       /* how much data do we want to extract ? */
7587 +       for (c = in->first; c && (out->bytes_in != con->request.content_length); c = c->next) {
7588 +               off_t weWant, weHave, toRead;
7589  
7590 -                       con->http_status = 414; /* Request-URI too large */
7591 -                       con->keep_alive = 0;
7592 -                       connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7593 -               }
7594 -               break;
7595 -       case CON_STATE_READ_POST: 
7596 -               for (c = cq->first; c && (dst_cq->bytes_in != (off_t)con->request.content_length); c = c->next) {
7597 -                       off_t weWant, weHave, toRead;
7598 -                       
7599 -                       weWant = con->request.content_length - dst_cq->bytes_in;
7600 -                       
7601 -                       assert(c->mem->used);
7602 -                       
7603 -                       weHave = c->mem->used - c->offset - 1;
7604 -                               
7605 -                       toRead = weHave > weWant ? weWant : weHave;
7606 -
7607 -                       /* the new way, copy everything into a chunkqueue whcih might use tempfiles */
7608 -                       if (con->request.content_length > 64 * 1024) {
7609 -                               chunk *dst_c = NULL;
7610 -                               /* copy everything to max 1Mb sized tempfiles */
7611 -
7612 -                               /*
7613 -                                * if the last chunk is 
7614 -                                * - smaller than 1Mb (size < 1Mb)
7615 -                                * - not read yet (offset == 0)
7616 -                                * -> append to it
7617 -                                * otherwise
7618 -                                * -> create a new chunk 
7619 -                                * 
7620 -                                * */
7621 -
7622 -                               if (dst_cq->last &&
7623 -                                   dst_cq->last->type == FILE_CHUNK &&
7624 -                                   dst_cq->last->file.is_temp &&
7625 -                                   dst_cq->last->offset == 0) {
7626 -                                       /* ok, take the last chunk for our job */
7627 -
7628 -                                       if (dst_cq->last->file.length < 1 * 1024 * 1024) {
7629 -                                               dst_c = dst_cq->last;
7630 -
7631 -                                               if (dst_c->file.fd == -1) {
7632 -                                                       /* this should not happen as we cache the fd, but you never know */
7633 -                                                       dst_c->file.fd = open(dst_c->file.name->ptr, O_WRONLY | O_APPEND);
7634 -                                               }
7635 -                                       } else {
7636 -                                               /* the chunk is too large now, close it */
7637 -                                               dst_c = dst_cq->last;
7638 +               weWant = con->request.content_length - out->bytes_in;
7639 +
7640 +               if (c->mem->used == 0) continue;
7641  
7642 -                                               if (dst_c->file.fd != -1) {
7643 -                                                       close(dst_c->file.fd);
7644 -                                                       dst_c->file.fd = -1;
7645 -                                               }
7646 -                                               dst_c = chunkqueue_get_append_tempfile(dst_cq);
7647 +               weHave = c->mem->used - c->offset - 1;
7648 +
7649 +               toRead = weHave > weWant ? weWant : weHave;
7650 +
7651 +               /* the new way, copy everything into a chunkqueue whcih might use tempfiles */
7652 +               if (con->request.content_length > 64 * 1024) {
7653 +                       chunk *dst_c = NULL;
7654 +                       /* copy everything to max 1Mb sized tempfiles */
7655 +
7656 +                       /*
7657 +                        * if the last chunk is
7658 +                        * - smaller than 1Mb (size < 1Mb)
7659 +                        * - not read yet (offset == 0)
7660 +                        * -> append to it
7661 +                        * otherwise
7662 +                        * -> create a new chunk
7663 +                        *
7664 +                        * */
7665 +
7666 +                       if (out->last &&
7667 +                           out->last->type == FILE_CHUNK &&
7668 +                           out->last->file.is_temp &&
7669 +                           out->last->offset == 0) {
7670 +                               /* ok, take the last chunk for our job */
7671 +
7672 +                               if (out->last->file.length < 1 * 1024 * 1024) {
7673 +                                       dst_c = out->last;
7674 +
7675 +                                       if (dst_c->file.fd == -1) {
7676 +                                               /* this should not happen as we cache the fd, but you never know */
7677 +                                               dst_c->file.fd = open(dst_c->file.name->ptr, O_WRONLY | O_APPEND);
7678                                         }
7679                                 } else {
7680 -                                       dst_c = chunkqueue_get_append_tempfile(dst_cq);
7681 +                                       /* the chunk is too large now, close it */
7682 +                                       dst_c = out->last;
7683 +
7684 +                                       if (dst_c->file.fd != -1) {
7685 +                                               close(dst_c->file.fd);
7686 +                                               dst_c->file.fd = -1;
7687 +                                       }
7688 +                                       dst_c = chunkqueue_get_append_tempfile(out);
7689                                 }
7690 +                       } else {
7691 +                               dst_c = chunkqueue_get_append_tempfile(out);
7692 +                       }
7693 +
7694 +                       /* we have a chunk, let's write to it */
7695  
7696 -                               /* we have a chunk, let's write to it */
7697 +                       if (dst_c->file.fd == -1) {
7698 +                               /* we don't have file to write to,
7699 +                                * EACCES might be one reason.
7700 +                                *
7701 +                                * Instead of sending 500 we send 413 and say the request is too large
7702 +                                *  */
7703  
7704 -                               if (dst_c->file.fd == -1) {
7705 -                                       /* we don't have file to write to, 
7706 -                                        * EACCES might be one reason.
7707 -                                        *
7708 -                                        * Instead of sending 500 we send 413 and say the request is too large
7709 -                                        *  */
7710 -
7711 -                                       log_error_write(srv, __FILE__, __LINE__, "sbs",
7712 -                                                       "denying upload as opening to temp-file for upload failed:", 
7713 -                                                       dst_c->file.name, strerror(errno));
7714 -
7715 -                                       con->http_status = 413; /* Request-Entity too large */
7716 -                                       con->keep_alive = 0;
7717 -                                       connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7718 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
7719 +                                               "denying upload as opening to temp-file for upload failed:",
7720 +                                               dst_c->file.name, strerror(errno));
7721  
7722 -                                       break;
7723 -                               }
7724 +                               con->http_status = 413; /* Request-Entity too large */
7725 +                               con->keep_alive = 0;
7726 +                               return HANDLER_FINISHED;
7727 +                       }
7728  
7729 -                               if (toRead != write(dst_c->file.fd, c->mem->ptr + c->offset, toRead)) {
7730 -                                       /* write failed for some reason ... disk full ? */ 
7731 -                                       log_error_write(srv, __FILE__, __LINE__, "sbs",
7732 -                                                       "denying upload as writing to file failed:", 
7733 -                                                       dst_c->file.name, strerror(errno));
7734 -                                       
7735 -                                       con->http_status = 413; /* Request-Entity too large */
7736 -                                       con->keep_alive = 0;
7737 -                                       connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7738 -                               
7739 -                                       close(dst_c->file.fd);
7740 -                                       dst_c->file.fd = -1;
7741 +                       if (toRead != write(dst_c->file.fd, c->mem->ptr + c->offset, toRead)) {
7742 +                               /* write failed for some reason ... disk full ? */
7743 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
7744 +                                               "denying upload as writing to file failed:",
7745 +                                               dst_c->file.name, strerror(errno));
7746  
7747 -                                       break;
7748 -                               }
7749 +                               con->http_status = 413; /* Request-Entity too large */
7750 +                               con->keep_alive = 0;
7751  
7752 -                               dst_c->file.length += toRead;
7753 -                                       
7754 -                               if (dst_cq->bytes_in + toRead == (off_t)con->request.content_length) {
7755 -                                       /* we read everything, close the chunk */
7756 -                                       close(dst_c->file.fd);
7757 -                                       dst_c->file.fd = -1;
7758 -                               }
7759 -                       } else {
7760 -                               buffer *b;
7761 +                               close(dst_c->file.fd);
7762 +                               dst_c->file.fd = -1;
7763  
7764 -                               b = chunkqueue_get_append_buffer(dst_cq);
7765 -                               buffer_copy_string_len(b, c->mem->ptr + c->offset, toRead);
7766 +                               return HANDLER_FINISHED;
7767                         }
7768 -                       
7769 -                       c->offset += toRead;
7770 -                       dst_cq->bytes_in += toRead;
7771 -               }
7772  
7773 -               /* Content is ready */
7774 -               if (dst_cq->bytes_in == (off_t)con->request.content_length) {
7775 -                       connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7776 +                       dst_c->file.length += toRead;
7777 +
7778 +                       if (out->bytes_in + toRead == con->request.content_length) {
7779 +                               /* we read everything, close the chunk */
7780 +                               close(dst_c->file.fd);
7781 +                               dst_c->file.fd = -1;
7782 +                       }
7783 +               } else {
7784 +                       buffer *b;
7785 +
7786 +                       b = chunkqueue_get_append_buffer(out);
7787 +                       buffer_copy_string_len(b, c->mem->ptr + c->offset, toRead);
7788                 }
7789 -                       
7790 -               break;
7791 +
7792 +               c->offset += toRead;
7793 +
7794 +               out->bytes_in += toRead;
7795 +               in->bytes_out += toRead;
7796         }
7797  
7798 -       chunkqueue_remove_finished_chunks(cq);
7799 +       if (out->bytes_in < con->request.content_length) {
7800 +               /* we have to read more content */
7801 +               fdevent_event_add(srv->ev, con->sock, FDEVENT_IN);
7802 +       }
7803  
7804 -       return 0;
7805 +       return HANDLER_GO_ON;
7806  }
7807  
7808  handler_t connection_handle_fdevent(void *s, void *context, int revents) {
7809         server     *srv = (server *)s;
7810         connection *con = context;
7811 -       
7812 -       joblist_append(srv, con);
7813 -       
7814 +
7815         if (revents & FDEVENT_IN) {
7816 -               con->is_readable = 1;
7817 -#if 0
7818 -               log_error_write(srv, __FILE__, __LINE__, "sd", "read-wait - done", con->fd);
7819 -#endif
7820 +               switch (con->state) {
7821 +               case CON_STATE_READ_REQUEST_HEADER:
7822 +               case CON_STATE_READ_REQUEST_CONTENT:
7823 +                       joblist_append(srv, con);
7824 +                       break;
7825 +               case CON_STATE_CLOSE:
7826 +                       break;
7827 +               default:
7828 +                       ERROR("%s", "I thought only READ_REQUEST_* need fdevent-in");
7829 +                       break;
7830 +               }
7831         }
7832 +
7833         if (revents & FDEVENT_OUT) {
7834 -               con->is_writable = 1;
7835 -               /* we don't need the event twice */
7836 +               switch (con->state) {
7837 +               case CON_STATE_WRITE_RESPONSE_HEADER:
7838 +               case CON_STATE_WRITE_RESPONSE_CONTENT:
7839 +                       joblist_append(srv, con);
7840 +                       break;
7841 +               default:
7842 +                       ERROR("%s", "I thought only WRITE_RESPONSE_* need fdevent-out");
7843 +                       break;
7844 +               }
7845         }
7846 -       
7847 -       
7848 +
7849         if (revents & ~(FDEVENT_IN | FDEVENT_OUT)) {
7850                 /* looks like an error */
7851 -                                               
7852 -               /* FIXME: revents = 0x19 still means that we should read from the queue */
7853 -               if (revents & FDEVENT_HUP) {
7854 -                       if (con->state == CON_STATE_CLOSE) {
7855 -                               con->close_timeout_ts = 0;
7856 -                       } else {
7857 -                               /* sigio reports the wrong event here
7858 -                                * 
7859 -                                * there was no HUP at all 
7860 -                                */
7861 -#ifdef USE_LINUX_SIGIO
7862 -                               if (srv->ev->in_sigio == 1) {
7863 -                                       log_error_write(srv, __FILE__, __LINE__, "sd",
7864 -                                               "connection closed: poll() -> HUP", con->fd);
7865 -                               } else {
7866 -                                       connection_set_state(srv, con, CON_STATE_ERROR);
7867 -                               }
7868 -#else
7869 -                               connection_set_state(srv, con, CON_STATE_ERROR);
7870 -#endif
7871 -                               
7872 -                       }
7873 -               } else if (revents & FDEVENT_ERR) {
7874 -#ifndef USE_LINUX_SIGIO
7875 -                       log_error_write(srv, __FILE__, __LINE__, "sd",
7876 -                                       "connection closed: poll() -> ERR", con->fd);
7877 -#endif 
7878 -                       connection_set_state(srv, con, CON_STATE_ERROR);
7879 -               } else {
7880 -                       log_error_write(srv, __FILE__, __LINE__, "sd",
7881 -                                       "connection closed: poll() -> ???", revents);
7882 -               } 
7883 -       }
7884 -       
7885 -       if (con->state == CON_STATE_READ ||
7886 -           con->state == CON_STATE_READ_POST) {
7887 -               connection_handle_read_state(srv, con);
7888 -       }
7889 -       
7890 -       if (con->state == CON_STATE_WRITE &&
7891 -           !chunkqueue_is_empty(con->write_queue) &&
7892 -           con->is_writable) {
7893 -               
7894 -               if (-1 == connection_handle_write(srv, con)) {
7895 -                       connection_set_state(srv, con, CON_STATE_ERROR);
7896 -                       
7897 -                       log_error_write(srv, __FILE__, __LINE__, "ds",
7898 -                                       con->fd,
7899 -                                       "handle write failed.");
7900 -               } else if (con->state == CON_STATE_WRITE) {
7901 -                       con->write_request_ts = srv->cur_ts;
7902 -               }
7903 -       }
7904 -       
7905 -       if (con->state == CON_STATE_CLOSE) {
7906 -               /* flush the read buffers */
7907 -               int b;
7908 -               
7909 -               if (ioctl(con->fd, FIONREAD, &b)) {
7910 -                       log_error_write(srv, __FILE__, __LINE__, "ss",
7911 -                                       "ioctl() failed", strerror(errno));
7912 -               }
7913 -               
7914 -               if (b > 0) {
7915 -                       char buf[1024];
7916 -                       log_error_write(srv, __FILE__, __LINE__, "sdd",
7917 -                                       "CLOSE-read()", con->fd, b);
7918 -                       
7919 -                       /* */
7920 -                       read(con->fd, buf, sizeof(buf));
7921 -               } else {
7922 -                       /* nothing to read */
7923 -                       
7924 -                       con->close_timeout_ts = 0;
7925 -               }
7926 +
7927 +               connection_set_state(srv, con, CON_STATE_ERROR);
7928 +               joblist_append(srv, con);
7929         }
7930 -       
7931 +
7932 +
7933         return HANDLER_FINISHED;
7934  }
7935  
7936 @@ -1229,63 +860,78 @@
7937         sock_addr cnt_addr;
7938         socklen_t cnt_len;
7939         /* accept it and register the fd */
7940 -       
7941 +
7942         cnt_len = sizeof(cnt_addr);
7943  
7944 -       if (-1 == (cnt = accept(srv_socket->fd, (struct sockaddr *) &cnt_addr, &cnt_len))) {
7945 -               if ((errno != EAGAIN) &&
7946 -                   (errno != EINTR)) {
7947 -                       log_error_write(srv, __FILE__, __LINE__, "ssd", "accept failed:", strerror(errno), errno);
7948 +       if (-1 == (cnt = accept(srv_socket->sock->fd, (struct sockaddr *) &cnt_addr, &cnt_len))) {
7949 +#ifdef _WIN32
7950 +               errno = WSAGetLastError();
7951 +#endif
7952 +               switch (errno) {
7953 +               case EAGAIN:
7954 +#if EWOULDBLOCK != EAGAIN
7955 +               case EWOULDBLOCK:
7956 +#endif
7957 +               case EINTR: 
7958 +                       /* we were stopped _before_ we had a connection */
7959 +               case ECONNABORTED: /* this is a FreeBSD thingy */
7960 +                       /* we were stopped _after_ we had a connection */
7961 +                       break;
7962 +               default:
7963 +                       ERROR("accept failed on fd=%d with error: (%d) %s", srv_socket->sock->fd, errno, strerror(errno));
7964 +                       break;
7965                 }
7966                 return NULL;
7967         } else {
7968                 connection *con;
7969 -               
7970 +
7971                 srv->cur_fds++;
7972 -               
7973 +
7974                 /* ok, we have the connection, register it */
7975  #if 0
7976                 log_error_write(srv, __FILE__, __LINE__, "sd",
7977                                 "appected()", cnt);
7978  #endif
7979                 srv->con_opened++;
7980 -               
7981 +
7982                 con = connections_get_new_connection(srv);
7983 -               
7984 -               con->fd = cnt;
7985 -               con->fde_ndx = -1;
7986 -#if 0          
7987 +               con->sock->fd = cnt;
7988 +               con->sock->fde_ndx = -1;
7989 +#if 0
7990                 gettimeofday(&(con->start_tv), NULL);
7991 -#endif         
7992 -               fdevent_register(srv->ev, con->fd, connection_handle_fdevent, con);
7993 -               
7994 +#endif
7995 +               fdevent_register(srv->ev, con->sock, connection_handle_fdevent, con);
7996 +
7997                 connection_set_state(srv, con, CON_STATE_REQUEST_START);
7998 -               
7999 +
8000                 con->connection_start = srv->cur_ts;
8001                 con->dst_addr = cnt_addr;
8002                 buffer_copy_string(con->dst_addr_buf, inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
8003                 con->srv_socket = srv_socket;
8004 -               
8005 -               if (-1 == (fdevent_fcntl_set(srv->ev, con->fd))) {
8006 +
8007 +               if (-1 == (fdevent_fcntl_set(srv->ev, con->sock))) {
8008                         log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
8009 +                       connection_close(srv, con);
8010                         return NULL;
8011                 }
8012 +                       
8013  #ifdef USE_OPENSSL
8014                 /* connect FD to SSL */
8015                 if (srv_socket->is_ssl) {
8016 -                       if (NULL == (con->ssl = SSL_new(srv_socket->ssl_ctx))) {
8017 -                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", 
8018 +                       if (NULL == (con->sock->ssl = SSL_new(srv_socket->ssl_ctx))) {
8019 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
8020                                                 ERR_error_string(ERR_get_error(), NULL));
8021 -                               
8022 +                               connection_close(srv, con);
8023                                 return NULL;
8024                         }
8025 -                       
8026 -                       SSL_set_accept_state(con->ssl);
8027 +
8028 +                       SSL_set_accept_state(con->sock->ssl);
8029                         con->conf.is_ssl=1;
8030 -                       
8031 -                       if (1 != (SSL_set_fd(con->ssl, cnt))) {
8032 -                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", 
8033 +
8034 +                       if (1 != (SSL_set_fd(con->sock->ssl, cnt))) {
8035 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
8036                                                 ERR_error_string(ERR_get_error(), NULL));
8037 +                               connection_close(srv, con);
8038                                 return NULL;
8039                         }
8040                 }
8041 @@ -1294,182 +940,452 @@
8042         }
8043  }
8044  
8045 +static int http_chunk_append_len(chunkqueue *cq, size_t len) {
8046 +       size_t i, olen = len, j;
8047 +       buffer *b;
8048 +
8049 +       b = buffer_init();
8050 +
8051 +       if (len == 0) {
8052 +               buffer_copy_string(b, "0");
8053 +       } else {
8054 +               for (i = 0; i < 8 && len; i++) {
8055 +                       len >>= 4;
8056 +               }
8057 +
8058 +               /* i is the number of hex digits we have */
8059 +               buffer_prepare_copy(b, i + 1);
8060 +
8061 +               for (j = i-1, len = olen; j+1 > 0; j--) {
8062 +                       b->ptr[j] = (len & 0xf) + (((len & 0xf) <= 9) ? '0' : 'a' - 10);
8063 +                       len >>= 4;
8064 +               }
8065 +               b->used = i;
8066 +               b->ptr[b->used++] = '\0';
8067 +       }
8068 +
8069 +       buffer_append_string(b, "\r\n");
8070 +       chunkqueue_append_buffer(cq, b);
8071 +
8072 +       buffer_free(b);
8073 +
8074 +       return 0;
8075 +}
8076 +
8077 +
8078 +/**
8079 + * apply chunk encoding if necessary
8080 + */
8081 +int http_stream_encoder(server *srv, connection *con, chunkqueue *in, chunkqueue *out) {
8082 +       chunk *c;
8083 +       int is_chunked;
8084 +
8085 +       /**/
8086 +
8087 +       is_chunked = (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED);
8088 +
8089 +       if (is_chunked) {
8090 +               for (c = in->first; c; c = c->next) {
8091 +                       switch (c->type) {
8092 +                       case MEM_CHUNK:
8093 +                               if (c->mem->used == 0) continue;
8094 +
8095 +                               http_chunk_append_len(out, c->mem->used - 1);
8096 +                               chunkqueue_append_buffer(out, c->mem);
8097 +                               c->offset = c->mem->used - 1;
8098 +                               break;
8099 +                       case FILE_CHUNK:
8100 +                               if (c->file.length == 0) continue;
8101 +
8102 +                               http_chunk_append_len(out, c->file.length);
8103 +                               chunkqueue_append_file(out, c->file.name, c->file.start, c->file.length);
8104 +
8105 +                               c->offset = c->file.length;
8106 +                               break;
8107 +                       }
8108 +                       chunkqueue_append_mem(out, "\r\n", 2 + 1);
8109 +               }
8110 +               if (in->is_closed) http_chunk_append_len(out, 0);
8111 +       } else {
8112 +               for (c = in->first; c; c = c->next) {
8113 +                       switch (c->type) {
8114 +                       case MEM_CHUNK:
8115 +                               if (c->mem->used == 0) continue;
8116 +
8117 +                               chunkqueue_append_buffer(out, c->mem);
8118 +                               c->offset = c->mem->used - 1;
8119 +                               break;
8120 +                       case FILE_CHUNK:
8121 +                               if (c->file.length == 0) continue;
8122 +
8123 +                               chunkqueue_append_file(out, c->file.name, c->file.start, c->file.length);
8124 +
8125 +                               c->offset = c->file.length;
8126 +                               break;
8127 +                       }
8128 +               }
8129 +       }
8130 +
8131 +       chunkqueue_remove_finished_chunks(in);
8132 +
8133 +       return 0;
8134 +}
8135  
8136  int connection_state_machine(server *srv, connection *con) {
8137         int done = 0, r;
8138  #ifdef USE_OPENSSL
8139         server_socket *srv_sock = con->srv_socket;
8140  #endif
8141 -       
8142 +
8143         if (srv->srvconf.log_state_handling) {
8144 -               log_error_write(srv, __FILE__, __LINE__, "sds", 
8145 -                               "state at start", 
8146 -                               con->fd,
8147 +               log_error_write(srv, __FILE__, __LINE__, "sds",
8148 +                               "state at start",
8149 +                               con->sock->fd,
8150                                 connection_get_state(con->state));
8151         }
8152  
8153         while (done == 0) {
8154                 size_t ostate = con->state;
8155                 int b;
8156 -               
8157 +
8158                 switch (con->state) {
8159 -               case CON_STATE_REQUEST_START: /* transient */
8160 +               case CON_STATE_CONNECT:
8161                         if (srv->srvconf.log_state_handling) {
8162 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
8163 -                                               "state for fd", con->fd, connection_get_state(con->state));
8164 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
8165 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
8166                         }
8167 -                       
8168 -                       con->request_start = srv->cur_ts;
8169 -                       con->read_idle_ts = srv->cur_ts;
8170 -                       
8171 -                       con->request_count++;
8172 -                       con->loops_per_request = 0;
8173 -                       
8174 -                       connection_set_state(srv, con, CON_STATE_READ);
8175 -                       
8176 +
8177 +                       chunkqueue_reset(con->recv_raw); /* this is a new connection, trash the pipeline */
8178 +
8179 +                       con->request_count = 0;
8180 +
8181                         break;
8182 -               case CON_STATE_REQUEST_END: /* transient */
8183 +               case CON_STATE_REQUEST_START:
8184 +                       /* init the request handling */
8185                         if (srv->srvconf.log_state_handling) {
8186 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
8187 -                                               "state for fd", con->fd, connection_get_state(con->state));
8188 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
8189 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
8190                         }
8191 -                       
8192 -                       if (http_request_parse(srv, con)) {
8193 -                               /* we have to read some data from the POST request */
8194 -                               
8195 -                               connection_set_state(srv, con, CON_STATE_READ_POST);
8196  
8197 +                       con->request_start = srv->cur_ts; /* start of the request */
8198 +                       con->read_idle_ts = srv->cur_ts;  /* start a read-call() */
8199 +
8200 +                       con->request_count++;             /* max-keepalive requests */
8201 +                       con->loops_per_request = 0;       /* infinite loops */
8202 +
8203 +                       /* if the content was short enough, it might have a header already in the pipe */
8204 +                       if (con->recv_raw->first &&
8205 +                           chunkqueue_length(con->recv_raw) - con->recv_raw->first->offset > 0) {
8206 +                               /* pipelining */
8207 +
8208 +                               switch (http_request_parse_cq(con->recv_raw, con->http_req)) {
8209 +                               case PARSE_ERROR:
8210 +                                       con->http_status = 400; /* the header is broken */
8211 +
8212 +                                       chunkqueue_remove_finished_chunks(con->recv_raw);
8213 +
8214 +                                       connection_set_state(srv, con, CON_STATE_HANDLE_RESPONSE_HEADER);
8215 +                                       break;
8216 +                               case PARSE_NEED_MORE:
8217 +                                       /* the read() call is on the way */
8218 +                                       connection_set_state(srv, con, CON_STATE_READ_REQUEST_HEADER);
8219 +                                       break;
8220 +                               case PARSE_SUCCESS:
8221 +                                       /* pipelining worked, validate the header */
8222 +                                       chunkqueue_remove_finished_chunks(con->recv_raw);
8223 +
8224 +                                       connection_set_state(srv, con, CON_STATE_VALIDATE_REQUEST_HEADER);
8225 +                                       break;
8226 +                               default:
8227 +                                       chunkqueue_remove_finished_chunks(con->recv_raw);
8228 +                                       TRACE("%s", "(error)");
8229 +                                       return HANDLER_ERROR;
8230 +                               }
8231 +                       } else {
8232 +                               connection_set_state(srv, con, CON_STATE_READ_REQUEST_HEADER);
8233 +                       }
8234 +
8235 +                       break;
8236 +               case CON_STATE_READ_REQUEST_HEADER: 
8237 +                       /* read us much data as needed into the recv_raw-cq for a valid header */
8238 +                       if (srv->srvconf.log_state_handling) {
8239 +                               TRACE("state for fd=%d: %s", con->sock->fd, connection_get_state(con->state));
8240 +                       }
8241 +
8242 +                       switch (connection_handle_read_request_header(srv, con)) {
8243 +                       case HANDLER_GO_ON:
8244 +                               connection_set_state(srv, con, CON_STATE_VALIDATE_REQUEST_HEADER);
8245 +                               break;
8246 +                       case HANDLER_FINISHED:
8247 +                               connection_set_state(srv, con, CON_STATE_WRITE_RESPONSE_HEADER);
8248 +                               break;
8249 +                       case HANDLER_WAIT_FOR_EVENT:
8250 +                               return HANDLER_WAIT_FOR_EVENT;
8251 +                       case HANDLER_ERROR:
8252 +                               TRACE("%s", "(error)");
8253 +                               connection_set_state(srv, con, CON_STATE_ERROR);
8254 +                               break;
8255 +                       default:
8256 +                               TRACE("%s", "(error)");
8257 +                               connection_set_state(srv, con, CON_STATE_ERROR);
8258                                 break;
8259                         }
8260 -                       
8261 -                       connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
8262 -                       
8263                         break;
8264 -               case CON_STATE_HANDLE_REQUEST:
8265 -                       /* 
8266 -                        * the request is parsed
8267 -                        * 
8268 -                        * decided what to do with the request
8269 -                        * - 
8270 -                        * 
8271 -                        * 
8272 -                        */
8273 -                       
8274 +               case CON_STATE_VALIDATE_REQUEST_HEADER:
8275 +                       /* we have the full header, parse it */
8276 +
8277 +                       http_request_parse(srv, con, con->http_req);
8278 +
8279 +                       if (con->http_status != 0) {
8280 +                               con->keep_alive = 0;
8281 +                               con->send->is_closed = 1; /* there is no content */
8282 +
8283 +                               connection_set_state(srv, con, CON_STATE_HANDLE_RESPONSE_HEADER);
8284 +                       } else if (array_get_element(con->request.headers, "Expect")) {
8285 +                               /* write */
8286 +                               con->http_status = 100;
8287 +                               con->send->is_closed = 1;
8288 +                               TRACE("%s", "setting status 100");
8289 +
8290 +                               connection_set_state(srv, con, CON_STATE_WRITE_RESPONSE_HEADER);
8291 +                       } else {
8292 +                               /* parsing the request went fine 
8293 +                                * let's find a handler for this request */
8294 +                               connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST_HEADER);
8295 +                       }
8296 +
8297 +                       break;
8298 +               case CON_STATE_HANDLE_REQUEST_HEADER:
8299 +                       /* the request header is parsed,
8300 +                        * find someone who wants to handle this request */
8301 +
8302                         if (srv->srvconf.log_state_handling) {
8303 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
8304 -                                               "state for fd", con->fd, connection_get_state(con->state));
8305 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
8306 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
8307                         }
8308 -                       
8309 -                       switch (r = http_response_prepare(srv, con)) {
8310 +
8311 +                       switch (r = handle_get_backend(srv, con)) {
8312 +                       case HANDLER_GO_ON:
8313                         case HANDLER_FINISHED:
8314 -                               if (con->http_status == 404 ||
8315 -                                   con->http_status == 403) {
8316 -                                       /* 404 error-handler */
8317 -                                       
8318 -                                       if (con->in_error_handler == 0 && 
8319 -                                           (!buffer_is_empty(con->conf.error_handler) ||
8320 -                                            !buffer_is_empty(con->error_handler))) {
8321 -                                               /* call error-handler */
8322 -                                               
8323 -                                               con->error_handler_saved_status = con->http_status;
8324 -                                               con->http_status = 0;
8325 -                                               
8326 -                                               if (buffer_is_empty(con->error_handler)) {
8327 -                                                       buffer_copy_string_buffer(con->request.uri, con->conf.error_handler);
8328 -                                               } else {
8329 -                                                       buffer_copy_string_buffer(con->request.uri, con->error_handler);
8330 -                                               }
8331 -                                               buffer_reset(con->physical.path);
8332 -                                               
8333 -                                               con->in_error_handler = 1;
8334 -                                               
8335 -                                               connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
8336 -                                               
8337 -                                               done = -1;
8338 -                                               break;
8339 -                                       } else if (con->in_error_handler) {
8340 -                                               /* error-handler is a 404 */
8341 -                                               
8342 -                                               /* continue as normal, status is the same */
8343 -                                               log_error_write(srv, __FILE__, __LINE__, "sb", 
8344 -                                                               "Warning: Either the error-handler returned status 404 or the error-handler itself was not found:", con->request.uri);
8345 -                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
8346 -                                                               "returning the original status", con->error_handler_saved_status);
8347 -                                               log_error_write(srv, __FILE__, __LINE__, "s", 
8348 -                                                               "If this is a rails app: check your production.log");
8349 -                                               con->http_status = con->error_handler_saved_status;
8350 -                                       }
8351 -                               } else if (con->in_error_handler) {
8352 -                                       /* error-handler is back and has generated content */
8353 -                                       /* if Status: was set, take it otherwise use 200 */
8354 -                               }
8355 -                               
8356 -                               if (con->http_status == 0) con->http_status = 200;
8357 -                               
8358 -                               /* we have something to send, go on */
8359 -                               connection_set_state(srv, con, CON_STATE_RESPONSE_START);
8360                                 break;
8361                         case HANDLER_WAIT_FOR_FD:
8362                                 srv->want_fds++;
8363 -                               
8364 +
8365                                 fdwaitqueue_append(srv, con);
8366 -                               
8367 -                               connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
8368 -                               
8369 +
8370 +                               connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST_HEADER);
8371 +
8372                                 break;
8373                         case HANDLER_COMEBACK:
8374                                 done = -1;
8375                         case HANDLER_WAIT_FOR_EVENT:
8376                                 /* come back here */
8377 -                               connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
8378 -                               
8379 +                               connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST_HEADER);
8380 +
8381                                 break;
8382                         case HANDLER_ERROR:
8383                                 /* something went wrong */
8384 +                               TRACE("%s", "(error)");
8385                                 connection_set_state(srv, con, CON_STATE_ERROR);
8386                                 break;
8387                         default:
8388 -                               log_error_write(srv, __FILE__, __LINE__, "sdd", "unknown ret-value: ", con->fd, r);
8389 +                               TRACE("handle_get_backend returned %d on fd %d", r, con->sock->fd);
8390                                 break;
8391                         }
8392 -                       
8393 +
8394 +                       if (r != HANDLER_FINISHED && r != HANDLER_GO_ON) break;
8395 +
8396 +                       if (con->http_status == 404 ||
8397 +                           con->http_status == 403) {
8398 +                               /* 404 error-handler */
8399 +
8400 +                               if (con->in_error_handler == 0 &&
8401 +                                   (!buffer_is_empty(con->conf.error_handler) ||
8402 +                                    !buffer_is_empty(con->error_handler))) {
8403 +                                       /* call error-handler */
8404 +
8405 +                                       con->error_handler_saved_status = con->http_status;
8406 +                                       con->http_status = 0;
8407 +
8408 +                                       if (buffer_is_empty(con->error_handler)) {
8409 +                                               buffer_copy_string_buffer(con->request.uri, con->conf.error_handler);
8410 +                                       } else {
8411 +                                               buffer_copy_string_buffer(con->request.uri, con->error_handler);
8412 +                                       }
8413 +                                       buffer_reset(con->physical.path);
8414 +
8415 +                                       con->in_error_handler = 1;
8416 +
8417 +                                       connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST_HEADER);
8418 +
8419 +                                       done = -1;
8420 +                                       break;
8421 +                               } else if (con->in_error_handler) {
8422 +                                       /* error-handler is a 404 */
8423 +
8424 +                                       /* continue as normal, status is the same */
8425 +                                       log_error_write(srv, __FILE__, __LINE__, "sb",
8426 +                                                       "Warning: Either the error-handler returned status 404 or the error-handler itself was not found:", con->request.uri);
8427 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
8428 +                                                       "returning the original status", con->error_handler_saved_status);
8429 +                                       log_error_write(srv, __FILE__, __LINE__, "s",
8430 +                                                       "If this is a rails app: check your production.log");
8431 +                                       con->http_status = con->error_handler_saved_status;
8432 +                               }
8433 +                       } else if (con->in_error_handler) {
8434 +                               /* error-handler is back and has generated content */
8435 +                               /* if Status: was set, take it otherwise use 200 */
8436 +                       }
8437 +
8438 +                       if (con->http_status == 0) con->http_status = 200;
8439 +
8440 +                       /* the backend is prepared, forward the content */
8441 +                       connection_set_state(srv, con, CON_STATE_READ_REQUEST_CONTENT);
8442 +
8443                         break;
8444 -               case CON_STATE_RESPONSE_START:
8445 +               case CON_STATE_READ_REQUEST_CONTENT:
8446 +                       /* the request-handle is setup, read all the data and push it into the request-handler */
8447 +
8448 +                       if (con->request.content_length == -1 ||
8449 +                           con->request.content_length == 0) {
8450 +                               con->recv->is_closed = 1;
8451 +                       }
8452 +
8453 +                       if (!con->recv->is_closed &&
8454 +                           con->recv->bytes_in < con->request.content_length) {
8455 +                               switch (connection_handle_read_request_content(srv, con)) {
8456 +                               case HANDLER_GO_ON:
8457 +                                       break;
8458 +                               case HANDLER_ERROR:
8459 +                               TRACE("%s", "(error)");
8460 +                                       connection_set_state(srv, con, CON_STATE_ERROR);
8461 +                                       break;
8462 +                               case HANDLER_WAIT_FOR_EVENT:
8463 +                                       break;
8464 +                               default:
8465 +                                       ERROR("%s", "oops, unknown return value: ...");
8466 +                               }
8467 +
8468 +                               if (con->recv->bytes_in == con->request.content_length) {
8469 +                                       TRACE("%s", "read-content-done");
8470 +                                       /* we read everything */
8471 +                                       fdevent_event_del(srv->ev, con->sock);
8472 +                                       con->recv->is_closed = 1;
8473 +                               }
8474 +                               chunkqueue_remove_finished_chunks(con->recv_raw);
8475 +                       }
8476 +
8477 +                       chunkqueue_remove_finished_chunks(con->recv);
8478 +
8479                         /* 
8480 -                        * the decision is done
8481 -                        * - create the HTTP-Response-Header
8482 +                        * this should call the backend
8483 +                        * they might build the connection now or stream the content to the upstream server
8484 +                        * */
8485 +
8486 +                       switch(r = plugins_call_handle_send_request_content(srv, con)) {
8487 +                       case HANDLER_GO_ON:
8488 +                               /* everything was forwarded */
8489 +                               break;
8490 +                       case HANDLER_FINISHED:
8491 +                               /* oops, we don't want this here */
8492 +                               break;
8493 +                       case HANDLER_WAIT_FOR_EVENT:
8494 +                               return HANDLER_WAIT_FOR_EVENT;
8495 +                       default:
8496 +                               /* something strange happened */
8497 +                               TRACE("%s", "(error)");
8498 +                               connection_set_state(srv, con, CON_STATE_ERROR);
8499 +                               break;
8500 +                       }
8501 +
8502 +                       chunkqueue_remove_finished_chunks(con->recv);
8503 +
8504 +                       if (con->state == CON_STATE_ERROR) break;
8505 +
8506 +                       if (con->recv->is_closed && 
8507 +                           con->recv->bytes_in == con->recv->bytes_out) {
8508 +                               /* everything we read is sent */
8509 +                               connection_set_state(srv, con, CON_STATE_HANDLE_RESPONSE_HEADER);
8510 +                       }
8511 +
8512 +                       break;
8513 +               case CON_STATE_HANDLE_RESPONSE_HEADER:
8514 +                       /* we got a response header from the backend
8515 +                        * call all plugins who want to modify the response header
8516 +                        * - mod_compress/deflate
8517 +                        * - HTTP/1.1 chunking
8518                          * 
8519                          */
8520 +
8521 +                       connection_set_state(srv, con, CON_STATE_WRITE_RESPONSE_HEADER);
8522 +
8523 +                       break;
8524 +               case CON_STATE_WRITE_RESPONSE_HEADER:
8525 +                       /* create the HTTP response header */
8526 +                       connection_handle_response_header(srv, con);
8527 +
8528 +                       connection_set_state(srv, con, CON_STATE_WRITE_RESPONSE_CONTENT);
8529                         
8530 -                       if (srv->srvconf.log_state_handling) {
8531 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
8532 -                                               "state for fd", con->fd, connection_get_state(con->state));
8533 -                       }
8534 -                       
8535 -                       if (-1 == connection_handle_write_prepare(srv, con)) {
8536 +                       break;
8537 +               case CON_STATE_WRITE_RESPONSE_CONTENT:
8538 +                       fdevent_event_del(srv->ev, con->sock);
8539 +
8540 +                       /* we might have new content in the con->send buffer 
8541 +                        * encode it for the network 
8542 +                        * - chunking
8543 +                        * - compression
8544 +                        */
8545 +
8546 +                       http_stream_encoder(srv, con, con->send, con->send_raw);
8547 +
8548 +                       switch(network_write_chunkqueue(srv, con, con->send_raw)) {
8549 +                       case NETWORK_STATUS_SUCCESS:
8550 +                               /* we send everything from the chunkqueue and the chunkqueue-sender signaled it is finished */
8551 +                               if (con->send->is_closed) {
8552 +                                       if (con->http_status == 100) {
8553 +                                               /* send out the 100 Continue header and handle the request as normal afterwards */
8554 +                                               con->http_status = 0;
8555 +
8556 +                                               connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST_HEADER);
8557 +                                       } else {
8558 +                                               connection_set_state(srv, con, CON_STATE_RESPONSE_END);
8559 +                                       }
8560 +                               }
8561 +                               break;
8562 +                       case NETWORK_STATUS_FATAL_ERROR: /* error on our side */
8563 +                               TRACE("%s", "(error)");
8564                                 connection_set_state(srv, con, CON_STATE_ERROR);
8565 -                               
8566 +                               break;
8567 +                       case NETWORK_STATUS_CONNECTION_CLOSE: /* remote close */
8568 +                               TRACE("%s", "(error)");
8569 +                               connection_set_state(srv, con, CON_STATE_ERROR);
8570 +                               break;
8571 +                       case NETWORK_STATUS_WAIT_FOR_EVENT:
8572 +                               fdevent_event_add(srv->ev, con->sock, FDEVENT_OUT);
8573 +
8574 +                               return HANDLER_WAIT_FOR_EVENT;
8575 +                       case NETWORK_STATUS_INTERRUPTED:
8576                                 break;
8577                         }
8578 -                       
8579 -                       connection_set_state(srv, con, CON_STATE_WRITE);
8580 +
8581 +
8582                         break;
8583                 case CON_STATE_RESPONSE_END: /* transient */
8584                         /* log the request */
8585 -                       
8586 +
8587                         if (srv->srvconf.log_state_handling) {
8588 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
8589 -                                               "state for fd", con->fd, connection_get_state(con->state));
8590 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
8591 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
8592                         }
8593 -                       
8594 -                       plugins_call_handle_request_done(srv, con);
8595 -                       
8596 +
8597 +                       plugins_call_handle_response_done(srv, con);
8598 +
8599                         srv->con_written++;
8600 -                       
8601 +
8602                         if (con->keep_alive) {
8603                                 connection_set_state(srv, con, CON_STATE_REQUEST_START);
8604 -                               
8605 -#if 0                                  
8606 +
8607 +#if 0
8608                                 con->request_start = srv->cur_ts;
8609                                 con->read_idle_ts = srv->cur_ts;
8610  #endif
8611 @@ -1482,150 +1398,83 @@
8612                                         log_error_write(srv, __FILE__, __LINE__, "sd", "unhandling return value", r);
8613                                         break;
8614                                 }
8615 -                               
8616 -#ifdef USE_OPENSSL
8617 -                               if (srv_sock->is_ssl) {
8618 -                                       switch (SSL_shutdown(con->ssl)) {
8619 -                                       case 1:
8620 -                                               /* done */
8621 -                                               break;
8622 -                                       case 0:
8623 -                                               /* wait for fd-event 
8624 -                                                * 
8625 -                                                * FIXME: wait for fdevent and call SSL_shutdown again
8626 -                                                * 
8627 -                                                */
8628 -                                               
8629 -                                               break;
8630 -                                       default:
8631 -                                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", 
8632 -                                                               ERR_error_string(ERR_get_error(), NULL));
8633 -                                       }
8634 -                               }
8635 -#endif
8636 +
8637                                 connection_close(srv, con);
8638 -                               
8639 +
8640                                 srv->con_closed++;
8641                         }
8642 -                       
8643 +
8644                         connection_reset(srv, con);
8645 -                       
8646 -                       break;
8647 -               case CON_STATE_CONNECT:
8648 -                       if (srv->srvconf.log_state_handling) {
8649 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
8650 -                                               "state for fd", con->fd, connection_get_state(con->state));
8651 -                       }
8652 -                       
8653 -                       chunkqueue_reset(con->read_queue);
8654 -                       
8655 -                       con->request_count = 0;
8656 -                       
8657 +
8658                         break;
8659                 case CON_STATE_CLOSE:
8660                         if (srv->srvconf.log_state_handling) {
8661 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
8662 -                                               "state for fd", con->fd, connection_get_state(con->state));
8663 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
8664 +                                               "state for fd", con->sock->fd, connection_get_state(con->state));
8665                         }
8666 -                       
8667 +
8668                         if (con->keep_alive) {
8669 -                               if (ioctl(con->fd, FIONREAD, &b)) {
8670 +                               if (ioctl(con->sock->fd, FIONREAD, &b)) {
8671                                         log_error_write(srv, __FILE__, __LINE__, "ss",
8672                                                         "ioctl() failed", strerror(errno));
8673                                 }
8674                                 if (b > 0) {
8675                                         char buf[1024];
8676                                         log_error_write(srv, __FILE__, __LINE__, "sdd",
8677 -                                                       "CLOSE-read()", con->fd, b);
8678 -                                       
8679 +                                                       "CLOSE-read()", con->sock->fd, b);
8680 +
8681                                         /* */
8682 -                                       read(con->fd, buf, sizeof(buf));
8683 +                                       read(con->sock->fd, buf, sizeof(buf));
8684                                 } else {
8685                                         /* nothing to read */
8686 -                                       
8687 +
8688                                         con->close_timeout_ts = 0;
8689                                 }
8690                         } else {
8691                                 con->close_timeout_ts = 0;
8692                         }
8693 -                       
8694 +
8695                         if (srv->cur_ts - con->close_timeout_ts > 1) {
8696                                 connection_close(srv, con);
8697 -                               
8698 +
8699                                 if (srv->srvconf.log_state_handling) {
8700 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
8701 -                                                       "connection closed for fd", con->fd);
8702 -                               }
8703 -                       }
8704 -                       
8705 -                       break;
8706 -               case CON_STATE_READ_POST:
8707 -               case CON_STATE_READ:
8708 -                       if (srv->srvconf.log_state_handling) {
8709 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
8710 -                                               "state for fd", con->fd, connection_get_state(con->state));
8711 -                       }
8712 -                       
8713 -                       connection_handle_read_state(srv, con);
8714 -                       break;
8715 -               case CON_STATE_WRITE:
8716 -                       if (srv->srvconf.log_state_handling) {
8717 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
8718 -                                               "state for fd", con->fd, connection_get_state(con->state));
8719 -                       }
8720 -                       
8721 -                       /* only try to write if we have something in the queue */
8722 -                       if (!chunkqueue_is_empty(con->write_queue)) {
8723 -#if 0
8724 -                               log_error_write(srv, __FILE__, __LINE__, "dsd",
8725 -                                               con->fd,
8726 -                                               "packets to write:",
8727 -                                               con->write_queue->used);
8728 -#endif
8729 -                       }
8730 -                       if (!chunkqueue_is_empty(con->write_queue) && con->is_writable) {
8731 -                               if (-1 == connection_handle_write(srv, con)) {
8732 -                                       log_error_write(srv, __FILE__, __LINE__, "ds",
8733 -                                                       con->fd,
8734 -                                                       "handle write failed.");
8735 -                                       connection_set_state(srv, con, CON_STATE_ERROR);
8736 -                               } else if (con->state == CON_STATE_WRITE) {
8737 -                                       con->write_request_ts = srv->cur_ts;
8738 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
8739 +                                                       "connection closed for fd", con->sock->fd);
8740                                 }
8741                         }
8742 -                       
8743 +
8744                         break;
8745                 case CON_STATE_ERROR: /* transient */
8746 -                       
8747 +
8748                         /* even if the connection was drop we still have to write it to the access log */
8749                         if (con->http_status) {
8750 -                               plugins_call_handle_request_done(srv, con);
8751 +                               plugins_call_handle_response_done(srv, con);
8752                         }
8753  #ifdef USE_OPENSSL
8754                         if (srv_sock->is_ssl) {
8755                                 int ret;
8756 -                               switch ((ret = SSL_shutdown(con->ssl))) {
8757 +                               switch ((ret = SSL_shutdown(con->sock->ssl))) {
8758                                 case 1:
8759                                         /* ok */
8760                                         break;
8761                                 case 0:
8762 -                                       SSL_shutdown(con->ssl);
8763 +                                       SSL_shutdown(con->sock->ssl);
8764                                         break;
8765                                 default:
8766 -                                       log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:", 
8767 -                                                       SSL_get_error(con->ssl, ret), 
8768 +                                       log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
8769 +                                                       SSL_get_error(con->sock->ssl, ret),
8770                                                         ERR_error_string(ERR_get_error(), NULL));
8771                                         return -1;
8772                                 }
8773                         }
8774  #endif
8775 -                       
8776 +
8777                         switch(con->mode) {
8778                         case DIRECT:
8779  #if 0
8780 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
8781 -                                               "emergency exit: direct", 
8782 -                                               con->fd);
8783 +                               log_error_write(srv, __FILE__, __LINE__, "sd",
8784 +                                               "emergency exit: direct",
8785 +                                               con->sock->fd);
8786  #endif
8787                                 break;
8788                         default:
8789 @@ -1639,35 +1488,35 @@
8790                                 }
8791                                 break;
8792                         }
8793 -                       
8794 +
8795                         connection_reset(srv, con);
8796 -                       
8797 +
8798                         /* close the connection */
8799                         if ((con->keep_alive == 1) &&
8800 -                           (0 == shutdown(con->fd, SHUT_WR))) {
8801 +                           (0 == shutdown(con->sock->fd, SHUT_WR))) {
8802                                 con->close_timeout_ts = srv->cur_ts;
8803                                 connection_set_state(srv, con, CON_STATE_CLOSE);
8804 -                               
8805 +
8806                                 if (srv->srvconf.log_state_handling) {
8807 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
8808 -                                                       "shutdown for fd", con->fd);
8809 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
8810 +                                                       "shutdown for fd", con->sock->fd);
8811                                 }
8812                         } else {
8813                                 connection_close(srv, con);
8814                         }
8815 -                       
8816 +
8817                         con->keep_alive = 0;
8818 -                       
8819 +
8820                         srv->con_closed++;
8821 -                       
8822 +
8823                         break;
8824                 default:
8825 -                       log_error_write(srv, __FILE__, __LINE__, "sdd", 
8826 -                                       "unknown state:", con->fd, con->state);
8827 -                       
8828 +                       log_error_write(srv, __FILE__, __LINE__, "sdd",
8829 +                                       "unknown state:", con->sock->fd, con->state);
8830 +
8831                         break;
8832                 }
8833 -               
8834 +
8835                 if (done == -1) {
8836                         done = 0;
8837                 } else if (ostate == con->state) {
8838 @@ -1676,35 +1525,11 @@
8839         }
8840  
8841         if (srv->srvconf.log_state_handling) {
8842 -               log_error_write(srv, __FILE__, __LINE__, "sds", 
8843 -                               "state at exit:", 
8844 -                               con->fd,
8845 +               log_error_write(srv, __FILE__, __LINE__, "sds",
8846 +                               "state at exit:",
8847 +                               con->sock->fd,
8848                                 connection_get_state(con->state));
8849         }
8850 -       
8851 -       switch(con->state) {
8852 -       case CON_STATE_READ_POST:
8853 -       case CON_STATE_READ:
8854 -       case CON_STATE_CLOSE:
8855 -               fdevent_event_add(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_IN);
8856 -               break;
8857 -       case CON_STATE_WRITE:
8858 -               /* request write-fdevent only if we really need it 
8859 -                * - if we have data to write
8860 -                * - if the socket is not writable yet 
8861 -                */
8862 -               if (!chunkqueue_is_empty(con->write_queue) && 
8863 -                   (con->is_writable == 0) &&
8864 -                   (con->traffic_limit_reached == 0)) {
8865 -                       fdevent_event_add(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_OUT);
8866 -               } else {
8867 -                       fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
8868 -               }
8869 -               break;
8870 -       default:
8871 -               fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
8872 -               break;
8873 -       }
8874  
8875         return 0;
8876  }
8877 --- ../lighttpd-1.4.11/src/crc32.h      2005-09-30 20:18:59.000000000 +0300
8878 +++ lighttpd-1.5.0/src/crc32.h  2006-07-16 00:26:04.000000000 +0300
8879 @@ -6,6 +6,7 @@
8880  #endif
8881  
8882  #include <sys/types.h>
8883 +#include <stdlib.h>
8884  
8885  #if defined HAVE_STDINT_H
8886  #include <stdint.h>
8887 @@ -13,6 +14,10 @@
8888  #include <inttypes.h>
8889  #endif
8890  
8891 +#ifdef _WIN32
8892 +#define uint32_t unsigned __int32
8893 +#endif
8894 +
8895  uint32_t generate_crc32c(char *string, size_t length);
8896  
8897  #endif
8898 --- ../lighttpd-1.4.11/src/data_array.c 2005-08-23 17:36:12.000000000 +0300
8899 +++ lighttpd-1.5.0/src/data_array.c     2006-07-16 00:26:04.000000000 +0300
8900 @@ -17,16 +17,16 @@
8901  
8902  static void data_array_free(data_unset *d) {
8903         data_array *ds = (data_array *)d;
8904 -       
8905 +
8906         buffer_free(ds->key);
8907         array_free(ds->value);
8908 -       
8909 +
8910         free(d);
8911  }
8912  
8913  static void data_array_reset(data_unset *d) {
8914         data_array *ds = (data_array *)d;
8915 -       
8916 +
8917         /* reused array elements */
8918         buffer_reset(ds->key);
8919         array_reset(ds->value);
8920 @@ -36,7 +36,7 @@
8921         UNUSED(dst);
8922  
8923         src->free(src);
8924 -       
8925 +
8926         return 0;
8927  }
8928  
8929 @@ -48,18 +48,18 @@
8930  
8931  data_array *data_array_init(void) {
8932         data_array *ds;
8933 -       
8934 +
8935         ds = calloc(1, sizeof(*ds));
8936 -       
8937 +
8938         ds->key = buffer_init();
8939         ds->value = array_init();
8940 -       
8941 +
8942         ds->copy = data_array_copy;
8943         ds->free = data_array_free;
8944         ds->reset = data_array_reset;
8945         ds->insert_dup = data_array_insert_dup;
8946         ds->print = data_array_print;
8947         ds->type = TYPE_ARRAY;
8948 -       
8949 +
8950         return ds;
8951  }
8952 --- ../lighttpd-1.4.11/src/data_config.c        2005-08-17 12:53:19.000000000 +0300
8953 +++ lighttpd-1.5.0/src/data_config.c    2006-07-16 00:26:03.000000000 +0300
8954 @@ -17,26 +17,26 @@
8955  
8956  static void data_config_free(data_unset *d) {
8957         data_config *ds = (data_config *)d;
8958 -       
8959 +
8960         buffer_free(ds->key);
8961         buffer_free(ds->op);
8962         buffer_free(ds->comp_key);
8963 -       
8964 +
8965         array_free(ds->value);
8966         array_free(ds->childs);
8967 -       
8968 +
8969         if (ds->string) buffer_free(ds->string);
8970  #ifdef HAVE_PCRE_H
8971         if (ds->regex) pcre_free(ds->regex);
8972         if (ds->regex_study) pcre_free(ds->regex_study);
8973  #endif
8974 -       
8975 +
8976         free(d);
8977  }
8978  
8979  static void data_config_reset(data_unset *d) {
8980         data_config *ds = (data_config *)d;
8981 -       
8982 +
8983         /* reused array elements */
8984         buffer_reset(ds->key);
8985         buffer_reset(ds->comp_key);
8986 @@ -45,9 +45,9 @@
8987  
8988  static int data_config_insert_dup(data_unset *dst, data_unset *src) {
8989         UNUSED(dst);
8990 -       
8991 +
8992         src->free(src);
8993 -       
8994 +
8995         return 0;
8996  }
8997  
8998 @@ -56,7 +56,7 @@
8999         array *a = (array *)ds->value;
9000         size_t i;
9001         size_t maxlen;
9002 -       
9003 +
9004         if (0 == ds->context_ndx) {
9005                 fprintf(stderr, "config {\n");
9006         }
9007 @@ -117,22 +117,22 @@
9008  
9009  data_config *data_config_init(void) {
9010         data_config *ds;
9011 -       
9012 +
9013         ds = calloc(1, sizeof(*ds));
9014 -       
9015 +
9016         ds->key = buffer_init();
9017         ds->op = buffer_init();
9018         ds->comp_key = buffer_init();
9019         ds->value = array_init();
9020         ds->childs = array_init();
9021         ds->childs->is_weakref = 1;
9022 -       
9023 +
9024         ds->copy = data_config_copy;
9025         ds->free = data_config_free;
9026         ds->reset = data_config_reset;
9027         ds->insert_dup = data_config_insert_dup;
9028         ds->print = data_config_print;
9029         ds->type = TYPE_CONFIG;
9030 -       
9031 +
9032         return ds;
9033  }
9034 --- ../lighttpd-1.4.11/src/data_count.c 2005-08-23 17:36:12.000000000 +0300
9035 +++ lighttpd-1.5.0/src/data_count.c     2006-07-16 00:26:03.000000000 +0300
9036 @@ -16,53 +16,53 @@
9037  
9038  static void data_count_free(data_unset *d) {
9039         data_count *ds = (data_count *)d;
9040 -       
9041 +
9042         buffer_free(ds->key);
9043 -       
9044 +
9045         free(d);
9046  }
9047  
9048  static void data_count_reset(data_unset *d) {
9049         data_count *ds = (data_count *)d;
9050 -       
9051 +
9052         buffer_reset(ds->key);
9053 -       
9054 +
9055         ds->count = 0;
9056  }
9057  
9058  static int data_count_insert_dup(data_unset *dst, data_unset *src) {
9059         data_count *ds_dst = (data_count *)dst;
9060         data_count *ds_src = (data_count *)src;
9061 -       
9062 +
9063         ds_dst->count += ds_src->count;
9064 -       
9065 +
9066         src->free(src);
9067 -       
9068 +
9069         return 0;
9070  }
9071  
9072  static void data_count_print(const data_unset *d, int depth) {
9073         data_count *ds = (data_count *)d;
9074         UNUSED(depth);
9075 -       
9076 +
9077         fprintf(stderr, "count(%d)", ds->count);
9078  }
9079  
9080  
9081  data_count *data_count_init(void) {
9082         data_count *ds;
9083 -       
9084 +
9085         ds = calloc(1, sizeof(*ds));
9086 -       
9087 +
9088         ds->key = buffer_init();
9089         ds->count = 1;
9090 -       
9091 +
9092         ds->copy = data_count_copy;
9093         ds->free = data_count_free;
9094         ds->reset = data_count_reset;
9095         ds->insert_dup = data_count_insert_dup;
9096         ds->print = data_count_print;
9097         ds->type = TYPE_COUNT;
9098 -       
9099 +
9100         return ds;
9101  }
9102 --- ../lighttpd-1.4.11/src/data_fastcgi.c       2005-08-23 17:36:12.000000000 +0300
9103 +++ lighttpd-1.5.0/src/data_fastcgi.c   2006-07-16 00:26:04.000000000 +0300
9104 @@ -17,53 +17,53 @@
9105  
9106  static void data_fastcgi_free(data_unset *d) {
9107         data_fastcgi *ds = (data_fastcgi *)d;
9108 -       
9109 +
9110         buffer_free(ds->key);
9111         buffer_free(ds->host);
9112 -       
9113 +
9114         free(d);
9115  }
9116  
9117  static void data_fastcgi_reset(data_unset *d) {
9118         data_fastcgi *ds = (data_fastcgi *)d;
9119 -       
9120 +
9121         buffer_reset(ds->key);
9122         buffer_reset(ds->host);
9123 -       
9124 +
9125  }
9126  
9127  static int data_fastcgi_insert_dup(data_unset *dst, data_unset *src) {
9128         UNUSED(dst);
9129  
9130         src->free(src);
9131 -       
9132 +
9133         return 0;
9134  }
9135  
9136  static void data_fastcgi_print(const data_unset *d, int depth) {
9137         data_fastcgi *ds = (data_fastcgi *)d;
9138         UNUSED(depth);
9139 -       
9140 +
9141         fprintf(stderr, "fastcgi(%s)", ds->host->ptr);
9142  }
9143  
9144  
9145  data_fastcgi *data_fastcgi_init(void) {
9146         data_fastcgi *ds;
9147 -       
9148 +
9149         ds = calloc(1, sizeof(*ds));
9150 -       
9151 +
9152         ds->key = buffer_init();
9153         ds->host = buffer_init();
9154         ds->port = 0;
9155         ds->is_disabled = 0;
9156 -       
9157 +
9158         ds->copy = data_fastcgi_copy;
9159         ds->free = data_fastcgi_free;
9160         ds->reset = data_fastcgi_reset;
9161         ds->insert_dup = data_fastcgi_insert_dup;
9162         ds->print = data_fastcgi_print;
9163         ds->type = TYPE_FASTCGI;
9164 -       
9165 +
9166         return ds;
9167  }
9168 --- ../lighttpd-1.4.11/src/data_integer.c       2005-08-23 17:36:12.000000000 +0300
9169 +++ lighttpd-1.5.0/src/data_integer.c   2006-07-16 00:26:03.000000000 +0300
9170 @@ -16,15 +16,15 @@
9171  
9172  static void data_integer_free(data_unset *d) {
9173         data_integer *ds = (data_integer *)d;
9174 -       
9175 +
9176         buffer_free(ds->key);
9177 -       
9178 +
9179         free(d);
9180  }
9181  
9182  static void data_integer_reset(data_unset *d) {
9183         data_integer *ds = (data_integer *)d;
9184 -       
9185 +
9186         /* reused integer elements */
9187         buffer_reset(ds->key);
9188         ds->value = 0;
9189 @@ -32,9 +32,9 @@
9190  
9191  static int data_integer_insert_dup(data_unset *dst, data_unset *src) {
9192         UNUSED(dst);
9193 -       
9194 +
9195         src->free(src);
9196 -       
9197 +
9198         return 0;
9199  }
9200  
9201 @@ -48,18 +48,18 @@
9202  
9203  data_integer *data_integer_init(void) {
9204         data_integer *ds;
9205 -       
9206 +
9207         ds = calloc(1, sizeof(*ds));
9208 -       
9209 +
9210         ds->key = buffer_init();
9211         ds->value = 0;
9212 -       
9213 +
9214         ds->copy = data_integer_copy;
9215         ds->free = data_integer_free;
9216         ds->reset = data_integer_reset;
9217         ds->insert_dup = data_integer_insert_dup;
9218         ds->print = data_integer_print;
9219         ds->type = TYPE_INTEGER;
9220 -       
9221 +
9222         return ds;
9223  }
9224 --- ../lighttpd-1.4.11/src/data_string.c        2005-08-23 17:36:12.000000000 +0300
9225 +++ lighttpd-1.5.0/src/data_string.c    2006-07-16 00:26:04.000000000 +0300
9226 @@ -17,16 +17,16 @@
9227  
9228  static void data_string_free(data_unset *d) {
9229         data_string *ds = (data_string *)d;
9230 -       
9231 +
9232         buffer_free(ds->key);
9233         buffer_free(ds->value);
9234 -       
9235 +
9236         free(d);
9237  }
9238  
9239  static void data_string_reset(data_unset *d) {
9240         data_string *ds = (data_string *)d;
9241 -       
9242 +
9243         /* reused array elements */
9244         buffer_reset(ds->key);
9245         buffer_reset(ds->value);
9246 @@ -35,23 +35,23 @@
9247  static int data_string_insert_dup(data_unset *dst, data_unset *src) {
9248         data_string *ds_dst = (data_string *)dst;
9249         data_string *ds_src = (data_string *)src;
9250 -       
9251 +
9252         if (ds_dst->value->used) {
9253                 buffer_append_string(ds_dst->value, ", ");
9254                 buffer_append_string_buffer(ds_dst->value, ds_src->value);
9255         } else {
9256                 buffer_copy_string_buffer(ds_dst->value, ds_src->value);
9257         }
9258 -       
9259 +
9260         src->free(src);
9261 -       
9262 +
9263         return 0;
9264  }
9265  
9266  static int data_response_insert_dup(data_unset *dst, data_unset *src) {
9267         data_string *ds_dst = (data_string *)dst;
9268         data_string *ds_src = (data_string *)src;
9269 -       
9270 +
9271         if (ds_dst->value->used) {
9272                 buffer_append_string(ds_dst->value, "\r\n");
9273                 buffer_append_string_buffer(ds_dst->value, ds_dst->key);
9274 @@ -60,9 +60,9 @@
9275         } else {
9276                 buffer_copy_string_buffer(ds_dst->value, ds_src->value);
9277         }
9278 -       
9279 +
9280         src->free(src);
9281 -       
9282 +
9283         return 0;
9284  }
9285  
9286 @@ -77,28 +77,28 @@
9287  
9288  data_string *data_string_init(void) {
9289         data_string *ds;
9290 -       
9291 +
9292         ds = calloc(1, sizeof(*ds));
9293         assert(ds);
9294 -       
9295 +
9296         ds->key = buffer_init();
9297         ds->value = buffer_init();
9298 -       
9299 +
9300         ds->copy = data_string_copy;
9301         ds->free = data_string_free;
9302         ds->reset = data_string_reset;
9303         ds->insert_dup = data_string_insert_dup;
9304         ds->print = data_string_print;
9305         ds->type = TYPE_STRING;
9306 -       
9307 +
9308         return ds;
9309  }
9310  
9311  data_string *data_response_init(void) {
9312         data_string *ds;
9313 -       
9314 +
9315         ds = data_string_init();
9316         ds->insert_dup = data_response_insert_dup;
9317 -       
9318 +
9319         return ds;
9320  }
9321 --- ../lighttpd-1.4.11/src/etag.c       2005-08-11 01:26:40.000000000 +0300
9322 +++ lighttpd-1.5.0/src/etag.c   2006-07-18 13:03:40.000000000 +0300
9323 @@ -4,7 +4,7 @@
9324  #include "etag.h"
9325  
9326  int etag_is_equal(buffer *etag, const char *matches) {
9327 -       if (0 == strcmp(etag->ptr, matches)) return 1;
9328 +       if (buffer_is_equal_string(etag, matches, strlen(matches))) return 1;
9329         return 0;
9330  }
9331  
9332 @@ -14,19 +14,19 @@
9333         buffer_append_off_t(etag, st->st_size);
9334         buffer_append_string_len(etag, CONST_STR_LEN("-"));
9335         buffer_append_long(etag, st->st_mtime);
9336 -       
9337 +
9338         return 0;
9339  }
9340  
9341  int etag_mutate(buffer *mut, buffer *etag) {
9342         size_t h, i;
9343 -       
9344 +
9345         for (h=0, i=0; i < etag->used; ++i) h = (h<<5)^(h>>27)^(etag->ptr[i]);
9346 -       
9347 +
9348         buffer_reset(mut);
9349         buffer_copy_string_len(mut, CONST_STR_LEN("\""));
9350         buffer_append_long(mut, h);
9351         buffer_append_string_len(mut, CONST_STR_LEN("\""));
9352 -       
9353 +
9354         return 0;
9355  }
9356 --- ../lighttpd-1.4.11/src/etag.h       2005-08-11 01:26:40.000000000 +0300
9357 +++ lighttpd-1.5.0/src/etag.h   2006-07-16 00:26:03.000000000 +0300
9358 @@ -3,13 +3,12 @@
9359  
9360  #include <sys/types.h>
9361  #include <sys/stat.h>
9362 -#include <unistd.h>
9363  
9364  #include "buffer.h"
9365  
9366  int etag_is_equal(buffer *etag, const char *matches);
9367  int etag_create(buffer *etag, struct stat *st);
9368  int etag_mutate(buffer *mut, buffer *etag);
9369 -       
9370 +
9371  
9372  #endif
9373 --- ../lighttpd-1.4.11/src/fastcgi.h    2005-08-11 01:26:40.000000000 +0300
9374 +++ lighttpd-1.5.0/src/fastcgi.h        2006-07-16 00:26:03.000000000 +0300
9375 @@ -1,4 +1,4 @@
9376 -/* 
9377 +/*
9378   * fastcgi.h --
9379   *
9380   *     Defines for the FastCGI protocol.
9381 @@ -123,7 +123,7 @@
9382  
9383  
9384  typedef struct {
9385 -    unsigned char type;    
9386 +    unsigned char type;
9387      unsigned char reserved[7];
9388  } FCGI_UnknownTypeBody;
9389  
9390 --- ../lighttpd-1.4.11/src/fdevent.c    2005-11-15 10:51:05.000000000 +0200
9391 +++ lighttpd-1.5.0/src/fdevent.c        2006-07-18 13:03:40.000000000 +0300
9392 @@ -2,7 +2,6 @@
9393  
9394  #include "settings.h"
9395  
9396 -#include <unistd.h>
9397  #include <stdlib.h>
9398  #include <string.h>
9399  #include <errno.h>
9400 @@ -11,60 +10,116 @@
9401  
9402  #include "fdevent.h"
9403  #include "buffer.h"
9404 +#include "log.h"
9405 +
9406 +#include "sys-socket.h"
9407 +
9408 +fdevent_revent *fdevent_revent_init(void) {
9409 +       STRUCT_INIT(fdevent_revent, revent);
9410 +
9411 +       return revent;
9412 +}
9413 +
9414 +void fdevent_revent_free(fdevent_revent *revent) {
9415 +       if (!revent) return;
9416 +
9417 +       free(revent);
9418 +}
9419 +
9420 +fdevent_revents *fdevent_revents_init(void) {
9421 +       STRUCT_INIT(fdevent_revents, revents);
9422 +
9423 +       return revents;
9424 +}
9425 +
9426 +void fdevent_revents_reset(fdevent_revents *revents) {
9427 +       if (!revents) return;
9428 +
9429 +       revents->used = 0;
9430 +}
9431 +
9432 +void fdevent_revents_add(fdevent_revents *revents, int fd, int events) {
9433 +       fdevent_revent *revent;
9434 +
9435 +       if (revents->used == revents->size) {
9436 +               /* resize the events-array */
9437 +               revents->ptr = realloc(revents->ptr, (revents->size + 1) * sizeof(*(revents->ptr)));
9438 +               revents->ptr[revents->size++] = fdevent_revent_init();
9439 +       }
9440 +
9441 +       revent = revents->ptr[revents->used++];
9442 +       revent->fd = fd;
9443 +       revent->revents = events;
9444 +}
9445 +
9446 +void fdevent_revents_free(fdevent_revents *revents) {
9447 +       size_t i;
9448 +       
9449 +       if (!revents) return;
9450 +
9451 +       if (revents->size) {
9452 +               for (i = 0; i < revents->size; i++) {
9453 +                       fdevent_revent_free(revents->ptr[i]);
9454 +               }
9455 +
9456 +               free(revents->ptr);
9457 +       }
9458 +       free(revents);
9459 +}
9460  
9461  fdevents *fdevent_init(size_t maxfds, fdevent_handler_t type) {
9462         fdevents *ev;
9463 -       
9464 +
9465         ev = calloc(1, sizeof(*ev));
9466         ev->fdarray = calloc(maxfds, sizeof(*ev->fdarray));
9467         ev->maxfds = maxfds;
9468 -       
9469 +
9470         switch(type) {
9471         case FDEVENT_HANDLER_POLL:
9472                 if (0 != fdevent_poll_init(ev)) {
9473 -                       fprintf(stderr, "%s.%d: event-handler poll failed\n", 
9474 +                       fprintf(stderr, "%s.%d: event-handler poll failed\n",
9475                                 __FILE__, __LINE__);
9476 -                       
9477 +
9478                         return NULL;
9479                 }
9480                 break;
9481         case FDEVENT_HANDLER_SELECT:
9482                 if (0 != fdevent_select_init(ev)) {
9483 -                       fprintf(stderr, "%s.%d: event-handler select failed\n", 
9484 +                       fprintf(stderr, "%s.%d: event-handler select failed\n",
9485                                 __FILE__, __LINE__);
9486                         return NULL;
9487                 }
9488                 break;
9489         case FDEVENT_HANDLER_LINUX_RTSIG:
9490                 if (0 != fdevent_linux_rtsig_init(ev)) {
9491 -                       fprintf(stderr, "%s.%d: event-handler linux-rtsig failed, try to set server.event-handler = \"poll\" or \"select\"\n", 
9492 +                       fprintf(stderr, "%s.%d: event-handler linux-rtsig failed, try to set server.event-handler = \"poll\" or \"select\"\n",
9493                                 __FILE__, __LINE__);
9494                         return NULL;
9495                 }
9496                 break;
9497         case FDEVENT_HANDLER_LINUX_SYSEPOLL:
9498                 if (0 != fdevent_linux_sysepoll_init(ev)) {
9499 -                       fprintf(stderr, "%s.%d: event-handler linux-sysepoll failed, try to set server.event-handler = \"poll\" or \"select\"\n", 
9500 +                       fprintf(stderr, "%s.%d: event-handler linux-sysepoll failed, try to set server.event-handler = \"poll\" or \"select\"\n",
9501                                 __FILE__, __LINE__);
9502                         return NULL;
9503                 }
9504                 break;
9505         case FDEVENT_HANDLER_SOLARIS_DEVPOLL:
9506                 if (0 != fdevent_solaris_devpoll_init(ev)) {
9507 -                       fprintf(stderr, "%s.%d: event-handler solaris-devpoll failed, try to set server.event-handler = \"poll\" or \"select\"\n", 
9508 +                       fprintf(stderr, "%s.%d: event-handler solaris-devpoll failed, try to set server.event-handler = \"poll\" or \"select\"\n",
9509                                 __FILE__, __LINE__);
9510                         return NULL;
9511                 }
9512                 break;
9513         case FDEVENT_HANDLER_FREEBSD_KQUEUE:
9514                 if (0 != fdevent_freebsd_kqueue_init(ev)) {
9515 -                       fprintf(stderr, "%s.%d: event-handler freebsd-kqueue failed, try to set server.event-handler = \"poll\" or \"select\"\n", 
9516 +                       fprintf(stderr, "%s.%d: event-handler freebsd-kqueue failed, try to set server.event-handler = \"poll\" or \"select\"\n",
9517                                 __FILE__, __LINE__);
9518                         return NULL;
9519                 }
9520                 break;
9521         default:
9522 -               fprintf(stderr, "%s.%d: event-handler is unknown, try to set server.event-handler = \"poll\" or \"select\"\n", 
9523 +               fprintf(stderr, "%s.%d: event-handler is unknown, try to set server.event-handler = \"poll\" or \"select\"\n",
9524                         __FILE__, __LINE__);
9525                 return NULL;
9526         }
9527 @@ -75,28 +130,29 @@
9528  void fdevent_free(fdevents *ev) {
9529         size_t i;
9530         if (!ev) return;
9531 -       
9532 +
9533         if (ev->free) ev->free(ev);
9534 -       
9535 +
9536         for (i = 0; i < ev->maxfds; i++) {
9537                 if (ev->fdarray[i]) free(ev->fdarray[i]);
9538         }
9539 -       
9540 +
9541         free(ev->fdarray);
9542         free(ev);
9543  }
9544  
9545  int fdevent_reset(fdevents *ev) {
9546         if (ev->reset) return ev->reset(ev);
9547 -       
9548 +
9549         return 0;
9550  }
9551  
9552  fdnode *fdnode_init() {
9553         fdnode *fdn;
9554 -       
9555 +
9556         fdn = calloc(1, sizeof(*fdn));
9557         fdn->fd = -1;
9558 +
9559         return fdn;
9560  }
9561  
9562 @@ -104,48 +160,40 @@
9563         free(fdn);
9564  }
9565  
9566 -int fdevent_register(fdevents *ev, int fd, fdevent_handler handler, void *ctx) {
9567 +int fdevent_register(fdevents *ev, iosocket *sock, fdevent_handler handler, void *ctx) {
9568         fdnode *fdn;
9569 -       
9570 +
9571         fdn = fdnode_init();
9572         fdn->handler = handler;
9573 -       fdn->fd      = fd;
9574 +       fdn->fd      = sock->fd;
9575         fdn->ctx     = ctx;
9576 -       
9577 -       ev->fdarray[fd] = fdn;
9578 +
9579 +       ev->fdarray[sock->fd] = fdn;
9580  
9581         return 0;
9582  }
9583  
9584 -int fdevent_unregister(fdevents *ev, int fd) {
9585 +int fdevent_unregister(fdevents *ev, iosocket *sock) {
9586         fdnode *fdn;
9587          if (!ev) return 0;
9588 -       fdn = ev->fdarray[fd];
9589 -       
9590 +       fdn = ev->fdarray[sock->fd];
9591 +
9592         fdnode_free(fdn);
9593 -       
9594 -       ev->fdarray[fd] = NULL;
9595 -       
9596 +
9597 +       ev->fdarray[sock->fd] = NULL;
9598 +
9599         return 0;
9600  }
9601  
9602 -int fdevent_event_del(fdevents *ev, int *fde_ndx, int fd) {
9603 -       int fde = fde_ndx ? *fde_ndx : -1;
9604 -       
9605 -       if (ev->event_del) fde = ev->event_del(ev, fde, fd);
9606 -       
9607 -       if (fde_ndx) *fde_ndx = fde;
9608 -       
9609 +int fdevent_event_del(fdevents *ev, iosocket *sock) {
9610 +       if (ev->event_del) ev->event_del(ev, sock);
9611 +
9612         return 0;
9613  }
9614  
9615 -int fdevent_event_add(fdevents *ev, int *fde_ndx, int fd, int events) {
9616 -       int fde = fde_ndx ? *fde_ndx : -1;
9617 -       
9618 -       if (ev->event_add) fde = ev->event_add(ev, fde, fd, events);
9619 -       
9620 -       if (fde_ndx) *fde_ndx = fde;
9621 -       
9622 +int fdevent_event_add(fdevents *ev, iosocket *sock, int events) {
9623 +       if (ev->event_add) ev->event_add(ev, sock, events);
9624 +
9625         return 0;
9626  }
9627  
9628 @@ -154,49 +202,41 @@
9629         return ev->poll(ev, timeout_ms);
9630  }
9631  
9632 -int fdevent_event_get_revent(fdevents *ev, size_t ndx) {
9633 -       if (ev->event_get_revent == NULL) SEGFAULT();
9634 -       
9635 -       return ev->event_get_revent(ev, ndx);
9636 -}
9637 +int fdevent_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
9638 +       size_t i;
9639  
9640 -int fdevent_event_get_fd(fdevents *ev, size_t ndx) {
9641 -       if (ev->event_get_fd == NULL) SEGFAULT();
9642 -       
9643 -       return ev->event_get_fd(ev, ndx);
9644 -}
9645 +       if (ev->get_revents == NULL) SEGFAULT();
9646  
9647 -fdevent_handler fdevent_get_handler(fdevents *ev, int fd) {
9648 -       if (ev->fdarray[fd] == NULL) SEGFAULT();
9649 -       if (ev->fdarray[fd]->fd != fd) SEGFAULT();
9650 -       
9651 -       return ev->fdarray[fd]->handler;
9652 -}
9653 +       fdevent_revents_reset(revents);
9654  
9655 -void * fdevent_get_context(fdevents *ev, int fd) {
9656 -       if (ev->fdarray[fd] == NULL) SEGFAULT();
9657 -       if (ev->fdarray[fd]->fd != fd) SEGFAULT();
9658 -       
9659 -       return ev->fdarray[fd]->ctx;
9660 +       ev->get_revents(ev, event_count, revents);
9661 +
9662 +       /* patch the event handlers */
9663 +       for (i = 0; i < event_count; i++) {
9664 +               fdevent_revent *r = revents->ptr[i];
9665 +
9666 +               r->handler = ev->fdarray[r->fd]->handler;
9667 +               r->context = ev->fdarray[r->fd]->ctx;
9668 +       }
9669 +
9670 +       return 0;
9671  }
9672  
9673 -int fdevent_fcntl_set(fdevents *ev, int fd) {
9674 +int fdevent_fcntl_set(fdevents *ev, iosocket *sock) {
9675 +#ifdef _WIN32
9676 +       int i = 1;
9677 +#endif
9678  #ifdef FD_CLOEXEC
9679         /* close fd on exec (cgi) */
9680 -       fcntl(fd, F_SETFD, FD_CLOEXEC);
9681 +       fcntl(sock->fd, F_SETFD, FD_CLOEXEC);
9682  #endif
9683 -       if ((ev) && (ev->fcntl_set)) return ev->fcntl_set(ev, fd);
9684 -#ifdef O_NONBLOCK      
9685 -       return fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR);
9686 +       if ((ev) && (ev->fcntl_set)) return ev->fcntl_set(ev, sock->fd);
9687 +#ifdef O_NONBLOCK
9688 +       return fcntl(sock->fd, F_SETFL, O_NONBLOCK | O_RDWR);
9689 +#elif defined _WIN32
9690 +       return ioctlsocket(sock->fd, FIONBIO, &i);
9691  #else
9692         return 0;
9693  #endif
9694  }
9695  
9696 -
9697 -int fdevent_event_next_fdndx(fdevents *ev, int ndx) {
9698 -       if (ev->event_next_fdndx) return ev->event_next_fdndx(ev, ndx);
9699 -       
9700 -       return -1;
9701 -}
9702 -
9703 --- ../lighttpd-1.4.11/src/fdevent.h    2005-09-27 11:26:33.000000000 +0300
9704 +++ lighttpd-1.5.0/src/fdevent.h        2006-07-18 13:03:40.000000000 +0300
9705 @@ -7,6 +7,9 @@
9706  #include "settings.h"
9707  #include "bitset.h"
9708  
9709 +#include "iosocket.h"
9710 +#include "array-static.h"
9711 +
9712  /* select event-system */
9713  
9714  #if defined(HAVE_EPOLL_CTL) && defined(HAVE_SYS_EPOLL_H)
9715 @@ -17,13 +20,13 @@
9716  # include <sys/epoll.h>
9717  #endif
9718  
9719 -/* MacOS 10.3.x has poll.h under /usr/include/, all other unixes 
9720 +/* MacOS 10.3.x has poll.h under /usr/include/, all other unixes
9721   * under /usr/include/sys/ */
9722  #if defined HAVE_POLL && (defined(HAVE_SYS_POLL_H) || defined(HAVE_POLL_H))
9723  # define USE_POLL
9724  # ifdef HAVE_POLL_H
9725  #  include <poll.h>
9726 -# else 
9727 +# else
9728  #  include <sys/poll.h>
9729  # endif
9730  # if defined HAVE_SIGTIMEDWAIT && defined(__linux__)
9731 @@ -31,9 +34,11 @@
9732  #  include <signal.h>
9733  # endif
9734  #endif
9735 -
9736 +#ifdef _WIN32
9737 +# define HAVE_SELECT
9738 +#endif
9739  #if defined HAVE_SELECT
9740 -# ifdef __WIN32
9741 +# ifdef _WIN32
9742  #  include <winsock2.h>
9743  # endif
9744  # define USE_SELECT
9745 @@ -67,14 +72,14 @@
9746  #define FDEVENT_HUP    BV(4)
9747  #define FDEVENT_NVAL   BV(5)
9748  
9749 -typedef enum { FD_EVENT_TYPE_UNSET = -1, 
9750 -               FD_EVENT_TYPE_CONNECTION, 
9751 -               FD_EVENT_TYPE_FCGI_CONNECTION, 
9752 -               FD_EVENT_TYPE_DIRWATCH, 
9753 -               FD_EVENT_TYPE_CGI_CONNECTION 
9754 +typedef enum { FD_EVENT_TYPE_UNSET = -1,
9755 +               FD_EVENT_TYPE_CONNECTION,
9756 +               FD_EVENT_TYPE_FCGI_CONNECTION,
9757 +               FD_EVENT_TYPE_DIRWATCH,
9758 +               FD_EVENT_TYPE_CGI_CONNECTION
9759  } fd_event_t;
9760  
9761 -typedef enum { FDEVENT_HANDLER_UNSET, 
9762 +typedef enum { FDEVENT_HANDLER_UNSET,
9763                 FDEVENT_HANDLER_SELECT,
9764                 FDEVENT_HANDLER_POLL,
9765                 FDEVENT_HANDLER_LINUX_RTSIG,
9766 @@ -86,7 +91,7 @@
9767  
9768  /**
9769   * a mapping from fd to connection structure
9770 - * 
9771 + *
9772   */
9773  typedef struct {
9774         int fd;                  /**< the fd */
9775 @@ -96,43 +101,51 @@
9776         int revents;
9777  } fd_conn;
9778  
9779 +ARRAY_STATIC_DEF(fd_conn_buffer, fd_conn, );
9780 +
9781 +/**
9782 + * revents
9783 + */
9784  typedef struct {
9785 -       fd_conn *ptr;
9786 -       
9787 -       size_t size;
9788 -       size_t used;
9789 -} fd_conn_buffer;
9790 +       int fd;
9791 +       int revents;
9792 +
9793 +       fdevent_handler handler;
9794 +       void *context;
9795 +} fdevent_revent;
9796 +
9797 +ARRAY_STATIC_DEF(fdevent_revents, fdevent_revent, );
9798  
9799  /**
9800   * array of unused fd's
9801 - * 
9802 + *
9803   */
9804  
9805  typedef struct _fdnode {
9806 -       fdevent_handler handler;
9807 -       void *ctx;
9808 -       int fd;
9809 -       
9810 +       fdevent_handler handler; /* who handles the events for this fd */
9811 +       void *ctx;               /* opaque pointer which is passed as 3rd parameter to the handler */
9812 +       int fd;                  /* fd */
9813 +
9814         struct _fdnode *prev, *next;
9815  } fdnode;
9816  
9817  typedef struct {
9818         int *ptr;
9819 -       
9820 +
9821         size_t used;
9822         size_t size;
9823  } buffer_int;
9824  
9825  /**
9826   * fd-event handler for select(), poll() and rt-signals on Linux 2.4
9827 - * 
9828 + *
9829   */
9830  typedef struct fdevents {
9831         fdevent_handler_t type;
9832 -       
9833 -       fdnode **fdarray;
9834 +
9835 +       fdnode **fdarray; /* a list of fdnodes */
9836         size_t maxfds;
9837 -       
9838 +
9839  #ifdef USE_LINUX_SIGIO
9840         int in_sigio;
9841         int signum;
9842 @@ -146,21 +159,21 @@
9843  #endif
9844  #ifdef USE_POLL
9845         struct pollfd *pollfds;
9846 -       
9847 +
9848         size_t size;
9849         size_t used;
9850 -       
9851 +
9852         buffer_int unused;
9853  #endif
9854  #ifdef USE_SELECT
9855         fd_set select_read;
9856         fd_set select_write;
9857         fd_set select_error;
9858 -       
9859 +
9860         fd_set select_set_read;
9861         fd_set select_set_write;
9862         fd_set select_set_error;
9863 -       
9864 +
9865         int select_max_fd;
9866  #endif
9867  #ifdef USE_SOLARIS_DEVPOLL
9868 @@ -177,16 +190,13 @@
9869  #endif
9870         int (*reset)(struct fdevents *ev);
9871         void (*free)(struct fdevents *ev);
9872 -       
9873 -       int (*event_add)(struct fdevents *ev, int fde_ndx, int fd, int events);
9874 -       int (*event_del)(struct fdevents *ev, int fde_ndx, int fd);
9875 -       int (*event_get_revent)(struct fdevents *ev, size_t ndx);
9876 -       int (*event_get_fd)(struct fdevents *ev, size_t ndx);
9877 -       
9878 -       int (*event_next_fdndx)(struct fdevents *ev, int ndx);
9879 -       
9880 +
9881 +       int (*event_add)(struct fdevents *ev, iosocket *sock, int events);
9882 +       int (*event_del)(struct fdevents *ev, iosocket *sock);
9883 +       int (*get_revents)(struct fdevents *ev, size_t event_count, fdevent_revents *revents);
9884 +
9885         int (*poll)(struct fdevents *ev, int timeout_ms);
9886 -       
9887 +
9888         int (*fcntl_set)(struct fdevents *ev, int fd);
9889  } fdevents;
9890  
9891 @@ -194,22 +204,44 @@
9892  int fdevent_reset(fdevents *ev);
9893  void fdevent_free(fdevents *ev);
9894  
9895 -int fdevent_event_add(fdevents *ev, int *fde_ndx, int fd, int events);
9896 -int fdevent_event_del(fdevents *ev, int *fde_ndx, int fd);
9897 -int fdevent_event_get_revent(fdevents *ev, size_t ndx);
9898 -int fdevent_event_get_fd(fdevents *ev, size_t ndx);
9899 -fdevent_handler fdevent_get_handler(fdevents *ev, int fd);
9900 -void * fdevent_get_context(fdevents *ev, int fd);
9901 +/**
9902 + * call the plugin for the number of available events
9903 + */
9904 +int fdevent_poll(fdevents *ev, int timeout_ms);
9905 +/**
9906 + * get all available events
9907 + */
9908 +int fdevent_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents);
9909  
9910 -int fdevent_event_next_fdndx(fdevents *ev, int ndx);
9911 +/**
9912 + * add or remove a fd to the handled-pool
9913 + */
9914 +int fdevent_register(fdevents *ev, iosocket *sock, fdevent_handler handler, void *ctx);
9915 +int fdevent_unregister(fdevents *ev, iosocket *sock);
9916  
9917 -int fdevent_poll(fdevents *ev, int timeout_ms);
9918 +/**
9919 + * add a event to a registered fd
9920 + */
9921 +int fdevent_event_add(fdevents *ev, iosocket *sock, int events);
9922 +int fdevent_event_del(fdevents *ev, iosocket *sock);
9923 +
9924 +/**
9925 + * set non-blocking
9926 + */
9927 +int fdevent_fcntl_set(fdevents *ev, iosocket *sock);
9928 +
9929 +fdevent_revents *fdevent_revents_init(void);
9930 +void fdevent_revents_reset(fdevent_revents *revents);
9931 +void fdevent_revents_add(fdevent_revents *revents, int fd, int events);
9932 +void fdevent_revents_free(fdevent_revents *revents);
9933  
9934 -int fdevent_register(fdevents *ev, int fd, fdevent_handler handler, void *ctx);
9935 -int fdevent_unregister(fdevents *ev, int fd);
9936 +fdevent_revent *fdevent_revent_init(void);
9937 +void fdevent_revent_free(fdevent_revent *revent);
9938  
9939 -int fdevent_fcntl_set(fdevents *ev, int fd);
9940  
9941 +/**
9942 + * plugin init
9943 + */
9944  int fdevent_select_init(fdevents *ev);
9945  int fdevent_poll_init(fdevents *ev);
9946  int fdevent_linux_rtsig_init(fdevents *ev);
9947 --- ../lighttpd-1.4.11/src/fdevent_freebsd_kqueue.c     2005-09-01 10:46:24.000000000 +0300
9948 +++ lighttpd-1.5.0/src/fdevent_freebsd_kqueue.c 2006-09-07 00:57:05.000000000 +0300
9949 @@ -1,6 +1,5 @@
9950  #include <sys/types.h>
9951  
9952 -#include <unistd.h>
9953  #include <stdlib.h>
9954  #include <stdio.h>
9955  #include <string.h>
9956 @@ -17,22 +16,24 @@
9957  #include <sys/event.h>
9958  #include <sys/time.h>
9959  
9960 +#include "sys-files.h"
9961 +
9962  static void fdevent_freebsd_kqueue_free(fdevents *ev) {
9963         close(ev->kq_fd);
9964         free(ev->kq_results);
9965         bitset_free(ev->kq_bevents);
9966  }
9967  
9968 -static int fdevent_freebsd_kqueue_event_del(fdevents *ev, int fde_ndx, int fd) {
9969 +static int fdevent_freebsd_kqueue_event_del(fdevents *ev, iosocket *sock) {
9970         int filter, ret;
9971         struct kevent kev;
9972         struct timespec ts;
9973  
9974 -       if (fde_ndx < 0) return -1;
9975 +       if (sock->fde_ndx < 0) return -1;
9976  
9977 -       filter = bitset_test_bit(ev->kq_bevents, fd) ? EVFILT_READ : EVFILT_WRITE;
9978 +       filter = bitset_test_bit(ev->kq_bevents, sock->fd) ? EVFILT_READ : EVFILT_WRITE;
9979  
9980 -       EV_SET(&kev, fd, filter, EV_DELETE, 0, 0, NULL);
9981 +       EV_SET(&kev, sock->fd, filter, EV_DELETE, 0, 0, NULL);
9982  
9983         ts.tv_sec  = 0;
9984         ts.tv_nsec = 0;
9985 @@ -42,30 +43,29 @@
9986                      NULL, 0,
9987                      &ts);
9988  
9989 +       sock->fde_ndx = -1;
9990         if (ret == -1) {
9991                 fprintf(stderr, "%s.%d: kqueue failed polling: %s\n",
9992                         __FILE__, __LINE__, strerror(errno));
9993  
9994 -               return -1;
9995 +               return 0;
9996         }
9997 -       
9998 -       return -1;
9999 +
10000 +       return 0;
10001  }
10002  
10003 -static int fdevent_freebsd_kqueue_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
10004 +static int fdevent_freebsd_kqueue_event_add(fdevents *ev, iosocket *sock, int events) {
10005         int filter, ret;
10006         struct kevent kev;
10007         struct timespec ts;
10008  
10009 -       UNUSED(fde_ndx);
10010 -
10011         filter = (events & FDEVENT_IN) ? EVFILT_READ : EVFILT_WRITE;
10012  
10013 -       EV_SET(&kev, fd, filter, EV_ADD|EV_CLEAR, 0, 0, NULL);
10014 +       EV_SET(&kev, sock->fd, filter, EV_ADD|EV_CLEAR, 0, 0, NULL);
10015  
10016         ts.tv_sec  = 0;
10017         ts.tv_nsec = 0;
10018 -       
10019 +
10020         ret = kevent(ev->kq_fd,
10021                      &kev, 1,
10022                      NULL, 0,
10023 @@ -77,14 +77,14 @@
10024  
10025                 return -1;
10026         }
10027 -       
10028 +
10029         if (filter == EVFILT_READ) {
10030 -               bitset_set_bit(ev->kq_bevents, fd);
10031 +               bitset_set_bit(ev->kq_bevents, sock->fd);
10032         } else {
10033 -               bitset_clear_bit(ev->kq_bevents, fd);
10034 +               bitset_clear_bit(ev->kq_bevents, sock->fd);
10035         }
10036  
10037 -       return fd;
10038 +       return 0;
10039  }
10040  
10041  static int fdevent_freebsd_kqueue_poll(fdevents *ev, int timeout_ms) {
10042 @@ -114,48 +114,44 @@
10043         return ret;
10044  }
10045  
10046 -static int fdevent_freebsd_kqueue_event_get_revent(fdevents *ev, size_t ndx) {
10047 -       int events = 0, e;
10048 +static int fdevent_freebsd_kqueue_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
10049 +       size_t ndx;
10050  
10051 -       e = ev->kq_results[ndx].filter;
10052 -
10053 -       if (e == EVFILT_READ) {
10054 -               events |= FDEVENT_IN;
10055 -       } else if (e == EVFILT_WRITE) {
10056 -               events |= FDEVENT_OUT;
10057 -       }
10058 -       
10059 -       e = ev->kq_results[ndx].flags;
10060 +       for (ndx = 0; ndx < ev->used; ndx++) {
10061 +               int events = 0, e;
10062  
10063 -       if (e & EV_EOF) {
10064 -               events |= FDEVENT_HUP;
10065 -       }
10066 +               e = ev->kq_results[ndx].filter;
10067  
10068 -       if (e & EV_ERROR) {
10069 -               events |= FDEVENT_ERR;
10070 -       }
10071 +               if (e == EVFILT_READ) {
10072 +                       events |= FDEVENT_IN;
10073 +               } else if (e == EVFILT_WRITE) {
10074 +                       events |= FDEVENT_OUT;
10075 +               }
10076  
10077 -       return events;
10078 -}
10079 +               e = ev->kq_results[ndx].flags;
10080  
10081 -static int fdevent_freebsd_kqueue_event_get_fd(fdevents *ev, size_t ndx) {
10082 -       return ev->kq_results[ndx].ident;
10083 -}
10084 +               if (e & EV_EOF) {
10085 +                       events |= FDEVENT_HUP;
10086 +               }
10087 +       
10088 +               if (e & EV_ERROR) {
10089 +                       events |= FDEVENT_ERR;
10090 +               }
10091  
10092 -static int fdevent_freebsd_kqueue_event_next_fdndx(fdevents *ev, int ndx) {
10093 -       UNUSED(ev);
10094 +               fdevent_revents_add(revents, ev->kq_results[ndx].ident, events);
10095 +       }
10096  
10097 -       return (ndx < 0) ? 0 : ndx + 1;
10098 +       return 0;
10099  }
10100  
10101  static int fdevent_freebsd_kqueue_reset(fdevents *ev) {
10102         if (-1 == (ev->kq_fd = kqueue())) {
10103                 fprintf(stderr, "%s.%d: kqueue failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
10104                         __FILE__, __LINE__, strerror(errno));
10105 -               
10106 +
10107                 return -1;
10108         }
10109 -       
10110 +
10111         return 0;
10112  }
10113  
10114 @@ -172,9 +168,7 @@
10115         SET(event_del);
10116         SET(event_add);
10117  
10118 -       SET(event_next_fdndx);
10119 -       SET(event_get_fd);
10120 -       SET(event_get_revent);
10121 +       SET(get_revents);
10122  
10123         ev->kq_fd = -1;
10124  
10125 @@ -186,7 +180,7 @@
10126         if (-1 == (ev->kq_fd = kqueue())) {
10127                 fprintf(stderr, "%s.%d: kqueue failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
10128                         __FILE__, __LINE__, strerror(errno));
10129 -               
10130 +
10131                 return -1;
10132         }
10133  
10134 --- ../lighttpd-1.4.11/src/fdevent_linux_rtsig.c        2005-11-21 19:56:11.000000000 +0200
10135 +++ lighttpd-1.5.0/src/fdevent_linux_rtsig.c    2006-07-18 13:03:40.000000000 +0300
10136 @@ -1,6 +1,5 @@
10137  #include <sys/types.h>
10138  
10139 -#include <unistd.h>
10140  #include <stdlib.h>
10141  #include <stdio.h>
10142  #include <string.h>
10143 @@ -14,6 +13,8 @@
10144  #include "fdevent.h"
10145  #include "settings.h"
10146  #include "buffer.h"
10147 +#include "sys-process.h"
10148 +#include "log.h"
10149  
10150  #ifdef USE_LINUX_SIGIO
10151  static void fdevent_linux_rtsig_free(fdevents *ev) {
10152 @@ -24,21 +25,21 @@
10153  }
10154  
10155  
10156 -static int fdevent_linux_rtsig_event_del(fdevents *ev, int fde_ndx, int fd) {
10157 -       if (fde_ndx < 0) return -1;
10158 -       
10159 -       if ((size_t)fde_ndx >= ev->used) {
10160 -               fprintf(stderr, "%s.%d: del! out of range %d %zu\n", __FILE__, __LINE__, fde_ndx, ev->used);
10161 +static int fdevent_linux_rtsig_event_del(fdevents *ev, iosocket *sock) {
10162 +       if (sock->fde_ndx < 0) return -1;
10163 +
10164 +       if ((size_t)sock->fde_ndx >= ev->used) {
10165 +               TRACE("del! out of range %d %zu\n", sock->fde_ndx, ev->used);
10166                 SEGFAULT();
10167         }
10168 -       
10169 -       if (ev->pollfds[fde_ndx].fd == fd) {
10170 -               size_t k = fde_ndx;
10171 -               
10172 +
10173 +       if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
10174 +               size_t k = sock->fde_ndx;
10175 +
10176                 ev->pollfds[k].fd = -1;
10177  
10178 -               bitset_clear_bit(ev->sigbset, fd);
10179 -               
10180 +               bitset_clear_bit(ev->sigbset, sock->fd);
10181 +
10182                 if (ev->unused.size == 0) {
10183                         ev->unused.size = 16;
10184                         ev->unused.ptr = malloc(sizeof(*(ev->unused.ptr)) * ev->unused.size);
10185 @@ -46,53 +47,54 @@
10186                         ev->unused.size += 16;
10187                         ev->unused.ptr = realloc(ev->unused.ptr, sizeof(*(ev->unused.ptr)) * ev->unused.size);
10188                 }
10189 -               
10190 +
10191                 ev->unused.ptr[ev->unused.used++] = k;
10192         } else {
10193 -               fprintf(stderr, "%s.%d: del! %d %d\n", __FILE__, __LINE__, ev->pollfds[fde_ndx].fd, fd);
10194 -               
10195 +               fprintf(stderr, "%s.%d: del! %d %d\n", __FILE__, __LINE__, ev->pollfds[sock->fde_ndx].fd, sock->fd);
10196 +
10197                 SEGFAULT();
10198         }
10199 -       
10200 -       return -1;
10201 +       sock->fde_ndx = -1;
10202 +
10203 +       return 0;
10204  }
10205  
10206  #if 0
10207  static int fdevent_linux_rtsig_event_compress(fdevents *ev) {
10208         size_t j;
10209 -       
10210 +
10211         if (ev->used == 0) return 0;
10212         if (ev->unused.used != 0) return 0;
10213 -       
10214 +
10215         for (j = ev->used - 1; j + 1 > 0; j--) {
10216                 if (ev->pollfds[j].fd == -1) ev->used--;
10217         }
10218 -       
10219 -       
10220 +
10221 +
10222         return 0;
10223  }
10224  #endif
10225  
10226 -static int fdevent_linux_rtsig_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
10227 +static int fdevent_linux_rtsig_event_add(fdevents *ev, iosocket *sock, int events) {
10228         /* known index */
10229 -       if (fde_ndx != -1) {
10230 -               if (ev->pollfds[fde_ndx].fd == fd) {
10231 -                       ev->pollfds[fde_ndx].events = events;
10232 -                       
10233 -                       return fde_ndx;
10234 +       if (sock->fde_ndx != -1) {
10235 +               if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
10236 +                       ev->pollfds[sock->fde_ndx].events = events;
10237 +
10238 +                       return sock->fde_ndx;
10239                 }
10240 -               fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, fde_ndx, ev->pollfds[fde_ndx].fd);
10241 +               fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, sock->fde_ndx, ev->pollfds[sock->fde_ndx].fd);
10242                 SEGFAULT();
10243         }
10244 -       
10245 +
10246         if (ev->unused.used > 0) {
10247                 int k = ev->unused.ptr[--ev->unused.used];
10248 -               
10249 -               ev->pollfds[k].fd = fd;
10250 +
10251 +               ev->pollfds[k].fd = sock->fd;
10252                 ev->pollfds[k].events = events;
10253  
10254 -               bitset_set_bit(ev->sigbset, fd);
10255 -               
10256 +               bitset_set_bit(ev->sigbset, sock->fd);
10257 +
10258                 return k;
10259         } else {
10260                 if (ev->size == 0) {
10261 @@ -102,12 +104,12 @@
10262                         ev->size += 16;
10263                         ev->pollfds = realloc(ev->pollfds, sizeof(*ev->pollfds) * ev->size);
10264                 }
10265 -               
10266 -               ev->pollfds[ev->used].fd = fd;
10267 +
10268 +               ev->pollfds[ev->used].fd = sock->fd;
10269                 ev->pollfds[ev->used].events = events;
10270  
10271 -               bitset_set_bit(ev->sigbset, fd);
10272 -       
10273 +               bitset_set_bit(ev->sigbset, sock->fd);
10274 +
10275                 return ev->used++;
10276         }
10277  }
10278 @@ -115,20 +117,20 @@
10279  static int fdevent_linux_rtsig_poll(fdevents *ev, int timeout_ms) {
10280         struct timespec ts;
10281         int r;
10282 -       
10283 +
10284  #if 0
10285         fdevent_linux_rtsig_event_compress(ev);
10286  #endif
10287 -       
10288 +
10289         ev->in_sigio = 1;
10290 -               
10291 +
10292         ts.tv_sec =  timeout_ms / 1000;
10293         ts.tv_nsec = (timeout_ms % 1000) * 1000000;
10294         r = sigtimedwait(&(ev->sigset), &(ev->siginfo), &(ts));
10295 -               
10296 -       if (r == -1) { 
10297 +
10298 +       if (r == -1) {
10299                 if (errno == EAGAIN) return 0;
10300 -               return r; 
10301 +               return r;
10302         } else if (r == SIGIO) {
10303                 struct sigaction act;
10304  
10305 @@ -140,7 +142,7 @@
10306                 /* re-enable the signal queue */
10307                 act.sa_handler = SIG_DFL;
10308                 sigaction(ev->signum, &act, NULL);
10309 -               
10310 +
10311                 ev->in_sigio = 0;
10312                 r = poll(ev->pollfds, ev->used, timeout_ms);
10313  
10314 @@ -156,97 +158,67 @@
10315         }
10316  }
10317  
10318 -static int fdevent_linux_rtsig_event_get_revent(fdevents *ev, size_t ndx) {
10319 +static int fdevent_linux_rtsig_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
10320         if (ev->in_sigio == 1) {
10321 -#  if 0
10322 -               if (ev->siginfo.si_band == POLLERR) {
10323 -                       fprintf(stderr, "event: %d %02lx %02x %s\n", ev->siginfo.si_fd, ev->siginfo.si_band, errno, strerror(errno));
10324 -               }
10325 -#  endif               
10326 -               if (ndx != 0) {
10327 -                       fprintf(stderr, "+\n");
10328 -                       return 0;
10329 -               }
10330 -               
10331 -               return ev->siginfo.si_band & 0x3f;
10332 +               /* only one event */
10333 +
10334 +               fdevent_revents_add(revents, ev->siginfo.si_fd, ev->siginfo.si_band & 0x3f);
10335         } else {
10336 -               if (ndx >= ev->used) {
10337 -                       fprintf(stderr, "%s.%d: event: %zu %zu\n", __FILE__, __LINE__, ndx, ev->used);
10338 -                       return 0;
10339 +               size_t ndx;
10340 +
10341 +               for (ndx = 0; ndx < ev->used; ndx++) {
10342 +                       if (ev->pollfds[ndx].revents) {
10343 +                               fdevent_revents_add(revents, ev->pollfds[ndx].fd, ev->pollfds[ndx].revents);
10344 +                       }
10345                 }
10346 -               return ev->pollfds[ndx].revents;
10347         }
10348 -}
10349  
10350 -static int fdevent_linux_rtsig_event_get_fd(fdevents *ev, size_t ndx) {
10351 -       if (ev->in_sigio == 1) {
10352 -               return ev->siginfo.si_fd;
10353 -       } else {
10354 -               return ev->pollfds[ndx].fd;
10355 -       }
10356 +       return 0;
10357  }
10358  
10359  static int fdevent_linux_rtsig_fcntl_set(fdevents *ev, int fd) {
10360         static pid_t pid = 0;
10361 -       
10362 +
10363         if (pid == 0) pid = getpid();
10364 -       
10365 +
10366         if (-1 == fcntl(fd, F_SETSIG, ev->signum)) return -1;
10367 -       
10368 +
10369         if (-1 == fcntl(fd, F_SETOWN, (int) pid)) return -1;
10370 -       
10371 +
10372         return fcntl(fd, F_SETFL, O_ASYNC | O_NONBLOCK | O_RDWR);
10373  }
10374  
10375  
10376 -static int fdevent_linux_rtsig_event_next_fdndx(fdevents *ev, int ndx) {
10377 -       if (ev->in_sigio == 1) {
10378 -               if (ndx < 0) return 0;
10379 -               return -1;
10380 -       } else {
10381 -               size_t i;
10382 -               
10383 -               i = (ndx < 0) ? 0 : ndx + 1;
10384 -               for (; i < ev->used; i++) {
10385 -                       if (ev->pollfds[i].revents) break;
10386 -               }
10387 -               
10388 -               return i;
10389 -       }
10390 -}
10391 -
10392  int fdevent_linux_rtsig_init(fdevents *ev) {
10393         ev->type = FDEVENT_HANDLER_LINUX_RTSIG;
10394  #define SET(x) \
10395         ev->x = fdevent_linux_rtsig_##x;
10396 -       
10397 +
10398         SET(free);
10399         SET(poll);
10400 -       
10401 +
10402         SET(event_del);
10403         SET(event_add);
10404 -       
10405 -       SET(event_next_fdndx);
10406 +
10407         SET(fcntl_set);
10408 -       SET(event_get_fd);
10409 -       SET(event_get_revent);
10410 -       
10411 +       SET(get_revents);
10412 +
10413         ev->signum = SIGRTMIN + 1;
10414 -       
10415 +
10416         sigemptyset(&(ev->sigset));
10417         sigaddset(&(ev->sigset), ev->signum);
10418         sigaddset(&(ev->sigset), SIGIO);
10419         if (-1 == sigprocmask(SIG_BLOCK, &(ev->sigset), NULL)) {
10420                 fprintf(stderr, "%s.%d: sigprocmask failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
10421                         __FILE__, __LINE__, strerror(errno));
10422 -               
10423 +
10424                 return -1;
10425         }
10426 -       
10427 +
10428         ev->in_sigio = 1;
10429  
10430         ev->sigbset = bitset_init(ev->maxfds);
10431 -       
10432 +
10433         return 0;
10434  }
10435  #else
10436 --- ../lighttpd-1.4.11/src/fdevent_linux_sysepoll.c     2005-09-30 20:29:27.000000000 +0300
10437 +++ lighttpd-1.5.0/src/fdevent_linux_sysepoll.c 2006-07-18 13:03:40.000000000 +0300
10438 @@ -1,6 +1,5 @@
10439  #include <sys/types.h>
10440  
10441 -#include <unistd.h>
10442  #include <stdlib.h>
10443  #include <stdio.h>
10444  #include <string.h>
10445 @@ -11,6 +10,9 @@
10446  #include "fdevent.h"
10447  #include "settings.h"
10448  #include "buffer.h"
10449 +#include "log.h"
10450 +
10451 +#include "sys-files.h"
10452  
10453  #ifdef USE_LINUX_EPOLL
10454  static void fdevent_linux_sysepoll_free(fdevents *ev) {
10455 @@ -18,38 +20,40 @@
10456         free(ev->epoll_events);
10457  }
10458  
10459 -static int fdevent_linux_sysepoll_event_del(fdevents *ev, int fde_ndx, int fd) {
10460 +static int fdevent_linux_sysepoll_event_del(fdevents *ev, iosocket *sock) {
10461         struct epoll_event ep;
10462 -       
10463 -       if (fde_ndx < 0) return -1;
10464 -       
10465 +
10466 +       if (sock->fde_ndx < 0) return -1;
10467 +
10468         memset(&ep, 0, sizeof(ep));
10469 -       
10470 -       ep.data.fd = fd;
10471 +
10472 +       ep.data.fd = sock->fd;
10473         ep.data.ptr = NULL;
10474 -       
10475 -       if (0 != epoll_ctl(ev->epoll_fd, EPOLL_CTL_DEL, fd, &ep)) {
10476 +
10477 +       if (0 != epoll_ctl(ev->epoll_fd, EPOLL_CTL_DEL, sock->fd, &ep)) {
10478                 fprintf(stderr, "%s.%d: epoll_ctl failed: %s, dying\n", __FILE__, __LINE__, strerror(errno));
10479 -               
10480 +
10481                 SEGFAULT();
10482 -               
10483 +
10484                 return 0;
10485         }
10486 -       
10487 -       
10488 -       return -1;
10489 +
10490 +       sock->fde_ndx = -1;
10491 +
10492 +       return 0;
10493  }
10494  
10495 -static int fdevent_linux_sysepoll_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
10496 +static int fdevent_linux_sysepoll_event_add(fdevents *ev, iosocket *sock, int events) {
10497         struct epoll_event ep;
10498         int add = 0;
10499 -       
10500 -       if (fde_ndx == -1) add = 1;
10501 -       
10502 +
10503 +       /* a new fd */
10504 +       if (sock->fde_ndx == -1) add = 1;
10505 +
10506         memset(&ep, 0, sizeof(ep));
10507 -       
10508 +
10509         ep.events = 0;
10510 -       
10511 +
10512         if (events & FDEVENT_IN)  ep.events |= EPOLLIN;
10513         if (events & FDEVENT_OUT) ep.events |= EPOLLOUT;
10514  
10515 @@ -60,73 +64,61 @@
10516          * sent.
10517          *
10518          */
10519 -       
10520 +
10521         ep.events |= EPOLLERR | EPOLLHUP /* | EPOLLET */;
10522 -       
10523 +
10524         ep.data.ptr = NULL;
10525 -       ep.data.fd = fd;
10526 -       
10527 -       if (0 != epoll_ctl(ev->epoll_fd, add ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, fd, &ep)) {
10528 +       ep.data.fd = sock->fd;
10529 +
10530 +       if (0 != epoll_ctl(ev->epoll_fd, add ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, sock->fd, &ep)) {
10531                 fprintf(stderr, "%s.%d: epoll_ctl failed: %s, dying\n", __FILE__, __LINE__, strerror(errno));
10532 -               
10533 +
10534                 SEGFAULT();
10535 -               
10536 +
10537                 return 0;
10538         }
10539 -       
10540 -       return fd;
10541 +
10542 +       sock->fde_ndx = sock->fd;
10543 +
10544 +       return 0;
10545  }
10546  
10547  static int fdevent_linux_sysepoll_poll(fdevents *ev, int timeout_ms) {
10548         return epoll_wait(ev->epoll_fd, ev->epoll_events, ev->maxfds, timeout_ms);
10549  }
10550  
10551 -static int fdevent_linux_sysepoll_event_get_revent(fdevents *ev, size_t ndx) {
10552 -       int events = 0, e;
10553 -       
10554 -       e = ev->epoll_events[ndx].events;
10555 -       if (e & EPOLLIN) events |= FDEVENT_IN;
10556 -       if (e & EPOLLOUT) events |= FDEVENT_OUT;
10557 -       if (e & EPOLLERR) events |= FDEVENT_ERR;
10558 -       if (e & EPOLLHUP) events |= FDEVENT_HUP;
10559 -       if (e & EPOLLPRI) events |= FDEVENT_PRI;
10560 -       
10561 -       return e;
10562 -}
10563 -
10564 -static int fdevent_linux_sysepoll_event_get_fd(fdevents *ev, size_t ndx) {
10565 -# if 0
10566 -       fprintf(stderr, "%s.%d: %d, %d\n", __FILE__, __LINE__, ndx, ev->epoll_events[ndx].data.fd);
10567 -# endif
10568 -       
10569 -       return ev->epoll_events[ndx].data.fd;
10570 -}
10571 -
10572 -static int fdevent_linux_sysepoll_event_next_fdndx(fdevents *ev, int ndx) {
10573 -       size_t i;
10574 -       
10575 -       UNUSED(ev);
10576 +static int fdevent_linux_sysepoll_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
10577 +       size_t ndx;
10578 +
10579 +       for (ndx = 0; ndx < event_count; ndx++) {
10580 +               int events = 0, e;
10581 +
10582 +               e = ev->epoll_events[ndx].events;
10583 +               if (e & EPOLLIN) events |= FDEVENT_IN;
10584 +               if (e & EPOLLOUT) events |= FDEVENT_OUT;
10585 +               if (e & EPOLLERR) events |= FDEVENT_ERR;
10586 +               if (e & EPOLLHUP) events |= FDEVENT_HUP;
10587 +               if (e & EPOLLPRI) events |= FDEVENT_PRI;
10588  
10589 -       i = (ndx < 0) ? 0 : ndx + 1;
10590 -       
10591 -       return i;
10592 +               fdevent_revents_add(revents, ev->epoll_events[ndx].data.fd, e);
10593 +       }
10594 +
10595 +       return 0;
10596  }
10597  
10598  int fdevent_linux_sysepoll_init(fdevents *ev) {
10599         ev->type = FDEVENT_HANDLER_LINUX_SYSEPOLL;
10600  #define SET(x) \
10601         ev->x = fdevent_linux_sysepoll_##x;
10602 -       
10603 +
10604         SET(free);
10605         SET(poll);
10606 -       
10607 +
10608         SET(event_del);
10609         SET(event_add);
10610 -       
10611 -       SET(event_next_fdndx);
10612 -       SET(event_get_fd);
10613 -       SET(event_get_revent);
10614 -       
10615 +
10616 +       SET(get_revents);
10617 +
10618         if (-1 == (ev->epoll_fd = epoll_create(ev->maxfds))) {
10619                 fprintf(stderr, "%s.%d: epoll_create failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
10620                         __FILE__, __LINE__, strerror(errno));
10621 @@ -154,7 +146,7 @@
10622  
10623         fprintf(stderr, "%s.%d: linux-sysepoll not supported, try to set server.event-handler = \"poll\" or \"select\"\n",
10624                 __FILE__, __LINE__);
10625 -       
10626 +
10627         return -1;
10628  }
10629  #endif
10630 --- ../lighttpd-1.4.11/src/fdevent_poll.c       2005-11-18 13:59:16.000000000 +0200
10631 +++ lighttpd-1.5.0/src/fdevent_poll.c   2006-09-07 00:57:05.000000000 +0300
10632 @@ -1,6 +1,5 @@
10633  #include <sys/types.h>
10634  
10635 -#include <unistd.h>
10636  #include <stdlib.h>
10637  #include <stdio.h>
10638  #include <string.h>
10639 @@ -11,6 +10,7 @@
10640  #include "fdevent.h"
10641  #include "settings.h"
10642  #include "buffer.h"
10643 +#include "log.h"
10644  
10645  #ifdef USE_POLL
10646  static void fdevent_poll_free(fdevents *ev) {
10647 @@ -18,21 +18,21 @@
10648         if (ev->unused.ptr) free(ev->unused.ptr);
10649  }
10650  
10651 -static int fdevent_poll_event_del(fdevents *ev, int fde_ndx, int fd) {
10652 -       if (fde_ndx < 0) return -1;
10653 -       
10654 -       if ((size_t)fde_ndx >= ev->used) {
10655 -               fprintf(stderr, "%s.%d: del! out of range %d %zd\n", __FILE__, __LINE__, fde_ndx, ev->used);
10656 +static int fdevent_poll_event_del(fdevents *ev, iosocket *sock) {
10657 +       if (sock->fde_ndx < 0) return -1;
10658 +
10659 +       if ((size_t)sock->fde_ndx >= ev->used) {
10660 +               fprintf(stderr, "%s.%d: del! out of range %d %zd\n", __FILE__, __LINE__, sock->fde_ndx, ev->used);
10661                 SEGFAULT();
10662         }
10663 -       
10664 -       if (ev->pollfds[fde_ndx].fd == fd) {
10665 -               size_t k = fde_ndx;
10666 -               
10667 +
10668 +       if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
10669 +               size_t k = sock->fde_ndx;
10670 +
10671                 ev->pollfds[k].fd = -1;
10672                 /* ev->pollfds[k].events = 0; */
10673                 /* ev->pollfds[k].revents = 0; */
10674 -               
10675 +
10676                 if (ev->unused.size == 0) {
10677                         ev->unused.size = 16;
10678                         ev->unused.ptr = malloc(sizeof(*(ev->unused.ptr)) * ev->unused.size);
10679 @@ -40,48 +40,52 @@
10680                         ev->unused.size += 16;
10681                         ev->unused.ptr = realloc(ev->unused.ptr, sizeof(*(ev->unused.ptr)) * ev->unused.size);
10682                 }
10683 -               
10684 +
10685                 ev->unused.ptr[ev->unused.used++] = k;
10686         } else {
10687 +               TRACE("(fdevent-poll-del) sock->fde_ndx: %d, sock->fd: %d -> stored fd: %d", sock->fde_ndx, sock->fd, ev->pollfds[sock->fde_ndx].fd);
10688                 SEGFAULT();
10689         }
10690 -       
10691 -       return -1;
10692 +
10693 +       sock->fde_ndx = -1;
10694 +
10695 +       return 0;
10696  }
10697  
10698  #if 0
10699  static int fdevent_poll_event_compress(fdevents *ev) {
10700         size_t j;
10701 -       
10702 +
10703         if (ev->used == 0) return 0;
10704         if (ev->unused.used != 0) return 0;
10705 -       
10706 +
10707         for (j = ev->used - 1; j + 1 > 0 && ev->pollfds[j].fd == -1; j--) ev->used--;
10708 -       
10709 +
10710         return 0;
10711  }
10712  #endif
10713  
10714 -static int fdevent_poll_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
10715 -       /* known index */
10716 -       
10717 -       if (fde_ndx != -1) {
10718 -               if (ev->pollfds[fde_ndx].fd == fd) {
10719 -                       ev->pollfds[fde_ndx].events = events;
10720 -                       
10721 -                       return fde_ndx;
10722 +static int fdevent_poll_event_add(fdevents *ev, iosocket *sock, int events) {
10723 +       if (sock->fde_ndx != -1) {
10724 +               /* this fd was already added, just change the requested events */
10725 +
10726 +               if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
10727 +                       ev->pollfds[sock->fde_ndx].events = events;
10728 +
10729 +                       return sock->fde_ndx;
10730                 }
10731 -               fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, fde_ndx, ev->pollfds[fde_ndx].fd);
10732 +               fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, sock->fde_ndx, ev->pollfds[sock->fde_ndx].fd);
10733                 SEGFAULT();
10734         }
10735 -       
10736 +
10737         if (ev->unused.used > 0) {
10738                 int k = ev->unused.ptr[--ev->unused.used];
10739 -               
10740 -               ev->pollfds[k].fd = fd;
10741 +
10742 +               ev->pollfds[k].fd = sock->fd;
10743                 ev->pollfds[k].events = events;
10744 -               
10745 -               return k;
10746 +
10747 +               sock->fde_ndx = k;
10748 +
10749         } else {
10750                 if (ev->size == 0) {
10751                         ev->size = 16;
10752 @@ -90,12 +94,13 @@
10753                         ev->size += 16;
10754                         ev->pollfds = realloc(ev->pollfds, sizeof(*ev->pollfds) * ev->size);
10755                 }
10756 -               
10757 -               ev->pollfds[ev->used].fd = fd;
10758 +
10759 +               ev->pollfds[ev->used].fd = sock->fd;
10760                 ev->pollfds[ev->used].events = events;
10761 -               
10762 -               return ev->used++;
10763 +
10764 +               sock->fde_ndx = ev->used++;
10765         }
10766 +       return 0;
10767  }
10768  
10769  static int fdevent_poll_poll(fdevents *ev, int timeout_ms) {
10770 @@ -105,71 +110,38 @@
10771         return poll(ev->pollfds, ev->used, timeout_ms);
10772  }
10773  
10774 -static int fdevent_poll_event_get_revent(fdevents *ev, size_t ndx) {
10775 -       int r, poll_r;
10776 -       if (ndx >= ev->used) {
10777 -               fprintf(stderr, "%s.%d: dying because: event: %zd >= %zd\n", __FILE__, __LINE__, ndx, ev->used);
10778 -               
10779 -               SEGFAULT();
10780 -               
10781 -               return 0;
10782 -       }
10783 -       
10784 -       if (ev->pollfds[ndx].revents & POLLNVAL) {
10785 -               /* should never happen */
10786 -               SEGFAULT();
10787 -       }
10788 +static int fdevent_poll_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
10789 +       size_t ndx;
10790  
10791 -       r = 0;
10792 -       poll_r = ev->pollfds[ndx].revents;
10793 +       for (ndx = 0; ndx < ev->used; ndx++) {
10794 +               if (ev->pollfds[ndx].revents) {
10795 +                       if (ev->pollfds[ndx].revents & POLLNVAL) {
10796 +                               /* should never happen */
10797 +                               SEGFAULT();
10798 +                       }
10799  
10800 -       /* map POLL* to FDEVEN_* */
10801 -
10802 -       if (poll_r & POLLIN) r |= FDEVENT_IN;
10803 -       if (poll_r & POLLOUT) r |= FDEVENT_OUT;
10804 -       if (poll_r & POLLERR) r |= FDEVENT_ERR;
10805 -       if (poll_r & POLLHUP) r |= FDEVENT_HUP;
10806 -       if (poll_r & POLLNVAL) r |= FDEVENT_NVAL;
10807 -       if (poll_r & POLLPRI) r |= FDEVENT_PRI;
10808 -       
10809 -       return ev->pollfds[ndx].revents;
10810 -}
10811 -
10812 -static int fdevent_poll_event_get_fd(fdevents *ev, size_t ndx) {
10813 -       return ev->pollfds[ndx].fd;
10814 -}
10815 -
10816 -static int fdevent_poll_event_next_fdndx(fdevents *ev, int ndx) {
10817 -       size_t i;
10818 -       
10819 -       i = (ndx < 0) ? 0 : ndx + 1;
10820 -       for (; i < ev->used; i++) {
10821 -               if (ev->pollfds[i].revents) break;
10822 +                       fdevent_revents_add(revents, ev->pollfds[ndx].fd, ev->pollfds[ndx].revents);
10823 +               }
10824         }
10825 -       
10826 -       return i;
10827 +
10828 +       return 0;
10829  }
10830  
10831  int fdevent_poll_init(fdevents *ev) {
10832         ev->type = FDEVENT_HANDLER_POLL;
10833  #define SET(x) \
10834         ev->x = fdevent_poll_##x;
10835 -       
10836 +
10837         SET(free);
10838         SET(poll);
10839 -       
10840 +
10841         SET(event_del);
10842         SET(event_add);
10843 -       
10844 -       SET(event_next_fdndx);
10845 -       SET(event_get_fd);
10846 -       SET(event_get_revent);
10847 -       
10848 -       return 0;
10849 -}
10850 -
10851  
10852 +       SET(get_revents);
10853  
10854 +       return 0;
10855 +}
10856  
10857  #else
10858  int fdevent_poll_init(fdevents *ev) {
10859 --- ../lighttpd-1.4.11/src/fdevent_select.c     2005-08-31 11:12:46.000000000 +0300
10860 +++ lighttpd-1.5.0/src/fdevent_select.c 2006-07-18 13:03:40.000000000 +0300
10861 @@ -1,18 +1,19 @@
10862 -#include <sys/time.h>
10863  #include <sys/types.h>
10864  
10865 -#include <unistd.h>
10866  #include <stdlib.h>
10867  #include <string.h>
10868  #include <errno.h>
10869  #include <signal.h>
10870  #include <fcntl.h>
10871  #include <assert.h>
10872 +#include <stdio.h>
10873  
10874  #include "fdevent.h"
10875  #include "settings.h"
10876  #include "buffer.h"
10877  
10878 +#include "sys-socket.h"
10879 +
10880  #ifdef USE_SELECT
10881  
10882  static int fdevent_select_reset(fdevents *ev) {
10883 @@ -24,101 +25,98 @@
10884         return 0;
10885  }
10886  
10887 -static int fdevent_select_event_del(fdevents *ev, int fde_ndx, int fd) {
10888 -       if (fde_ndx < 0) return -1;
10889 +static int fdevent_select_event_del(fdevents *ev, iosocket *sock) {
10890 +       if (sock->fde_ndx < 0) return -1;
10891  
10892 -       FD_CLR(fd, &(ev->select_set_read));
10893 -       FD_CLR(fd, &(ev->select_set_write));
10894 -       FD_CLR(fd, &(ev->select_set_error));
10895 +       FD_CLR(sock->fd, &(ev->select_set_read));
10896 +       FD_CLR(sock->fd, &(ev->select_set_write));
10897 +       FD_CLR(sock->fd, &(ev->select_set_error));
10898  
10899 -       return -1;
10900 -}
10901 +       /* mark the fdevent as deleted */
10902 +       sock->fde_ndx = -1;
10903  
10904 -static int fdevent_select_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
10905 -       UNUSED(fde_ndx);
10906 +       return 0;
10907 +}
10908  
10909 +static int fdevent_select_event_add(fdevents *ev, iosocket *sock, int events) {
10910         /* we should be protected by max-fds, but you never know */
10911 -       assert(fd < FD_SETSIZE);
10912 +#ifndef _WIN32
10913 +       assert(sock->fd < FD_SETSIZE);
10914 +#endif
10915  
10916         if (events & FDEVENT_IN) {
10917 -               FD_SET(fd, &(ev->select_set_read));
10918 -               FD_CLR(fd, &(ev->select_set_write));
10919 +               FD_SET(sock->fd, &(ev->select_set_read));
10920 +               FD_CLR(sock->fd, &(ev->select_set_write));
10921         }
10922         if (events & FDEVENT_OUT) {
10923 -               FD_CLR(fd, &(ev->select_set_read));
10924 -               FD_SET(fd, &(ev->select_set_write));
10925 +               FD_CLR(sock->fd, &(ev->select_set_read));
10926 +               FD_SET(sock->fd, &(ev->select_set_write));
10927         }
10928 -       FD_SET(fd, &(ev->select_set_error));
10929 -       
10930 -       if (fd > ev->select_max_fd) ev->select_max_fd = fd;
10931 -       
10932 -       return fd;
10933 +       FD_SET(sock->fd, &(ev->select_set_error));
10934 +
10935 +       /* we need this for the poll */
10936 +       if (sock->fd > ev->select_max_fd) ev->select_max_fd = sock->fd;
10937 +
10938 +       /* mark fd as added */
10939 +       sock->fde_ndx = sock->fd;
10940 +
10941 +       return 0;
10942  }
10943  
10944  static int fdevent_select_poll(fdevents *ev, int timeout_ms) {
10945         struct timeval tv;
10946 -       
10947 +
10948         tv.tv_sec =  timeout_ms / 1000;
10949         tv.tv_usec = (timeout_ms % 1000) * 1000;
10950 -       
10951 +
10952         ev->select_read = ev->select_set_read;
10953         ev->select_write = ev->select_set_write;
10954         ev->select_error = ev->select_set_error;
10955 -       
10956 +
10957         return select(ev->select_max_fd + 1, &(ev->select_read), &(ev->select_write), &(ev->select_error), &tv);
10958  }
10959  
10960 -static int fdevent_select_event_get_revent(fdevents *ev, size_t ndx) {
10961 -       int revents = 0;
10962 -       
10963 -       if (FD_ISSET(ndx, &(ev->select_read))) {
10964 -               revents |= FDEVENT_IN;
10965 +/**
10966 + * scan the fdset for events 
10967 + */
10968 +static int fdevent_select_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
10969 +
10970 +       int ndx = 0;
10971 +
10972 +       for (ndx = 0; ndx < ev->select_max_fd; ndx++) {
10973 +               int events = 0;
10974 +
10975 +               if (FD_ISSET(ndx, &(ev->select_read))) {
10976 +                       events |= FDEVENT_IN;
10977 +               }
10978 +               if (FD_ISSET(ndx, &(ev->select_write))) {
10979 +                       events |= FDEVENT_OUT;
10980 +               }
10981 +               if (FD_ISSET(ndx, &(ev->select_error))) {
10982 +                       events |= FDEVENT_ERR;
10983 +               }
10984 +
10985 +               if (events) {
10986 +                       fdevent_revents_add(revents, ndx, events);
10987 +               }
10988         }
10989 -       if (FD_ISSET(ndx, &(ev->select_write))) {
10990 -               revents |= FDEVENT_OUT;
10991 -       }
10992 -       if (FD_ISSET(ndx, &(ev->select_error))) {
10993 -               revents |= FDEVENT_ERR;
10994 -       }
10995 -       
10996 -       return revents;
10997 -}
10998 -
10999 -static int fdevent_select_event_get_fd(fdevents *ev, size_t ndx) {
11000 -       UNUSED(ev);
11001 -
11002 -       return ndx;
11003 -}
11004  
11005 -static int fdevent_select_event_next_fdndx(fdevents *ev, int ndx) {
11006 -       int i;
11007 -       
11008 -       i = (ndx < 0) ? 0 : ndx + 1;
11009 -       
11010 -       for (; i < ev->select_max_fd + 1; i++) {
11011 -               if (FD_ISSET(i, &(ev->select_read))) break;
11012 -               if (FD_ISSET(i, &(ev->select_write))) break;
11013 -               if (FD_ISSET(i, &(ev->select_error))) break;
11014 -       }
11015 -       
11016 -       return i;
11017 +       return 0;
11018  }
11019  
11020  int fdevent_select_init(fdevents *ev) {
11021         ev->type = FDEVENT_HANDLER_SELECT;
11022  #define SET(x) \
11023         ev->x = fdevent_select_##x;
11024 -       
11025 +
11026         SET(reset);
11027         SET(poll);
11028 -       
11029 +
11030         SET(event_del);
11031         SET(event_add);
11032 -       
11033 -       SET(event_next_fdndx);
11034 -       SET(event_get_fd);
11035 -       SET(event_get_revent);
11036 -       
11037 +
11038 +       SET(get_revents);
11039 +
11040         return 0;
11041  }
11042  
11043 --- ../lighttpd-1.4.11/src/fdevent_solaris_devpoll.c    2005-09-01 10:45:26.000000000 +0300
11044 +++ lighttpd-1.5.0/src/fdevent_solaris_devpoll.c        2006-07-16 00:26:03.000000000 +0300
11045 @@ -1,6 +1,5 @@
11046  #include <sys/types.h>
11047  
11048 -#include <unistd.h>
11049  #include <stdlib.h>
11050  #include <stdio.h>
11051  #include <string.h>
11052 @@ -23,55 +22,55 @@
11053  
11054  static int fdevent_solaris_devpoll_event_del(fdevents *ev, int fde_ndx, int fd) {
11055         struct pollfd pfd;
11056 -               
11057 +
11058         if (fde_ndx < 0) return -1;
11059 -       
11060 +
11061         pfd.fd = fd;
11062         pfd.events = POLLREMOVE;
11063         pfd.revents = 0;
11064 -       
11065 +
11066         if (-1 == write(ev->devpoll_fd, &pfd, sizeof(pfd))) {
11067 -               fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n", 
11068 -                       __FILE__, __LINE__, 
11069 +               fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n",
11070 +                       __FILE__, __LINE__,
11071                         fd, strerror(errno));
11072 -               
11073 +
11074                 return -1;
11075         }
11076 -       
11077 +
11078         return -1;
11079  }
11080  
11081  static int fdevent_solaris_devpoll_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
11082         struct pollfd pfd;
11083         int add = 0;
11084 -               
11085 +
11086         if (fde_ndx == -1) add = 1;
11087 -       
11088 +
11089         pfd.fd = fd;
11090         pfd.events = events;
11091         pfd.revents = 0;
11092 -       
11093 +
11094         if (-1 == write(ev->devpoll_fd, &pfd, sizeof(pfd))) {
11095 -               fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n", 
11096 -                       __FILE__, __LINE__, 
11097 +               fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n",
11098 +                       __FILE__, __LINE__,
11099                         fd, strerror(errno));
11100 -               
11101 +
11102                 return -1;
11103         }
11104 -       
11105 +
11106         return fd;
11107  }
11108  
11109  static int fdevent_solaris_devpoll_poll(fdevents *ev, int timeout_ms) {
11110         struct dvpoll dopoll;
11111         int ret;
11112 -       
11113 +
11114         dopoll.dp_timeout = timeout_ms;
11115         dopoll.dp_nfds = ev->maxfds;
11116         dopoll.dp_fds = ev->devpollfds;
11117 -       
11118 +
11119         ret = ioctl(ev->devpoll_fd, DP_POLL, &dopoll);
11120 -       
11121 +
11122         return ret;
11123  }
11124  
11125 @@ -85,11 +84,11 @@
11126  
11127  static int fdevent_solaris_devpoll_event_next_fdndx(fdevents *ev, int last_ndx) {
11128         size_t i;
11129 -       
11130 +
11131         UNUSED(ev);
11132  
11133         i = (last_ndx < 0) ? 0 : last_ndx + 1;
11134 -       
11135 +
11136         return i;
11137  }
11138  
11139 @@ -117,20 +116,20 @@
11140         ev->type = FDEVENT_HANDLER_SOLARIS_DEVPOLL;
11141  #define SET(x) \
11142         ev->x = fdevent_solaris_devpoll_##x;
11143 -       
11144 +
11145         SET(free);
11146         SET(poll);
11147         SET(reset);
11148 -       
11149 +
11150         SET(event_del);
11151         SET(event_add);
11152 -       
11153 +
11154         SET(event_next_fdndx);
11155         SET(event_get_fd);
11156         SET(event_get_revent);
11157 -       
11158 +
11159         ev->devpollfds = malloc(sizeof(*ev->devpollfds) * ev->maxfds);
11160 -       
11161 +
11162         if ((ev->devpoll_fd = open("/dev/poll", O_RDWR)) < 0) {
11163                 fprintf(stderr, "%s.%d: opening /dev/poll failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
11164                         __FILE__, __LINE__, strerror(errno));
11165 @@ -152,7 +151,7 @@
11166  
11167         fprintf(stderr, "%s.%d: solaris-devpoll not supported, try to set server.event-handler = \"poll\" or \"select\"\n",
11168                         __FILE__, __LINE__);
11169 -       
11170 +
11171         return -1;
11172  }
11173  #endif
11174 --- ../lighttpd-1.4.11/src/http-header-glue.c   2006-02-08 15:31:36.000000000 +0200
11175 +++ lighttpd-1.5.0/src/http-header-glue.c       2006-09-07 00:57:05.000000000 +0300
11176 @@ -45,20 +45,20 @@
11177  #   ifdef HAVE_STRUCT_SOCKADDR_STORAGE
11178  static size_t get_sa_len(const struct sockaddr *addr) {
11179         switch (addr->sa_family) {
11180 -               
11181 +
11182  #    ifdef AF_INET
11183         case AF_INET:
11184                 return (sizeof (struct sockaddr_in));
11185  #    endif
11186 -               
11187 +
11188  #    ifdef AF_INET6
11189         case AF_INET6:
11190                 return (sizeof (struct sockaddr_in6));
11191  #    endif
11192 -               
11193 +
11194         default:
11195                 return (sizeof (struct sockaddr));
11196 -               
11197 +
11198         }
11199  }
11200  #    define SA_LEN(addr)   (get_sa_len(addr))
11201 @@ -74,7 +74,7 @@
11202  
11203  int response_header_insert(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen) {
11204         data_string *ds;
11205 -       
11206 +
11207         UNUSED(srv);
11208  
11209         if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
11210 @@ -82,32 +82,32 @@
11211         }
11212         buffer_copy_string_len(ds->key, key, keylen);
11213         buffer_copy_string_len(ds->value, value, vallen);
11214 -       
11215 +
11216         array_insert_unique(con->response.headers, (data_unset *)ds);
11217 -       
11218 +
11219         return 0;
11220  }
11221  
11222  int response_header_overwrite(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen) {
11223         data_string *ds;
11224 -       
11225 +
11226         UNUSED(srv);
11227  
11228         /* if there already is a key by this name overwrite the value */
11229         if (NULL != (ds = (data_string *)array_get_element(con->response.headers, key))) {
11230                 buffer_copy_string(ds->value, value);
11231 -               
11232 +
11233                 return 0;
11234         }
11235 -       
11236 +
11237         return response_header_insert(srv, con, key, keylen, value, vallen);
11238  }
11239  
11240  int http_response_redirect_to_directory(server *srv, connection *con) {
11241         buffer *o;
11242 -       
11243 +
11244         o = buffer_init();
11245 -       
11246 +
11247         if (con->conf.is_ssl) {
11248                 buffer_copy_string(o, "https://");
11249         } else {
11250 @@ -123,36 +123,36 @@
11251  #endif
11252                 sock_addr our_addr;
11253                 socklen_t our_addr_len;
11254 -               
11255 +
11256                 our_addr_len = sizeof(our_addr);
11257 -               
11258 -               if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) {
11259 +
11260 +               if (-1 == getsockname(con->sock->fd, &(our_addr.plain), &our_addr_len)) {
11261                         con->http_status = 500;
11262 -                       
11263 +
11264                         log_error_write(srv, __FILE__, __LINE__, "ss",
11265                                         "can't get sockname", strerror(errno));
11266 -                       
11267 +
11268                         buffer_free(o);
11269                         return 0;
11270                 }
11271 -               
11272 -               
11273 +
11274 +
11275                 /* Lookup name: secondly try to get hostname for bind address */
11276                 switch(our_addr.plain.sa_family) {
11277  #ifdef HAVE_IPV6
11278                 case AF_INET6:
11279 -                       if (0 != getnameinfo((const struct sockaddr *)(&our_addr.ipv6), 
11280 -                                            SA_LEN((const struct sockaddr *)&our_addr.ipv6), 
11281 +                       if (0 != getnameinfo((const struct sockaddr *)(&our_addr.ipv6),
11282 +                                            SA_LEN((const struct sockaddr *)&our_addr.ipv6),
11283                                              hbuf, sizeof(hbuf), NULL, 0, 0)) {
11284 -                               
11285 +
11286                                 char dst[INET6_ADDRSTRLEN];
11287 -                               
11288 +
11289                                 log_error_write(srv, __FILE__, __LINE__,
11290                                                 "SSSS", "NOTICE: getnameinfo failed: ",
11291                                                 strerror(errno), ", using ip-address instead");
11292 -                               
11293 -                               buffer_append_string(o, 
11294 -                                                    inet_ntop(AF_INET6, (char *)&our_addr.ipv6.sin6_addr, 
11295 +
11296 +                               buffer_append_string(o,
11297 +                                                    inet_ntop(AF_INET6, (char *)&our_addr.ipv6.sin6_addr,
11298                                                                dst, sizeof(dst)));
11299                         } else {
11300                                 buffer_append_string(o, hbuf);
11301 @@ -164,7 +164,7 @@
11302                                 log_error_write(srv, __FILE__, __LINE__,
11303                                                 "SdSS", "NOTICE: gethostbyaddr failed: ",
11304                                                 h_errno, ", using ip-address instead");
11305 -                               
11306 +
11307                                 buffer_append_string(o, inet_ntoa(our_addr.ipv4.sin_addr));
11308                         } else {
11309                                 buffer_append_string(o, he->h_name);
11310 @@ -173,12 +173,12 @@
11311                 default:
11312                         log_error_write(srv, __FILE__, __LINE__,
11313                                         "S", "ERROR: unsupported address-type");
11314 -                       
11315 +
11316                         buffer_free(o);
11317                         return -1;
11318                 }
11319 -               
11320 -               if (!((con->conf.is_ssl == 0 && srv->srvconf.port == 80) || 
11321 +
11322 +               if (!((con->conf.is_ssl == 0 && srv->srvconf.port == 80) ||
11323                       (con->conf.is_ssl == 1 && srv->srvconf.port == 443))) {
11324                         buffer_append_string(o, ":");
11325                         buffer_append_long(o, srv->srvconf.port);
11326 @@ -190,46 +190,49 @@
11327                 buffer_append_string(o, "?");
11328                 buffer_append_string_buffer(o, con->uri.query);
11329         }
11330 -       
11331 +
11332         response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(o));
11333 -       
11334 +
11335         con->http_status = 301;
11336 -       con->file_finished = 1;
11337 -       
11338 +       con->send->is_closed = 1; /* no content */
11339 +
11340         buffer_free(o);
11341 -       
11342 +
11343         return 0;
11344  }
11345  
11346  buffer * strftime_cache_get(server *srv, time_t last_mod) {
11347         struct tm *tm;
11348         size_t i;
11349 -               
11350 +
11351         for (i = 0; i < FILE_CACHE_MAX; i++) {
11352                 /* found cache-entry */
11353                 if (srv->mtime_cache[i].mtime == last_mod) return srv->mtime_cache[i].str;
11354 -                               
11355 +
11356                 /* found empty slot */
11357                 if (srv->mtime_cache[i].mtime == 0) break;
11358         }
11359 -       
11360 +
11361         if (i == FILE_CACHE_MAX) {
11362                 i = 0;
11363         }
11364 -               
11365 +
11366         srv->mtime_cache[i].mtime = last_mod;
11367         buffer_prepare_copy(srv->mtime_cache[i].str, 1024);
11368         tm = gmtime(&(srv->mtime_cache[i].mtime));
11369 -       srv->mtime_cache[i].str->used = strftime(srv->mtime_cache[i].str->ptr, 
11370 +       srv->mtime_cache[i].str->used = strftime(srv->mtime_cache[i].str->ptr,
11371                                                  srv->mtime_cache[i].str->size - 1,
11372                                                  "%a, %d %b %Y %H:%M:%S GMT", tm);
11373         srv->mtime_cache[i].str->used++;
11374 -       
11375 +
11376         return srv->mtime_cache[i].str;
11377  }
11378  
11379  
11380  int http_response_handle_cachable(server *srv, connection *con, buffer *mtime) {
11381 +       data_string *http_if_none_match;
11382 +       data_string *http_if_modified_since;
11383 +
11384         /*
11385          * 14.26 If-None-Match
11386          *    [...]
11387 @@ -239,56 +242,63 @@
11388          *    request. That is, if no entity tags match, then the server MUST NOT
11389          *    return a 304 (Not Modified) response.
11390          */
11391 -       
11392 +
11393 +       http_if_none_match = (data_string *)array_get_element(con->request.headers, "if-none-match");
11394 +       http_if_modified_since = (data_string *)array_get_element(con->request.headers, "if-modified-since");
11395 +
11396         /* last-modified handling */
11397 -       if (con->request.http_if_none_match) {
11398 -               if (etag_is_equal(con->physical.etag, con->request.http_if_none_match)) {
11399 -                       if (con->request.http_method == HTTP_METHOD_GET || 
11400 +       if (http_if_none_match) {
11401 +               if (etag_is_equal(con->physical.etag, BUF_STR(http_if_none_match->value))) {
11402 +                       if (con->request.http_method == HTTP_METHOD_GET ||
11403                             con->request.http_method == HTTP_METHOD_HEAD) {
11404 -                               
11405 +
11406                                 /* check if etag + last-modified */
11407 -                               if (con->request.http_if_modified_since) {
11408 +                               if (http_if_modified_since) {
11409                                         size_t used_len;
11410                                         char *semicolon;
11411 -                                       
11412 -                                       if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) {
11413 -                                               used_len = strlen(con->request.http_if_modified_since);
11414 +
11415 +                                       if (NULL == (semicolon = strchr(BUF_STR(http_if_modified_since->value), ';'))) {
11416 +                                               used_len = http_if_modified_since->value->used - 1;
11417                                         } else {
11418 -                                               used_len = semicolon - con->request.http_if_modified_since;
11419 +                                               used_len = semicolon - BUF_STR(http_if_modified_since->value);
11420                                         }
11421 -                                       
11422 -                                       if (0 == strncmp(con->request.http_if_modified_since, mtime->ptr, used_len)) {
11423 +
11424 +                                       if (0 == strncmp(BUF_STR(http_if_modified_since->value), mtime->ptr, used_len)) {
11425                                                 con->http_status = 304;
11426                                                 return HANDLER_FINISHED;
11427                                         } else {
11428 +#ifdef HAVE_STRPTIME
11429                                                 char buf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
11430 +                                               time_t t_header, t_file;
11431 +                                               struct tm tm;
11432 +
11433 +                                               /* check if we can safely copy the string */
11434 +                                               if (used_len >= sizeof(buf)) {
11435 +                                                       TRACE("last-mod check failed as timestamp was too long: %s: %d, %d", 
11436 +                                                                       BUF_STR(http_if_modified_since->value), 
11437 +                                                                       used_len, sizeof(buf) - 1);
11438  
11439 -                                               /* convert to timestamp */
11440 -                                               if (used_len < sizeof(buf)) {
11441 -                                                       time_t t_header, t_file;
11442 -                                                       struct tm tm;
11443 -                                                       
11444 -                                                       strncpy(buf, con->request.http_if_modified_since, used_len);
11445 -                                                       buf[used_len] = '\0';
11446 -                                                       
11447 -                                                       strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm);
11448 -                                                       t_header = mktime(&tm);
11449 -                                                       
11450 -                                                       strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
11451 -                                                       t_file = mktime(&tm);
11452 -
11453 -                                                       if (t_file > t_header) {
11454 -                                                               con->http_status = 304;
11455 -                                                               return HANDLER_FINISHED;
11456 -                                                       }
11457 -                                               } else {
11458 -                                                       log_error_write(srv, __FILE__, __LINE__, "ssdd", 
11459 -                                                                       "DEBUG: Last-Modified check failed as the received timestamp was too long:", 
11460 -                                                                       con->request.http_if_modified_since, used_len, sizeof(buf) - 1);
11461 -                                                       
11462                                                         con->http_status = 412;
11463                                                         return HANDLER_FINISHED;
11464                                                 }
11465 +
11466 +
11467 +                                               strncpy(buf, BUF_STR(http_if_modified_since->value), used_len);
11468 +                                               buf[used_len] = '\0';
11469 +
11470 +                                               strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm);
11471 +                                               t_header = mktime(&tm);
11472 +
11473 +                                               strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
11474 +                                               t_file = mktime(&tm);
11475 +
11476 +                                               if (t_file > t_header) return HANDLER_GO_ON;
11477 +
11478 +                                               con->http_status = 304;
11479 +                                               return HANDLER_FINISHED;
11480 +#else
11481 +                                               return HANDLER_GO_ON;
11482 +#endif
11483                                         }
11484                                 } else {
11485                                         con->http_status = 304;
11486 @@ -299,19 +309,44 @@
11487                                 return HANDLER_FINISHED;
11488                         }
11489                 }
11490 -       } else if (con->request.http_if_modified_since) {
11491 +       } else if (http_if_modified_since) {
11492                 size_t used_len;
11493                 char *semicolon;
11494 -               
11495 -               if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) {
11496 -                       used_len = strlen(con->request.http_if_modified_since);
11497 +
11498 +               if (NULL == (semicolon = strchr(BUF_STR(http_if_modified_since->value), ';'))) {
11499 +                       used_len = http_if_modified_since->value->used - 1;
11500                 } else {
11501 -                       used_len = semicolon - con->request.http_if_modified_since;
11502 +                       used_len = semicolon - BUF_STR(http_if_modified_since->value);
11503                 }
11504 -               
11505 -               if (0 == strncmp(con->request.http_if_modified_since, mtime->ptr, used_len)) {
11506 +
11507 +               if (0 == strncmp(BUF_STR(http_if_modified_since->value), mtime->ptr, used_len)) {
11508                         con->http_status = 304;
11509                         return HANDLER_FINISHED;
11510 +               } else {
11511 +#ifdef HAVE_STRPTIME
11512 +                       char buf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
11513 +                       time_t t_header, t_file;
11514 +                       struct tm tm;
11515 +
11516 +                       /* convert to timestamp */
11517 +                       if (used_len >= sizeof(buf)) return HANDLER_GO_ON;
11518 +
11519 +                       strncpy(buf, BUF_STR(http_if_modified_since->value), used_len);
11520 +                       buf[used_len] = '\0';
11521 +
11522 +                       strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm);
11523 +                       t_header = mktime(&tm);
11524 +
11525 +                       strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
11526 +                       t_file = mktime(&tm);
11527 +
11528 +                       if (t_file > t_header) return HANDLER_GO_ON;
11529 +
11530 +                       con->http_status = 304;
11531 +                       return HANDLER_FINISHED;
11532 +#else
11533 +            return HANDLER_GO_ON;
11534 +#endif
11535                 }
11536         }
11537  
11538 --- ../lighttpd-1.4.11/src/http_auth.c  2006-02-01 13:02:52.000000000 +0200
11539 +++ lighttpd-1.5.0/src/http_auth.c      2006-09-07 00:57:05.000000000 +0300
11540 @@ -22,7 +22,6 @@
11541  #include <string.h>
11542  #include <time.h>
11543  #include <errno.h>
11544 -#include <unistd.h>
11545  #include <ctype.h>
11546  
11547  #include "server.h"
11548 @@ -31,23 +30,15 @@
11549  #include "http_auth_digest.h"
11550  #include "stream.h"
11551  
11552 +#include "sys-strings.h"
11553 +#include "sys-files.h"
11554 +
11555  #ifdef USE_OPENSSL
11556  # include <openssl/md5.h>
11557  #else
11558  # include "md5.h"
11559  #endif
11560  
11561 -
11562 -#ifdef USE_PAM
11563 -#include <security/pam_appl.h>
11564 -#include <security/pam_misc.h>
11565 -
11566 -static struct pam_conv conv = {
11567 -       misc_conv,
11568 -               NULL
11569 -};
11570 -#endif
11571 -
11572  handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s);
11573  
11574  static const char base64_pad = '=';
11575 @@ -75,25 +66,25 @@
11576         unsigned char *result;
11577         int ch, j = 0, k;
11578         size_t i;
11579 -       
11580 +
11581         size_t in_len = strlen(in);
11582 -       
11583 +
11584         buffer_prepare_copy(out, in_len);
11585 -       
11586 +
11587         result = (unsigned char *)out->ptr;
11588 -       
11589 +
11590         ch = in[0];
11591         /* run through the whole string, converting as we go */
11592         for (i = 0; i < in_len; i++) {
11593                 ch = in[i];
11594 -               
11595 +
11596                 if (ch == '\0') break;
11597 -               
11598 +
11599                 if (ch == base64_pad) break;
11600 -               
11601 +
11602                 ch = base64_reverse_table[ch];
11603                 if (ch < 0) continue;
11604 -               
11605 +
11606                 switch(i % 4) {
11607                 case 0:
11608                         result[j] = ch << 2;
11609 @@ -125,168 +116,168 @@
11610                 }
11611         }
11612         result[k] = '\0';
11613 -       
11614 +
11615         out->used = k;
11616 -       
11617 +
11618         return result;
11619  }
11620  
11621  static int http_auth_get_password(server *srv, mod_auth_plugin_data *p, buffer *username, buffer *realm, buffer *password) {
11622         int ret = -1;
11623 -       
11624 +
11625         if (!username->used|| !realm->used) return -1;
11626 -       
11627 +
11628         if (p->conf.auth_backend == AUTH_BACKEND_HTDIGEST) {
11629                 stream f;
11630                 char * f_line;
11631 -               
11632 +
11633                 if (buffer_is_empty(p->conf.auth_htdigest_userfile)) return -1;
11634 -               
11635 +
11636                 if (0 != stream_open(&f, p->conf.auth_htdigest_userfile)) {
11637                         log_error_write(srv, __FILE__, __LINE__, "sbss", "opening digest-userfile", p->conf.auth_htdigest_userfile, "failed:", strerror(errno));
11638 -                       
11639 +
11640                         return -1;
11641                 }
11642 -               
11643 +
11644                 f_line = f.start;
11645 -               
11646 +
11647                 while (f_line - f.start != f.size) {
11648                         char *f_user, *f_pwd, *e, *f_realm;
11649                         size_t u_len, pwd_len, r_len;
11650 -                       
11651 +
11652                         f_user = f_line;
11653 -                       
11654 -                       /* 
11655 +
11656 +                       /*
11657                          * htdigest format
11658 -                        * 
11659 -                        * user:realm:md5(user:realm:password) 
11660 +                        *
11661 +                        * user:realm:md5(user:realm:password)
11662                          */
11663 -                       
11664 +
11665                         if (NULL == (f_realm = memchr(f_user, ':', f.size - (f_user - f.start) ))) {
11666 -                               log_error_write(srv, __FILE__, __LINE__, "sbs", 
11667 -                                               "parsed error in", p->conf.auth_htdigest_userfile, 
11668 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
11669 +                                               "parsed error in", p->conf.auth_htdigest_userfile,
11670                                                 "expected 'username:realm:hashed password'");
11671 -                               
11672 +
11673                                 stream_close(&f);
11674 -                               
11675 +
11676                                 return -1;
11677                         }
11678 -                       
11679 +
11680                         if (NULL == (f_pwd = memchr(f_realm + 1, ':', f.size - (f_realm + 1 - f.start)))) {
11681 -                               log_error_write(srv, __FILE__, __LINE__, "sbs", 
11682 -                                               "parsed error in", p->conf.auth_plain_userfile, 
11683 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
11684 +                                               "parsed error in", p->conf.auth_plain_userfile,
11685                                                 "expected 'username:realm:hashed password'");
11686 -                               
11687 +
11688                                 stream_close(&f);
11689 -                               
11690 +
11691                                 return -1;
11692                         }
11693 -                       
11694 +
11695                         /* get pointers to the fields */
11696 -                       u_len = f_realm - f_user; 
11697 +                       u_len = f_realm - f_user;
11698                         f_realm++;
11699                         r_len = f_pwd - f_realm;
11700                         f_pwd++;
11701 -                       
11702 +
11703                         if (NULL != (e = memchr(f_pwd, '\n', f.size - (f_pwd - f.start)))) {
11704                                 pwd_len = e - f_pwd;
11705                         } else {
11706                                 pwd_len = f.size - (f_pwd - f.start);
11707                         }
11708 -                       
11709 +
11710                         if (username->used - 1 == u_len &&
11711                             (realm->used - 1 == r_len) &&
11712                             (0 == strncmp(username->ptr, f_user, u_len)) &&
11713                             (0 == strncmp(realm->ptr, f_realm, r_len))) {
11714                                 /* found */
11715 -                               
11716 +
11717                                 buffer_copy_string_len(password, f_pwd, pwd_len);
11718 -                               
11719 +
11720                                 ret = 0;
11721                                 break;
11722                         }
11723 -                       
11724 +
11725                         /* EOL */
11726                         if (!e) break;
11727 -                       
11728 +
11729                         f_line = e + 1;
11730                 }
11731 -               
11732 +
11733                 stream_close(&f);
11734         } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD ||
11735                    p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
11736                 stream f;
11737                 char * f_line;
11738                 buffer *auth_fn;
11739 -               
11740 +
11741                 auth_fn = (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) ? p->conf.auth_htpasswd_userfile : p->conf.auth_plain_userfile;
11742 -               
11743 +
11744                 if (buffer_is_empty(auth_fn)) return -1;
11745 -               
11746 +
11747                 if (0 != stream_open(&f, auth_fn)) {
11748 -                       log_error_write(srv, __FILE__, __LINE__, "sbss", 
11749 +                       log_error_write(srv, __FILE__, __LINE__, "sbss",
11750                                         "opening plain-userfile", auth_fn, "failed:", strerror(errno));
11751 -                       
11752 +
11753                         return -1;
11754                 }
11755 -               
11756 +
11757                 f_line = f.start;
11758 -               
11759 +
11760                 while (f_line - f.start != f.size) {
11761                         char *f_user, *f_pwd, *e;
11762                         size_t u_len, pwd_len;
11763 -                       
11764 +
11765                         f_user = f_line;
11766 -                       
11767 -                       /* 
11768 +
11769 +                       /*
11770                          * htpasswd format
11771 -                        * 
11772 +                        *
11773                          * user:crypted passwd
11774                          */
11775 -                       
11776 +
11777                         if (NULL == (f_pwd = memchr(f_user, ':', f.size - (f_user - f.start) ))) {
11778 -                               log_error_write(srv, __FILE__, __LINE__, "sbs", 
11779 -                                               "parsed error in", auth_fn, 
11780 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
11781 +                                               "parsed error in", auth_fn,
11782                                                 "expected 'username:hashed password'");
11783 -                               
11784 +
11785                                 stream_close(&f);
11786 -                               
11787 +
11788                                 return -1;
11789                         }
11790 -                       
11791 +
11792                         /* get pointers to the fields */
11793 -                       u_len = f_pwd - f_user; 
11794 +                       u_len = f_pwd - f_user;
11795                         f_pwd++;
11796 -                       
11797 +
11798                         if (NULL != (e = memchr(f_pwd, '\n', f.size - (f_pwd - f.start)))) {
11799                                 pwd_len = e - f_pwd;
11800                         } else {
11801                                 pwd_len = f.size - (f_pwd - f.start);
11802                         }
11803 -                       
11804 +
11805                         if (username->used - 1 == u_len &&
11806                             (0 == strncmp(username->ptr, f_user, u_len))) {
11807                                 /* found */
11808 -                               
11809 +
11810                                 buffer_copy_string_len(password, f_pwd, pwd_len);
11811 -                               
11812 +
11813                                 ret = 0;
11814                                 break;
11815                         }
11816 -                       
11817 +
11818                         /* EOL */
11819                         if (!e) break;
11820 -                       
11821 +
11822                         f_line = e + 1;
11823                 }
11824 -               
11825 +
11826                 stream_close(&f);
11827         } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) {
11828                 ret = 0;
11829         } else {
11830                 return -1;
11831         }
11832 -       
11833 +
11834         return ret;
11835  }
11836  
11837 @@ -296,7 +287,7 @@
11838         int username_len;
11839         data_string *require;
11840         array *req;
11841 -       
11842 +
11843         UNUSED(group);
11844         UNUSED(host);
11845  
11846 @@ -304,12 +295,12 @@
11847         /* search auth-directives for path */
11848         for (i = 0; i < p->conf.auth_require->used; i++) {
11849                 if (p->conf.auth_require->data[i]->key->used == 0) continue;
11850 -               
11851 +
11852                 if (0 == strncmp(url, p->conf.auth_require->data[i]->key->ptr, p->conf.auth_require->data[i]->key->used - 1)) {
11853                         break;
11854                 }
11855         }
11856 -       
11857 +
11858         if (i == p->conf.auth_require->used) {
11859                 return -1;
11860         }
11861 @@ -317,72 +308,72 @@
11862         req = ((data_array *)(p->conf.auth_require->data[i]))->value;
11863  
11864         require = (data_string *)array_get_element(req, "require");
11865 -       
11866 +
11867         /* if we get here, the user we got a authed user */
11868 -       if (0 == strcmp(require->value->ptr, "valid-user")) {
11869 +       if (buffer_is_equal_string(require->value, CONST_STR_LEN("valid-user"))) {
11870                 return 0;
11871         }
11872 -       
11873 +
11874         /* user=name1|group=name3|host=name4 */
11875 -       
11876 +
11877         /* seperate the string by | */
11878  #if 0
11879         log_error_write(srv, __FILE__, __LINE__, "sb", "rules", require->value);
11880 -#endif 
11881 -       
11882 +#endif
11883 +
11884         username_len = username ? strlen(username) : 0;
11885 -       
11886 +
11887         r = rules = require->value->ptr;
11888 -       
11889 +
11890         while (1) {
11891                 const char *eq;
11892                 const char *k, *v, *e;
11893                 int k_len, v_len, r_len;
11894 -               
11895 +
11896                 e = strchr(r, '|');
11897 -               
11898 +
11899                 if (e) {
11900                         r_len = e - r;
11901                 } else {
11902                         r_len = strlen(rules) - (r - rules);
11903                 }
11904 -               
11905 +
11906                 /* from r to r + r_len is a rule */
11907 -               
11908 +
11909                 if (0 == strncmp(r, "valid-user", r_len)) {
11910 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
11911 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
11912                                         "parsing the 'require' section in 'auth.require' failed: valid-user cannot be combined with other require rules",
11913                                         require->value);
11914                         return -1;
11915                 }
11916 -               
11917 +
11918                 /* search for = in the rules */
11919                 if (NULL == (eq = strchr(r, '='))) {
11920 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
11921 -                                       "parsing the 'require' section in 'auth.require' failed: a = is missing", 
11922 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
11923 +                                       "parsing the 'require' section in 'auth.require' failed: a = is missing",
11924                                         require->value);
11925                         return -1;
11926                 }
11927 -               
11928 +
11929                 /* = out of range */
11930                 if (eq > r + r_len) {
11931 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
11932 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
11933                                         "parsing the 'require' section in 'auth.require' failed: = out of range",
11934                                         require->value);
11935 -                       
11936 +
11937                         return -1;
11938                 }
11939 -               
11940 +
11941                 /* the part before the = is user|group|host */
11942 -               
11943 +
11944                 k = r;
11945                 k_len = eq - r;
11946                 v = eq + 1;
11947                 v_len = r_len - k_len - 1;
11948 -               
11949 +
11950                 if (k_len == 4) {
11951                         if (0 == strncmp(k, "user", k_len)) {
11952 -                               if (username && 
11953 +                               if (username &&
11954                                     username_len == v_len &&
11955                                     0 == strncmp(username, v, v_len)) {
11956                                         return 0;
11957 @@ -404,19 +395,19 @@
11958                         log_error_write(srv, __FILE__, __LINE__, "s", "unknown  key");
11959                         return -1;
11960                 }
11961 -               
11962 +
11963                 if (!e) break;
11964                 r = e + 1;
11965         }
11966 -       
11967 +
11968         log_error_write(srv, __FILE__, __LINE__, "s", "nothing matched");
11969 -       
11970 +
11971         return -1;
11972  }
11973  
11974  /**
11975 - * 
11976 - * 
11977 + *
11978 + *
11979   * @param password password-string from the auth-backend
11980   * @param pw       password-string from the client
11981   */
11982 @@ -426,16 +417,16 @@
11983         UNUSED(req);
11984  
11985         if (p->conf.auth_backend == AUTH_BACKEND_HTDIGEST) {
11986 -               /* 
11987 +               /*
11988                  * htdigest format
11989 -                * 
11990 -                * user:realm:md5(user:realm:password) 
11991 +                *
11992 +                * user:realm:md5(user:realm:password)
11993                  */
11994 -               
11995 +
11996                 MD5_CTX Md5Ctx;
11997                 HASH HA1;
11998                 char a1[256];
11999 -               
12000 +
12001                 MD5_Init(&Md5Ctx);
12002                 MD5_Update(&Md5Ctx, (unsigned char *)username->ptr, username->used - 1);
12003                 MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
12004 @@ -443,24 +434,24 @@
12005                 MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
12006                 MD5_Update(&Md5Ctx, (unsigned char *)pw, strlen(pw));
12007                 MD5_Final(HA1, &Md5Ctx);
12008 -               
12009 +
12010                 CvtHex(HA1, a1);
12011 -               
12012 -               if (0 == strcmp(password->ptr, a1)) {
12013 +
12014 +               if (buffer_is_equal_string(password, a1, strlen(a1))) {
12015                         return 0;
12016                 }
12017 -       } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) { 
12018 -#ifdef HAVE_CRYPT      
12019 +       } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) {
12020 +#ifdef HAVE_CRYPT
12021                 char salt[32];
12022                 char *crypted;
12023                 size_t salt_len = 0;
12024 -               /* 
12025 +               /*
12026                  * htpasswd format
12027 -                * 
12028 +                *
12029                  * user:crypted password
12030                  */
12031  
12032 -               /* 
12033 +               /*
12034                  *  Algorithm      Salt
12035                  *  CRYPT_STD_DES   2-character (Default)
12036                  *  CRYPT_EXT_DES   9-character
12037 @@ -478,7 +469,7 @@
12038                         salt_len = 2;
12039                 } else if (password->ptr[0] == '$' && password->ptr[2] == '$') {
12040                         char *dollar = NULL;
12041 -               
12042 +
12043                         if (NULL == (dollar = strchr(password->ptr + 3, '$'))) {
12044                                 fprintf(stderr, "%s.%d\n", __FILE__, __LINE__);
12045                                 return -1;
12046 @@ -495,48 +486,21 @@
12047                 strncpy(salt, password->ptr, salt_len);
12048  
12049                 salt[salt_len] = '\0';
12050 -               
12051 +
12052                 crypted = crypt(pw, salt);
12053  
12054 -               if (0 == strcmp(password->ptr, crypted)) {
12055 +               if (buffer_is_equal_string(password, crypted, strlen(crypted))) {
12056                         return 0;
12057                 } else {
12058                         fprintf(stderr, "%s.%d\n", __FILE__, __LINE__);
12059                 }
12060 -       
12061 -#endif 
12062 -       } else if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) { 
12063 -               if (0 == strcmp(password->ptr, pw)) {
12064 -                       return 0;
12065 -               }
12066 -       } else if (p->conf.auth_backend == AUTH_BACKEND_PAM) { 
12067 -#ifdef USE_PAM
12068 -               pam_handle_t *pamh=NULL;
12069 -               int retval;
12070 -               
12071 -               retval = pam_start("lighttpd", username->ptr, &conv, &pamh);
12072 -               
12073 -               if (retval == PAM_SUCCESS)
12074 -                       retval = pam_authenticate(pamh, 0);    /* is user really user? */
12075 -               
12076 -               if (retval == PAM_SUCCESS)
12077 -                       retval = pam_acct_mgmt(pamh, 0);       /* permitted access? */
12078 -               
12079 -               /* This is where we have been authorized or not. */
12080 -               
12081 -               if (pam_end(pamh,retval) != PAM_SUCCESS) {     /* close Linux-PAM */
12082 -                       pamh = NULL;
12083 -                       log_error_write(srv, __FILE__, __LINE__, "s", "failed to release authenticator");
12084 -               }
12085 -               
12086 -               if (retval == PAM_SUCCESS) {
12087 -                       log_error_write(srv, __FILE__, __LINE__, "s", "Authenticated");
12088 +
12089 +#endif
12090 +       } else if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
12091 +               if (buffer_is_equal_string(password, pw, strlen(pw))) {
12092                         return 0;
12093 -               } else {
12094 -                       log_error_write(srv, __FILE__, __LINE__, "s", "Not Authenticated");
12095                 }
12096 -#endif
12097 -       } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) { 
12098 +       } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) {
12099  #ifdef USE_LDAP
12100                 LDAP *ldap;
12101                 LDAPMessage *lm, *first;
12102 @@ -544,45 +508,45 @@
12103                 int ret;
12104                 char *attrs[] = { LDAP_NO_ATTRS, NULL };
12105                 size_t i;
12106 -               
12107 +
12108                 /* for now we stay synchronous */
12109 -               
12110 -               /* 
12111 +
12112 +               /*
12113                  * 1. connect anonymously (done in plugin init)
12114                  * 2. get DN for uid = username
12115                  * 3. auth against ldap server
12116                  * 4. (optional) check a field
12117                  * 5. disconnect
12118 -                * 
12119 +                *
12120                  */
12121 -               
12122 +
12123                 /* check username
12124 -                * 
12125 +                *
12126                  * we have to protect us againt username which modifies out filter in
12127                  * a unpleasant way
12128                  */
12129 -               
12130 +
12131                 for (i = 0; i < username->used - 1; i++) {
12132                         char c = username->ptr[i];
12133 -                       
12134 +
12135                         if (!isalpha(c) &&
12136                             !isdigit(c)) {
12137 -                               
12138 -                               log_error_write(srv, __FILE__, __LINE__, "sbd", 
12139 +
12140 +                               log_error_write(srv, __FILE__, __LINE__, "sbd",
12141                                         "ldap: invalid character (a-zA-Z0-9 allowed) in username:", username, i);
12142 -                               
12143 +
12144                                 return -1;
12145                         }
12146                 }
12147 -               
12148 -               
12149 -               
12150 +
12151 +
12152 +
12153                 /* build filter */
12154                 buffer_copy_string_buffer(p->ldap_filter, p->conf.ldap_filter_pre);
12155                 buffer_append_string_buffer(p->ldap_filter, username);
12156                 buffer_append_string_buffer(p->ldap_filter, p->conf.ldap_filter_post);
12157 -               
12158 -               
12159 +
12160 +
12161                 /* 2. */
12162                 if (p->conf.ldap == NULL ||
12163                     LDAP_SUCCESS != (ret = ldap_search_s(p->conf.ldap, p->conf.auth_ldap_basedn->ptr, LDAP_SCOPE_SUBTREE, p->ldap_filter->ptr, attrs, 0, &lm))) {
12164 @@ -590,71 +554,71 @@
12165                                 return -1;
12166                         if (LDAP_SUCCESS != (ret = ldap_search_s(p->conf.ldap, p->conf.auth_ldap_basedn->ptr, LDAP_SCOPE_SUBTREE, p->ldap_filter->ptr, attrs, 0, &lm))) {
12167  
12168 -                       log_error_write(srv, __FILE__, __LINE__, "sssb", 
12169 +                       log_error_write(srv, __FILE__, __LINE__, "sssb",
12170                                         "ldap:", ldap_err2string(ret), "filter:", p->ldap_filter);
12171 -                       
12172 +
12173                         return -1;
12174                         }
12175                 }
12176 -               
12177 +
12178                 if (NULL == (first = ldap_first_entry(p->conf.ldap, lm))) {
12179                         log_error_write(srv, __FILE__, __LINE__, "s", "ldap ...");
12180 -                       
12181 +
12182                         ldap_msgfree(lm);
12183 -                       
12184 +
12185                         return -1;
12186                 }
12187 -               
12188 +
12189                 if (NULL == (dn = ldap_get_dn(p->conf.ldap, first))) {
12190                         log_error_write(srv, __FILE__, __LINE__, "s", "ldap ...");
12191 -                       
12192 +
12193                         ldap_msgfree(lm);
12194 -                       
12195 +
12196                         return -1;
12197                 }
12198 -               
12199 +
12200                 ldap_msgfree(lm);
12201 -               
12202 -               
12203 +
12204 +
12205                 /* 3. */
12206                 if (NULL == (ldap = ldap_init(p->conf.auth_ldap_hostname->ptr, LDAP_PORT))) {
12207                         log_error_write(srv, __FILE__, __LINE__, "ss", "ldap ...", strerror(errno));
12208                         return -1;
12209                 }
12210 -               
12211 +
12212                 ret = LDAP_VERSION3;
12213                 if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &ret))) {
12214                         log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
12215 -                       
12216 +
12217                         ldap_unbind_s(ldap);
12218 -                       
12219 +
12220                         return -1;
12221                 }
12222 -               
12223 +
12224                 if (p->conf.auth_ldap_starttls == 1) {
12225                         if (LDAP_OPT_SUCCESS != (ret = ldap_start_tls_s(ldap, NULL,  NULL))) {
12226                                 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap startTLS failed:", ldap_err2string(ret));
12227 -               
12228 +
12229                                 ldap_unbind_s(ldap);
12230 -                               
12231 +
12232                                 return -1;
12233                         }
12234                 }
12235  
12236 -               
12237 +
12238                 if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(ldap, dn, pw))) {
12239                         log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
12240 -                       
12241 +
12242                         ldap_unbind_s(ldap);
12243 -                       
12244 +
12245                         return -1;
12246                 }
12247 -               
12248 +
12249                 /* 5. */
12250                 ldap_unbind_s(ldap);
12251 -               
12252 +
12253                 /* everything worked, good, access granted */
12254 -               
12255 +
12256                 return 0;
12257  #endif
12258         }
12259 @@ -664,65 +628,65 @@
12260  int http_auth_basic_check(server *srv, connection *con, mod_auth_plugin_data *p, array *req, buffer *url, const char *realm_str) {
12261         buffer *username, *password;
12262         char *pw;
12263 -       
12264 +
12265         data_string *realm;
12266 -       
12267 +
12268         realm = (data_string *)array_get_element(req, "realm");
12269 -       
12270 +
12271         username = buffer_init();
12272         password = buffer_init();
12273 -       
12274 +
12275         base64_decode(username, realm_str);
12276 -       
12277 +
12278         /* r2 == user:password */
12279         if (NULL == (pw = strchr(username->ptr, ':'))) {
12280                 buffer_free(username);
12281 -               
12282 +
12283                 log_error_write(srv, __FILE__, __LINE__, "sb", ": is missing in", username);
12284 -               
12285 +
12286                 return 0;
12287         }
12288 -       
12289 +
12290         *pw++ = '\0';
12291 -       
12292 +
12293         username->used = pw - username->ptr;
12294 -       
12295 +
12296         /* copy password to r1 */
12297         if (http_auth_get_password(srv, p, username, realm->value, password)) {
12298                 buffer_free(username);
12299                 buffer_free(password);
12300 -               
12301 +
12302                 log_error_write(srv, __FILE__, __LINE__, "s", "get_password failed");
12303 -               
12304 +
12305                 return 0;
12306         }
12307 -       
12308 +
12309         /* password doesn't match */
12310         if (http_auth_basic_password_compare(srv, p, req, username, realm->value, password, pw)) {
12311                 log_error_write(srv, __FILE__, __LINE__, "sbb", "password doesn't match for", con->uri.path, username);
12312 -               
12313 +
12314                 buffer_free(username);
12315                 buffer_free(password);
12316 -               
12317 +
12318                 return 0;
12319         }
12320 -       
12321 +
12322         /* value is our allow-rules */
12323         if (http_auth_match_rules(srv, p, url->ptr, username->ptr, NULL, NULL)) {
12324                 buffer_free(username);
12325                 buffer_free(password);
12326 -               
12327 +
12328                 log_error_write(srv, __FILE__, __LINE__, "s", "rules didn't match");
12329 -               
12330 +
12331                 return 0;
12332         }
12333 -       
12334 +
12335         /* remember the username */
12336         buffer_copy_string_buffer(p->auth_user, username);
12337 -       
12338 +
12339         buffer_free(username);
12340         buffer_free(password);
12341 -       
12342 +
12343         return 1;
12344  }
12345  
12346 @@ -735,7 +699,7 @@
12347  int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p, array *req, buffer *url, const char *realm_str) {
12348         char a1[256];
12349         char a2[256];
12350 -       
12351 +
12352         char *username;
12353         char *realm;
12354         char *nonce;
12355 @@ -745,18 +709,18 @@
12356         char *cnonce;
12357         char *nc;
12358         char *respons;
12359 -       
12360 +
12361         char *e, *c;
12362         const char *m = NULL;
12363         int i;
12364         buffer *password, *b, *username_buf, *realm_buf;
12365 -       
12366 +
12367         MD5_CTX Md5Ctx;
12368         HASH HA1;
12369         HASH HA2;
12370         HASH RespHash;
12371         HASHHEX HA2Hex;
12372 -       
12373 +
12374  
12375         /* init pointers */
12376  #define S(x) \
12377 @@ -771,11 +735,11 @@
12378                 { S("cnonce=") },
12379                 { S("nc=") },
12380                 { S("response=") },
12381 -               
12382 +
12383                 { NULL, 0, NULL }
12384         };
12385  #undef S
12386 -       
12387 +
12388         dkv[0].ptr = &username;
12389         dkv[1].ptr = &realm;
12390         dkv[2].ptr = &nonce;
12391 @@ -786,24 +750,24 @@
12392         dkv[7].ptr = &nc;
12393         dkv[8].ptr = &respons;
12394         dkv[9].ptr = NULL;
12395 -       
12396 +
12397         UNUSED(req);
12398 -       
12399 +
12400         for (i = 0; dkv[i].key; i++) {
12401                 *(dkv[i].ptr) = NULL;
12402         }
12403 -       
12404 -       
12405 +
12406 +
12407         if (p->conf.auth_backend != AUTH_BACKEND_HTDIGEST &&
12408             p->conf.auth_backend != AUTH_BACKEND_PLAIN) {
12409 -               log_error_write(srv, __FILE__, __LINE__, "s", 
12410 +               log_error_write(srv, __FILE__, __LINE__, "s",
12411                                 "digest: unsupported backend (only htdigest or plain)");
12412 -               
12413 +
12414                 return -1;
12415         }
12416 -       
12417 +
12418         b = buffer_init_string(realm_str);
12419 -       
12420 +
12421         /* parse credentials from client */
12422         for (c = b->ptr; *c; c++) {
12423                 /* skip whitespaces */
12424 @@ -812,18 +776,18 @@
12425  
12426                 for (i = 0; dkv[i].key; i++) {
12427                         if ((0 == strncmp(c, dkv[i].key, dkv[i].key_len))) {
12428 -                               if ((c[dkv[i].key_len] == '"') && 
12429 +                               if ((c[dkv[i].key_len] == '"') &&
12430                                     (NULL != (e = strchr(c + dkv[i].key_len + 1, '"')))) {
12431                                         /* value with "..." */
12432                                         *(dkv[i].ptr) = c + dkv[i].key_len + 1;
12433                                         c = e;
12434 -       
12435 +
12436                                         *e = '\0';
12437                                 } else if (NULL != (e = strchr(c + dkv[i].key_len, ','))) {
12438                                         /* value without "...", terminated by ',' */
12439                                         *(dkv[i].ptr) = c + dkv[i].key_len;
12440                                         c = e;
12441 -                                       
12442 +
12443                                         *e = '\0';
12444                                 } else {
12445                                         /* value without "...", terminated by EOL */
12446 @@ -833,7 +797,7 @@
12447                         }
12448                 }
12449         }
12450 -       
12451 +
12452         if (p->conf.auth_debug > 1) {
12453                 log_error_write(srv, __FILE__, __LINE__, "ss", "username", username);
12454                 log_error_write(srv, __FILE__, __LINE__, "ss", "realm", realm);
12455 @@ -845,22 +809,22 @@
12456                 log_error_write(srv, __FILE__, __LINE__, "ss", "nc", nc);
12457                 log_error_write(srv, __FILE__, __LINE__, "ss", "response", respons);
12458         }
12459 -       
12460 +
12461         /* check if everything is transmitted */
12462 -       if (!username || 
12463 +       if (!username ||
12464             !realm ||
12465             !nonce ||
12466             !uri ||
12467             (qop && (!nc || !cnonce)) ||
12468             !respons ) {
12469                 /* missing field */
12470 -               
12471 -               log_error_write(srv, __FILE__, __LINE__, "s", 
12472 +
12473 +               log_error_write(srv, __FILE__, __LINE__, "s",
12474                                 "digest: missing field");
12475                 return -1;
12476         }
12477  
12478 -       m = get_http_method_name(con->request.http_method);     
12479 +       m = get_http_method_name(con->request.http_method);
12480  
12481         /* password-string == HA1 */
12482         password = buffer_init();
12483 @@ -873,10 +837,10 @@
12484                 buffer_free(realm_buf);
12485                 return 0;
12486         }
12487 -       
12488 +
12489         buffer_free(username_buf);
12490         buffer_free(realm_buf);
12491 -       
12492 +
12493         if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
12494                 /* generate password from plain-text */
12495                 MD5_Init(&Md5Ctx);
12496 @@ -890,16 +854,16 @@
12497                 /* HA1 */
12498                 /* transform the 32-byte-hex-md5 to a 16-byte-md5 */
12499                 for (i = 0; i < HASHLEN; i++) {
12500 -                       HA1[i] = hex2int(password->ptr[i*2]) << 4; 
12501 -                       HA1[i] |= hex2int(password->ptr[i*2+1]); 
12502 +                       HA1[i] = hex2int(password->ptr[i*2]) << 4;
12503 +                       HA1[i] |= hex2int(password->ptr[i*2+1]);
12504                 }
12505         } else {
12506                 /* we already check that above */
12507                 SEGFAULT();
12508         }
12509 -       
12510 +
12511         buffer_free(password);
12512 -       
12513 +
12514         if (algorithm &&
12515             strcasecmp(algorithm, "md5-sess") == 0) {
12516                 MD5_Init(&Md5Ctx);
12517 @@ -910,9 +874,9 @@
12518                 MD5_Update(&Md5Ctx, (unsigned char *)cnonce, strlen(cnonce));
12519                 MD5_Final(HA1, &Md5Ctx);
12520         }
12521 -       
12522 +
12523         CvtHex(HA1, a1);
12524 -       
12525 +
12526         /* calculate H(A2) */
12527         MD5_Init(&Md5Ctx);
12528         MD5_Update(&Md5Ctx, (unsigned char *)m, strlen(m));
12529 @@ -924,7 +888,7 @@
12530         }
12531         MD5_Final(HA2, &Md5Ctx);
12532         CvtHex(HA2, HA2Hex);
12533 -       
12534 +
12535         /* calculate response */
12536         MD5_Init(&Md5Ctx);
12537         MD5_Update(&Md5Ctx, (unsigned char *)a1, HASHHEXLEN);
12538 @@ -942,39 +906,39 @@
12539         MD5_Update(&Md5Ctx, (unsigned char *)HA2Hex, HASHHEXLEN);
12540         MD5_Final(RespHash, &Md5Ctx);
12541         CvtHex(RespHash, a2);
12542 -       
12543 +
12544         if (0 != strcmp(a2, respons)) {
12545                 /* digest not ok */
12546 -               
12547 +
12548                 if (p->conf.auth_debug) {
12549 -                       log_error_write(srv, __FILE__, __LINE__, "sss", 
12550 +                       log_error_write(srv, __FILE__, __LINE__, "sss",
12551                                 "digest: digest mismatch", a2, respons);
12552                 }
12553 -               
12554 -               log_error_write(srv, __FILE__, __LINE__, "sss", 
12555 +
12556 +               log_error_write(srv, __FILE__, __LINE__, "sss",
12557                                 "digest: auth failed for", username, "wrong password");
12558 -               
12559 +
12560                 buffer_free(b);
12561                 return 0;
12562         }
12563 -       
12564 +
12565         /* value is our allow-rules */
12566         if (http_auth_match_rules(srv, p, url->ptr, username, NULL, NULL)) {
12567                 buffer_free(b);
12568 -               
12569 -               log_error_write(srv, __FILE__, __LINE__, "s", 
12570 +
12571 +               log_error_write(srv, __FILE__, __LINE__, "s",
12572                                 "digest: rules did match");
12573 -               
12574 +
12575                 return 0;
12576         }
12577 -       
12578 +
12579         /* remember the username */
12580         buffer_copy_string(p->auth_user, username);
12581 -       
12582 +
12583         buffer_free(b);
12584 -       
12585 +
12586         if (p->conf.auth_debug) {
12587 -               log_error_write(srv, __FILE__, __LINE__, "s", 
12588 +               log_error_write(srv, __FILE__, __LINE__, "s",
12589                                 "digest: auth ok");
12590         }
12591         return 1;
12592 @@ -985,23 +949,23 @@
12593         HASH h;
12594         MD5_CTX Md5Ctx;
12595         char hh[32];
12596 -       
12597 +
12598         UNUSED(p);
12599  
12600         /* generate shared-secret */
12601         MD5_Init(&Md5Ctx);
12602         MD5_Update(&Md5Ctx, (unsigned char *)fn->ptr, fn->used - 1);
12603         MD5_Update(&Md5Ctx, (unsigned char *)"+", 1);
12604 -       
12605 +
12606         /* we assume sizeof(time_t) == 4 here, but if not it ain't a problem at all */
12607         ltostr(hh, srv->cur_ts);
12608         MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
12609         ltostr(hh, rand());
12610         MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
12611 -       
12612 +
12613         MD5_Final(h, &Md5Ctx);
12614 -       
12615 +
12616         CvtHex(h, out);
12617 -       
12618 +
12619         return 0;
12620  }
12621 --- ../lighttpd-1.4.11/src/http_auth.h  2005-08-14 17:12:31.000000000 +0300
12622 +++ lighttpd-1.5.0/src/http_auth.h      2006-07-16 00:26:04.000000000 +0300
12623 @@ -9,22 +9,26 @@
12624  # include <ldap.h>
12625  #endif
12626  
12627 -typedef enum { AUTH_BACKEND_UNSET, AUTH_BACKEND_PLAIN, 
12628 -               AUTH_BACKEND_LDAP, AUTH_BACKEND_HTPASSWD, 
12629 -               AUTH_BACKEND_HTDIGEST, AUTH_BACKEND_PAM } auth_backend_t;
12630 +typedef enum {
12631 +       AUTH_BACKEND_UNSET,
12632 +       AUTH_BACKEND_PLAIN,
12633 +       AUTH_BACKEND_LDAP,
12634 +       AUTH_BACKEND_HTPASSWD,
12635 +       AUTH_BACKEND_HTDIGEST
12636 +} auth_backend_t;
12637  
12638  typedef struct {
12639         /* auth */
12640         array  *auth_require;
12641 -       
12642 +
12643         buffer *auth_plain_groupfile;
12644         buffer *auth_plain_userfile;
12645 -       
12646 +
12647         buffer *auth_htdigest_userfile;
12648         buffer *auth_htpasswd_userfile;
12649 -       
12650 +
12651         buffer *auth_backend_conf;
12652 -       
12653 +
12654         buffer *auth_ldap_hostname;
12655         buffer *auth_ldap_basedn;
12656         buffer *auth_ldap_binddn;
12657 @@ -32,15 +36,15 @@
12658         buffer *auth_ldap_filter;
12659         buffer *auth_ldap_cafile;
12660         unsigned short auth_ldap_starttls;
12661 -       
12662 +
12663         unsigned short auth_debug;
12664 -       
12665 +
12666         /* generated */
12667         auth_backend_t auth_backend;
12668 -       
12669 +
12670  #ifdef USE_LDAP
12671         LDAP *ldap;
12672 -       
12673 +
12674         buffer *ldap_filter_pre;
12675         buffer *ldap_filter_post;
12676  #endif
12677 @@ -49,15 +53,15 @@
12678  typedef struct {
12679         PLUGIN_DATA;
12680         buffer *tmp_buf;
12681 -       
12682 +
12683         buffer *auth_user;
12684  
12685  #ifdef USE_LDAP
12686         buffer *ldap_filter;
12687  #endif
12688 -       
12689 +
12690         mod_auth_plugin_config **config_storage;
12691 -       
12692 +
12693         mod_auth_plugin_config conf; /* this is only used as long as no handler_ctx is setup */
12694  } mod_auth_plugin_data;
12695  
12696 --- ../lighttpd-1.4.11/src/http_auth_digest.h   2006-01-05 00:54:01.000000000 +0200
12697 +++ lighttpd-1.5.0/src/http_auth_digest.h       2006-07-16 00:26:04.000000000 +0300
12698 @@ -12,7 +12,7 @@
12699  #ifdef USE_OPENSSL
12700  #define IN const
12701  #else
12702 -#define IN 
12703 +#define IN
12704  #endif
12705  #define OUT
12706  
12707 --- ../lighttpd-1.4.11/src/http_chunk.c 2005-08-11 01:26:50.000000000 +0300
12708 +++ lighttpd-1.5.0/src/http_chunk.c     1970-01-01 03:00:00.000000000 +0300
12709 @@ -1,133 +0,0 @@
12710 -/**
12711 - * the HTTP chunk-API
12712 - * 
12713 - * 
12714 - */
12715 -
12716 -#include <sys/types.h>
12717 -#include <sys/stat.h>
12718 -
12719 -#include <stdlib.h>
12720 -#include <fcntl.h>
12721 -#include <unistd.h>
12722 -
12723 -#include <stdio.h>
12724 -#include <errno.h>
12725 -#include <string.h>
12726 -
12727 -#include "server.h"
12728 -#include "chunk.h"
12729 -#include "http_chunk.h"
12730 -#include "log.h"
12731 -
12732 -static int http_chunk_append_len(server *srv, connection *con, size_t len) {
12733 -       size_t i, olen = len, j;
12734 -       buffer *b;
12735 -       
12736 -       b = srv->tmp_chunk_len;
12737 -       
12738 -       if (len == 0) {
12739 -               buffer_copy_string(b, "0");
12740 -       } else {
12741 -               for (i = 0; i < 8 && len; i++) {
12742 -                       len >>= 4;
12743 -               }
12744 -               
12745 -               /* i is the number of hex digits we have */
12746 -               buffer_prepare_copy(b, i + 1);
12747 -               
12748 -               for (j = i-1, len = olen; j+1 > 0; j--) {
12749 -                       b->ptr[j] = (len & 0xf) + (((len & 0xf) <= 9) ? '0' : 'a' - 10);
12750 -                       len >>= 4;
12751 -               }
12752 -               b->used = i;
12753 -               b->ptr[b->used++] = '\0';
12754 -       }
12755 -               
12756 -       buffer_append_string(b, "\r\n");
12757 -       chunkqueue_append_buffer(con->write_queue, b);
12758 -       
12759 -       return 0;
12760 -}
12761 -
12762 -
12763 -int http_chunk_append_file(server *srv, connection *con, buffer *fn, off_t offset, off_t len) {
12764 -       chunkqueue *cq;
12765 -       
12766 -       if (!con) return -1;
12767 -       
12768 -       cq = con->write_queue;
12769 -       
12770 -       if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
12771 -               http_chunk_append_len(srv, con, len);
12772 -       }
12773 -       
12774 -       chunkqueue_append_file(cq, fn, offset, len);
12775 -       
12776 -       if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED && len > 0) {
12777 -               chunkqueue_append_mem(cq, "\r\n", 2 + 1);
12778 -       }
12779 -       
12780 -       return 0;
12781 -}
12782 -
12783 -int http_chunk_append_buffer(server *srv, connection *con, buffer *mem) {
12784 -       chunkqueue *cq;
12785 -       
12786 -       if (!con) return -1;
12787 -       
12788 -       cq = con->write_queue;
12789 -       
12790 -       if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
12791 -               http_chunk_append_len(srv, con, mem->used - 1);
12792 -       }
12793 -       
12794 -       chunkqueue_append_buffer(cq, mem);
12795 -       
12796 -       if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED && mem->used > 0) {
12797 -               chunkqueue_append_mem(cq, "\r\n", 2 + 1);
12798 -       }
12799 -       
12800 -       return 0;
12801 -}
12802 -
12803 -int http_chunk_append_mem(server *srv, connection *con, const char * mem, size_t len) {
12804 -       chunkqueue *cq;
12805 -       
12806 -       if (!con) return -1;
12807 -       
12808 -       cq = con->write_queue;
12809 -       
12810 -       if (len == 0) {
12811 -               if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
12812 -                       http_chunk_append_len(srv, con, 0);
12813 -                       chunkqueue_append_mem(cq, "\r\n", 2 + 1);
12814 -               } else {
12815 -                       chunkqueue_append_mem(cq, "", 1);
12816 -               }
12817 -               return 0;
12818 -       }
12819 -       
12820 -       if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
12821 -               http_chunk_append_len(srv, con, len - 1);
12822 -       }
12823 -       
12824 -       chunkqueue_append_mem(cq, mem, len);
12825 -       
12826 -       if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
12827 -               chunkqueue_append_mem(cq, "\r\n", 2 + 1);
12828 -       }
12829 -       
12830 -       return 0;
12831 -}
12832 -
12833 -
12834 -off_t http_chunkqueue_length(server *srv, connection *con) {
12835 -       if (!con) {
12836 -               log_error_write(srv, __FILE__, __LINE__, "s", "connection is NULL!!");
12837 -               
12838 -               return 0;
12839 -       }
12840 -       
12841 -       return chunkqueue_length(con->write_queue);
12842 -}
12843 --- ../lighttpd-1.4.11/src/http_chunk.h 2005-08-11 01:26:50.000000000 +0300
12844 +++ lighttpd-1.5.0/src/http_chunk.h     1970-01-01 03:00:00.000000000 +0300
12845 @@ -1,12 +0,0 @@
12846 -#ifndef _HTTP_CHUNK_H_
12847 -#define _HTTP_CHUNK_H_
12848 -
12849 -#include "server.h"
12850 -#include <sys/types.h>
12851 -
12852 -int http_chunk_append_mem(server *srv, connection *con, const char * mem, size_t len);
12853 -int http_chunk_append_buffer(server *srv, connection *con, buffer *mem);
12854 -int http_chunk_append_file(server *srv, connection *con, buffer *fn, off_t offset, off_t len);
12855 -off_t http_chunkqueue_length(server *srv, connection *con);
12856 -
12857 -#endif
12858 --- ../lighttpd-1.4.11/src/http_parser.h        1970-01-01 03:00:00.000000000 +0300
12859 +++ lighttpd-1.5.0/src/http_parser.h    2006-09-07 00:57:05.000000000 +0300
12860 @@ -0,0 +1,11 @@
12861 +#ifndef _HTTP_PARSER_H_
12862 +#define _HTTP_PARSER_H_
12863 +
12864 +typedef enum {
12865 +    PARSE_UNSET,
12866 +    PARSE_SUCCESS,
12867 +    PARSE_ERROR,
12868 +    PARSE_NEED_MORE
12869 +} parse_status_t;
12870 +
12871 +#endif
12872 --- ../lighttpd-1.4.11/src/http_req.c   1970-01-01 03:00:00.000000000 +0300
12873 +++ lighttpd-1.5.0/src/http_req.c       2006-09-07 00:57:05.000000000 +0300
12874 @@ -0,0 +1,301 @@
12875 +#include <string.h>
12876 +#include <stdlib.h>
12877 +#include <stdio.h>
12878 +#include <assert.h>
12879 +
12880 +#include "log.h"
12881 +#include "http_req.h"
12882 +#include "http_req_parser.h"
12883 +
12884 +/* declare prototypes for the parser */
12885 +void *http_req_parserAlloc(void *(*mallocProc)(size_t));
12886 +void http_req_parserFree(void *p,  void (*freeProc)(void*));
12887 +void http_req_parserTrace(FILE *TraceFILE, char *zTracePrompt);
12888 +void http_req_parser(void *, int, buffer *, http_req_ctx_t *);
12889 +
12890 +typedef struct {
12891 +       chunkqueue *cq;
12892 +
12893 +       chunk *c; /* current chunk in the chunkqueue */
12894 +       size_t offset; /* current offset in current chunk */
12895 +
12896 +       chunk *lookup_c;
12897 +       size_t lookup_offset;
12898 +
12899 +       int last_token_id;
12900 +
12901 +       int is_key;
12902 +       int is_statusline;
12903 +} http_req_tokenizer_t;
12904 +
12905 +http_req *http_request_init(void) {
12906 +       http_req *req = calloc(1, sizeof(*req));
12907 +
12908 +       req->uri_raw = buffer_init();
12909 +       req->headers = array_init();
12910 +
12911 +       return req;
12912 +}
12913 +
12914 +void http_request_reset(http_req *req) {
12915 +       if (!req) return;
12916 +
12917 +       buffer_reset(req->uri_raw);
12918 +       array_reset(req->headers);
12919 +
12920 +}
12921 +
12922 +void http_request_free(http_req *req) {
12923 +       if (!req) return;
12924 +
12925 +       buffer_free(req->uri_raw);
12926 +       array_free(req->headers);
12927 +
12928 +       free(req);
12929 +}
12930 +
12931 +static int http_req_get_next_char(http_req_tokenizer_t *t, unsigned char *c) {
12932 +       if (t->c->mem->used == 0) {
12933 +               TRACE("chunk-len: %zd", t->c->mem->used);
12934 +       }
12935 +
12936 +       if (t->offset == t->c->mem->used - 1) {
12937 +               /* end of chunk, open next chunk */
12938 +
12939 +               if (!t->c->next) return -1;
12940 +
12941 +               t->c = t->c->next;
12942 +               /* skip empty chunks */
12943 +               while (t->c && t->c->mem->used == 0) t->c = t->c->next;
12944 +               if (!t->c) return -1;
12945 +
12946 +               t->offset = 0;
12947 +       }
12948 +
12949 +       *c = t->c->mem->ptr[t->offset++];
12950 +
12951 +       t->lookup_offset = t->offset;
12952 +       t->lookup_c = t->c;
12953 +
12954 +#if 0
12955 +       fprintf(stderr, "%s.%d: get: %c (%d) at offset: %d\r\n", __FILE__, __LINE__, *c > 31 ? *c : ' ', *c, t->offset - 1);
12956 +#endif
12957 +
12958 +       return 0;
12959 +}
12960 +
12961 +static int http_req_lookup_next_char(http_req_tokenizer_t *t, unsigned char *c) {
12962 +       if (t->lookup_c->mem->used == 0) {
12963 +               TRACE("chunk-len: %zd", t->lookup_c->mem->used);
12964 +       }
12965 +       if (t->lookup_offset == t->lookup_c->mem->used - 1) {
12966 +               /* end of chunk, open next chunk */
12967 +
12968 +               if (!t->lookup_c->next) return -1;
12969 +
12970 +               t->lookup_c = t->lookup_c->next;
12971 +
12972 +               /* skip empty chunks */
12973 +               while (t->lookup_c && t->lookup_c->mem->used == 0) t->lookup_c = t->lookup_c->next;
12974 +               if (!t->lookup_c) return -1;
12975 +
12976 +               t->lookup_offset = 0;
12977 +       }
12978 +
12979 +       *c = t->lookup_c->mem->ptr[t->lookup_offset++];
12980 +#if 0
12981 +       fprintf(stderr, "%s.%d: lookup: %c (%d) at offset: %d\r\n", __FILE__, __LINE__, *c > 31 ? *c : ' ', *c, t->lookup_offset - 1);
12982 +#endif
12983 +
12984 +       return 0;
12985 +}
12986 +
12987 +
12988 +static int http_req_tokenizer(
12989 +       http_req_tokenizer_t *t,
12990 +       int *token_id,
12991 +       buffer *token
12992 +) {
12993 +       unsigned char c;
12994 +       int tid = 0;
12995 +
12996 +       /* push the token to the parser */
12997 +
12998 +       while (tid == 0 && 0 == http_req_get_next_char(t, &c)) {
12999 +               switch (c) {
13000 +               case ':':
13001 +                       tid = TK_COLON;
13002 +
13003 +                       t->is_key = 0;
13004 +
13005 +                       break;
13006 +               case ' ':
13007 +               case '\t':
13008 +                       if (t->last_token_id == TK_CRLF) {
13009 +                               /* WS as the start of a line */
13010 +
13011 +                               tid = TK_TAB;
13012 +                               t->is_key = 0;
13013 +                       }
13014 +                       /* ignore the rest of the WS-chars */
13015 +                       break;
13016 +               case '\r':
13017 +                       if (0 != http_req_lookup_next_char(t, &c)) return -1;
13018 +
13019 +                       if (c == '\n') {
13020 +                               tid = TK_CRLF;
13021 +
13022 +                               t->c = t->lookup_c;
13023 +                               t->offset = t->lookup_offset;
13024 +
13025 +                               t->is_statusline = 0;
13026 +                               t->is_key = 1;
13027 +                       } else {
13028 +                               fprintf(stderr, "%s.%d: CR with out LF\r\n", __FILE__, __LINE__);
13029 +                               return -1;
13030 +                       }
13031 +                       break;
13032 +               case '\n':
13033 +                       tid = TK_CRLF;
13034 +
13035 +                       t->is_statusline = 0;
13036 +                       t->is_key = 1;
13037 +
13038 +                       break;
13039 +               default:
13040 +                       while (c >= 32 && c != 127 && c != 255) {
13041 +                               if (t->is_statusline) {
13042 +                                       if (c == 32) break; /* the space is a splitter in the statusline */
13043 +                               } else {
13044 +                                       if (t->is_key) {
13045 +                                               if (c == ':') break; /* the : is the splitter between key and value */
13046 +                                               if (c == ' ') break; /* no spaces in keys */
13047 +                                       }
13048 +                               }
13049 +                               if (0 != http_req_lookup_next_char(t, &c)) return -1;
13050 +                       }
13051 +
13052 +                       if (t->c == t->lookup_c &&
13053 +                               t->offset == t->lookup_offset + 1) {
13054 +
13055 +                               fprintf(stderr, "%s.%d: invalid char in string\n", __FILE__, __LINE__);
13056 +                               return -1;
13057 +                       }
13058 +
13059 +                       tid = TK_STRING;
13060 +
13061 +                       /* the lookup points to the first invalid char */
13062 +                       t->lookup_offset--;
13063 +
13064 +                       /* no overlapping string */
13065 +                       if (t->c == t->lookup_c) {
13066 +                               buffer_copy_string_len(token, t->c->mem->ptr + t->offset - 1, t->lookup_offset - t->offset + 1);
13067 +                       } else {
13068 +                               /* first chunk */
13069 +                               buffer_copy_string_len(token, t->c->mem->ptr + t->offset - 1, t->c->mem->used - t->offset);
13070 +
13071 +                               /* chunks in the middle */
13072 +                               for (t->c = t->c->next; t->c != t->lookup_c; t->c = t->c->next) {
13073 +                                       buffer_append_string_buffer(token, t->c->mem);
13074 +                                       t->offset = t->c->mem->used - 1;
13075 +                               }
13076 +
13077 +                               /* last chunk */
13078 +                               buffer_append_string_len(token, t->c->mem->ptr, t->lookup_offset);
13079 +                       }
13080 +
13081 +                       t->offset = t->lookup_offset;
13082 +
13083 +                       break;
13084 +               }
13085 +       }
13086 +
13087 +       if (tid) {
13088 +               *token_id = tid;
13089 +
13090 +               return 1;
13091 +       }
13092 +
13093 +       return -1;
13094 +}
13095 +
13096 +parse_status_t http_request_parse_cq(chunkqueue *cq, http_req *req) {
13097 +       http_req_tokenizer_t t;
13098 +       void *pParser = NULL;
13099 +       int token_id = 0;
13100 +       buffer *token = NULL;
13101 +       http_req_ctx_t context;
13102 +       parse_status_t ret = PARSE_UNSET;
13103 +
13104 +       t.cq = cq;
13105 +       t.c = cq->first;
13106 +       t.offset = t.c->offset;
13107 +       t.is_key = 0;
13108 +       t.is_statusline = 1;
13109 +       t.last_token_id = 0;
13110 +
13111 +       context.ok = 1;
13112 +       context.errmsg = buffer_init();
13113 +       context.req = req;
13114 +
13115 +       pParser = http_req_parserAlloc( malloc );
13116 +       token = buffer_init();
13117 +
13118 +#if 0
13119 +       http_req_parserTrace(stderr, "http-request: "); 
13120 +#endif
13121 +
13122 +       while((1 == http_req_tokenizer(&t, &token_id, token)) && context.ok) {
13123 +               http_req_parser(pParser, token_id, token, &context);
13124 +
13125 +               token = buffer_init();
13126 +
13127 +               /* CRLF CRLF ... the header end sequence */
13128 +               if (t.last_token_id == TK_CRLF &&
13129 +                   token_id == TK_CRLF) break;
13130 +
13131 +               t.last_token_id = token_id;
13132 +       }
13133 +
13134 +       /* oops, the parser failed */
13135 +       if (context.ok == 0) {
13136 +               ret = PARSE_ERROR;
13137 +
13138 +               if (!buffer_is_empty(context.errmsg)) {
13139 +                       TRACE("parsing failed: %s", BUF_STR(context.errmsg));
13140 +               } else {
13141 +                       TRACE("%s", "parsing failed ... (no error-msg)");
13142 +               }
13143 +       }
13144 +
13145 +       http_req_parser(pParser, 0, token, &context);
13146 +       http_req_parserFree(pParser, free);
13147 +
13148 +       if (context.ok == 0) {
13149 +               /* we are missing the some tokens */
13150 +
13151 +               if (!buffer_is_empty(context.errmsg)) {
13152 +                       TRACE("parsing failed: %s", BUF_STR(context.errmsg));
13153 +               }
13154 +
13155 +               if (ret == PARSE_UNSET) {
13156 +                       ret = buffer_is_empty(context.errmsg) ? PARSE_NEED_MORE : PARSE_ERROR;
13157 +               }
13158 +       } else {
13159 +               chunk *c;
13160 +
13161 +               for (c = cq->first; c != t.c; c = c->next) {
13162 +                       c->offset = c->mem->used - 1;
13163 +               }
13164 +
13165 +               c->offset = t.offset;
13166 +
13167 +               ret = PARSE_SUCCESS;
13168 +       }
13169 +
13170 +       buffer_free(token);
13171 +       buffer_free(context.errmsg);
13172 +
13173 +       return ret;
13174 +}
13175 +
13176 --- ../lighttpd-1.4.11/src/http_req.h   1970-01-01 03:00:00.000000000 +0300
13177 +++ lighttpd-1.5.0/src/http_req.h       2006-09-07 00:57:05.000000000 +0300
13178 @@ -0,0 +1,28 @@
13179 +#ifndef _HTTP_REQ_H_
13180 +#define _HTTP_REQ_H_
13181 +
13182 +#include "array.h"
13183 +#include "chunk.h"
13184 +#include "http_parser.h"
13185 +
13186 +typedef struct {
13187 +    int protocol;   /* http/1.0, http/1.1 */
13188 +    int method;     /* e.g. GET */
13189 +    buffer *uri_raw; /* e.g. /foobar/ */
13190 +    array *headers;
13191 +} http_req;
13192 +
13193 +typedef struct {
13194 +       int     ok;
13195 +       buffer *errmsg;
13196 +
13197 +       http_req *req;
13198 +} http_req_ctx_t;
13199 +
13200 +http_req *http_request_init(void);
13201 +void http_request_free(http_req *req);
13202 +void http_request_reset(http_req *req);
13203 +
13204 +parse_status_t http_request_parse_cq(chunkqueue *cq, http_req *http_request);
13205 +
13206 +#endif
13207 --- ../lighttpd-1.4.11/src/http_req_parser.c    1970-01-01 03:00:00.000000000 +0300
13208 +++ lighttpd-1.5.0/src/http_req_parser.c        2006-09-07 01:02:19.000000000 +0300
13209 @@ -0,0 +1,914 @@
13210 +/* Driver template for the LEMON parser generator.
13211 +** The author disclaims copyright to this source code.
13212 +*/
13213 +/* First off, code is include which follows the "include" declaration
13214 +** in the input file. */
13215 +#include <stdio.h>
13216 +#line 6 "./http_req_parser.y"
13217 +
13218 +#include <assert.h>
13219 +#include <string.h>
13220 +#include "http_req.h"
13221 +#include "keyvalue.h"
13222 +#include "array.h"
13223 +#include "log.h"
13224 +
13225 +#line 17 "http_req_parser.c"
13226 +/* Next is all token values, in a form suitable for use by makeheaders.
13227 +** This section will be null unless lemon is run with the -m switch.
13228 +*/
13229 +/*
13230 +** These constants (all generated automatically by the parser generator)
13231 +** specify the various kinds of tokens (terminals) that the parser
13232 +** understands.
13233 +**
13234 +** Each symbol here is a terminal symbol in the grammar.
13235 +*/
13236 +/* Make sure the INTERFACE macro is defined.
13237 +*/
13238 +#ifndef INTERFACE
13239 +# define INTERFACE 1
13240 +#endif
13241 +/* The next thing included is series of defines which control
13242 +** various aspects of the generated parser.
13243 +**    YYCODETYPE         is the data type used for storing terminal
13244 +**                       and nonterminal numbers.  "unsigned char" is
13245 +**                       used if there are fewer than 250 terminals
13246 +**                       and nonterminals.  "int" is used otherwise.
13247 +**    YYNOCODE           is a number of type YYCODETYPE which corresponds
13248 +**                       to no legal terminal or nonterminal number.  This
13249 +**                       number is used to fill in empty slots of the hash
13250 +**                       table.
13251 +**    YYFALLBACK         If defined, this indicates that one or more tokens
13252 +**                       have fall-back values which should be used if the
13253 +**                       original value of the token will not parse.
13254 +**    YYACTIONTYPE       is the data type used for storing terminal
13255 +**                       and nonterminal numbers.  "unsigned char" is
13256 +**                       used if there are fewer than 250 rules and
13257 +**                       states combined.  "int" is used otherwise.
13258 +**    http_req_parserTOKENTYPE     is the data type used for minor tokens given
13259 +**                       directly to the parser from the tokenizer.
13260 +**    YYMINORTYPE        is the data type used for all minor tokens.
13261 +**                       This is typically a union of many types, one of
13262 +**                       which is http_req_parserTOKENTYPE.  The entry in the union
13263 +**                       for base tokens is called "yy0".
13264 +**    YYSTACKDEPTH       is the maximum depth of the parser's stack.
13265 +**    http_req_parserARG_SDECL     A static variable declaration for the %extra_argument
13266 +**    http_req_parserARG_PDECL     A parameter declaration for the %extra_argument
13267 +**    http_req_parserARG_STORE     Code to store %extra_argument into yypParser
13268 +**    http_req_parserARG_FETCH     Code to extract %extra_argument from yypParser
13269 +**    YYNSTATE           the combined number of states.
13270 +**    YYNRULE            the number of rules in the grammar
13271 +**    YYERRORSYMBOL      is the code number of the error symbol.  If not
13272 +**                       defined, then do no error processing.
13273 +*/
13274 +/* \ 1 */
13275 +#define YYCODETYPE unsigned char
13276 +#define YYNOCODE 13
13277 +#define YYACTIONTYPE unsigned char
13278 +#define http_req_parserTOKENTYPE buffer *
13279 +typedef union {
13280 +  http_req_parserTOKENTYPE yy0;
13281 +  http_req * yy2;
13282 +  array * yy6;
13283 +  http_method_t yy8;
13284 +  data_string * yy15;
13285 +  buffer * yy17;
13286 +  http_version_t yy21;
13287 +  int yy25;
13288 +} YYMINORTYPE;
13289 +#define YYSTACKDEPTH 100
13290 +#define http_req_parserARG_SDECL http_req_ctx_t *ctx;
13291 +#define http_req_parserARG_PDECL ,http_req_ctx_t *ctx
13292 +#define http_req_parserARG_FETCH http_req_ctx_t *ctx = yypParser->ctx
13293 +#define http_req_parserARG_STORE yypParser->ctx = ctx
13294 +#define YYNSTATE 20
13295 +#define YYNRULE 10
13296 +#define YYERRORSYMBOL 5
13297 +#define YYERRSYMDT yy25
13298 +#define YY_NO_ACTION      (YYNSTATE+YYNRULE+2)
13299 +#define YY_ACCEPT_ACTION  (YYNSTATE+YYNRULE+1)
13300 +#define YY_ERROR_ACTION   (YYNSTATE+YYNRULE)
13301 +
13302 +/* Next are that tables used to determine what action to take based on the
13303 +** current state and lookahead token.  These tables are used to implement
13304 +** functions that take a state number and lookahead value and return an
13305 +** action integer.
13306 +**
13307 +** Suppose the action integer is N.  Then the action is determined as
13308 +** follows
13309 +**
13310 +**   0 <= N < YYNSTATE                  Shift N.  That is, push the lookahead
13311 +**                                      token onto the stack and goto state N.
13312 +**
13313 +**   YYNSTATE <= N < YYNSTATE+YYNRULE   Reduce by rule N-YYNSTATE.
13314 +**
13315 +**   N == YYNSTATE+YYNRULE              A syntax error has occurred.
13316 +**
13317 +**   N == YYNSTATE+YYNRULE+1            The parser accepts its input.
13318 +**
13319 +**   N == YYNSTATE+YYNRULE+2            No such action.  Denotes unused
13320 +**                                      slots in the yy_action[] table.
13321 +**
13322 +** The action table is constructed as a single large table named yy_action[].
13323 +** Given state S and lookahead X, the action is computed as
13324 +**
13325 +**      yy_action[ yy_shift_ofst[S] + X ]
13326 +**
13327 +** If the index value yy_shift_ofst[S]+X is out of range or if the value
13328 +** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
13329 +** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
13330 +** and that yy_default[S] should be used instead.
13331 +**
13332 +** The formula above is for computing the action when the lookahead is
13333 +** a terminal symbol.  If the lookahead is a non-terminal (as occurs after
13334 +** a reduce action) then the yy_reduce_ofst[] array is used in place of
13335 +** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
13336 +** YY_SHIFT_USE_DFLT.
13337 +**
13338 +** The following are the tables generated in this section:
13339 +**
13340 +**  yy_action[]        A single table containing all actions.
13341 +**  yy_lookahead[]     A table containing the lookahead for each entry in
13342 +**                     yy_action.  Used to detect hash collisions.
13343 +**  yy_shift_ofst[]    For each state, the offset into yy_action for
13344 +**                     shifting terminals.
13345 +**  yy_reduce_ofst[]   For each state, the offset into yy_action for
13346 +**                     shifting non-terminals after a reduce.
13347 +**  yy_default[]       Default action for each state.
13348 +*/
13349 +static YYACTIONTYPE yy_action[] = {
13350 + /*     0 */     1,   31,    8,   16,    5,   17,    8,    6,   12,   11,
13351 + /*    10 */    19,    2,   18,    7,    3,    4,   20,    9,   24,   13,
13352 + /*    20 */    24,   12,   14,   10,   21,   23,   15,   22,
13353 +};
13354 +static YYCODETYPE yy_lookahead[] = {
13355 + /*     0 */     7,    8,    1,    2,    9,   10,    1,    2,    1,    2,
13356 + /*    10 */     1,    1,    1,   10,    6,    2,    0,    3,   12,    2,
13357 + /*    20 */    12,    1,    4,   11,    0,    2,   11,    1,
13358 +};
13359 +#define YY_SHIFT_USE_DFLT (-1)
13360 +static signed char yy_shift_ofst[] = {
13361 + /*     0 */     9,   10,   11,   13,    1,    5,   16,   -1,   14,    7,
13362 + /*    10 */    -1,   -1,   17,   18,   20,   -1,   24,   -1,   23,   26,
13363 +};
13364 +#define YY_REDUCE_USE_DFLT (-8)
13365 +static signed char yy_reduce_ofst[] = {
13366 + /*     0 */    -7,   -8,    8,   -8,   -5,    3,   -8,   -8,   -8,   12,
13367 + /*    10 */    -8,   -8,   -8,   -8,   15,   -8,   -8,   -8,   -8,   -8,
13368 +};
13369 +static YYACTIONTYPE yy_default[] = {
13370 + /*     0 */    30,   30,   30,   30,   30,   30,   30,   24,   30,   30,
13371 + /*    10 */    26,   27,   30,   29,   30,   28,   30,   25,   30,   30,
13372 +};
13373 +#define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0]))
13374 +
13375 +/* The next table maps tokens into fallback tokens.  If a construct
13376 +** like the following:
13377 +**
13378 +**      %fallback ID X Y Z.
13379 +**
13380 +** appears in the grammer, then ID becomes a fallback token for X, Y,
13381 +** and Z.  Whenever one of the tokens X, Y, or Z is input to the parser
13382 +** but it does not parse, the type of the token is changed to ID and
13383 +** the parse is retried before an error is thrown.
13384 +*/
13385 +#ifdef YYFALLBACK
13386 +static const YYCODETYPE yyFallback[] = {
13387 +};
13388 +#endif /* YYFALLBACK */
13389 +
13390 +/* The following structure represents a single element of the
13391 +** parser's stack.  Information stored includes:
13392 +**
13393 +**   +  The state number for the parser at this level of the stack.
13394 +**
13395 +**   +  The value of the token stored at this level of the stack.
13396 +**      (In other words, the "major" token.)
13397 +**
13398 +**   +  The semantic value stored at this level of the stack.  This is
13399 +**      the information used by the action routines in the grammar.
13400 +**      It is sometimes called the "minor" token.
13401 +*/
13402 +struct yyStackEntry {
13403 +  int stateno;       /* The state-number */
13404 +  int major;         /* The major token value.  This is the code
13405 +                     ** number for the token at this stack level */
13406 +  YYMINORTYPE minor; /* The user-supplied minor token value.  This
13407 +                     ** is the value of the token  */
13408 +};
13409 +typedef struct yyStackEntry yyStackEntry;
13410 +
13411 +/* The state of the parser is completely contained in an instance of
13412 +** the following structure */
13413 +struct yyParser {
13414 +  int yyidx;                    /* Index of top element in stack */
13415 +  int yyerrcnt;                 /* Shifts left before out of the error */
13416 +  http_req_parserARG_SDECL                /* A place to hold %extra_argument */
13417 +  yyStackEntry yystack[YYSTACKDEPTH];  /* The parser's stack */
13418 +};
13419 +typedef struct yyParser yyParser;
13420 +
13421 +#ifndef NDEBUG
13422 +#include <stdio.h>
13423 +static FILE *yyTraceFILE = 0;
13424 +static char *yyTracePrompt = 0;
13425 +#endif /* NDEBUG */
13426 +
13427 +#ifndef NDEBUG
13428 +/*
13429 +** Turn parser tracing on by giving a stream to which to write the trace
13430 +** and a prompt to preface each trace message.  Tracing is turned off
13431 +** by making either argument NULL
13432 +**
13433 +** Inputs:
13434 +** <ul>
13435 +** <li> A FILE* to which trace output should be written.
13436 +**      If NULL, then tracing is turned off.
13437 +** <li> A prefix string written at the beginning of every
13438 +**      line of trace output.  If NULL, then tracing is
13439 +**      turned off.
13440 +** </ul>
13441 +**
13442 +** Outputs:
13443 +** None.
13444 +*/
13445 +void http_req_parserTrace(FILE *TraceFILE, char *zTracePrompt){
13446 +  yyTraceFILE = TraceFILE;
13447 +  yyTracePrompt = zTracePrompt;
13448 +  if( yyTraceFILE==0 ) yyTracePrompt = 0;
13449 +  else if( yyTracePrompt==0 ) yyTraceFILE = 0;
13450 +}
13451 +#endif /* NDEBUG */
13452 +
13453 +#ifndef NDEBUG
13454 +/* For tracing shifts, the names of all terminals and nonterminals
13455 +** are required.  The following table supplies these names */
13456 +static const char *yyTokenName[] = {
13457 +  "$",             "STRING",        "CRLF",          "COLON",       
13458 +  "TAB",           "error",         "protocol",      "method",      
13459 +  "request_hdr",   "headers",       "header",        "multiline",   
13460 +};
13461 +#endif /* NDEBUG */
13462 +
13463 +#ifndef NDEBUG
13464 +/* For tracing reduce actions, the names of all rules are required.
13465 +*/
13466 +static const char *yyRuleName[] = {
13467 + /*   0 */ "request_hdr ::= method STRING protocol CRLF headers CRLF",
13468 + /*   1 */ "request_hdr ::= method STRING protocol CRLF CRLF",
13469 + /*   2 */ "method ::= STRING",
13470 + /*   3 */ "protocol ::= STRING",
13471 + /*   4 */ "headers ::= headers header",
13472 + /*   5 */ "headers ::= header",
13473 + /*   6 */ "header ::= STRING COLON multiline",
13474 + /*   7 */ "header ::= STRING COLON CRLF",
13475 + /*   8 */ "multiline ::= STRING CRLF TAB multiline",
13476 + /*   9 */ "multiline ::= STRING CRLF",
13477 +};
13478 +#endif /* NDEBUG */
13479 +
13480 +/*
13481 +** This function returns the symbolic name associated with a token
13482 +** value.
13483 +*/
13484 +const char *http_req_parserTokenName(int tokenType){
13485 +#ifndef NDEBUG
13486 +  if( tokenType>0 && tokenType<(sizeof(yyTokenName)/sizeof(yyTokenName[0])) ){
13487 +    return yyTokenName[tokenType];
13488 +  }else{
13489 +    return "Unknown";
13490 +  }
13491 +#else
13492 +  return "";
13493 +#endif
13494 +}
13495 +
13496 +/*
13497 +** This function allocates a new parser.
13498 +** The only argument is a pointer to a function which works like
13499 +** malloc.
13500 +**
13501 +** Inputs:
13502 +** A pointer to the function used to allocate memory.
13503 +**
13504 +** Outputs:
13505 +** A pointer to a parser.  This pointer is used in subsequent calls
13506 +** to http_req_parser and http_req_parserFree.
13507 +*/
13508 +void *http_req_parserAlloc(void *(*mallocProc)(size_t)){
13509 +  yyParser *pParser;
13510 +  pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) );
13511 +  if( pParser ){
13512 +    pParser->yyidx = -1;
13513 +  }
13514 +  return pParser;
13515 +}
13516 +
13517 +/* The following function deletes the value associated with a
13518 +** symbol.  The symbol can be either a terminal or nonterminal.
13519 +** "yymajor" is the symbol code, and "yypminor" is a pointer to
13520 +** the value.
13521 +*/
13522 +static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){
13523 +  switch( yymajor ){
13524 +    /* Here is inserted the actions which take place when a
13525 +    ** terminal or non-terminal is destroyed.  This can happen
13526 +    ** when the symbol is popped from the stack during a
13527 +    ** reduce or during error processing or when a parser is
13528 +    ** being destroyed before it is finished parsing.
13529 +    **
13530 +    ** Note: during a reduce, the only symbols destroyed are those
13531 +    ** which appear on the RHS of the rule, but which are not used
13532 +    ** inside the C code.
13533 +    */
13534 +    case 1:
13535 +    case 2:
13536 +    case 3:
13537 +    case 4:
13538 +#line 25 "./http_req_parser.y"
13539 +{ buffer_free((yypminor->yy0)); }
13540 +#line 331 "http_req_parser.c"
13541 +      break;
13542 +    default:  break;   /* If no destructor action specified: do nothing */
13543 +  }
13544 +}
13545 +
13546 +/*
13547 +** Pop the parser's stack once.
13548 +**
13549 +** If there is a destructor routine associated with the token which
13550 +** is popped from the stack, then call it.
13551 +**
13552 +** Return the major token number for the symbol popped.
13553 +*/
13554 +static int yy_pop_parser_stack(yyParser *pParser){
13555 +  YYCODETYPE yymajor;
13556 +  yyStackEntry *yytos = &pParser->yystack[pParser->yyidx];
13557 +
13558 +  if( pParser->yyidx<0 ) return 0;
13559 +#ifndef NDEBUG
13560 +  if( yyTraceFILE && pParser->yyidx>=0 ){
13561 +    fprintf(yyTraceFILE,"%sPopping %s\n",
13562 +      yyTracePrompt,
13563 +      yyTokenName[yytos->major]);
13564 +  }
13565 +#endif
13566 +  yymajor = yytos->major;
13567 +  yy_destructor( yymajor, &yytos->minor);
13568 +  pParser->yyidx--;
13569 +  return yymajor;
13570 +}
13571 +
13572 +/*
13573 +** Deallocate and destroy a parser.  Destructors are all called for
13574 +** all stack elements before shutting the parser down.
13575 +**
13576 +** Inputs:
13577 +** <ul>
13578 +** <li>  A pointer to the parser.  This should be a pointer
13579 +**       obtained from http_req_parserAlloc.
13580 +** <li>  A pointer to a function used to reclaim memory obtained
13581 +**       from malloc.
13582 +** </ul>
13583 +*/
13584 +void http_req_parserFree(
13585 +  void *p,                    /* The parser to be deleted */
13586 +  void (*freeProc)(void*)     /* Function used to reclaim memory */
13587 +){
13588 +  yyParser *pParser = (yyParser*)p;
13589 +  if( pParser==0 ) return;
13590 +  while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
13591 +  (*freeProc)((void*)pParser);
13592 +}
13593 +
13594 +/*
13595 +** Find the appropriate action for a parser given the terminal
13596 +** look-ahead token iLookAhead.
13597 +**
13598 +** If the look-ahead token is YYNOCODE, then check to see if the action is
13599 +** independent of the look-ahead.  If it is, return the action, otherwise
13600 +** return YY_NO_ACTION.
13601 +*/
13602 +static int yy_find_shift_action(
13603 +  yyParser *pParser,        /* The parser */
13604 +  int iLookAhead            /* The look-ahead token */
13605 +){
13606 +  int i;
13607 +  int stateno = pParser->yystack[pParser->yyidx].stateno;
13608 +
13609 +  /* if( pParser->yyidx<0 ) return YY_NO_ACTION;  */
13610 +  i = yy_shift_ofst[stateno];
13611 +  if( i==YY_SHIFT_USE_DFLT ){
13612 +    return yy_default[stateno];
13613 +  }
13614 +  if( iLookAhead==YYNOCODE ){
13615 +    return YY_NO_ACTION;
13616 +  }
13617 +  i += iLookAhead;
13618 +  if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
13619 +#ifdef YYFALLBACK
13620 +    int iFallback;            /* Fallback token */
13621 +    if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
13622 +           && (iFallback = yyFallback[iLookAhead])!=0 ){
13623 +#ifndef NDEBUG
13624 +      if( yyTraceFILE ){
13625 +        fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
13626 +           yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
13627 +      }
13628 +#endif
13629 +      return yy_find_shift_action(pParser, iFallback);
13630 +    }
13631 +#endif
13632 +    return yy_default[stateno];
13633 +  }else{
13634 +    return yy_action[i];
13635 +  }
13636 +}
13637 +
13638 +/*
13639 +** Find the appropriate action for a parser given the non-terminal
13640 +** look-ahead token iLookAhead.
13641 +**
13642 +** If the look-ahead token is YYNOCODE, then check to see if the action is
13643 +** independent of the look-ahead.  If it is, return the action, otherwise
13644 +** return YY_NO_ACTION.
13645 +*/
13646 +static int yy_find_reduce_action(
13647 +  yyParser *pParser,        /* The parser */
13648 +  int iLookAhead            /* The look-ahead token */
13649 +){
13650 +  int i;
13651 +  int stateno = pParser->yystack[pParser->yyidx].stateno;
13652 +
13653 +  i = yy_reduce_ofst[stateno];
13654 +  if( i==YY_REDUCE_USE_DFLT ){
13655 +    return yy_default[stateno];
13656 +  }
13657 +  if( iLookAhead==YYNOCODE ){
13658 +    return YY_NO_ACTION;
13659 +  }
13660 +  i += iLookAhead;
13661 +  if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
13662 +    return yy_default[stateno];
13663 +  }else{
13664 +    return yy_action[i];
13665 +  }
13666 +}
13667 +
13668 +/*
13669 +** Perform a shift action.
13670 +*/
13671 +static void yy_shift(
13672 +  yyParser *yypParser,          /* The parser to be shifted */
13673 +  int yyNewState,               /* The new state to shift in */
13674 +  int yyMajor,                  /* The major token to shift in */
13675 +  YYMINORTYPE *yypMinor         /* Pointer ot the minor token to shift in */
13676 +){
13677 +  yyStackEntry *yytos;
13678 +  yypParser->yyidx++;
13679 +  if( yypParser->yyidx>=YYSTACKDEPTH ){
13680 +     http_req_parserARG_FETCH;
13681 +     yypParser->yyidx--;
13682 +#ifndef NDEBUG
13683 +     if( yyTraceFILE ){
13684 +       fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
13685 +     }
13686 +#endif
13687 +     while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
13688 +     /* Here code is inserted which will execute if the parser
13689 +     ** stack every overflows */
13690 +     http_req_parserARG_STORE; /* Suppress warning about unused %extra_argument var */
13691 +     return;
13692 +  }
13693 +  yytos = &yypParser->yystack[yypParser->yyidx];
13694 +  yytos->stateno = yyNewState;
13695 +  yytos->major = yyMajor;
13696 +  yytos->minor = *yypMinor;
13697 +#ifndef NDEBUG
13698 +  if( yyTraceFILE && yypParser->yyidx>0 ){
13699 +    int i;
13700 +    fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState);
13701 +    fprintf(yyTraceFILE,"%sStack:",yyTracePrompt);
13702 +    for(i=1; i<=yypParser->yyidx; i++)
13703 +      fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]);
13704 +    fprintf(yyTraceFILE,"\n");
13705 +  }
13706 +#endif
13707 +}
13708 +
13709 +/* The following table contains information about every rule that
13710 +** is used during the reduce.
13711 +*/
13712 +static struct {
13713 +  YYCODETYPE lhs;         /* Symbol on the left-hand side of the rule */
13714 +  unsigned char nrhs;     /* Number of right-hand side symbols in the rule */
13715 +} yyRuleInfo[] = {
13716 +  { 8, 6 },
13717 +  { 8, 5 },
13718 +  { 7, 1 },
13719 +  { 6, 1 },
13720 +  { 9, 2 },
13721 +  { 9, 1 },
13722 +  { 10, 3 },
13723 +  { 10, 3 },
13724 +  { 11, 4 },
13725 +  { 11, 2 },
13726 +};
13727 +
13728 +static void yy_accept(yyParser*);  /* Forward Declaration */
13729 +
13730 +/*
13731 +** Perform a reduce action and the shift that must immediately
13732 +** follow the reduce.
13733 +*/
13734 +static void yy_reduce(
13735 +  yyParser *yypParser,         /* The parser */
13736 +  int yyruleno                 /* Number of the rule by which to reduce */
13737 +){
13738 +  int yygoto;                     /* The next state */
13739 +  int yyact;                      /* The next action */
13740 +  YYMINORTYPE yygotominor;        /* The LHS of the rule reduced */
13741 +  yyStackEntry *yymsp;            /* The top of the parser's stack */
13742 +  int yysize;                     /* Amount to pop the stack */
13743 +  http_req_parserARG_FETCH;
13744 +  yymsp = &yypParser->yystack[yypParser->yyidx];
13745 +#ifndef NDEBUG
13746 +  if( yyTraceFILE && yyruleno>=0
13747 +        && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
13748 +    fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
13749 +      yyRuleName[yyruleno]);
13750 +  }
13751 +#endif /* NDEBUG */
13752 +
13753 +  switch( yyruleno ){
13754 +  /* Beginning here are the reduction cases.  A typical example
13755 +  ** follows:
13756 +  **   case 0:
13757 +  **  #line <lineno> <grammarfile>
13758 +  **     { ... }           // User supplied code
13759 +  **  #line <lineno> <thisfile>
13760 +  **     break;
13761 +  */
13762 +      case 0:
13763 +#line 28 "./http_req_parser.y"
13764 +{
13765 +    http_req *req = ctx->req;
13766 +    
13767 +    req->method = yymsp[-5].minor.yy8;
13768 +    req->protocol = yymsp[-3].minor.yy21;
13769 +    buffer_copy_string_buffer(req->uri_raw, yymsp[-4].minor.yy0);
13770 +    buffer_free(yymsp[-4].minor.yy0); 
13771 +
13772 +    array_free(req->headers);
13773 +    
13774 +    req->headers = yymsp[-1].minor.yy6;
13775 +}
13776 +#line 567 "http_req_parser.c"
13777 +  yy_destructor(2,&yymsp[-2].minor);
13778 +  yy_destructor(2,&yymsp[0].minor);
13779 +        break;
13780 +      case 1:
13781 +#line 41 "./http_req_parser.y"
13782 +{
13783 +    http_req *req = ctx->req;
13784 +    
13785 +    req->method = yymsp[-4].minor.yy8;
13786 +    req->protocol = yymsp[-2].minor.yy21;
13787 +    buffer_copy_string_buffer(req->uri_raw, yymsp[-3].minor.yy0);
13788 +    buffer_free(yymsp[-3].minor.yy0); 
13789 +}
13790 +#line 581 "http_req_parser.c"
13791 +  yy_destructor(2,&yymsp[-1].minor);
13792 +  yy_destructor(2,&yymsp[0].minor);
13793 +        break;
13794 +      case 2:
13795 +#line 51 "./http_req_parser.y"
13796 +{
13797 +    yygotominor.yy8 = get_http_method_key(BUF_STR(yymsp[0].minor.yy0));
13798 +
13799 +    buffer_free(yymsp[0].minor.yy0);
13800 +}
13801 +#line 592 "http_req_parser.c"
13802 +        break;
13803 +      case 3:
13804 +#line 57 "./http_req_parser.y"
13805 +{
13806 +    /* the protocol might be HTTP/1.0 or HTTP/1.1
13807 +    *  the version string is allowed to have leading zeros
13808 +    */
13809 +    yygotominor.yy21 = HTTP_VERSION_UNSET;
13810 +
13811 +    if (0 == strncmp(BUF_STR(yymsp[0].minor.yy0), "HTTP/", 5)) {
13812 +       char *err = NULL;
13813 +       /* is there a dot */
13814 +       char *major, *minor;
13815 +       
13816 +       major = BUF_STR(yymsp[0].minor.yy0) + 5;
13817 +       minor = strchr(major, '.');
13818 +       if (minor) {
13819 +         int hi, lo;
13820 +         hi = strtol(major, &err, 10);
13821 +         minor++;
13822 +         if (*err == '.' && *minor != '\0') {
13823 +            lo = strtol(minor, &err, 10);
13824 +            if (*err == '\0') {
13825 +              if (hi == 1 && lo == 1) {
13826 +                yygotominor.yy21 = HTTP_VERSION_1_1;
13827 +              } else if (hi == 1 && lo == 0) {
13828 +                yygotominor.yy21 = HTTP_VERSION_1_0;
13829 +              }
13830 +            }
13831 +         }
13832 +       }
13833 +    }
13834 +
13835 +    buffer_free(yymsp[0].minor.yy0);
13836 +}
13837 +#line 628 "http_req_parser.c"
13838 +        break;
13839 +      case 4:
13840 +#line 90 "./http_req_parser.y"
13841 +{
13842 +    yygotominor.yy6 = yymsp[-1].minor.yy6;
13843 +   
13844 +    if (yymsp[0].minor.yy15) { 
13845 +      array_insert_unique(yygotominor.yy6, (data_unset *)yymsp[0].minor.yy15);
13846 +    }
13847 +}
13848 +#line 639 "http_req_parser.c"
13849 +        break;
13850 +      case 5:
13851 +#line 98 "./http_req_parser.y"
13852 +{
13853 +    if (yymsp[0].minor.yy15) {
13854 +      yygotominor.yy6 = array_init();
13855 +
13856 +      array_insert_unique(yygotominor.yy6, (data_unset *)yymsp[0].minor.yy15);
13857 +    }
13858 +}
13859 +#line 650 "http_req_parser.c"
13860 +        break;
13861 +      case 6:
13862 +#line 106 "./http_req_parser.y"
13863 +{
13864 +    yygotominor.yy15 = data_string_init();
13865 +    
13866 +    buffer_copy_string_buffer(yygotominor.yy15->key, yymsp[-2].minor.yy0);
13867 +    buffer_copy_string_buffer(yygotominor.yy15->value, yymsp[0].minor.yy17);    
13868 +    buffer_free(yymsp[-2].minor.yy0);
13869 +    buffer_free(yymsp[0].minor.yy17);
13870 +}
13871 +#line 662 "http_req_parser.c"
13872 +  yy_destructor(3,&yymsp[-1].minor);
13873 +        break;
13874 +      case 7:
13875 +#line 115 "./http_req_parser.y"
13876 +{
13877 +    /* ignore empty header fields */
13878 +
13879 +    yygotominor.yy15 = NULL;
13880 +}
13881 +#line 672 "http_req_parser.c"
13882 +  yy_destructor(1,&yymsp[-2].minor);
13883 +  yy_destructor(3,&yymsp[-1].minor);
13884 +  yy_destructor(2,&yymsp[0].minor);
13885 +        break;
13886 +      case 8:
13887 +#line 121 "./http_req_parser.y"
13888 +{
13889 +   buffer_append_string_buffer(yymsp[-3].minor.yy0, yymsp[0].minor.yy17);
13890 +   yygotominor.yy17 = yymsp[-3].minor.yy0;
13891 +
13892 +   yymsp[-3].minor.yy0 = NULL;
13893 +   buffer_free(yymsp[0].minor.yy17);
13894 +}
13895 +#line 686 "http_req_parser.c"
13896 +  yy_destructor(2,&yymsp[-2].minor);
13897 +  yy_destructor(4,&yymsp[-1].minor);
13898 +        break;
13899 +      case 9:
13900 +#line 130 "./http_req_parser.y"
13901 +{
13902 +   yygotominor.yy17 = yymsp[-1].minor.yy0;
13903 +
13904 +   yymsp[-1].minor.yy0 = NULL;
13905 +}
13906 +#line 697 "http_req_parser.c"
13907 +  yy_destructor(2,&yymsp[0].minor);
13908 +        break;
13909 +  };
13910 +  yygoto = yyRuleInfo[yyruleno].lhs;
13911 +  yysize = yyRuleInfo[yyruleno].nrhs;
13912 +  yypParser->yyidx -= yysize;
13913 +  yyact = yy_find_reduce_action(yypParser,yygoto);
13914 +  if( yyact < YYNSTATE ){
13915 +    yy_shift(yypParser,yyact,yygoto,&yygotominor);
13916 +  }else if( yyact == YYNSTATE + YYNRULE + 1 ){
13917 +    yy_accept(yypParser);
13918 +  }
13919 +}
13920 +
13921 +/*
13922 +** The following code executes when the parse fails
13923 +*/
13924 +static void yy_parse_failed(
13925 +  yyParser *yypParser           /* The parser */
13926 +){
13927 +  http_req_parserARG_FETCH;
13928 +#ifndef NDEBUG
13929 +  if( yyTraceFILE ){
13930 +    fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
13931 +  }
13932 +#endif
13933 +  while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
13934 +  /* Here code is inserted which will be executed whenever the
13935 +  ** parser fails */
13936 +#line 15 "./http_req_parser.y"
13937 +
13938 +  ctx->ok = 0;
13939 +
13940 +#line 731 "http_req_parser.c"
13941 +  http_req_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
13942 +}
13943 +
13944 +/*
13945 +** The following code executes when a syntax error first occurs.
13946 +*/
13947 +static void yy_syntax_error(
13948 +  yyParser *yypParser,           /* The parser */
13949 +  int yymajor,                   /* The major type of the error token */
13950 +  YYMINORTYPE yyminor            /* The minor type of the error token */
13951 +){
13952 +  http_req_parserARG_FETCH;
13953 +#define TOKEN (yyminor.yy0)
13954 +  http_req_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
13955 +}
13956 +
13957 +/*
13958 +** The following is executed when the parser accepts
13959 +*/
13960 +static void yy_accept(
13961 +  yyParser *yypParser           /* The parser */
13962 +){
13963 +  http_req_parserARG_FETCH;
13964 +#ifndef NDEBUG
13965 +  if( yyTraceFILE ){
13966 +    fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
13967 +  }
13968 +#endif
13969 +  while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
13970 +  /* Here code is inserted which will be executed whenever the
13971 +  ** parser accepts */
13972 +  http_req_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
13973 +}
13974 +
13975 +/* The main parser program.
13976 +** The first argument is a pointer to a structure obtained from
13977 +** "http_req_parserAlloc" which describes the current state of the parser.
13978 +** The second argument is the major token number.  The third is
13979 +** the minor token.  The fourth optional argument is whatever the
13980 +** user wants (and specified in the grammar) and is available for
13981 +** use by the action routines.
13982 +**
13983 +** Inputs:
13984 +** <ul>
13985 +** <li> A pointer to the parser (an opaque structure.)
13986 +** <li> The major token number.
13987 +** <li> The minor token number.
13988 +** <li> An option argument of a grammar-specified type.
13989 +** </ul>
13990 +**
13991 +** Outputs:
13992 +** None.
13993 +*/
13994 +void http_req_parser(
13995 +  void *yyp,                   /* The parser */
13996 +  int yymajor,                 /* The major token code number */
13997 +  http_req_parserTOKENTYPE yyminor       /* The value for the token */
13998 +  http_req_parserARG_PDECL               /* Optional %extra_argument parameter */
13999 +){
14000 +  YYMINORTYPE yyminorunion;
14001 +  int yyact;            /* The parser action. */
14002 +  int yyendofinput;     /* True if we are at the end of input */
14003 +  int yyerrorhit = 0;   /* True if yymajor has invoked an error */
14004 +  yyParser *yypParser;  /* The parser */
14005 +
14006 +  /* (re)initialize the parser, if necessary */
14007 +  yypParser = (yyParser*)yyp;
14008 +  if( yypParser->yyidx<0 ){
14009 +    if( yymajor==0 ) return;
14010 +    yypParser->yyidx = 0;
14011 +    yypParser->yyerrcnt = -1;
14012 +    yypParser->yystack[0].stateno = 0;
14013 +    yypParser->yystack[0].major = 0;
14014 +  }
14015 +  yyminorunion.yy0 = yyminor;
14016 +  yyendofinput = (yymajor==0);
14017 +  http_req_parserARG_STORE;
14018 +
14019 +#ifndef NDEBUG
14020 +  if( yyTraceFILE ){
14021 +    fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]);
14022 +  }
14023 +#endif
14024 +
14025 +  do{
14026 +    yyact = yy_find_shift_action(yypParser,yymajor);
14027 +    if( yyact<YYNSTATE ){
14028 +      yy_shift(yypParser,yyact,yymajor,&yyminorunion);
14029 +      yypParser->yyerrcnt--;
14030 +      if( yyendofinput && yypParser->yyidx>=0 ){
14031 +        yymajor = 0;
14032 +      }else{
14033 +        yymajor = YYNOCODE;
14034 +      }
14035 +    }else if( yyact < YYNSTATE + YYNRULE ){
14036 +      yy_reduce(yypParser,yyact-YYNSTATE);
14037 +    }else if( yyact == YY_ERROR_ACTION ){
14038 +      int yymx;
14039 +#ifndef NDEBUG
14040 +      if( yyTraceFILE ){
14041 +        fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
14042 +      }
14043 +#endif
14044 +#ifdef YYERRORSYMBOL
14045 +      /* A syntax error has occurred.
14046 +      ** The response to an error depends upon whether or not the
14047 +      ** grammar defines an error token "ERROR".
14048 +      **
14049 +      ** This is what we do if the grammar does define ERROR:
14050 +      **
14051 +      **  * Call the %syntax_error function.
14052 +      **
14053 +      **  * Begin popping the stack until we enter a state where
14054 +      **    it is legal to shift the error symbol, then shift
14055 +      **    the error symbol.
14056 +      **
14057 +      **  * Set the error count to three.
14058 +      **
14059 +      **  * Begin accepting and shifting new tokens.  No new error
14060 +      **    processing will occur until three tokens have been
14061 +      **    shifted successfully.
14062 +      **
14063 +      */
14064 +      if( yypParser->yyerrcnt<0 ){
14065 +        yy_syntax_error(yypParser,yymajor,yyminorunion);
14066 +      }
14067 +      yymx = yypParser->yystack[yypParser->yyidx].major;
14068 +      if( yymx==YYERRORSYMBOL || yyerrorhit ){
14069 +#ifndef NDEBUG
14070 +        if( yyTraceFILE ){
14071 +          fprintf(yyTraceFILE,"%sDiscard input token %s\n",
14072 +             yyTracePrompt,yyTokenName[yymajor]);
14073 +        }
14074 +#endif
14075 +        yy_destructor(yymajor,&yyminorunion);
14076 +        yymajor = YYNOCODE;
14077 +      }else{
14078 +         while(
14079 +          yypParser->yyidx >= 0 &&
14080 +          yymx != YYERRORSYMBOL &&
14081 +          (yyact = yy_find_shift_action(yypParser,YYERRORSYMBOL)) >= YYNSTATE
14082 +        ){
14083 +          yy_pop_parser_stack(yypParser);
14084 +        }
14085 +        if( yypParser->yyidx < 0 || yymajor==0 ){
14086 +          yy_destructor(yymajor,&yyminorunion);
14087 +          yy_parse_failed(yypParser);
14088 +          yymajor = YYNOCODE;
14089 +        }else if( yymx!=YYERRORSYMBOL ){
14090 +          YYMINORTYPE u2;
14091 +          u2.YYERRSYMDT = 0;
14092 +          yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2);
14093 +        }
14094 +      }
14095 +      yypParser->yyerrcnt = 3;
14096 +      yyerrorhit = 1;
14097 +#else  /* YYERRORSYMBOL is not defined */
14098 +      /* This is what we do if the grammar does not define ERROR:
14099 +      **
14100 +      **  * Report an error message, and throw away the input token.
14101 +      **
14102 +      **  * If the input token is $, then fail the parse.
14103 +      **
14104 +      ** As before, subsequent error messages are suppressed until
14105 +      ** three input tokens have been successfully shifted.
14106 +      */
14107 +      if( yypParser->yyerrcnt<=0 ){
14108 +        yy_syntax_error(yypParser,yymajor,yyminorunion);
14109 +      }
14110 +      yypParser->yyerrcnt = 3;
14111 +      yy_destructor(yymajor,&yyminorunion);
14112 +      if( yyendofinput ){
14113 +        yy_parse_failed(yypParser);
14114 +      }
14115 +      yymajor = YYNOCODE;
14116 +#endif
14117 +    }else{
14118 +      yy_accept(yypParser);
14119 +      yymajor = YYNOCODE;
14120 +    }
14121 +  }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
14122 +  return;
14123 +}
14124 --- ../lighttpd-1.4.11/src/http_req_parser.h    1970-01-01 03:00:00.000000000 +0300
14125 +++ lighttpd-1.5.0/src/http_req_parser.h        2006-09-07 01:02:19.000000000 +0300
14126 @@ -0,0 +1,4 @@
14127 +#define TK_STRING                          1
14128 +#define TK_CRLF                            2
14129 +#define TK_COLON                           3
14130 +#define TK_TAB                             4
14131 --- ../lighttpd-1.4.11/src/http_req_parser.y    1970-01-01 03:00:00.000000000 +0300
14132 +++ lighttpd-1.5.0/src/http_req_parser.y        2006-09-07 00:57:05.000000000 +0300
14133 @@ -0,0 +1,136 @@
14134 +%token_prefix TK_
14135 +%token_type {buffer *}
14136 +%extra_argument {http_req_ctx_t *ctx}
14137 +%name http_req_parser
14138 +
14139 +%include {
14140 +#include <assert.h>
14141 +#include <string.h>
14142 +#include "http_req.h"
14143 +#include "keyvalue.h"
14144 +#include "array.h"
14145 +#include "log.h"
14146 +}
14147 +
14148 +%parse_failure {
14149 +  ctx->ok = 0;
14150 +}
14151 +
14152 +%type protocol { http_version_t }
14153 +%type method { http_method_t }
14154 +%type request_hdr { http_req * }
14155 +%type headers { array * }
14156 +%type header { data_string * }
14157 +%type multiline { buffer * }
14158 +%token_destructor { buffer_free($$); }
14159 +
14160 +/* GET ... HTTP/1.0 */
14161 +request_hdr ::= method(B) STRING(C) protocol(D) CRLF headers(HDR) CRLF . {
14162 +    http_req *req = ctx->req;
14163 +    
14164 +    req->method = B;
14165 +    req->protocol = D;
14166 +    buffer_copy_string_buffer(req->uri_raw, C);
14167 +    buffer_free(C); 
14168 +
14169 +    array_free(req->headers);
14170 +    
14171 +    req->headers = HDR;
14172 +}
14173 +
14174 +request_hdr ::= method(B) STRING(C) protocol(D) CRLF CRLF . {
14175 +    http_req *req = ctx->req;
14176 +    
14177 +    req->method = B;
14178 +    req->protocol = D;
14179 +    buffer_copy_string_buffer(req->uri_raw, C);
14180 +    buffer_free(C); 
14181 +}
14182 +
14183 +
14184 +method(A) ::= STRING(B) . {
14185 +    A = get_http_method_key(BUF_STR(B));
14186 +
14187 +    buffer_free(B);
14188 +}
14189 +
14190 +protocol(A) ::= STRING(B). {
14191 +    /* the protocol might be HTTP/1.0 or HTTP/1.1
14192 +    *  the version string is allowed to have leading zeros
14193 +    */
14194 +    A = HTTP_VERSION_UNSET;
14195 +
14196 +    if (0 == strncmp(BUF_STR(B), "HTTP/", 5)) {
14197 +       char *err = NULL;
14198 +       /* is there a dot */
14199 +       char *major, *minor;
14200 +       
14201 +       major = BUF_STR(B) + 5;
14202 +       minor = strchr(major, '.');
14203 +       if (minor) {
14204 +         int hi, lo;
14205 +         hi = strtol(major, &err, 10);
14206 +         minor++;
14207 +         if (*err == '.' && *minor != '\0') {
14208 +            lo = strtol(minor, &err, 10);
14209 +            if (*err == '\0') {
14210 +              if (hi == 1 && lo == 1) {
14211 +                A = HTTP_VERSION_1_1;
14212 +              } else if (hi == 1 && lo == 0) {
14213 +                A = HTTP_VERSION_1_0;
14214 +              }
14215 +            }
14216 +         }
14217 +       }
14218 +    }
14219 +
14220 +    buffer_free(B);
14221 +}
14222 +
14223 +headers(HDRS) ::= headers(SRC) header(HDR). {
14224 +    HDRS = SRC;
14225 +   
14226 +    if (HDR) { 
14227 +      array_insert_unique(HDRS, (data_unset *)HDR);
14228 +    }
14229 +}
14230 +
14231 +headers(HDRS) ::= header(HDR). {
14232 +    if (HDR) {
14233 +      HDRS = array_init();
14234 +
14235 +      array_insert_unique(HDRS, (data_unset *)HDR);
14236 +    }
14237 +}
14238 +
14239 +header(HDR) ::= STRING(A) COLON multiline(B). {
14240 +    HDR = data_string_init();
14241 +    
14242 +    buffer_copy_string_buffer(HDR->key, A);
14243 +    buffer_copy_string_buffer(HDR->value, B);    
14244 +    buffer_free(A);
14245 +    buffer_free(B);
14246 +}
14247 +
14248 +header(HDR) ::= STRING COLON CRLF . {
14249 +    /* ignore empty header fields */
14250 +
14251 +    HDR = NULL;
14252 +}
14253 +
14254 +multiline(A) ::= STRING(B) CRLF TAB multiline(C). {
14255 +   buffer_append_string_buffer(B, C);
14256 +   A = B;
14257 +
14258 +   B = NULL;
14259 +   buffer_free(C);
14260 +}
14261 +
14262 +/* the simple form */
14263 +multiline(A) ::= STRING(B) CRLF. {
14264 +   A = B;
14265 +
14266 +   B = NULL;
14267 +}
14268 +
14269 +
14270 --- ../lighttpd-1.4.11/src/http_req_range.c     1970-01-01 03:00:00.000000000 +0300
14271 +++ lighttpd-1.5.0/src/http_req_range.c 2006-09-07 00:57:05.000000000 +0300
14272 @@ -0,0 +1,192 @@
14273 +#include <string.h>
14274 +#include <stdlib.h>
14275 +#include <stdio.h>
14276 +#include <assert.h>
14277 +
14278 +#include "log.h"
14279 +#include "http_req_range.h"
14280 +#include "http_req_range_parser.h"
14281 +
14282 +/* declare prototypes for the parser */
14283 +void *http_req_range_parserAlloc(void *(*mallocProc)(size_t));
14284 +void http_req_range_parserFree(void *p,  void (*freeProc)(void*));
14285 +void http_req_range_parserTrace(FILE *TraceFILE, char *zTracePrompt);
14286 +void http_req_range_parser(void *, int, buffer *, http_req_range_ctx_t *);
14287 +
14288 +typedef struct {
14289 +       buffer *hdr;
14290 +       size_t ndx;
14291 +
14292 +       chunk *lookup_c;
14293 +       size_t lookup_offset;
14294 +} http_req_range_tokenizer_t;
14295 +
14296 +http_req_range *http_request_range_init(void) {
14297 +       http_req_range *range = calloc(1, sizeof(*range));
14298 +
14299 +       range->start = -1;
14300 +       range->end = -1;
14301 +
14302 +       return range;
14303 +}
14304 +
14305 +void http_request_range_reset(http_req_range *range) {
14306 +       if (!range) return;
14307 +
14308 +       http_request_range_free(range->next);
14309 +
14310 +       range->next = NULL;
14311 +
14312 +       range->start = -1;
14313 +       range->end = -1;
14314 +}
14315 +
14316 +void http_request_range_free(http_req_range *range) {
14317 +       if (!range) return;
14318 +
14319 +       http_request_range_free(range->next);
14320 +
14321 +       free(range);
14322 +}
14323 +
14324 +static int http_req_range_tokenizer(
14325 +       http_req_range_tokenizer_t *t,
14326 +       int *token_id,
14327 +       buffer *token
14328 +) {
14329 +       int tid = 0;
14330 +
14331 +       /* push the token to the parser */
14332 +
14333 +       while (tid == 0) {
14334 +               char c = t->hdr->ptr[t->ndx];
14335 +               
14336 +               switch (c) {
14337 +               case '-':
14338 +                       tid = TK_MINUS;
14339 +                       t->ndx++;
14340 +
14341 +                       break;
14342 +               case '=':
14343 +                       tid = TK_EQUAL;
14344 +                       t->ndx++;
14345 +
14346 +                       break;
14347 +               case ',':
14348 +                       tid = TK_COMMA;
14349 +                       t->ndx++;
14350 +
14351 +                       break;
14352 +
14353 +               case ' ':
14354 +               case '\t':
14355 +                       /* ignore WS */
14356 +                       t->ndx++;
14357 +                       break;
14358 +               case '\0':
14359 +                       return 0;
14360 +               default:
14361 +                       /* 'bytes' or a number */
14362 +                       if (0 == strncmp(t->hdr->ptr + t->ndx, "bytes", 5)) {
14363 +                               tid = TK_BYTES;
14364 +
14365 +                               t->ndx += 5;
14366 +                       } else {
14367 +                               size_t d;
14368 +                               /* */
14369 +                               for (d = t->ndx; d < t->hdr->used; d++) {
14370 +                                       char dc = t->hdr->ptr[d];
14371 +                                       if (dc < '0' || dc > '9') {
14372 +                                               break;
14373 +                                       }
14374 +                               }
14375 +
14376 +                               if (d == t->ndx) {
14377 +                                       /* no digit found */
14378 +
14379 +                                       TRACE("%s", "no digit found");
14380 +
14381 +                                       return -1;
14382 +                               }
14383 +
14384 +                               tid = TK_NUMBER;
14385 +
14386 +                               buffer_copy_string_len(token, t->hdr->ptr + t->ndx, d - t->ndx);
14387 +
14388 +                               t->ndx = d;
14389 +                       }
14390 +
14391 +                       break;
14392 +               }
14393 +       }
14394 +
14395 +       if (tid) {
14396 +               *token_id = tid;
14397 +
14398 +               return 1;
14399 +       }
14400 +
14401 +       return -1;
14402 +}
14403 +
14404 +parse_status_t http_request_range_parse(buffer *hdr, http_req_range *ranges) {
14405 +       http_req_range_tokenizer_t t;
14406 +       void *pParser = NULL;
14407 +       int token_id = 0;
14408 +       buffer *token = NULL;
14409 +       http_req_range_ctx_t context;
14410 +       parse_status_t ret = PARSE_UNSET;
14411 +
14412 +       t.hdr = hdr;
14413 +       t.ndx = 0;
14414 +
14415 +       context.ok = 1;
14416 +       context.errmsg = buffer_init();
14417 +       context.ranges = ranges;
14418 +
14419 +       pParser = http_req_range_parserAlloc( malloc );
14420 +       token = buffer_init();
14421 +#if 0
14422 +       http_req_range_parserTrace(stderr, "range: "); 
14423 +#endif
14424 +
14425 +       while((1 == http_req_range_tokenizer(&t, &token_id, token)) && context.ok) {
14426 +               http_req_range_parser(pParser, token_id, token, &context);
14427 +
14428 +               token = buffer_init();
14429 +       }
14430 +
14431 +       /* oops, the parser failed */
14432 +       if (context.ok == 0) {
14433 +               ret = PARSE_ERROR;
14434 +
14435 +               if (!buffer_is_empty(context.errmsg)) {
14436 +                       TRACE("parsing failed: %s", BUF_STR(context.errmsg));
14437 +               } else {
14438 +                       TRACE("%s", "parsing failed ...");
14439 +               }
14440 +       }
14441 +
14442 +       http_req_range_parser(pParser, 0, token, &context);
14443 +       http_req_range_parserFree(pParser, free);
14444 +
14445 +       if (context.ok == 0) {
14446 +               /* we are missing the some tokens */
14447 +
14448 +               if (!buffer_is_empty(context.errmsg)) {
14449 +                       TRACE("parsing failed: %s", BUF_STR(context.errmsg));
14450 +               }
14451 +
14452 +               if (ret == PARSE_UNSET) {
14453 +                       ret = buffer_is_empty(context.errmsg) ? PARSE_NEED_MORE : PARSE_ERROR;
14454 +               }
14455 +       } else {
14456 +               ret = PARSE_SUCCESS;
14457 +       }
14458 +
14459 +       buffer_free(token);
14460 +       buffer_free(context.errmsg);
14461 +
14462 +       return ret;
14463 +}
14464 +
14465 --- ../lighttpd-1.4.11/src/http_req_range.h     1970-01-01 03:00:00.000000000 +0300
14466 +++ lighttpd-1.5.0/src/http_req_range.h 2006-09-07 00:57:05.000000000 +0300
14467 @@ -0,0 +1,27 @@
14468 +#ifndef _HTTP_REQ_RANGE_H_
14469 +#define _HTTP_REQ_RANGE_H_
14470 +
14471 +#include "array.h"
14472 +#include "chunk.h"
14473 +#include "http_parser.h"
14474 +
14475 +typedef struct _http_req_range {
14476 +       off_t start;
14477 +       off_t end;
14478 +       struct _http_req_range *next;
14479 +} http_req_range;
14480 +
14481 +typedef struct {
14482 +       int     ok;
14483 +       buffer *errmsg;
14484 +
14485 +       http_req_range *ranges;
14486 +} http_req_range_ctx_t;
14487 +
14488 +http_req_range *http_request_range_init(void);
14489 +void http_request_range_free(http_req_range *range);
14490 +void http_request_range_reset(http_req_range *range);
14491 +
14492 +parse_status_t http_request_range_parse(buffer *range_hdr, http_req_range *ranges);
14493 +
14494 +#endif
14495 --- ../lighttpd-1.4.11/src/http_req_range_parser.c      1970-01-01 03:00:00.000000000 +0300
14496 +++ lighttpd-1.5.0/src/http_req_range_parser.c  2006-09-07 01:00:42.000000000 +0300
14497 @@ -0,0 +1,836 @@
14498 +/* Driver template for the LEMON parser generator.
14499 +** The author disclaims copyright to this source code.
14500 +*/
14501 +/* First off, code is include which follows the "include" declaration
14502 +** in the input file. */
14503 +#include <stdio.h>
14504 +#line 6 "./http_req_range_parser.y"
14505 +
14506 +#ifdef HAVE_CONFIG_H
14507 +#include "config.h"
14508 +#endif
14509 +#include <sys/types.h>
14510 +#include <string.h>
14511 +#include "http_req_range.h"
14512 +#include "log.h"
14513 +
14514 +#line 18 "http_req_range_parser.c"
14515 +/* Next is all token values, in a form suitable for use by makeheaders.
14516 +** This section will be null unless lemon is run with the -m switch.
14517 +*/
14518 +/*
14519 +** These constants (all generated automatically by the parser generator)
14520 +** specify the various kinds of tokens (terminals) that the parser
14521 +** understands.
14522 +**
14523 +** Each symbol here is a terminal symbol in the grammar.
14524 +*/
14525 +/* Make sure the INTERFACE macro is defined.
14526 +*/
14527 +#ifndef INTERFACE
14528 +# define INTERFACE 1
14529 +#endif
14530 +/* The next thing included is series of defines which control
14531 +** various aspects of the generated parser.
14532 +**    YYCODETYPE         is the data type used for storing terminal
14533 +**                       and nonterminal numbers.  "unsigned char" is
14534 +**                       used if there are fewer than 250 terminals
14535 +**                       and nonterminals.  "int" is used otherwise.
14536 +**    YYNOCODE           is a number of type YYCODETYPE which corresponds
14537 +**                       to no legal terminal or nonterminal number.  This
14538 +**                       number is used to fill in empty slots of the hash
14539 +**                       table.
14540 +**    YYFALLBACK         If defined, this indicates that one or more tokens
14541 +**                       have fall-back values which should be used if the
14542 +**                       original value of the token will not parse.
14543 +**    YYACTIONTYPE       is the data type used for storing terminal
14544 +**                       and nonterminal numbers.  "unsigned char" is
14545 +**                       used if there are fewer than 250 rules and
14546 +**                       states combined.  "int" is used otherwise.
14547 +**    http_req_range_parserTOKENTYPE     is the data type used for minor tokens given
14548 +**                       directly to the parser from the tokenizer.
14549 +**    YYMINORTYPE        is the data type used for all minor tokens.
14550 +**                       This is typically a union of many types, one of
14551 +**                       which is http_req_range_parserTOKENTYPE.  The entry in the union
14552 +**                       for base tokens is called "yy0".
14553 +**    YYSTACKDEPTH       is the maximum depth of the parser's stack.
14554 +**    http_req_range_parserARG_SDECL     A static variable declaration for the %extra_argument
14555 +**    http_req_range_parserARG_PDECL     A parameter declaration for the %extra_argument
14556 +**    http_req_range_parserARG_STORE     Code to store %extra_argument into yypParser
14557 +**    http_req_range_parserARG_FETCH     Code to extract %extra_argument from yypParser
14558 +**    YYNSTATE           the combined number of states.
14559 +**    YYNRULE            the number of rules in the grammar
14560 +**    YYERRORSYMBOL      is the code number of the error symbol.  If not
14561 +**                       defined, then do no error processing.
14562 +*/
14563 +/* \ 1 */
14564 +#define YYCODETYPE unsigned char
14565 +#define YYNOCODE 12
14566 +#define YYACTIONTYPE unsigned char
14567 +#define http_req_range_parserTOKENTYPE buffer *
14568 +typedef union {
14569 +  http_req_range_parserTOKENTYPE yy0;
14570 +  http_req_range * yy18;
14571 +  off_t yy19;
14572 +  int yy23;
14573 +} YYMINORTYPE;
14574 +#define YYSTACKDEPTH 100
14575 +#define http_req_range_parserARG_SDECL http_req_range_ctx_t *ctx;
14576 +#define http_req_range_parserARG_PDECL ,http_req_range_ctx_t *ctx
14577 +#define http_req_range_parserARG_FETCH http_req_range_ctx_t *ctx = yypParser->ctx
14578 +#define http_req_range_parserARG_STORE yypParser->ctx = ctx
14579 +#define YYNSTATE 13
14580 +#define YYNRULE 7
14581 +#define YYERRORSYMBOL 6
14582 +#define YYERRSYMDT yy23
14583 +#define YY_NO_ACTION      (YYNSTATE+YYNRULE+2)
14584 +#define YY_ACCEPT_ACTION  (YYNSTATE+YYNRULE+1)
14585 +#define YY_ERROR_ACTION   (YYNSTATE+YYNRULE)
14586 +
14587 +/* Next are that tables used to determine what action to take based on the
14588 +** current state and lookahead token.  These tables are used to implement
14589 +** functions that take a state number and lookahead value and return an
14590 +** action integer.
14591 +**
14592 +** Suppose the action integer is N.  Then the action is determined as
14593 +** follows
14594 +**
14595 +**   0 <= N < YYNSTATE                  Shift N.  That is, push the lookahead
14596 +**                                      token onto the stack and goto state N.
14597 +**
14598 +**   YYNSTATE <= N < YYNSTATE+YYNRULE   Reduce by rule N-YYNSTATE.
14599 +**
14600 +**   N == YYNSTATE+YYNRULE              A syntax error has occurred.
14601 +**
14602 +**   N == YYNSTATE+YYNRULE+1            The parser accepts its input.
14603 +**
14604 +**   N == YYNSTATE+YYNRULE+2            No such action.  Denotes unused
14605 +**                                      slots in the yy_action[] table.
14606 +**
14607 +** The action table is constructed as a single large table named yy_action[].
14608 +** Given state S and lookahead X, the action is computed as
14609 +**
14610 +**      yy_action[ yy_shift_ofst[S] + X ]
14611 +**
14612 +** If the index value yy_shift_ofst[S]+X is out of range or if the value
14613 +** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
14614 +** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
14615 +** and that yy_default[S] should be used instead.
14616 +**
14617 +** The formula above is for computing the action when the lookahead is
14618 +** a terminal symbol.  If the lookahead is a non-terminal (as occurs after
14619 +** a reduce action) then the yy_reduce_ofst[] array is used in place of
14620 +** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
14621 +** YY_SHIFT_USE_DFLT.
14622 +**
14623 +** The following are the tables generated in this section:
14624 +**
14625 +**  yy_action[]        A single table containing all actions.
14626 +**  yy_lookahead[]     A table containing the lookahead for each entry in
14627 +**                     yy_action.  Used to detect hash collisions.
14628 +**  yy_shift_ofst[]    For each state, the offset into yy_action for
14629 +**                     shifting terminals.
14630 +**  yy_reduce_ofst[]   For each state, the offset into yy_action for
14631 +**                     shifting non-terminals after a reduce.
14632 +**  yy_default[]       Default action for each state.
14633 +*/
14634 +static YYACTIONTYPE yy_action[] = {
14635 + /*     0 */     6,   12,    3,   10,    9,   13,   21,    1,    4,    6,
14636 + /*    10 */     5,    2,    7,   20,    8,    9,   20,   20,   11,
14637 +};
14638 +static YYCODETYPE yy_lookahead[] = {
14639 + /*     0 */     7,    8,    9,    4,    5,    0,   10,    1,    3,    7,
14640 + /*    10 */     8,    2,    4,   11,    7,    5,   11,   11,    7,
14641 +};
14642 +#define YY_SHIFT_USE_DFLT (-2)
14643 +static signed char yy_shift_ofst[] = {
14644 + /*     0 */     6,    9,   -1,    5,   -1,   -2,    8,   10,   -2,   -2,
14645 + /*    10 */    10,   -2,   -2,
14646 +};
14647 +#define YY_REDUCE_USE_DFLT (-8)
14648 +static signed char yy_reduce_ofst[] = {
14649 + /*     0 */    -4,   -8,   -7,   -8,    2,   -8,   -8,    7,   -8,   -8,
14650 + /*    10 */    11,   -8,   -8,
14651 +};
14652 +static YYACTIONTYPE yy_default[] = {
14653 + /*     0 */    20,   20,   20,   20,   20,   14,   20,   16,   17,   19,
14654 + /*    10 */    20,   18,   15,
14655 +};
14656 +#define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0]))
14657 +
14658 +/* The next table maps tokens into fallback tokens.  If a construct
14659 +** like the following:
14660 +**
14661 +**      %fallback ID X Y Z.
14662 +**
14663 +** appears in the grammer, then ID becomes a fallback token for X, Y,
14664 +** and Z.  Whenever one of the tokens X, Y, or Z is input to the parser
14665 +** but it does not parse, the type of the token is changed to ID and
14666 +** the parse is retried before an error is thrown.
14667 +*/
14668 +#ifdef YYFALLBACK
14669 +static const YYCODETYPE yyFallback[] = {
14670 +};
14671 +#endif /* YYFALLBACK */
14672 +
14673 +/* The following structure represents a single element of the
14674 +** parser's stack.  Information stored includes:
14675 +**
14676 +**   +  The state number for the parser at this level of the stack.
14677 +**
14678 +**   +  The value of the token stored at this level of the stack.
14679 +**      (In other words, the "major" token.)
14680 +**
14681 +**   +  The semantic value stored at this level of the stack.  This is
14682 +**      the information used by the action routines in the grammar.
14683 +**      It is sometimes called the "minor" token.
14684 +*/
14685 +struct yyStackEntry {
14686 +  int stateno;       /* The state-number */
14687 +  int major;         /* The major token value.  This is the code
14688 +                     ** number for the token at this stack level */
14689 +  YYMINORTYPE minor; /* The user-supplied minor token value.  This
14690 +                     ** is the value of the token  */
14691 +};
14692 +typedef struct yyStackEntry yyStackEntry;
14693 +
14694 +/* The state of the parser is completely contained in an instance of
14695 +** the following structure */
14696 +struct yyParser {
14697 +  int yyidx;                    /* Index of top element in stack */
14698 +  int yyerrcnt;                 /* Shifts left before out of the error */
14699 +  http_req_range_parserARG_SDECL                /* A place to hold %extra_argument */
14700 +  yyStackEntry yystack[YYSTACKDEPTH];  /* The parser's stack */
14701 +};
14702 +typedef struct yyParser yyParser;
14703 +
14704 +#ifndef NDEBUG
14705 +#include <stdio.h>
14706 +static FILE *yyTraceFILE = 0;
14707 +static char *yyTracePrompt = 0;
14708 +#endif /* NDEBUG */
14709 +
14710 +#ifndef NDEBUG
14711 +/*
14712 +** Turn parser tracing on by giving a stream to which to write the trace
14713 +** and a prompt to preface each trace message.  Tracing is turned off
14714 +** by making either argument NULL
14715 +**
14716 +** Inputs:
14717 +** <ul>
14718 +** <li> A FILE* to which trace output should be written.
14719 +**      If NULL, then tracing is turned off.
14720 +** <li> A prefix string written at the beginning of every
14721 +**      line of trace output.  If NULL, then tracing is
14722 +**      turned off.
14723 +** </ul>
14724 +**
14725 +** Outputs:
14726 +** None.
14727 +*/
14728 +void http_req_range_parserTrace(FILE *TraceFILE, char *zTracePrompt){
14729 +  yyTraceFILE = TraceFILE;
14730 +  yyTracePrompt = zTracePrompt;
14731 +  if( yyTraceFILE==0 ) yyTracePrompt = 0;
14732 +  else if( yyTracePrompt==0 ) yyTraceFILE = 0;
14733 +}
14734 +#endif /* NDEBUG */
14735 +
14736 +#ifndef NDEBUG
14737 +/* For tracing shifts, the names of all terminals and nonterminals
14738 +** are required.  The following table supplies these names */
14739 +static const char *yyTokenName[] = {
14740 +  "$",             "BYTES",         "EQUAL",         "COMMA",       
14741 +  "MINUS",         "NUMBER",        "error",         "num",         
14742 +  "range",         "ranges",        "range_hdr",   
14743 +};
14744 +#endif /* NDEBUG */
14745 +
14746 +#ifndef NDEBUG
14747 +/* For tracing reduce actions, the names of all rules are required.
14748 +*/
14749 +static const char *yyRuleName[] = {
14750 + /*   0 */ "range_hdr ::= BYTES EQUAL ranges",
14751 + /*   1 */ "ranges ::= ranges COMMA range",
14752 + /*   2 */ "ranges ::= range",
14753 + /*   3 */ "range ::= num MINUS",
14754 + /*   4 */ "range ::= num MINUS num",
14755 + /*   5 */ "range ::= MINUS num",
14756 + /*   6 */ "num ::= NUMBER",
14757 +};
14758 +#endif /* NDEBUG */
14759 +
14760 +/*
14761 +** This function returns the symbolic name associated with a token
14762 +** value.
14763 +*/
14764 +const char *http_req_range_parserTokenName(int tokenType){
14765 +#ifndef NDEBUG
14766 +  if( tokenType>0 && tokenType<(sizeof(yyTokenName)/sizeof(yyTokenName[0])) ){
14767 +    return yyTokenName[tokenType];
14768 +  }else{
14769 +    return "Unknown";
14770 +  }
14771 +#else
14772 +  return "";
14773 +#endif
14774 +}
14775 +
14776 +/*
14777 +** This function allocates a new parser.
14778 +** The only argument is a pointer to a function which works like
14779 +** malloc.
14780 +**
14781 +** Inputs:
14782 +** A pointer to the function used to allocate memory.
14783 +**
14784 +** Outputs:
14785 +** A pointer to a parser.  This pointer is used in subsequent calls
14786 +** to http_req_range_parser and http_req_range_parserFree.
14787 +*/
14788 +void *http_req_range_parserAlloc(void *(*mallocProc)(size_t)){
14789 +  yyParser *pParser;
14790 +  pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) );
14791 +  if( pParser ){
14792 +    pParser->yyidx = -1;
14793 +  }
14794 +  return pParser;
14795 +}
14796 +
14797 +/* The following function deletes the value associated with a
14798 +** symbol.  The symbol can be either a terminal or nonterminal.
14799 +** "yymajor" is the symbol code, and "yypminor" is a pointer to
14800 +** the value.
14801 +*/
14802 +static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){
14803 +  switch( yymajor ){
14804 +    /* Here is inserted the actions which take place when a
14805 +    ** terminal or non-terminal is destroyed.  This can happen
14806 +    ** when the symbol is popped from the stack during a
14807 +    ** reduce or during error processing or when a parser is
14808 +    ** being destroyed before it is finished parsing.
14809 +    **
14810 +    ** Note: during a reduce, the only symbols destroyed are those
14811 +    ** which appear on the RHS of the rule, but which are not used
14812 +    ** inside the C code.
14813 +    */
14814 +    case 1:
14815 +    case 2:
14816 +    case 3:
14817 +    case 4:
14818 +    case 5:
14819 +#line 23 "./http_req_range_parser.y"
14820 +{ buffer_free((yypminor->yy0)); }
14821 +#line 324 "http_req_range_parser.c"
14822 +      break;
14823 +    default:  break;   /* If no destructor action specified: do nothing */
14824 +  }
14825 +}
14826 +
14827 +/*
14828 +** Pop the parser's stack once.
14829 +**
14830 +** If there is a destructor routine associated with the token which
14831 +** is popped from the stack, then call it.
14832 +**
14833 +** Return the major token number for the symbol popped.
14834 +*/
14835 +static int yy_pop_parser_stack(yyParser *pParser){
14836 +  YYCODETYPE yymajor;
14837 +  yyStackEntry *yytos = &pParser->yystack[pParser->yyidx];
14838 +
14839 +  if( pParser->yyidx<0 ) return 0;
14840 +#ifndef NDEBUG
14841 +  if( yyTraceFILE && pParser->yyidx>=0 ){
14842 +    fprintf(yyTraceFILE,"%sPopping %s\n",
14843 +      yyTracePrompt,
14844 +      yyTokenName[yytos->major]);
14845 +  }
14846 +#endif
14847 +  yymajor = yytos->major;
14848 +  yy_destructor( yymajor, &yytos->minor);
14849 +  pParser->yyidx--;
14850 +  return yymajor;
14851 +}
14852 +
14853 +/*
14854 +** Deallocate and destroy a parser.  Destructors are all called for
14855 +** all stack elements before shutting the parser down.
14856 +**
14857 +** Inputs:
14858 +** <ul>
14859 +** <li>  A pointer to the parser.  This should be a pointer
14860 +**       obtained from http_req_range_parserAlloc.
14861 +** <li>  A pointer to a function used to reclaim memory obtained
14862 +**       from malloc.
14863 +** </ul>
14864 +*/
14865 +void http_req_range_parserFree(
14866 +  void *p,                    /* The parser to be deleted */
14867 +  void (*freeProc)(void*)     /* Function used to reclaim memory */
14868 +){
14869 +  yyParser *pParser = (yyParser*)p;
14870 +  if( pParser==0 ) return;
14871 +  while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
14872 +  (*freeProc)((void*)pParser);
14873 +}
14874 +
14875 +/*
14876 +** Find the appropriate action for a parser given the terminal
14877 +** look-ahead token iLookAhead.
14878 +**
14879 +** If the look-ahead token is YYNOCODE, then check to see if the action is
14880 +** independent of the look-ahead.  If it is, return the action, otherwise
14881 +** return YY_NO_ACTION.
14882 +*/
14883 +static int yy_find_shift_action(
14884 +  yyParser *pParser,        /* The parser */
14885 +  int iLookAhead            /* The look-ahead token */
14886 +){
14887 +  int i;
14888 +  int stateno = pParser->yystack[pParser->yyidx].stateno;
14889 +
14890 +  /* if( pParser->yyidx<0 ) return YY_NO_ACTION;  */
14891 +  i = yy_shift_ofst[stateno];
14892 +  if( i==YY_SHIFT_USE_DFLT ){
14893 +    return yy_default[stateno];
14894 +  }
14895 +  if( iLookAhead==YYNOCODE ){
14896 +    return YY_NO_ACTION;
14897 +  }
14898 +  i += iLookAhead;
14899 +  if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
14900 +#ifdef YYFALLBACK
14901 +    int iFallback;            /* Fallback token */
14902 +    if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
14903 +           && (iFallback = yyFallback[iLookAhead])!=0 ){
14904 +#ifndef NDEBUG
14905 +      if( yyTraceFILE ){
14906 +        fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
14907 +           yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
14908 +      }
14909 +#endif
14910 +      return yy_find_shift_action(pParser, iFallback);
14911 +    }
14912 +#endif
14913 +    return yy_default[stateno];
14914 +  }else{
14915 +    return yy_action[i];
14916 +  }
14917 +}
14918 +
14919 +/*
14920 +** Find the appropriate action for a parser given the non-terminal
14921 +** look-ahead token iLookAhead.
14922 +**
14923 +** If the look-ahead token is YYNOCODE, then check to see if the action is
14924 +** independent of the look-ahead.  If it is, return the action, otherwise
14925 +** return YY_NO_ACTION.
14926 +*/
14927 +static int yy_find_reduce_action(
14928 +  yyParser *pParser,        /* The parser */
14929 +  int iLookAhead            /* The look-ahead token */
14930 +){
14931 +  int i;
14932 +  int stateno = pParser->yystack[pParser->yyidx].stateno;
14933 +
14934 +  i = yy_reduce_ofst[stateno];
14935 +  if( i==YY_REDUCE_USE_DFLT ){
14936 +    return yy_default[stateno];
14937 +  }
14938 +  if( iLookAhead==YYNOCODE ){
14939 +    return YY_NO_ACTION;
14940 +  }
14941 +  i += iLookAhead;
14942 +  if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
14943 +    return yy_default[stateno];
14944 +  }else{
14945 +    return yy_action[i];
14946 +  }
14947 +}
14948 +
14949 +/*
14950 +** Perform a shift action.
14951 +*/
14952 +static void yy_shift(
14953 +  yyParser *yypParser,          /* The parser to be shifted */
14954 +  int yyNewState,               /* The new state to shift in */
14955 +  int yyMajor,                  /* The major token to shift in */
14956 +  YYMINORTYPE *yypMinor         /* Pointer ot the minor token to shift in */
14957 +){
14958 +  yyStackEntry *yytos;
14959 +  yypParser->yyidx++;
14960 +  if( yypParser->yyidx>=YYSTACKDEPTH ){
14961 +     http_req_range_parserARG_FETCH;
14962 +     yypParser->yyidx--;
14963 +#ifndef NDEBUG
14964 +     if( yyTraceFILE ){
14965 +       fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
14966 +     }
14967 +#endif
14968 +     while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
14969 +     /* Here code is inserted which will execute if the parser
14970 +     ** stack every overflows */
14971 +     http_req_range_parserARG_STORE; /* Suppress warning about unused %extra_argument var */
14972 +     return;
14973 +  }
14974 +  yytos = &yypParser->yystack[yypParser->yyidx];
14975 +  yytos->stateno = yyNewState;
14976 +  yytos->major = yyMajor;
14977 +  yytos->minor = *yypMinor;
14978 +#ifndef NDEBUG
14979 +  if( yyTraceFILE && yypParser->yyidx>0 ){
14980 +    int i;
14981 +    fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState);
14982 +    fprintf(yyTraceFILE,"%sStack:",yyTracePrompt);
14983 +    for(i=1; i<=yypParser->yyidx; i++)
14984 +      fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]);
14985 +    fprintf(yyTraceFILE,"\n");
14986 +  }
14987 +#endif
14988 +}
14989 +
14990 +/* The following table contains information about every rule that
14991 +** is used during the reduce.
14992 +*/
14993 +static struct {
14994 +  YYCODETYPE lhs;         /* Symbol on the left-hand side of the rule */
14995 +  unsigned char nrhs;     /* Number of right-hand side symbols in the rule */
14996 +} yyRuleInfo[] = {
14997 +  { 10, 3 },
14998 +  { 9, 3 },
14999 +  { 9, 1 },
15000 +  { 8, 2 },
15001 +  { 8, 3 },
15002 +  { 8, 2 },
15003 +  { 7, 1 },
15004 +};
15005 +
15006 +static void yy_accept(yyParser*);  /* Forward Declaration */
15007 +
15008 +/*
15009 +** Perform a reduce action and the shift that must immediately
15010 +** follow the reduce.
15011 +*/
15012 +static void yy_reduce(
15013 +  yyParser *yypParser,         /* The parser */
15014 +  int yyruleno                 /* Number of the rule by which to reduce */
15015 +){
15016 +  int yygoto;                     /* The next state */
15017 +  int yyact;                      /* The next action */
15018 +  YYMINORTYPE yygotominor;        /* The LHS of the rule reduced */
15019 +  yyStackEntry *yymsp;            /* The top of the parser's stack */
15020 +  int yysize;                     /* Amount to pop the stack */
15021 +  http_req_range_parserARG_FETCH;
15022 +  yymsp = &yypParser->yystack[yypParser->yyidx];
15023 +#ifndef NDEBUG
15024 +  if( yyTraceFILE && yyruleno>=0
15025 +        && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
15026 +    fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
15027 +      yyRuleName[yyruleno]);
15028 +  }
15029 +#endif /* NDEBUG */
15030 +
15031 +  switch( yyruleno ){
15032 +  /* Beginning here are the reduction cases.  A typical example
15033 +  ** follows:
15034 +  **   case 0:
15035 +  **  #line <lineno> <grammarfile>
15036 +  **     { ... }           // User supplied code
15037 +  **  #line <lineno> <thisfile>
15038 +  **     break;
15039 +  */
15040 +      case 0:
15041 +#line 26 "./http_req_range_parser.y"
15042 +{
15043 +  ctx->ranges->start = yymsp[0].minor.yy18->start;
15044 +  ctx->ranges->end  = yymsp[0].minor.yy18->end;
15045 +  ctx->ranges->next = yymsp[0].minor.yy18->next;
15046 +
15047 +  yymsp[0].minor.yy18->next = NULL;
15048 +  http_request_range_free(yymsp[0].minor.yy18);
15049 +}
15050 +#line 553 "http_req_range_parser.c"
15051 +  yy_destructor(1,&yymsp[-2].minor);
15052 +  yy_destructor(2,&yymsp[-1].minor);
15053 +        break;
15054 +      case 1:
15055 +#line 35 "./http_req_range_parser.y"
15056 +{
15057 +  for (yygotominor.yy18 = yymsp[-2].minor.yy18; yygotominor.yy18->next; yygotominor.yy18 = yygotominor.yy18->next);
15058 +
15059 +  yygotominor.yy18->next = yymsp[0].minor.yy18;
15060 +
15061 +  yygotominor.yy18 = yymsp[-2].minor.yy18;
15062 +}
15063 +#line 566 "http_req_range_parser.c"
15064 +  yy_destructor(3,&yymsp[-1].minor);
15065 +        break;
15066 +      case 2:
15067 +#line 42 "./http_req_range_parser.y"
15068 +{
15069 +  yygotominor.yy18 = yymsp[0].minor.yy18;
15070 +}
15071 +#line 574 "http_req_range_parser.c"
15072 +        break;
15073 +      case 3:
15074 +#line 45 "./http_req_range_parser.y"
15075 +{
15076 +  http_req_range *r = http_request_range_init();
15077 +
15078 +  r->start = yymsp[-1].minor.yy19;
15079 +  r->end = -1;
15080 +
15081 +  yygotominor.yy18 = r;
15082 +}
15083 +#line 586 "http_req_range_parser.c"
15084 +  yy_destructor(4,&yymsp[0].minor);
15085 +        break;
15086 +      case 4:
15087 +#line 54 "./http_req_range_parser.y"
15088 +{
15089 +  http_req_range *r = http_request_range_init();
15090 +
15091 +  r->start = yymsp[-2].minor.yy19;
15092 +  r->end = yymsp[0].minor.yy19;
15093 +
15094 +  yygotominor.yy18 = r;
15095 +}
15096 +#line 599 "http_req_range_parser.c"
15097 +  yy_destructor(4,&yymsp[-1].minor);
15098 +        break;
15099 +      case 5:
15100 +#line 63 "./http_req_range_parser.y"
15101 +{
15102 +  http_req_range *r = http_request_range_init();
15103 +
15104 +  r->start = -1;
15105 +  r->end = yymsp[0].minor.yy19;
15106 +
15107 +  yygotominor.yy18 = r;
15108 +}
15109 +#line 612 "http_req_range_parser.c"
15110 +  yy_destructor(4,&yymsp[-1].minor);
15111 +        break;
15112 +      case 6:
15113 +#line 72 "./http_req_range_parser.y"
15114 +{
15115 +  yygotominor.yy19 = strtoull(BUF_STR(yymsp[0].minor.yy0), NULL, 10);
15116 +}
15117 +#line 620 "http_req_range_parser.c"
15118 +        break;
15119 +  };
15120 +  yygoto = yyRuleInfo[yyruleno].lhs;
15121 +  yysize = yyRuleInfo[yyruleno].nrhs;
15122 +  yypParser->yyidx -= yysize;
15123 +  yyact = yy_find_reduce_action(yypParser,yygoto);
15124 +  if( yyact < YYNSTATE ){
15125 +    yy_shift(yypParser,yyact,yygoto,&yygotominor);
15126 +  }else if( yyact == YYNSTATE + YYNRULE + 1 ){
15127 +    yy_accept(yypParser);
15128 +  }
15129 +}
15130 +
15131 +/*
15132 +** The following code executes when the parse fails
15133 +*/
15134 +static void yy_parse_failed(
15135 +  yyParser *yypParser           /* The parser */
15136 +){
15137 +  http_req_range_parserARG_FETCH;
15138 +#ifndef NDEBUG
15139 +  if( yyTraceFILE ){
15140 +    fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
15141 +  }
15142 +#endif
15143 +  while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
15144 +  /* Here code is inserted which will be executed whenever the
15145 +  ** parser fails */
15146 +#line 16 "./http_req_range_parser.y"
15147 +
15148 +  ctx->ok = 0;
15149 +
15150 +#line 653 "http_req_range_parser.c"
15151 +  http_req_range_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
15152 +}
15153 +
15154 +/*
15155 +** The following code executes when a syntax error first occurs.
15156 +*/
15157 +static void yy_syntax_error(
15158 +  yyParser *yypParser,           /* The parser */
15159 +  int yymajor,                   /* The major type of the error token */
15160 +  YYMINORTYPE yyminor            /* The minor type of the error token */
15161 +){
15162 +  http_req_range_parserARG_FETCH;
15163 +#define TOKEN (yyminor.yy0)
15164 +  http_req_range_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
15165 +}
15166 +
15167 +/*
15168 +** The following is executed when the parser accepts
15169 +*/
15170 +static void yy_accept(
15171 +  yyParser *yypParser           /* The parser */
15172 +){
15173 +  http_req_range_parserARG_FETCH;
15174 +#ifndef NDEBUG
15175 +  if( yyTraceFILE ){
15176 +    fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
15177 +  }
15178 +#endif
15179 +  while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
15180 +  /* Here code is inserted which will be executed whenever the
15181 +  ** parser accepts */
15182 +  http_req_range_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
15183 +}
15184 +
15185 +/* The main parser program.
15186 +** The first argument is a pointer to a structure obtained from
15187 +** "http_req_range_parserAlloc" which describes the current state of the parser.
15188 +** The second argument is the major token number.  The third is
15189 +** the minor token.  The fourth optional argument is whatever the
15190 +** user wants (and specified in the grammar) and is available for
15191 +** use by the action routines.
15192 +**
15193 +** Inputs:
15194 +** <ul>
15195 +** <li> A pointer to the parser (an opaque structure.)
15196 +** <li> The major token number.
15197 +** <li> The minor token number.
15198 +** <li> An option argument of a grammar-specified type.
15199 +** </ul>
15200 +**
15201 +** Outputs:
15202 +** None.
15203 +*/
15204 +void http_req_range_parser(
15205 +  void *yyp,                   /* The parser */
15206 +  int yymajor,                 /* The major token code number */
15207 +  http_req_range_parserTOKENTYPE yyminor       /* The value for the token */
15208 +  http_req_range_parserARG_PDECL               /* Optional %extra_argument parameter */
15209 +){
15210 +  YYMINORTYPE yyminorunion;
15211 +  int yyact;            /* The parser action. */
15212 +  int yyendofinput;     /* True if we are at the end of input */
15213 +  int yyerrorhit = 0;   /* True if yymajor has invoked an error */
15214 +  yyParser *yypParser;  /* The parser */
15215 +
15216 +  /* (re)initialize the parser, if necessary */
15217 +  yypParser = (yyParser*)yyp;
15218 +  if( yypParser->yyidx<0 ){
15219 +    if( yymajor==0 ) return;
15220 +    yypParser->yyidx = 0;
15221 +    yypParser->yyerrcnt = -1;
15222 +    yypParser->yystack[0].stateno = 0;
15223 +    yypParser->yystack[0].major = 0;
15224 +  }
15225 +  yyminorunion.yy0 = yyminor;
15226 +  yyendofinput = (yymajor==0);
15227 +  http_req_range_parserARG_STORE;
15228 +
15229 +#ifndef NDEBUG
15230 +  if( yyTraceFILE ){
15231 +    fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]);
15232 +  }
15233 +#endif
15234 +
15235 +  do{
15236 +    yyact = yy_find_shift_action(yypParser,yymajor);
15237 +    if( yyact<YYNSTATE ){
15238 +      yy_shift(yypParser,yyact,yymajor,&yyminorunion);
15239 +      yypParser->yyerrcnt--;
15240 +      if( yyendofinput && yypParser->yyidx>=0 ){
15241 +        yymajor = 0;
15242 +      }else{
15243 +        yymajor = YYNOCODE;
15244 +      }
15245 +    }else if( yyact < YYNSTATE + YYNRULE ){
15246 +      yy_reduce(yypParser,yyact-YYNSTATE);
15247 +    }else if( yyact == YY_ERROR_ACTION ){
15248 +      int yymx;
15249 +#ifndef NDEBUG
15250 +      if( yyTraceFILE ){
15251 +        fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
15252 +      }
15253 +#endif
15254 +#ifdef YYERRORSYMBOL
15255 +      /* A syntax error has occurred.
15256 +      ** The response to an error depends upon whether or not the
15257 +      ** grammar defines an error token "ERROR".
15258 +      **
15259 +      ** This is what we do if the grammar does define ERROR:
15260 +      **
15261 +      **  * Call the %syntax_error function.
15262 +      **
15263 +      **  * Begin popping the stack until we enter a state where
15264 +      **    it is legal to shift the error symbol, then shift
15265 +      **    the error symbol.
15266 +      **
15267 +      **  * Set the error count to three.
15268 +      **
15269 +      **  * Begin accepting and shifting new tokens.  No new error
15270 +      **    processing will occur until three tokens have been
15271 +      **    shifted successfully.
15272 +      **
15273 +      */
15274 +      if( yypParser->yyerrcnt<0 ){
15275 +        yy_syntax_error(yypParser,yymajor,yyminorunion);
15276 +      }
15277 +      yymx = yypParser->yystack[yypParser->yyidx].major;
15278 +      if( yymx==YYERRORSYMBOL || yyerrorhit ){
15279 +#ifndef NDEBUG
15280 +        if( yyTraceFILE ){
15281 +          fprintf(yyTraceFILE,"%sDiscard input token %s\n",
15282 +             yyTracePrompt,yyTokenName[yymajor]);
15283 +        }
15284 +#endif
15285 +        yy_destructor(yymajor,&yyminorunion);
15286 +        yymajor = YYNOCODE;
15287 +      }else{
15288 +         while(
15289 +          yypParser->yyidx >= 0 &&
15290 +          yymx != YYERRORSYMBOL &&
15291 +          (yyact = yy_find_shift_action(yypParser,YYERRORSYMBOL)) >= YYNSTATE
15292 +        ){
15293 +          yy_pop_parser_stack(yypParser);
15294 +        }
15295 +        if( yypParser->yyidx < 0 || yymajor==0 ){
15296 +          yy_destructor(yymajor,&yyminorunion);
15297 +          yy_parse_failed(yypParser);
15298 +          yymajor = YYNOCODE;
15299 +        }else if( yymx!=YYERRORSYMBOL ){
15300 +          YYMINORTYPE u2;
15301 +          u2.YYERRSYMDT = 0;
15302 +          yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2);
15303 +        }
15304 +      }
15305 +      yypParser->yyerrcnt = 3;
15306 +      yyerrorhit = 1;
15307 +#else  /* YYERRORSYMBOL is not defined */
15308 +      /* This is what we do if the grammar does not define ERROR:
15309 +      **
15310 +      **  * Report an error message, and throw away the input token.
15311 +      **
15312 +      **  * If the input token is $, then fail the parse.
15313 +      **
15314 +      ** As before, subsequent error messages are suppressed until
15315 +      ** three input tokens have been successfully shifted.
15316 +      */
15317 +      if( yypParser->yyerrcnt<=0 ){
15318 +        yy_syntax_error(yypParser,yymajor,yyminorunion);
15319 +      }
15320 +      yypParser->yyerrcnt = 3;
15321 +      yy_destructor(yymajor,&yyminorunion);
15322 +      if( yyendofinput ){
15323 +        yy_parse_failed(yypParser);
15324 +      }
15325 +      yymajor = YYNOCODE;
15326 +#endif
15327 +    }else{
15328 +      yy_accept(yypParser);
15329 +      yymajor = YYNOCODE;
15330 +    }
15331 +  }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
15332 +  return;
15333 +}
15334 --- ../lighttpd-1.4.11/src/http_req_range_parser.h      1970-01-01 03:00:00.000000000 +0300
15335 +++ lighttpd-1.5.0/src/http_req_range_parser.h  2006-09-07 01:00:42.000000000 +0300
15336 @@ -0,0 +1,5 @@
15337 +#define TK_BYTES                           1
15338 +#define TK_EQUAL                           2
15339 +#define TK_COMMA                           3
15340 +#define TK_MINUS                           4
15341 +#define TK_NUMBER                          5
15342 --- ../lighttpd-1.4.11/src/http_req_range_parser.y      1970-01-01 03:00:00.000000000 +0300
15343 +++ lighttpd-1.5.0/src/http_req_range_parser.y  2006-09-07 00:57:05.000000000 +0300
15344 @@ -0,0 +1,74 @@
15345 +%token_prefix TK_
15346 +%token_type {buffer *}
15347 +%extra_argument {http_req_range_ctx_t *ctx}
15348 +%name http_req_range_parser
15349 +
15350 +%include {
15351 +#ifdef HAVE_CONFIG_H
15352 +#include "config.h"
15353 +#endif
15354 +#include <sys/types.h>
15355 +#include <string.h>
15356 +#include "http_req_range.h"
15357 +#include "log.h"
15358 +}
15359 +
15360 +%parse_failure {
15361 +  ctx->ok = 0;
15362 +}
15363 +
15364 +%type num { off_t }
15365 +%type range { http_req_range * }
15366 +%type ranges { http_req_range * }
15367 +%token_destructor { buffer_free($$); }
15368 +
15369 +
15370 +range_hdr ::= BYTES EQUAL ranges(A) . {
15371 +  ctx->ranges->start = A->start;
15372 +  ctx->ranges->end  = A->end;
15373 +  ctx->ranges->next = A->next;
15374 +
15375 +  A->next = NULL;
15376 +  http_request_range_free(A);
15377 +}
15378 +
15379 +ranges(A) ::= ranges(B) COMMA range(C) . {
15380 +  for (A = B; A->next; A = A->next);
15381 +
15382 +  A->next = C;
15383 +
15384 +  A = B;
15385 +}
15386 +ranges(A) ::= range(B) . {
15387 +  A = B;
15388 +}
15389 +range(A) ::= num(B) MINUS . {
15390 +  http_req_range *r = http_request_range_init();
15391 +
15392 +  r->start = B;
15393 +  r->end = -1;
15394 +
15395 +  A = r;
15396 +}
15397 +
15398 +range(A) ::= num(B) MINUS num(C) . {
15399 +  http_req_range *r = http_request_range_init();
15400 +
15401 +  r->start = B;
15402 +  r->end = C;
15403 +
15404 +  A = r;
15405 +}
15406 +
15407 +range(A) ::= MINUS num(B) . {
15408 +  http_req_range *r = http_request_range_init();
15409 +
15410 +  r->start = -1;
15411 +  r->end = B;
15412 +
15413 +  A = r;
15414 +}
15415 +
15416 +num(A) ::= NUMBER(B) . {
15417 +  A = strtoull(BUF_STR(B), NULL, 10);
15418 +}
15419 --- ../lighttpd-1.4.11/src/http_resp.c  1970-01-01 03:00:00.000000000 +0300
15420 +++ lighttpd-1.5.0/src/http_resp.c      2006-07-18 13:03:40.000000000 +0300
15421 @@ -0,0 +1,277 @@
15422 +#include <string.h>
15423 +#include <stdlib.h>
15424 +#include <stdio.h>
15425 +#include <assert.h>
15426 +
15427 +#include "log.h"
15428 +#include "http_resp.h"
15429 +#include "http_resp_parser.h"
15430 +
15431 +/* declare prototypes for the parser */
15432 +void *http_resp_parserAlloc(void *(*mallocProc)(size_t));
15433 +void http_resp_parserFree(void *p,  void (*freeProc)(void*));
15434 +void http_resp_parserTrace(FILE *TraceFILE, char *zTracePrompt);
15435 +void http_resp_parser(void *, int, buffer *, http_resp_ctx_t *);
15436 +
15437 +typedef struct {
15438 +       chunkqueue *cq;
15439 +
15440 +       chunk *c; /* current chunk in the chunkqueue */
15441 +       size_t offset; /* current offset in current chunk */
15442 +
15443 +       chunk *lookup_c;
15444 +       size_t lookup_offset;
15445 +
15446 +       int is_key;
15447 +       int is_statusline;
15448 +} http_resp_tokenizer_t;
15449 +
15450 +http_resp *http_response_init(void) {
15451 +       http_resp *resp = calloc(1, sizeof(*resp));
15452 +
15453 +       resp->reason = buffer_init();
15454 +       resp->headers = array_init();
15455 +
15456 +       return resp;
15457 +}
15458 +
15459 +void http_response_reset(http_resp *resp) {
15460 +       if (!resp) return;
15461 +
15462 +       buffer_reset(resp->reason);
15463 +       array_reset(resp->headers);
15464 +
15465 +}
15466 +
15467 +void http_response_free(http_resp *resp) {
15468 +       if (!resp) return;
15469 +
15470 +       buffer_free(resp->reason);
15471 +       array_free(resp->headers);
15472 +
15473 +       free(resp);
15474 +}
15475 +
15476 +static int http_resp_get_next_char(http_resp_tokenizer_t *t, unsigned char *c) {
15477 +       if (t->offset == t->c->mem->used - 1) {
15478 +               /* end of chunk, open next chunk */
15479 +
15480 +               if (!t->c->next) return -1;
15481 +
15482 +               t->c = t->c->next;
15483 +               t->offset = 0;
15484 +       }
15485 +
15486 +       *c = t->c->mem->ptr[t->offset++];
15487 +
15488 +       t->lookup_offset = t->offset;
15489 +       t->lookup_c = t->c;
15490 +
15491 +#if 0
15492 +       fprintf(stderr, "%s.%d: get: %c (%d) at offset: %d\r\n", __FILE__, __LINE__, *c > 31 ? *c : ' ', *c, t->offset - 1);
15493 +#endif
15494 +
15495 +       return 0;
15496 +}
15497 +
15498 +static int http_resp_lookup_next_char(http_resp_tokenizer_t *t, unsigned char *c) {
15499 +       if (t->lookup_offset == t->lookup_c->mem->used - 1) {
15500 +               /* end of chunk, open next chunk */
15501 +
15502 +               if (!t->lookup_c->next) return -1;
15503 +
15504 +               t->lookup_c = t->lookup_c->next;
15505 +               t->lookup_offset = 0;
15506 +       }
15507 +
15508 +       *c = t->lookup_c->mem->ptr[t->lookup_offset++];
15509 +#if 0
15510 +       fprintf(stderr, "%s.%d: lookup: %c (%d) at offset: %d\r\n", __FILE__, __LINE__, *c > 31 ? *c : ' ', *c, t->lookup_offset - 1);
15511 +#endif
15512 +
15513 +       return 0;
15514 +}
15515 +
15516 +
15517 +static int http_resp_tokenizer(
15518 +       http_resp_tokenizer_t *t,
15519 +       int *token_id,
15520 +       buffer *token
15521 +) {
15522 +       unsigned char c;
15523 +       int tid = 0;
15524 +
15525 +       /* push the token to the parser */
15526 +
15527 +       while (tid == 0 && 0 == http_resp_get_next_char(t, &c)) {
15528 +               switch (c) {
15529 +               case ':':
15530 +                       tid = TK_COLON;
15531 +
15532 +                       t->is_key = 0;
15533 +
15534 +                       break;
15535 +               case ' ':
15536 +               case '\t':
15537 +                       /* ignore WS */
15538 +
15539 +                       break;
15540 +               case '\r':
15541 +                       if (0 != http_resp_lookup_next_char(t, &c)) return -1;
15542 +
15543 +                       if (c == '\n') {
15544 +                               tid = TK_CRLF;
15545 +
15546 +                               t->c = t->lookup_c;
15547 +                               t->offset = t->lookup_offset;
15548 +
15549 +                               t->is_statusline = 0;
15550 +                               t->is_key = 1;
15551 +                       } else {
15552 +                               fprintf(stderr, "%s.%d: CR with out LF\r\n", __FILE__, __LINE__);
15553 +                               return -1;
15554 +                       }
15555 +                       break;
15556 +               case '\n':
15557 +                       tid = TK_CRLF;
15558 +
15559 +                       t->is_statusline = 0;
15560 +                       t->is_key = 1;
15561 +
15562 +                       break;
15563 +               default:
15564 +                       while (c >= 32 && c != 127 && c != 255) {
15565 +                               if (t->is_statusline) {
15566 +                                       if (c == ':') { t->is_statusline = 0; break; } /* this is not a status line by a real header */
15567 +                                       if (c == 32) break; /* the space is a splitter in the statusline */
15568 +                               } else {
15569 +                                       if (t->is_key) {
15570 +                                               if (c == ':') break; /* the : is the splitter between key and value */
15571 +                                       }
15572 +                               }
15573 +                               if (0 != http_resp_lookup_next_char(t, &c)) return -1;
15574 +                       }
15575 +
15576 +                       if (t->c == t->lookup_c &&
15577 +                               t->offset == t->lookup_offset + 1) {
15578 +
15579 +                               fprintf(stderr, "%s.%d: invalid char in string\n", __FILE__, __LINE__);
15580 +                               return -1;
15581 +                       }
15582 +
15583 +                       tid = TK_STRING;
15584 +
15585 +                       /* the lookup points to the first invalid char */
15586 +                       t->lookup_offset--;
15587 +
15588 +                       /* no overlapping string */
15589 +                       if (t->c == t->lookup_c) {
15590 +                               buffer_copy_string_len(token, t->c->mem->ptr + t->offset - 1, t->lookup_offset - t->offset + 1);
15591 +                       } else {
15592 +                               /* first chunk */
15593 +                               buffer_copy_string_len(token, t->c->mem->ptr + t->offset - 1, t->c->mem->used - t->offset);
15594 +
15595 +                               /* chunks in the middle */
15596 +                               for (t->c = t->c->next; t->c != t->lookup_c; t->c = t->c->next) {
15597 +                                       buffer_append_string_buffer(token, t->c->mem);
15598 +                                       t->offset = t->c->mem->used - 1;
15599 +                               }
15600 +
15601 +                               /* last chunk */
15602 +                               buffer_append_string_len(token, t->c->mem->ptr, t->lookup_offset);
15603 +                       }
15604 +
15605 +                       t->offset = t->lookup_offset;
15606 +
15607 +                       break;
15608 +               }
15609 +       }
15610 +
15611 +       if (tid) {
15612 +               *token_id = tid;
15613 +
15614 +               return 1;
15615 +       }
15616 +
15617 +       return -1;
15618 +}
15619 +
15620 +parse_status_t http_response_parse_cq(chunkqueue *cq, http_resp *resp) {
15621 +       http_resp_tokenizer_t t;
15622 +       void *pParser = NULL;
15623 +       int token_id = 0;
15624 +       buffer *token = NULL;
15625 +       http_resp_ctx_t context;
15626 +       parse_status_t ret = PARSE_UNSET;
15627 +       int last_token_id = 0;
15628 +
15629 +       t.cq = cq;
15630 +       t.c = cq->first;
15631 +       t.offset = t.c->offset;
15632 +       t.is_key = 0;
15633 +       t.is_statusline = 1;
15634 +
15635 +       context.ok = 1;
15636 +       context.errmsg = buffer_init();
15637 +       context.resp = resp;
15638 +
15639 +       pParser = http_resp_parserAlloc( malloc );
15640 +       token = buffer_init();
15641 +#if 0
15642 +       http_resp_parserTrace(stderr, "http-response: "); 
15643 +#endif
15644 +
15645 +       while((1 == http_resp_tokenizer(&t, &token_id, token)) && context.ok) {
15646 +               http_resp_parser(pParser, token_id, token, &context);
15647 +
15648 +               token = buffer_init();
15649 +
15650 +               /* CRLF CRLF ... the header end sequence */
15651 +               if (last_token_id == TK_CRLF &&
15652 +                   token_id == TK_CRLF) break;
15653 +
15654 +               last_token_id = token_id;
15655 +       }
15656 +
15657 +       /* oops, the parser failed */
15658 +       if (context.ok == 0) {
15659 +               ret = PARSE_ERROR;
15660 +
15661 +               if (!buffer_is_empty(context.errmsg)) {
15662 +                       TRACE("parsing failed: %s", BUF_STR(context.errmsg));
15663 +               } else {
15664 +                       TRACE("%s", "parsing failed ...");
15665 +               }
15666 +       }
15667 +
15668 +       http_resp_parser(pParser, 0, token, &context);
15669 +       http_resp_parserFree(pParser, free);
15670 +
15671 +       if (context.ok == 0) {
15672 +               /* we are missing the some tokens */
15673 +
15674 +               if (!buffer_is_empty(context.errmsg)) {
15675 +                       TRACE("parsing failed: %s", BUF_STR(context.errmsg));
15676 +               }
15677 +
15678 +               if (ret == PARSE_UNSET) {
15679 +                       ret = buffer_is_empty(context.errmsg) ? PARSE_NEED_MORE : PARSE_ERROR;
15680 +               }
15681 +       } else {
15682 +               chunk *c;
15683 +
15684 +               for (c = cq->first; c != t.c; c = c->next) {
15685 +                       c->offset = c->mem->used - 1;
15686 +               }
15687 +
15688 +               c->offset = t.offset;
15689 +
15690 +               ret = PARSE_SUCCESS;
15691 +       }
15692 +
15693 +       buffer_free(token);
15694 +       buffer_free(context.errmsg);
15695 +
15696 +       return ret;
15697 +}
15698 +
15699 --- ../lighttpd-1.4.11/src/http_resp.h  1970-01-01 03:00:00.000000000 +0300
15700 +++ lighttpd-1.5.0/src/http_resp.h      2006-09-07 00:57:05.000000000 +0300
15701 @@ -0,0 +1,28 @@
15702 +#ifndef _HTTP_RESP_H_
15703 +#define _HTTP_RESP_H_
15704 +
15705 +#include "array.h"
15706 +#include "chunk.h"
15707 +#include "http_parser.h"
15708 +
15709 +typedef struct {
15710 +    int protocol;   /* http/1.0, http/1.1 */
15711 +    int status;     /* e.g. 200 */
15712 +    buffer *reason; /* e.g. Ok */
15713 +    array *headers;
15714 +} http_resp;
15715 +
15716 +typedef struct {
15717 +       int     ok;
15718 +    buffer *errmsg;
15719 +
15720 +    http_resp *resp;
15721 +} http_resp_ctx_t;
15722 +
15723 +http_resp *http_response_init(void);
15724 +void http_response_free(http_resp *resp);
15725 +void http_response_reset(http_resp *resp);
15726 +
15727 +parse_status_t http_response_parse_cq(chunkqueue *cq, http_resp *http_response);
15728 +
15729 +#endif
15730 --- ../lighttpd-1.4.11/src/http_resp_parser.c   1970-01-01 03:00:00.000000000 +0300
15731 +++ lighttpd-1.5.0/src/http_resp_parser.c       2006-09-07 00:57:07.000000000 +0300
15732 @@ -0,0 +1,901 @@
15733 +/* Driver template for the LEMON parser generator.
15734 +** The author disclaims copyright to this source code.
15735 +*/
15736 +/* First off, code is include which follows the "include" declaration
15737 +** in the input file. */
15738 +#include <stdio.h>
15739 +#line 6 "./http_resp_parser.y"
15740 +
15741 +#include <assert.h>
15742 +#include <string.h>
15743 +#include "http_resp.h"
15744 +#include "keyvalue.h"
15745 +#include "array.h"
15746 +#include "log.h"
15747 +
15748 +#line 17 "http_resp_parser.c"
15749 +/* Next is all token values, in a form suitable for use by makeheaders.
15750 +** This section will be null unless lemon is run with the -m switch.
15751 +*/
15752 +/*
15753 +** These constants (all generated automatically by the parser generator)
15754 +** specify the various kinds of tokens (terminals) that the parser
15755 +** understands.
15756 +**
15757 +** Each symbol here is a terminal symbol in the grammar.
15758 +*/
15759 +/* Make sure the INTERFACE macro is defined.
15760 +*/
15761 +#ifndef INTERFACE
15762 +# define INTERFACE 1
15763 +#endif
15764 +/* The next thing included is series of defines which control
15765 +** various aspects of the generated parser.
15766 +**    YYCODETYPE         is the data type used for storing terminal
15767 +**                       and nonterminal numbers.  "unsigned char" is
15768 +**                       used if there are fewer than 250 terminals
15769 +**                       and nonterminals.  "int" is used otherwise.
15770 +**    YYNOCODE           is a number of type YYCODETYPE which corresponds
15771 +**                       to no legal terminal or nonterminal number.  This
15772 +**                       number is used to fill in empty slots of the hash
15773 +**                       table.
15774 +**    YYFALLBACK         If defined, this indicates that one or more tokens
15775 +**                       have fall-back values which should be used if the
15776 +**                       original value of the token will not parse.
15777 +**    YYACTIONTYPE       is the data type used for storing terminal
15778 +**                       and nonterminal numbers.  "unsigned char" is
15779 +**                       used if there are fewer than 250 rules and
15780 +**                       states combined.  "int" is used otherwise.
15781 +**    http_resp_parserTOKENTYPE     is the data type used for minor tokens given
15782 +**                       directly to the parser from the tokenizer.
15783 +**    YYMINORTYPE        is the data type used for all minor tokens.
15784 +**                       This is typically a union of many types, one of
15785 +**                       which is http_resp_parserTOKENTYPE.  The entry in the union
15786 +**                       for base tokens is called "yy0".
15787 +**    YYSTACKDEPTH       is the maximum depth of the parser's stack.
15788 +**    http_resp_parserARG_SDECL     A static variable declaration for the %extra_argument
15789 +**    http_resp_parserARG_PDECL     A parameter declaration for the %extra_argument
15790 +**    http_resp_parserARG_STORE     Code to store %extra_argument into yypParser
15791 +**    http_resp_parserARG_FETCH     Code to extract %extra_argument from yypParser
15792 +**    YYNSTATE           the combined number of states.
15793 +**    YYNRULE            the number of rules in the grammar
15794 +**    YYERRORSYMBOL      is the code number of the error symbol.  If not
15795 +**                       defined, then do no error processing.
15796 +*/
15797 +/* \ 1 */
15798 +#define YYCODETYPE unsigned char
15799 +#define YYNOCODE 12
15800 +#define YYACTIONTYPE unsigned char
15801 +#define http_resp_parserTOKENTYPE buffer *
15802 +typedef union {
15803 +  http_resp_parserTOKENTYPE yy0;
15804 +  http_resp * yy2;
15805 +  data_string * yy9;
15806 +  array * yy12;
15807 +  int yy20;
15808 +  int yy23;
15809 +} YYMINORTYPE;
15810 +#define YYSTACKDEPTH 100
15811 +#define http_resp_parserARG_SDECL http_resp_ctx_t *ctx;
15812 +#define http_resp_parserARG_PDECL ,http_resp_ctx_t *ctx
15813 +#define http_resp_parserARG_FETCH http_resp_ctx_t *ctx = yypParser->ctx
15814 +#define http_resp_parserARG_STORE yypParser->ctx = ctx
15815 +#define YYNSTATE 19
15816 +#define YYNRULE 9
15817 +#define YYERRORSYMBOL 4
15818 +#define YYERRSYMDT yy23
15819 +#define YY_NO_ACTION      (YYNSTATE+YYNRULE+2)
15820 +#define YY_ACCEPT_ACTION  (YYNSTATE+YYNRULE+1)
15821 +#define YY_ERROR_ACTION   (YYNSTATE+YYNRULE)
15822 +
15823 +/* Next are that tables used to determine what action to take based on the
15824 +** current state and lookahead token.  These tables are used to implement
15825 +** functions that take a state number and lookahead value and return an
15826 +** action integer.
15827 +**
15828 +** Suppose the action integer is N.  Then the action is determined as
15829 +** follows
15830 +**
15831 +**   0 <= N < YYNSTATE                  Shift N.  That is, push the lookahead
15832 +**                                      token onto the stack and goto state N.
15833 +**
15834 +**   YYNSTATE <= N < YYNSTATE+YYNRULE   Reduce by rule N-YYNSTATE.
15835 +**
15836 +**   N == YYNSTATE+YYNRULE              A syntax error has occurred.
15837 +**
15838 +**   N == YYNSTATE+YYNRULE+1            The parser accepts its input.
15839 +**
15840 +**   N == YYNSTATE+YYNRULE+2            No such action.  Denotes unused
15841 +**                                      slots in the yy_action[] table.
15842 +**
15843 +** The action table is constructed as a single large table named yy_action[].
15844 +** Given state S and lookahead X, the action is computed as
15845 +**
15846 +**      yy_action[ yy_shift_ofst[S] + X ]
15847 +**
15848 +** If the index value yy_shift_ofst[S]+X is out of range or if the value
15849 +** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
15850 +** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
15851 +** and that yy_default[S] should be used instead.
15852 +**
15853 +** The formula above is for computing the action when the lookahead is
15854 +** a terminal symbol.  If the lookahead is a non-terminal (as occurs after
15855 +** a reduce action) then the yy_reduce_ofst[] array is used in place of
15856 +** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
15857 +** YY_SHIFT_USE_DFLT.
15858 +**
15859 +** The following are the tables generated in this section:
15860 +**
15861 +**  yy_action[]        A single table containing all actions.
15862 +**  yy_lookahead[]     A table containing the lookahead for each entry in
15863 +**                     yy_action.  Used to detect hash collisions.
15864 +**  yy_shift_ofst[]    For each state, the offset into yy_action for
15865 +**                     shifting terminals.
15866 +**  yy_reduce_ofst[]   For each state, the offset into yy_action for
15867 +**                     shifting non-terminals after a reduce.
15868 +**  yy_default[]       Default action for each state.
15869 +*/
15870 +static YYACTIONTYPE yy_action[] = {
15871 + /*     0 */     8,   29,   18,    1,   14,    2,    4,   11,   15,   12,
15872 + /*    10 */    14,   13,    4,   21,    5,   19,    3,    5,    6,    7,
15873 + /*    20 */     9,   17,   16,    4,   20,   22,   22,   10,
15874 +};
15875 +static YYCODETYPE yy_lookahead[] = {
15876 + /*     0 */     5,    6,    2,    8,    9,    1,    2,    1,    2,    8,
15877 + /*    10 */     9,    1,    2,    2,    3,    0,    9,    3,    2,    1,
15878 + /*    20 */     7,    2,    2,    2,    0,    2,   11,   10,
15879 +};
15880 +#define YY_SHIFT_USE_DFLT (-1)
15881 +static signed char yy_shift_ofst[] = {
15882 + /*     0 */     0,    4,   15,   -1,   14,   16,   18,   -1,   19,   20,
15883 + /*    10 */     6,   21,   10,   24,   -1,   -1,   -1,   23,   11,
15884 +};
15885 +#define YY_REDUCE_USE_DFLT (-6)
15886 +static signed char yy_reduce_ofst[] = {
15887 + /*     0 */    -5,    7,   -6,   -6,   -6,   -6,   -6,   -6,   13,   17,
15888 + /*    10 */    -6,    1,    7,   -6,   -6,   -6,   -6,   -6,   -6,
15889 +};
15890 +static YYACTIONTYPE yy_default[] = {
15891 + /*     0 */    28,   28,   28,   25,   28,   28,   28,   27,   28,   28,
15892 + /*    10 */    28,   28,   28,   28,   26,   24,   23,   28,   28,
15893 +};
15894 +#define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0]))
15895 +
15896 +/* The next table maps tokens into fallback tokens.  If a construct
15897 +** like the following:
15898 +**
15899 +**      %fallback ID X Y Z.
15900 +**
15901 +** appears in the grammer, then ID becomes a fallback token for X, Y,
15902 +** and Z.  Whenever one of the tokens X, Y, or Z is input to the parser
15903 +** but it does not parse, the type of the token is changed to ID and
15904 +** the parse is retried before an error is thrown.
15905 +*/
15906 +#ifdef YYFALLBACK
15907 +static const YYCODETYPE yyFallback[] = {
15908 +};
15909 +#endif /* YYFALLBACK */
15910 +
15911 +/* The following structure represents a single element of the
15912 +** parser's stack.  Information stored includes:
15913 +**
15914 +**   +  The state number for the parser at this level of the stack.
15915 +**
15916 +**   +  The value of the token stored at this level of the stack.
15917 +**      (In other words, the "major" token.)
15918 +**
15919 +**   +  The semantic value stored at this level of the stack.  This is
15920 +**      the information used by the action routines in the grammar.
15921 +**      It is sometimes called the "minor" token.
15922 +*/
15923 +struct yyStackEntry {
15924 +  int stateno;       /* The state-number */
15925 +  int major;         /* The major token value.  This is the code
15926 +                     ** number for the token at this stack level */
15927 +  YYMINORTYPE minor; /* The user-supplied minor token value.  This
15928 +                     ** is the value of the token  */
15929 +};
15930 +typedef struct yyStackEntry yyStackEntry;
15931 +
15932 +/* The state of the parser is completely contained in an instance of
15933 +** the following structure */
15934 +struct yyParser {
15935 +  int yyidx;                    /* Index of top element in stack */
15936 +  int yyerrcnt;                 /* Shifts left before out of the error */
15937 +  http_resp_parserARG_SDECL                /* A place to hold %extra_argument */
15938 +  yyStackEntry yystack[YYSTACKDEPTH];  /* The parser's stack */
15939 +};
15940 +typedef struct yyParser yyParser;
15941 +
15942 +#ifndef NDEBUG
15943 +#include <stdio.h>
15944 +static FILE *yyTraceFILE = 0;
15945 +static char *yyTracePrompt = 0;
15946 +#endif /* NDEBUG */
15947 +
15948 +#ifndef NDEBUG
15949 +/*
15950 +** Turn parser tracing on by giving a stream to which to write the trace
15951 +** and a prompt to preface each trace message.  Tracing is turned off
15952 +** by making either argument NULL
15953 +**
15954 +** Inputs:
15955 +** <ul>
15956 +** <li> A FILE* to which trace output should be written.
15957 +**      If NULL, then tracing is turned off.
15958 +** <li> A prefix string written at the beginning of every
15959 +**      line of trace output.  If NULL, then tracing is
15960 +**      turned off.
15961 +** </ul>
15962 +**
15963 +** Outputs:
15964 +** None.
15965 +*/
15966 +void http_resp_parserTrace(FILE *TraceFILE, char *zTracePrompt){
15967 +  yyTraceFILE = TraceFILE;
15968 +  yyTracePrompt = zTracePrompt;
15969 +  if( yyTraceFILE==0 ) yyTracePrompt = 0;
15970 +  else if( yyTracePrompt==0 ) yyTraceFILE = 0;
15971 +}
15972 +#endif /* NDEBUG */
15973 +
15974 +#ifndef NDEBUG
15975 +/* For tracing shifts, the names of all terminals and nonterminals
15976 +** are required.  The following table supplies these names */
15977 +static const char *yyTokenName[] = {
15978 +  "$",             "CRLF",          "STRING",        "COLON",       
15979 +  "error",         "protocol",      "response_hdr",  "number",      
15980 +  "headers",       "header",        "reason",      
15981 +};
15982 +#endif /* NDEBUG */
15983 +
15984 +#ifndef NDEBUG
15985 +/* For tracing reduce actions, the names of all rules are required.
15986 +*/
15987 +static const char *yyRuleName[] = {
15988 + /*   0 */ "response_hdr ::= headers CRLF",
15989 + /*   1 */ "response_hdr ::= protocol number reason CRLF headers CRLF",
15990 + /*   2 */ "protocol ::= STRING",
15991 + /*   3 */ "number ::= STRING",
15992 + /*   4 */ "reason ::= STRING",
15993 + /*   5 */ "reason ::= reason STRING",
15994 + /*   6 */ "headers ::= headers header",
15995 + /*   7 */ "headers ::= header",
15996 + /*   8 */ "header ::= STRING COLON STRING CRLF",
15997 +};
15998 +#endif /* NDEBUG */
15999 +
16000 +/*
16001 +** This function returns the symbolic name associated with a token
16002 +** value.
16003 +*/
16004 +const char *http_resp_parserTokenName(int tokenType){
16005 +#ifndef NDEBUG
16006 +  if( tokenType>0 && tokenType<(sizeof(yyTokenName)/sizeof(yyTokenName[0])) ){
16007 +    return yyTokenName[tokenType];
16008 +  }else{
16009 +    return "Unknown";
16010 +  }
16011 +#else
16012 +  return "";
16013 +#endif
16014 +}
16015 +
16016 +/*
16017 +** This function allocates a new parser.
16018 +** The only argument is a pointer to a function which works like
16019 +** malloc.
16020 +**
16021 +** Inputs:
16022 +** A pointer to the function used to allocate memory.
16023 +**
16024 +** Outputs:
16025 +** A pointer to a parser.  This pointer is used in subsequent calls
16026 +** to http_resp_parser and http_resp_parserFree.
16027 +*/
16028 +void *http_resp_parserAlloc(void *(*mallocProc)(size_t)){
16029 +  yyParser *pParser;
16030 +  pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) );
16031 +  if( pParser ){
16032 +    pParser->yyidx = -1;
16033 +  }
16034 +  return pParser;
16035 +}
16036 +
16037 +/* The following function deletes the value associated with a
16038 +** symbol.  The symbol can be either a terminal or nonterminal.
16039 +** "yymajor" is the symbol code, and "yypminor" is a pointer to
16040 +** the value.
16041 +*/
16042 +static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){
16043 +  switch( yymajor ){
16044 +    /* Here is inserted the actions which take place when a
16045 +    ** terminal or non-terminal is destroyed.  This can happen
16046 +    ** when the symbol is popped from the stack during a
16047 +    ** reduce or during error processing or when a parser is
16048 +    ** being destroyed before it is finished parsing.
16049 +    **
16050 +    ** Note: during a reduce, the only symbols destroyed are those
16051 +    ** which appear on the RHS of the rule, but which are not used
16052 +    ** inside the C code.
16053 +    */
16054 +    case 1:
16055 +    case 2:
16056 +    case 3:
16057 +#line 25 "./http_resp_parser.y"
16058 +{ buffer_free((yypminor->yy0)); }
16059 +#line 327 "http_resp_parser.c"
16060 +      break;
16061 +    case 10:
16062 +#line 24 "./http_resp_parser.y"
16063 +{ buffer_free((yypminor->yy0)); }
16064 +#line 332 "http_resp_parser.c"
16065 +      break;
16066 +    default:  break;   /* If no destructor action specified: do nothing */
16067 +  }
16068 +}
16069 +
16070 +/*
16071 +** Pop the parser's stack once.
16072 +**
16073 +** If there is a destructor routine associated with the token which
16074 +** is popped from the stack, then call it.
16075 +**
16076 +** Return the major token number for the symbol popped.
16077 +*/
16078 +static int yy_pop_parser_stack(yyParser *pParser){
16079 +  YYCODETYPE yymajor;
16080 +  yyStackEntry *yytos = &pParser->yystack[pParser->yyidx];
16081 +
16082 +  if( pParser->yyidx<0 ) return 0;
16083 +#ifndef NDEBUG
16084 +  if( yyTraceFILE && pParser->yyidx>=0 ){
16085 +    fprintf(yyTraceFILE,"%sPopping %s\n",
16086 +      yyTracePrompt,
16087 +      yyTokenName[yytos->major]);
16088 +  }
16089 +#endif
16090 +  yymajor = yytos->major;
16091 +  yy_destructor( yymajor, &yytos->minor);
16092 +  pParser->yyidx--;
16093 +  return yymajor;
16094 +}
16095 +
16096 +/*
16097 +** Deallocate and destroy a parser.  Destructors are all called for
16098 +** all stack elements before shutting the parser down.
16099 +**
16100 +** Inputs:
16101 +** <ul>
16102 +** <li>  A pointer to the parser.  This should be a pointer
16103 +**       obtained from http_resp_parserAlloc.
16104 +** <li>  A pointer to a function used to reclaim memory obtained
16105 +**       from malloc.
16106 +** </ul>
16107 +*/
16108 +void http_resp_parserFree(
16109 +  void *p,                    /* The parser to be deleted */
16110 +  void (*freeProc)(void*)     /* Function used to reclaim memory */
16111 +){
16112 +  yyParser *pParser = (yyParser*)p;
16113 +  if( pParser==0 ) return;
16114 +  while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
16115 +  (*freeProc)((void*)pParser);
16116 +}
16117 +
16118 +/*
16119 +** Find the appropriate action for a parser given the terminal
16120 +** look-ahead token iLookAhead.
16121 +**
16122 +** If the look-ahead token is YYNOCODE, then check to see if the action is
16123 +** independent of the look-ahead.  If it is, return the action, otherwise
16124 +** return YY_NO_ACTION.
16125 +*/
16126 +static int yy_find_shift_action(
16127 +  yyParser *pParser,        /* The parser */
16128 +  int iLookAhead            /* The look-ahead token */
16129 +){
16130 +  int i;
16131 +  int stateno = pParser->yystack[pParser->yyidx].stateno;
16132 +
16133 +  /* if( pParser->yyidx<0 ) return YY_NO_ACTION;  */
16134 +  i = yy_shift_ofst[stateno];
16135 +  if( i==YY_SHIFT_USE_DFLT ){
16136 +    return yy_default[stateno];
16137 +  }
16138 +  if( iLookAhead==YYNOCODE ){
16139 +    return YY_NO_ACTION;
16140 +  }
16141 +  i += iLookAhead;
16142 +  if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
16143 +#ifdef YYFALLBACK
16144 +    int iFallback;            /* Fallback token */
16145 +    if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
16146 +           && (iFallback = yyFallback[iLookAhead])!=0 ){
16147 +#ifndef NDEBUG
16148 +      if( yyTraceFILE ){
16149 +        fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
16150 +           yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
16151 +      }
16152 +#endif
16153 +      return yy_find_shift_action(pParser, iFallback);
16154 +    }
16155 +#endif
16156 +    return yy_default[stateno];
16157 +  }else{
16158 +    return yy_action[i];
16159 +  }
16160 +}
16161 +
16162 +/*
16163 +** Find the appropriate action for a parser given the non-terminal
16164 +** look-ahead token iLookAhead.
16165 +**
16166 +** If the look-ahead token is YYNOCODE, then check to see if the action is
16167 +** independent of the look-ahead.  If it is, return the action, otherwise
16168 +** return YY_NO_ACTION.
16169 +*/
16170 +static int yy_find_reduce_action(
16171 +  yyParser *pParser,        /* The parser */
16172 +  int iLookAhead            /* The look-ahead token */
16173 +){
16174 +  int i;
16175 +  int stateno = pParser->yystack[pParser->yyidx].stateno;
16176 +
16177 +  i = yy_reduce_ofst[stateno];
16178 +  if( i==YY_REDUCE_USE_DFLT ){
16179 +    return yy_default[stateno];
16180 +  }
16181 +  if( iLookAhead==YYNOCODE ){
16182 +    return YY_NO_ACTION;
16183 +  }
16184 +  i += iLookAhead;
16185 +  if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
16186 +    return yy_default[stateno];
16187 +  }else{
16188 +    return yy_action[i];
16189 +  }
16190 +}
16191 +
16192 +/*
16193 +** Perform a shift action.
16194 +*/
16195 +static void yy_shift(
16196 +  yyParser *yypParser,          /* The parser to be shifted */
16197 +  int yyNewState,               /* The new state to shift in */
16198 +  int yyMajor,                  /* The major token to shift in */
16199 +  YYMINORTYPE *yypMinor         /* Pointer ot the minor token to shift in */
16200 +){
16201 +  yyStackEntry *yytos;
16202 +  yypParser->yyidx++;
16203 +  if( yypParser->yyidx>=YYSTACKDEPTH ){
16204 +     http_resp_parserARG_FETCH;
16205 +     yypParser->yyidx--;
16206 +#ifndef NDEBUG
16207 +     if( yyTraceFILE ){
16208 +       fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
16209 +     }
16210 +#endif
16211 +     while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
16212 +     /* Here code is inserted which will execute if the parser
16213 +     ** stack every overflows */
16214 +     http_resp_parserARG_STORE; /* Suppress warning about unused %extra_argument var */
16215 +     return;
16216 +  }
16217 +  yytos = &yypParser->yystack[yypParser->yyidx];
16218 +  yytos->stateno = yyNewState;
16219 +  yytos->major = yyMajor;
16220 +  yytos->minor = *yypMinor;
16221 +#ifndef NDEBUG
16222 +  if( yyTraceFILE && yypParser->yyidx>0 ){
16223 +    int i;
16224 +    fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState);
16225 +    fprintf(yyTraceFILE,"%sStack:",yyTracePrompt);
16226 +    for(i=1; i<=yypParser->yyidx; i++)
16227 +      fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]);
16228 +    fprintf(yyTraceFILE,"\n");
16229 +  }
16230 +#endif
16231 +}
16232 +
16233 +/* The following table contains information about every rule that
16234 +** is used during the reduce.
16235 +*/
16236 +static struct {
16237 +  YYCODETYPE lhs;         /* Symbol on the left-hand side of the rule */
16238 +  unsigned char nrhs;     /* Number of right-hand side symbols in the rule */
16239 +} yyRuleInfo[] = {
16240 +  { 6, 2 },
16241 +  { 6, 6 },
16242 +  { 5, 1 },
16243 +  { 7, 1 },
16244 +  { 10, 1 },
16245 +  { 10, 2 },
16246 +  { 8, 2 },
16247 +  { 8, 1 },
16248 +  { 9, 4 },
16249 +};
16250 +
16251 +static void yy_accept(yyParser*);  /* Forward Declaration */
16252 +
16253 +/*
16254 +** Perform a reduce action and the shift that must immediately
16255 +** follow the reduce.
16256 +*/
16257 +static void yy_reduce(
16258 +  yyParser *yypParser,         /* The parser */
16259 +  int yyruleno                 /* Number of the rule by which to reduce */
16260 +){
16261 +  int yygoto;                     /* The next state */
16262 +  int yyact;                      /* The next action */
16263 +  YYMINORTYPE yygotominor;        /* The LHS of the rule reduced */
16264 +  yyStackEntry *yymsp;            /* The top of the parser's stack */
16265 +  int yysize;                     /* Amount to pop the stack */
16266 +  http_resp_parserARG_FETCH;
16267 +  yymsp = &yypParser->yystack[yypParser->yyidx];
16268 +#ifndef NDEBUG
16269 +  if( yyTraceFILE && yyruleno>=0
16270 +        && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
16271 +    fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
16272 +      yyRuleName[yyruleno]);
16273 +  }
16274 +#endif /* NDEBUG */
16275 +
16276 +  switch( yyruleno ){
16277 +  /* Beginning here are the reduction cases.  A typical example
16278 +  ** follows:
16279 +  **   case 0:
16280 +  **  #line <lineno> <grammarfile>
16281 +  **     { ... }           // User supplied code
16282 +  **  #line <lineno> <thisfile>
16283 +  **     break;
16284 +  */
16285 +      case 0:
16286 +#line 28 "./http_resp_parser.y"
16287 +{
16288 +    http_resp *resp = ctx->resp;
16289 +    data_string *ds;
16290
16291 +    resp->protocol = HTTP_VERSION_UNSET;
16292 +
16293 +    buffer_copy_string(resp->reason, ""); /* no reason */
16294 +    array_free(resp->headers);
16295 +    resp->headers = yymsp[-1].minor.yy12;
16296 +
16297 +    if (NULL == (ds = (data_string *)array_get_element(yymsp[-1].minor.yy12, "Status"))) { 
16298 +        resp->status = 0;
16299 +    } else {
16300 +        char *err;
16301 +        resp->status = strtol(ds->value->ptr, &err, 10);
16302 +   
16303 +        if (*err != '\0' && *err != ' ') {
16304 +            buffer_copy_string(ctx->errmsg, "expected a number: ");
16305 +            buffer_append_string_buffer(ctx->errmsg, ds->value);
16306 +            buffer_append_string(ctx->errmsg, err);
16307 +        
16308 +            ctx->ok = 0;
16309 +        }
16310 +    }
16311 +
16312 +    yymsp[-1].minor.yy12 = NULL;
16313 +}
16314 +#line 582 "http_resp_parser.c"
16315 +  yy_destructor(1,&yymsp[0].minor);
16316 +        break;
16317 +      case 1:
16318 +#line 56 "./http_resp_parser.y"
16319 +{
16320 +    http_resp *resp = ctx->resp;
16321 +    
16322 +    resp->status = yymsp[-4].minor.yy20;
16323 +    resp->protocol = yymsp[-5].minor.yy20;
16324 +    buffer_copy_string_buffer(resp->reason, yymsp[-3].minor.yy0);
16325 +    buffer_free(yymsp[-3].minor.yy0); 
16326 +
16327 +    array_free(resp->headers);
16328 +    
16329 +    resp->headers = yymsp[-1].minor.yy12;
16330 +}
16331 +#line 599 "http_resp_parser.c"
16332 +  yy_destructor(1,&yymsp[-2].minor);
16333 +  yy_destructor(1,&yymsp[0].minor);
16334 +        break;
16335 +      case 2:
16336 +#line 69 "./http_resp_parser.y"
16337 +{
16338 +    if (buffer_is_equal_string(yymsp[0].minor.yy0, CONST_STR_LEN("HTTP/1.0"))) {
16339 +        yygotominor.yy20 = HTTP_VERSION_1_0;
16340 +    } else if (buffer_is_equal_string(yymsp[0].minor.yy0, CONST_STR_LEN("HTTP/1.1"))) {
16341 +        yygotominor.yy20 = HTTP_VERSION_1_1;
16342 +    } else {
16343 +        buffer_copy_string(ctx->errmsg, "unknown protocol: ");
16344 +        buffer_append_string_buffer(ctx->errmsg, yymsp[0].minor.yy0);
16345 +        
16346 +        ctx->ok = 0;
16347 +    }
16348 +    buffer_free(yymsp[0].minor.yy0);
16349 +}
16350 +#line 618 "http_resp_parser.c"
16351 +        break;
16352 +      case 3:
16353 +#line 83 "./http_resp_parser.y"
16354 +{
16355 +    char *err;
16356 +    yygotominor.yy20 = strtol(yymsp[0].minor.yy0->ptr, &err, 10);
16357 +    
16358 +    if (*err != '\0') {
16359 +        buffer_copy_string(ctx->errmsg, "expected a number, got: ");
16360 +        buffer_append_string_buffer(ctx->errmsg, yymsp[0].minor.yy0);
16361 +        
16362 +        ctx->ok = 0;
16363 +    }
16364 +    buffer_free(yymsp[0].minor.yy0);
16365 +}
16366 +#line 634 "http_resp_parser.c"
16367 +        break;
16368 +      case 4:
16369 +#line 96 "./http_resp_parser.y"
16370 +{
16371 +    yygotominor.yy0 = yymsp[0].minor.yy0;
16372 +}
16373 +#line 641 "http_resp_parser.c"
16374 +        break;
16375 +      case 5:
16376 +#line 100 "./http_resp_parser.y"
16377 +{
16378 +    yygotominor.yy0 = yymsp[-1].minor.yy0;
16379 +    
16380 +    buffer_append_string(yygotominor.yy0, " ");
16381 +    buffer_append_string_buffer(yygotominor.yy0, yymsp[0].minor.yy0);
16382 +
16383 +    buffer_free(yymsp[0].minor.yy0); 
16384 +}
16385 +#line 653 "http_resp_parser.c"
16386 +        break;
16387 +      case 6:
16388 +#line 109 "./http_resp_parser.y"
16389 +{
16390 +    yygotominor.yy12 = yymsp[-1].minor.yy12;
16391 +    
16392 +    array_insert_unique(yygotominor.yy12, (data_unset *)yymsp[0].minor.yy9);
16393 +}
16394 +#line 662 "http_resp_parser.c"
16395 +        break;
16396 +      case 7:
16397 +#line 115 "./http_resp_parser.y"
16398 +{
16399 +    yygotominor.yy12 = array_init();
16400 +
16401 +    array_insert_unique(yygotominor.yy12, (data_unset *)yymsp[0].minor.yy9);
16402 +}
16403 +#line 671 "http_resp_parser.c"
16404 +        break;
16405 +      case 8:
16406 +#line 120 "./http_resp_parser.y"
16407 +{
16408 +    yygotominor.yy9 = data_response_init();
16409 +    
16410 +    buffer_copy_string_buffer(yygotominor.yy9->key, yymsp[-3].minor.yy0);
16411 +    buffer_copy_string_buffer(yygotominor.yy9->value, yymsp[-1].minor.yy0);    
16412 +    buffer_free(yymsp[-3].minor.yy0);
16413 +    buffer_free(yymsp[-1].minor.yy0);
16414 +}
16415 +#line 683 "http_resp_parser.c"
16416 +  yy_destructor(3,&yymsp[-2].minor);
16417 +  yy_destructor(1,&yymsp[0].minor);
16418 +        break;
16419 +  };
16420 +  yygoto = yyRuleInfo[yyruleno].lhs;
16421 +  yysize = yyRuleInfo[yyruleno].nrhs;
16422 +  yypParser->yyidx -= yysize;
16423 +  yyact = yy_find_reduce_action(yypParser,yygoto);
16424 +  if( yyact < YYNSTATE ){
16425 +    yy_shift(yypParser,yyact,yygoto,&yygotominor);
16426 +  }else if( yyact == YYNSTATE + YYNRULE + 1 ){
16427 +    yy_accept(yypParser);
16428 +  }
16429 +}
16430 +
16431 +/*
16432 +** The following code executes when the parse fails
16433 +*/
16434 +static void yy_parse_failed(
16435 +  yyParser *yypParser           /* The parser */
16436 +){
16437 +  http_resp_parserARG_FETCH;
16438 +#ifndef NDEBUG
16439 +  if( yyTraceFILE ){
16440 +    fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
16441 +  }
16442 +#endif
16443 +  while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
16444 +  /* Here code is inserted which will be executed whenever the
16445 +  ** parser fails */
16446 +#line 15 "./http_resp_parser.y"
16447 +
16448 +  ctx->ok = 0;
16449 +
16450 +#line 718 "http_resp_parser.c"
16451 +  http_resp_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
16452 +}
16453 +
16454 +/*
16455 +** The following code executes when a syntax error first occurs.
16456 +*/
16457 +static void yy_syntax_error(
16458 +  yyParser *yypParser,           /* The parser */
16459 +  int yymajor,                   /* The major type of the error token */
16460 +  YYMINORTYPE yyminor            /* The minor type of the error token */
16461 +){
16462 +  http_resp_parserARG_FETCH;
16463 +#define TOKEN (yyminor.yy0)
16464 +  http_resp_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
16465 +}
16466 +
16467 +/*
16468 +** The following is executed when the parser accepts
16469 +*/
16470 +static void yy_accept(
16471 +  yyParser *yypParser           /* The parser */
16472 +){
16473 +  http_resp_parserARG_FETCH;
16474 +#ifndef NDEBUG
16475 +  if( yyTraceFILE ){
16476 +    fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
16477 +  }
16478 +#endif
16479 +  while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
16480 +  /* Here code is inserted which will be executed whenever the
16481 +  ** parser accepts */
16482 +  http_resp_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
16483 +}
16484 +
16485 +/* The main parser program.
16486 +** The first argument is a pointer to a structure obtained from
16487 +** "http_resp_parserAlloc" which describes the current state of the parser.
16488 +** The second argument is the major token number.  The third is
16489 +** the minor token.  The fourth optional argument is whatever the
16490 +** user wants (and specified in the grammar) and is available for
16491 +** use by the action routines.
16492 +**
16493 +** Inputs:
16494 +** <ul>
16495 +** <li> A pointer to the parser (an opaque structure.)
16496 +** <li> The major token number.
16497 +** <li> The minor token number.
16498 +** <li> An option argument of a grammar-specified type.
16499 +** </ul>
16500 +**
16501 +** Outputs:
16502 +** None.
16503 +*/
16504 +void http_resp_parser(
16505 +  void *yyp,                   /* The parser */
16506 +  int yymajor,                 /* The major token code number */
16507 +  http_resp_parserTOKENTYPE yyminor       /* The value for the token */
16508 +  http_resp_parserARG_PDECL               /* Optional %extra_argument parameter */
16509 +){
16510 +  YYMINORTYPE yyminorunion;
16511 +  int yyact;            /* The parser action. */
16512 +  int yyendofinput;     /* True if we are at the end of input */
16513 +  int yyerrorhit = 0;   /* True if yymajor has invoked an error */
16514 +  yyParser *yypParser;  /* The parser */
16515 +
16516 +  /* (re)initialize the parser, if necessary */
16517 +  yypParser = (yyParser*)yyp;
16518 +  if( yypParser->yyidx<0 ){
16519 +    if( yymajor==0 ) return;
16520 +    yypParser->yyidx = 0;
16521 +    yypParser->yyerrcnt = -1;
16522 +    yypParser->yystack[0].stateno = 0;
16523 +    yypParser->yystack[0].major = 0;
16524 +  }
16525 +  yyminorunion.yy0 = yyminor;
16526 +  yyendofinput = (yymajor==0);
16527 +  http_resp_parserARG_STORE;
16528 +
16529 +#ifndef NDEBUG
16530 +  if( yyTraceFILE ){
16531 +    fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]);
16532 +  }
16533 +#endif
16534 +
16535 +  do{
16536 +    yyact = yy_find_shift_action(yypParser,yymajor);
16537 +    if( yyact<YYNSTATE ){
16538 +      yy_shift(yypParser,yyact,yymajor,&yyminorunion);
16539 +      yypParser->yyerrcnt--;
16540 +      if( yyendofinput && yypParser->yyidx>=0 ){
16541 +        yymajor = 0;
16542 +      }else{
16543 +        yymajor = YYNOCODE;
16544 +      }
16545 +    }else if( yyact < YYNSTATE + YYNRULE ){
16546 +      yy_reduce(yypParser,yyact-YYNSTATE);
16547 +    }else if( yyact == YY_ERROR_ACTION ){
16548 +      int yymx;
16549 +#ifndef NDEBUG
16550 +      if( yyTraceFILE ){
16551 +        fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
16552 +      }
16553 +#endif
16554 +#ifdef YYERRORSYMBOL
16555 +      /* A syntax error has occurred.
16556 +      ** The response to an error depends upon whether or not the
16557 +      ** grammar defines an error token "ERROR".
16558 +      **
16559 +      ** This is what we do if the grammar does define ERROR:
16560 +      **
16561 +      **  * Call the %syntax_error function.
16562 +      **
16563 +      **  * Begin popping the stack until we enter a state where
16564 +      **    it is legal to shift the error symbol, then shift
16565 +      **    the error symbol.
16566 +      **
16567 +      **  * Set the error count to three.
16568 +      **
16569 +      **  * Begin accepting and shifting new tokens.  No new error
16570 +      **    processing will occur until three tokens have been
16571 +      **    shifted successfully.
16572 +      **
16573 +      */
16574 +      if( yypParser->yyerrcnt<0 ){
16575 +        yy_syntax_error(yypParser,yymajor,yyminorunion);
16576 +      }
16577 +      yymx = yypParser->yystack[yypParser->yyidx].major;
16578 +      if( yymx==YYERRORSYMBOL || yyerrorhit ){
16579 +#ifndef NDEBUG
16580 +        if( yyTraceFILE ){
16581 +          fprintf(yyTraceFILE,"%sDiscard input token %s\n",
16582 +             yyTracePrompt,yyTokenName[yymajor]);
16583 +        }
16584 +#endif
16585 +        yy_destructor(yymajor,&yyminorunion);
16586 +        yymajor = YYNOCODE;
16587 +      }else{
16588 +         while(
16589 +          yypParser->yyidx >= 0 &&
16590 +          yymx != YYERRORSYMBOL &&
16591 +          (yyact = yy_find_shift_action(yypParser,YYERRORSYMBOL)) >= YYNSTATE
16592 +        ){
16593 +          yy_pop_parser_stack(yypParser);
16594 +        }
16595 +        if( yypParser->yyidx < 0 || yymajor==0 ){
16596 +          yy_destructor(yymajor,&yyminorunion);
16597 +          yy_parse_failed(yypParser);
16598 +          yymajor = YYNOCODE;
16599 +        }else if( yymx!=YYERRORSYMBOL ){
16600 +          YYMINORTYPE u2;
16601 +          u2.YYERRSYMDT = 0;
16602 +          yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2);
16603 +        }
16604 +      }
16605 +      yypParser->yyerrcnt = 3;
16606 +      yyerrorhit = 1;
16607 +#else  /* YYERRORSYMBOL is not defined */
16608 +      /* This is what we do if the grammar does not define ERROR:
16609 +      **
16610 +      **  * Report an error message, and throw away the input token.
16611 +      **
16612 +      **  * If the input token is $, then fail the parse.
16613 +      **
16614 +      ** As before, subsequent error messages are suppressed until
16615 +      ** three input tokens have been successfully shifted.
16616 +      */
16617 +      if( yypParser->yyerrcnt<=0 ){
16618 +        yy_syntax_error(yypParser,yymajor,yyminorunion);
16619 +      }
16620 +      yypParser->yyerrcnt = 3;
16621 +      yy_destructor(yymajor,&yyminorunion);
16622 +      if( yyendofinput ){
16623 +        yy_parse_failed(yypParser);
16624 +      }
16625 +      yymajor = YYNOCODE;
16626 +#endif
16627 +    }else{
16628 +      yy_accept(yypParser);
16629 +      yymajor = YYNOCODE;
16630 +    }
16631 +  }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
16632 +  return;
16633 +}
16634 --- ../lighttpd-1.4.11/src/http_resp_parser.h   1970-01-01 03:00:00.000000000 +0300
16635 +++ lighttpd-1.5.0/src/http_resp_parser.h       2006-09-07 00:57:07.000000000 +0300
16636 @@ -0,0 +1,3 @@
16637 +#define TK_CRLF                            1
16638 +#define TK_STRING                          2
16639 +#define TK_COLON                           3
16640 --- ../lighttpd-1.4.11/src/http_resp_parser.y   1970-01-01 03:00:00.000000000 +0300
16641 +++ lighttpd-1.5.0/src/http_resp_parser.y       2006-09-07 00:57:05.000000000 +0300
16642 @@ -0,0 +1,127 @@
16643 +%token_prefix TK_
16644 +%token_type {buffer *}
16645 +%extra_argument {http_resp_ctx_t *ctx}
16646 +%name http_resp_parser
16647 +
16648 +%include {
16649 +#include <assert.h>
16650 +#include <string.h>
16651 +#include "http_resp.h"
16652 +#include "keyvalue.h"
16653 +#include "array.h"
16654 +#include "log.h"
16655 +}
16656 +
16657 +%parse_failure {
16658 +  ctx->ok = 0;
16659 +}
16660 +
16661 +%type protocol { int }
16662 +%type response_hdr { http_resp * }
16663 +%type number { int }
16664 +%type headers { array * }
16665 +%type header { data_string * }
16666 +%destructor reason { buffer_free($$); }
16667 +%token_destructor { buffer_free($$); }
16668 +
16669 +/* just headers + Status: ... */
16670 +response_hdr ::= headers(HDR) CRLF . {
16671 +    http_resp *resp = ctx->resp;
16672 +    data_string *ds;
16673
16674 +    resp->protocol = HTTP_VERSION_UNSET;
16675 +
16676 +    buffer_copy_string(resp->reason, ""); /* no reason */
16677 +    array_free(resp->headers);
16678 +    resp->headers = HDR;
16679 +
16680 +    if (NULL == (ds = (data_string *)array_get_element(HDR, "Status"))) { 
16681 +        resp->status = 0;
16682 +    } else {
16683 +        char *err;
16684 +        resp->status = strtol(ds->value->ptr, &err, 10);
16685 +   
16686 +        if (*err != '\0' && *err != ' ') {
16687 +            buffer_copy_string(ctx->errmsg, "expected a number: ");
16688 +            buffer_append_string_buffer(ctx->errmsg, ds->value);
16689 +            buffer_append_string(ctx->errmsg, err);
16690 +        
16691 +            ctx->ok = 0;
16692 +        }
16693 +    }
16694 +
16695 +    HDR = NULL;
16696 +}
16697 +/* HTTP/1.0 <status> ... */
16698 +response_hdr ::= protocol(B) number(C) reason(D) CRLF headers(HDR) CRLF . {
16699 +    http_resp *resp = ctx->resp;
16700 +    
16701 +    resp->status = C;
16702 +    resp->protocol = B;
16703 +    buffer_copy_string_buffer(resp->reason, D);
16704 +    buffer_free(D); 
16705 +
16706 +    array_free(resp->headers);
16707 +    
16708 +    resp->headers = HDR;
16709 +}
16710 +
16711 +protocol(A) ::= STRING(B). {
16712 +    if (buffer_is_equal_string(B, CONST_STR_LEN("HTTP/1.0"))) {
16713 +        A = HTTP_VERSION_1_0;
16714 +    } else if (buffer_is_equal_string(B, CONST_STR_LEN("HTTP/1.1"))) {
16715 +        A = HTTP_VERSION_1_1;
16716 +    } else {
16717 +        buffer_copy_string(ctx->errmsg, "unknown protocol: ");
16718 +        buffer_append_string_buffer(ctx->errmsg, B);
16719 +        
16720 +        ctx->ok = 0;
16721 +    }
16722 +    buffer_free(B);
16723 +}
16724 +
16725 +number(A) ::= STRING(B). {
16726 +    char *err;
16727 +    A = strtol(B->ptr, &err, 10);
16728 +    
16729 +    if (*err != '\0') {
16730 +        buffer_copy_string(ctx->errmsg, "expected a number, got: ");
16731 +        buffer_append_string_buffer(ctx->errmsg, B);
16732 +        
16733 +        ctx->ok = 0;
16734 +    }
16735 +    buffer_free(B);
16736 +}
16737 +
16738 +reason(A) ::= STRING(B). {
16739 +    A = B;
16740 +}
16741 +
16742 +reason(A) ::= reason(C) STRING(B). {
16743 +    A = C;
16744 +    
16745 +    buffer_append_string(A, " ");
16746 +    buffer_append_string_buffer(A, B);
16747 +
16748 +    buffer_free(B); 
16749 +}
16750 +
16751 +headers(HDRS) ::= headers(SRC) header(HDR). {
16752 +    HDRS = SRC;
16753 +    
16754 +    array_insert_unique(HDRS, (data_unset *)HDR);
16755 +}
16756 +
16757 +headers(HDRS) ::= header(HDR). {
16758 +    HDRS = array_init();
16759 +
16760 +    array_insert_unique(HDRS, (data_unset *)HDR);
16761 +}
16762 +header(HDR) ::= STRING(A) COLON STRING(B) CRLF. {
16763 +    HDR = data_response_init();
16764 +    
16765 +    buffer_copy_string_buffer(HDR->key, A);
16766 +    buffer_copy_string_buffer(HDR->value, B);    
16767 +    buffer_free(A);
16768 +    buffer_free(B);
16769 +}
16770 --- ../lighttpd-1.4.11/src/inet_ntop_cache.c    2005-08-11 01:26:38.000000000 +0300
16771 +++ lighttpd-1.5.0/src/inet_ntop_cache.c        2006-07-16 00:26:04.000000000 +0300
16772 @@ -8,7 +8,7 @@
16773  #include "sys-socket.h"
16774  
16775  const char * inet_ntop_cache_get_ip(server *srv, sock_addr *addr) {
16776 -#ifdef HAVE_IPV6       
16777 +#ifdef HAVE_IPV6
16778         size_t ndx = 0, i;
16779         for (i = 0; i < INET_NTOP_CACHE_MAX; i++) {
16780                 if (srv->inet_ntop_cache[i].ts != 0) {
16781 @@ -20,31 +20,31 @@
16782                                    srv->inet_ntop_cache[i].addr.ipv4.s_addr == addr->ipv4.sin_addr.s_addr) {
16783                                 /* IPv4 found in cache */
16784                                 break;
16785 -                               
16786 +
16787                         }
16788                 }
16789         }
16790 -       
16791 +
16792         if (i == INET_NTOP_CACHE_MAX) {
16793                 /* not found in cache */
16794 -               
16795 +
16796                 i = ndx;
16797 -               inet_ntop(addr->plain.sa_family, 
16798 -                         addr->plain.sa_family == AF_INET6 ? 
16799 +               inet_ntop(addr->plain.sa_family,
16800 +                         addr->plain.sa_family == AF_INET6 ?
16801                           (const void *) &(addr->ipv6.sin6_addr) :
16802                           (const void *) &(addr->ipv4.sin_addr),
16803                           srv->inet_ntop_cache[i].b2, INET6_ADDRSTRLEN);
16804 -               
16805 +
16806                 srv->inet_ntop_cache[i].ts = srv->cur_ts;
16807                 srv->inet_ntop_cache[i].family = addr->plain.sa_family;
16808 -               
16809 +
16810                 if (srv->inet_ntop_cache[i].family == AF_INET) {
16811                         srv->inet_ntop_cache[i].addr.ipv4.s_addr = addr->ipv4.sin_addr.s_addr;
16812                 } else if (srv->inet_ntop_cache[i].family == AF_INET6) {
16813                         memcpy(srv->inet_ntop_cache[i].addr.ipv6.s6_addr, addr->ipv6.sin6_addr.s6_addr, 16);
16814                 }
16815         }
16816 -       
16817 +
16818         return srv->inet_ntop_cache[i].b2;
16819  #else
16820         UNUSED(srv);
16821 --- ../lighttpd-1.4.11/src/iosocket.c   1970-01-01 03:00:00.000000000 +0300
16822 +++ lighttpd-1.5.0/src/iosocket.c       2006-07-18 13:03:40.000000000 +0300
16823 @@ -0,0 +1,36 @@
16824 +#include <stdlib.h>
16825 +
16826 +#include "iosocket.h"
16827 +#include "sys-socket.h"
16828 +#include "sys-files.h"
16829 +#include "array-static.h"
16830 +
16831 +iosocket *iosocket_init(void) {
16832 +       STRUCT_INIT(iosocket, sock);
16833 +
16834 +       sock->fde_ndx = -1;
16835 +       sock->fd = -1;
16836 +
16837 +       sock->type = IOSOCKET_TYPE_SOCKET;
16838 +
16839 +       return sock;
16840 +}
16841 +
16842 +void iosocket_free(iosocket *sock) {
16843 +       if (!sock) return;
16844 +
16845 +       if (sock->fd != -1) {
16846 +               switch (sock->type) {
16847 +               case IOSOCKET_TYPE_SOCKET:
16848 +                       closesocket(sock->fd);
16849 +                       break;
16850 +               case IOSOCKET_TYPE_PIPE:
16851 +                       close(sock->fd);
16852 +                       break;
16853 +               default:
16854 +                       break;
16855 +               }
16856 +       }
16857 +
16858 +       free(sock);
16859 +}
16860 --- ../lighttpd-1.4.11/src/iosocket.h   1970-01-01 03:00:00.000000000 +0300
16861 +++ lighttpd-1.5.0/src/iosocket.h       2006-07-20 01:14:57.000000000 +0300
16862 @@ -0,0 +1,44 @@
16863 +#ifndef _IOSOCKET_H_
16864 +#define _IOSOCKET_H_
16865 +
16866 +/**
16867 + * make sure we know about OPENSSL all the time
16868 + *
16869 + * if we don't include config.h here we run into different sizes 
16870 + * for the iosocket-struct depending on config.h include before 
16871 + * iosocket.h or not
16872 + */
16873 +
16874 +#ifdef HAVE_CONFIG_H
16875 +# include "config.h"
16876 +#endif
16877 +
16878 +#if defined HAVE_LIBSSL && defined HAVE_OPENSSL_SSL_H
16879 +# define USE_OPENSSL
16880 +# include <openssl/ssl.h>
16881 +#endif
16882 +
16883 +typedef enum {
16884 +       IOSOCKET_TYPE_UNSET,
16885 +       IOSOCKET_TYPE_SOCKET,
16886 +       IOSOCKET_TYPE_PIPE
16887 +} iosocket_t;
16888 +
16889 +/**
16890 + * a non-blocking fd
16891 + */
16892 +typedef struct {
16893 +       int fd;
16894 +       int fde_ndx;
16895 +
16896 +#ifdef USE_OPENSSL
16897 +       SSL *ssl;
16898 +#endif
16899 +
16900 +       iosocket_t type; /**< sendfile on solaris doesn't work on pipes */
16901 +} iosocket;
16902 +
16903 +iosocket *iosocket_init(void);
16904 +void iosocket_free(iosocket *sock);
16905 +
16906 +#endif
16907 --- ../lighttpd-1.4.11/src/joblist.c    2005-08-11 01:26:41.000000000 +0300
16908 +++ lighttpd-1.5.0/src/joblist.c        2006-07-16 00:26:03.000000000 +0300
16909 @@ -7,7 +7,7 @@
16910  
16911  int joblist_append(server *srv, connection *con) {
16912         if (con->in_joblist) return 0;
16913 -       
16914 +
16915         if (srv->joblist->size == 0) {
16916                 srv->joblist->size  = 16;
16917                 srv->joblist->ptr   = malloc(sizeof(*srv->joblist->ptr) * srv->joblist->size);
16918 @@ -15,15 +15,15 @@
16919                 srv->joblist->size += 16;
16920                 srv->joblist->ptr   = realloc(srv->joblist->ptr, sizeof(*srv->joblist->ptr) * srv->joblist->size);
16921         }
16922 -       
16923 +
16924         srv->joblist->ptr[srv->joblist->used++] = con;
16925 -       
16926 +
16927         return 0;
16928  }
16929  
16930  void joblist_free(server *srv, connections *joblist) {
16931         UNUSED(srv);
16932 -               
16933 +
16934         free(joblist->ptr);
16935         free(joblist);
16936  }
16937 @@ -31,14 +31,14 @@
16938  connection *fdwaitqueue_unshift(server *srv, connections *fdwaitqueue) {
16939         connection *con;
16940         UNUSED(srv);
16941 -               
16942 -       
16943 +
16944 +
16945         if (fdwaitqueue->used == 0) return NULL;
16946 -       
16947 +
16948         con = fdwaitqueue->ptr[0];
16949 -       
16950 +
16951         memmove(fdwaitqueue->ptr, &(fdwaitqueue->ptr[1]), --fdwaitqueue->used * sizeof(*(fdwaitqueue->ptr)));
16952 -       
16953 +
16954         return con;
16955  }
16956  
16957 @@ -50,9 +50,9 @@
16958                 srv->fdwaitqueue->size += 16;
16959                 srv->fdwaitqueue->ptr   = realloc(srv->fdwaitqueue->ptr, sizeof(*(srv->fdwaitqueue->ptr)) * srv->fdwaitqueue->size);
16960         }
16961 -       
16962 +
16963         srv->fdwaitqueue->ptr[srv->fdwaitqueue->used++] = con;
16964 -       
16965 +
16966         return 0;
16967  }
16968  
16969 --- ../lighttpd-1.4.11/src/keyvalue.c   2006-03-02 16:08:06.000000000 +0200
16970 +++ lighttpd-1.5.0/src/keyvalue.c       2006-07-16 00:26:03.000000000 +0300
16971 @@ -87,7 +87,8 @@
16972         { 504, "Gateway Timeout" },
16973         { 505, "HTTP Version Not Supported" },
16974         { 507, "Insufficient Storage" }, /* WebDAV */
16975 -       
16976 +       { 509, "Bandwidth Limit exceeded" },
16977 +
16978         { -1, NULL }
16979  };
16980  
16981 @@ -102,12 +103,12 @@
16982         { 501, "501.html" },
16983         { 503, "503.html" },
16984         { 505, "505.html" },
16985 -       
16986 +
16987         { -1, NULL }
16988  };
16989  
16990  
16991 -const char *keyvalue_get_value(keyvalue *kv, int k) { 
16992 +const char *keyvalue_get_value(keyvalue *kv, int k) {
16993         int i;
16994         for (i = 0; kv[i].value; i++) {
16995                 if (kv[i].key == k) return kv[i].value;
16996 @@ -115,7 +116,7 @@
16997         return NULL;
16998  }
16999  
17000 -int keyvalue_get_key(keyvalue *kv, const char *s) { 
17001 +int keyvalue_get_key(keyvalue *kv, const char *s) {
17002         int i;
17003         for (i = 0; kv[i].value; i++) {
17004                 if (0 == strcmp(kv[i].value, s)) return kv[i].key;
17005 @@ -125,9 +126,9 @@
17006  
17007  keyvalue_buffer *keyvalue_buffer_init(void) {
17008         keyvalue_buffer *kvb;
17009 -       
17010 +
17011         kvb = calloc(1, sizeof(*kvb));
17012 -       
17013 +
17014         return kvb;
17015  }
17016  
17017 @@ -135,49 +136,49 @@
17018         size_t i;
17019         if (kvb->size == 0) {
17020                 kvb->size = 4;
17021 -               
17022 +
17023                 kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
17024 -               
17025 +
17026                 for(i = 0; i < kvb->size; i++) {
17027                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
17028                 }
17029         } else if (kvb->used == kvb->size) {
17030                 kvb->size += 4;
17031 -               
17032 +
17033                 kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
17034 -               
17035 +
17036                 for(i = kvb->used; i < kvb->size; i++) {
17037                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
17038                 }
17039         }
17040 -       
17041 +
17042         kvb->kv[kvb->used]->key = key;
17043         kvb->kv[kvb->used]->value = strdup(value);
17044 -       
17045 +
17046         kvb->used++;
17047 -       
17048 +
17049         return 0;
17050  }
17051  
17052  void keyvalue_buffer_free(keyvalue_buffer *kvb) {
17053         size_t i;
17054 -       
17055 +
17056         for (i = 0; i < kvb->size; i++) {
17057                 if (kvb->kv[i]->value) free(kvb->kv[i]->value);
17058                 free(kvb->kv[i]);
17059         }
17060 -       
17061 +
17062         if (kvb->kv) free(kvb->kv);
17063 -       
17064 +
17065         free(kvb);
17066  }
17067  
17068  
17069  s_keyvalue_buffer *s_keyvalue_buffer_init(void) {
17070         s_keyvalue_buffer *kvb;
17071 -       
17072 +
17073         kvb = calloc(1, sizeof(*kvb));
17074 -       
17075 +
17076         return kvb;
17077  }
17078  
17079 @@ -186,50 +187,50 @@
17080         if (kvb->size == 0) {
17081                 kvb->size = 4;
17082                 kvb->used = 0;
17083 -               
17084 +
17085                 kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
17086 -               
17087 +
17088                 for(i = 0; i < kvb->size; i++) {
17089                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
17090                 }
17091         } else if (kvb->used == kvb->size) {
17092                 kvb->size += 4;
17093 -               
17094 +
17095                 kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
17096 -               
17097 +
17098                 for(i = kvb->used; i < kvb->size; i++) {
17099                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
17100                 }
17101         }
17102 -       
17103 +
17104         kvb->kv[kvb->used]->key = key ? strdup(key) : NULL;
17105         kvb->kv[kvb->used]->value = strdup(value);
17106 -       
17107 +
17108         kvb->used++;
17109 -       
17110 +
17111         return 0;
17112  }
17113  
17114  void s_keyvalue_buffer_free(s_keyvalue_buffer *kvb) {
17115         size_t i;
17116 -       
17117 +
17118         for (i = 0; i < kvb->size; i++) {
17119                 if (kvb->kv[i]->key) free(kvb->kv[i]->key);
17120                 if (kvb->kv[i]->value) free(kvb->kv[i]->value);
17121                 free(kvb->kv[i]);
17122         }
17123 -       
17124 +
17125         if (kvb->kv) free(kvb->kv);
17126 -       
17127 +
17128         free(kvb);
17129  }
17130  
17131  
17132  httpauth_keyvalue_buffer *httpauth_keyvalue_buffer_init(void) {
17133         httpauth_keyvalue_buffer *kvb;
17134 -       
17135 +
17136         kvb = calloc(1, sizeof(*kvb));
17137 -       
17138 +
17139         return kvb;
17140  }
17141  
17142 @@ -237,42 +238,42 @@
17143         size_t i;
17144         if (kvb->size == 0) {
17145                 kvb->size = 4;
17146 -               
17147 +
17148                 kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
17149 -               
17150 +
17151                 for(i = 0; i < kvb->size; i++) {
17152                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
17153                 }
17154         } else if (kvb->used == kvb->size) {
17155                 kvb->size += 4;
17156 -               
17157 +
17158                 kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
17159 -               
17160 +
17161                 for(i = kvb->used; i < kvb->size; i++) {
17162                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
17163                 }
17164         }
17165 -       
17166 +
17167         kvb->kv[kvb->used]->key = strdup(key);
17168         kvb->kv[kvb->used]->realm = strdup(realm);
17169         kvb->kv[kvb->used]->type = type;
17170 -       
17171 +
17172         kvb->used++;
17173 -       
17174 +
17175         return 0;
17176  }
17177  
17178  void httpauth_keyvalue_buffer_free(httpauth_keyvalue_buffer *kvb) {
17179         size_t i;
17180 -       
17181 +
17182         for (i = 0; i < kvb->size; i++) {
17183                 if (kvb->kv[i]->key) free(kvb->kv[i]->key);
17184                 if (kvb->kv[i]->realm) free(kvb->kv[i]->realm);
17185                 free(kvb->kv[i]);
17186         }
17187 -       
17188 +
17189         if (kvb->kv) free(kvb->kv);
17190 -       
17191 +
17192         free(kvb);
17193  }
17194  
17195 @@ -306,9 +307,9 @@
17196  
17197  pcre_keyvalue_buffer *pcre_keyvalue_buffer_init(void) {
17198         pcre_keyvalue_buffer *kvb;
17199 -       
17200 +
17201         kvb = calloc(1, sizeof(*kvb));
17202 -       
17203 +
17204         return kvb;
17205  }
17206  
17207 @@ -319,46 +320,46 @@
17208         int erroff;
17209         pcre_keyvalue *kv;
17210  #endif
17211 -       
17212 +
17213         if (!key) return -1;
17214  
17215  #ifdef HAVE_PCRE_H
17216         if (kvb->size == 0) {
17217                 kvb->size = 4;
17218                 kvb->used = 0;
17219 -               
17220 +
17221                 kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
17222 -               
17223 +
17224                 for(i = 0; i < kvb->size; i++) {
17225                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
17226                 }
17227         } else if (kvb->used == kvb->size) {
17228                 kvb->size += 4;
17229 -               
17230 +
17231                 kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
17232 -               
17233 +
17234                 for(i = kvb->used; i < kvb->size; i++) {
17235                         kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
17236                 }
17237         }
17238 -       
17239 +
17240         kv = kvb->kv[kvb->used];
17241         if (NULL == (kv->key = pcre_compile(key,
17242                                           0, &errptr, &erroff, NULL))) {
17243 -               
17244 +
17245                 fprintf(stderr, "%s.%d: rexexp compilation error at %s\n", __FILE__, __LINE__, errptr);
17246                 return -1;
17247         }
17248  
17249 -       if (NULL == (kv->key_extra = pcre_study(kv->key, 0, &errptr)) &&  
17250 +       if (NULL == (kv->key_extra = pcre_study(kv->key, 0, &errptr)) &&
17251                         errptr != NULL) {
17252                 return -1;
17253         }
17254 -       
17255 +
17256         kv->value = buffer_init_string(value);
17257 -       
17258 +
17259         kvb->used++;
17260 -       
17261 +
17262         return 0;
17263  #else
17264         UNUSED(kvb);
17265 @@ -380,9 +381,9 @@
17266                 if (kv->value) buffer_free(kv->value);
17267                 free(kv);
17268         }
17269 -       
17270 +
17271         if (kvb->kv) free(kvb->kv);
17272  #endif
17273 -       
17274 +
17275         free(kvb);
17276  }
17277 --- ../lighttpd-1.4.11/src/keyvalue.h   2006-03-02 16:08:06.000000000 +0200
17278 +++ lighttpd-1.5.0/src/keyvalue.h       2006-09-07 00:57:05.000000000 +0300
17279 @@ -9,19 +9,19 @@
17280  # include <pcre.h>
17281  #endif
17282  
17283 -typedef enum { 
17284 -       HTTP_METHOD_UNSET = -1, 
17285 -       HTTP_METHOD_GET, 
17286 -       HTTP_METHOD_POST, 
17287 -       HTTP_METHOD_HEAD, 
17288 -       HTTP_METHOD_OPTIONS, 
17289 +typedef enum {
17290 +       HTTP_METHOD_UNSET = -1,
17291 +       HTTP_METHOD_GET,
17292 +       HTTP_METHOD_POST,
17293 +       HTTP_METHOD_HEAD,
17294 +       HTTP_METHOD_OPTIONS,
17295         HTTP_METHOD_PROPFIND,  /* WebDAV */
17296 -       HTTP_METHOD_MKCOL, 
17297 -       HTTP_METHOD_PUT, 
17298 -       HTTP_METHOD_DELETE, 
17299 -       HTTP_METHOD_COPY, 
17300 -       HTTP_METHOD_MOVE, 
17301 -       HTTP_METHOD_PROPPATCH, 
17302 +       HTTP_METHOD_MKCOL,
17303 +       HTTP_METHOD_PUT,
17304 +       HTTP_METHOD_DELETE,
17305 +       HTTP_METHOD_COPY,
17306 +       HTTP_METHOD_MOVE,
17307 +       HTTP_METHOD_PROPPATCH,
17308         HTTP_METHOD_REPORT, /* DeltaV */
17309         HTTP_METHOD_CHECKOUT,
17310         HTTP_METHOD_CHECKIN,
17311 @@ -35,17 +35,21 @@
17312         HTTP_METHOD_CONNECT
17313  } http_method_t;
17314  
17315 -typedef enum { HTTP_VERSION_UNSET = -1, HTTP_VERSION_1_0, HTTP_VERSION_1_1 } http_version_t;
17316 +typedef enum { 
17317 +       HTTP_VERSION_UNSET = -1, 
17318 +       HTTP_VERSION_1_0, 
17319 +       HTTP_VERSION_1_1
17320 +} http_version_t;
17321  
17322  typedef struct {
17323         int key;
17324 -       
17325 +
17326         char *value;
17327  } keyvalue;
17328  
17329  typedef struct {
17330         char *key;
17331 -       
17332 +
17333         char *value;
17334  } s_keyvalue;
17335  
17336 @@ -54,7 +58,7 @@
17337         pcre *key;
17338         pcre_extra *key_extra;
17339  #endif
17340 -       
17341 +
17342         buffer *value;
17343  } pcre_keyvalue;
17344  
17345 @@ -62,7 +66,7 @@
17346  
17347  typedef struct {
17348         char *key;
17349 -       
17350 +
17351         char *realm;
17352         httpauth_type type;
17353  } httpauth_keyvalue;
17354 --- ../lighttpd-1.4.11/src/lemon.c      2005-09-01 00:21:34.000000000 +0300
17355 +++ lighttpd-1.5.0/src/lemon.c  2006-07-16 00:26:03.000000000 +0300
17356 @@ -579,7 +579,7 @@
17357  */
17358  
17359  /* Find a precedence symbol of every rule in the grammar.
17360 -** 
17361 +**
17362  ** Those rules which have a precedence symbol coded in the input
17363  ** grammar using the "[symbol]" construct will already have the
17364  ** rp->precsym field filled.  Other rules take as their precedence
17365 @@ -869,7 +869,7 @@
17366        cfp->status = INCOMPLETE;
17367      }
17368    }
17369 -  
17370 +
17371    do{
17372      progress = 0;
17373      for(i=0; i<lemp->nstate; i++){
17374 @@ -900,7 +900,7 @@
17375    struct symbol *sp;
17376    struct rule *rp;
17377  
17378 -  /* Add all of the reduce actions 
17379 +  /* Add all of the reduce actions
17380    ** A reduce action is added for each element of the followset of
17381    ** a configuration which has its dot at the extreme right.
17382    */
17383 @@ -1017,7 +1017,7 @@
17384        apx->type = RD_RESOLVED;
17385      }
17386    }else{
17387 -    assert( 
17388 +    assert(
17389        apx->type==SH_RESOLVED ||
17390        apx->type==RD_RESOLVED ||
17391        apx->type==CONFLICT ||
17392 @@ -1350,7 +1350,7 @@
17393    OptInit(argv,options,stderr);
17394    if( version ){
17395       printf("Lemon version 1.0\n");
17396 -     exit(0); 
17397 +     exit(0);
17398    }
17399    if( OptNArgs() < 1 ){
17400      fprintf(stderr,"Exactly one filename argument is required.\n");
17401 @@ -2031,7 +2031,7 @@
17402      case IN_RHS:
17403        if( x[0]=='.' ){
17404          struct rule *rp;
17405 -        rp = (struct rule *)malloc( sizeof(struct rule) + 
17406 +        rp = (struct rule *)malloc( sizeof(struct rule) +
17407               sizeof(struct symbol*)*psp->nrhs + sizeof(char*)*psp->nrhs );
17408          if( rp==0 ){
17409            ErrorMsg(psp->filename,psp->tokenlineno,
17410 @@ -2546,7 +2546,7 @@
17411    return fp;
17412  }
17413  
17414 -/* Duplicate the input file without comments and without actions 
17415 +/* Duplicate the input file without comments and without actions
17416  ** on rules */
17417  void Reprint(lemp)
17418  struct lemon *lemp;
17419 @@ -2822,7 +2822,7 @@
17420  PRIVATE FILE *tplt_open(lemp)
17421  struct lemon *lemp;
17422  {
17423 -  
17424 +
17425    char buf[1000];
17426    FILE *in;
17427    char *tpltname;
17428 @@ -2930,7 +2930,7 @@
17429    return ret;
17430  }
17431  
17432 -/* 
17433 +/*
17434  ** Generate code which executes when the rule "rp" is reduced.  Write
17435  ** the code to "out".  Make sure lineno stays up-to-date.
17436  */
17437 @@ -3384,7 +3384,7 @@
17438  
17439    /* Output the yy_shift_ofst[] table */
17440    fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", mnTknOfst-1); lineno++;
17441 -  fprintf(out, "static %s yy_shift_ofst[] = {\n", 
17442 +  fprintf(out, "static %s yy_shift_ofst[] = {\n",
17443            minimum_size_type(mnTknOfst-1, mxTknOfst)); lineno++;
17444    n = lemp->nstate;
17445    for(i=j=0; i<n; i++){
17446 @@ -3405,7 +3405,7 @@
17447  
17448    /* Output the yy_reduce_ofst[] table */
17449    fprintf(out, "#define YY_REDUCE_USE_DFLT (%d)\n", mnNtOfst-1); lineno++;
17450 -  fprintf(out, "static %s yy_reduce_ofst[] = {\n", 
17451 +  fprintf(out, "static %s yy_reduce_ofst[] = {\n",
17452            minimum_size_type(mnNtOfst-1, mxNtOfst)); lineno++;
17453    n = lemp->nstate;
17454    for(i=j=0; i<n; i++){
17455 @@ -3480,7 +3480,7 @@
17456    tplt_xfer(lemp->name,in,out,&lineno);
17457  
17458    /* Generate code which executes every time a symbol is popped from
17459 -  ** the stack while processing errors or while destroying the parser. 
17460 +  ** the stack while processing errors or while destroying the parser.
17461    ** (In other words, generate the %destructor actions)
17462    */
17463    if( lemp->tokendest ){
17464 @@ -3522,7 +3522,7 @@
17465    tplt_print(out,lemp,lemp->overflow,lemp->overflowln,&lineno);
17466    tplt_xfer(lemp->name,in,out,&lineno);
17467  
17468 -  /* Generate the table of rule information 
17469 +  /* Generate the table of rule information
17470    **
17471    ** Note: This code depends on the fact that rules are number
17472    ** sequentually beginning with 0.
17473 @@ -3589,7 +3589,7 @@
17474      for(i=1; i<lemp->nterminal; i++){
17475        fprintf(out,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i);
17476      }
17477 -    fclose(out);  
17478 +    fclose(out);
17479    }
17480    return;
17481  }
17482 @@ -3630,7 +3630,7 @@
17483          rbest = rp;
17484        }
17485      }
17486
17487 +
17488      /* Do not make a default if the number of rules to default
17489      ** is not at least 2 */
17490      if( nbest<2 ) continue;
17491 @@ -3781,7 +3781,7 @@
17492    if( x1a ){
17493      x1a->size = 1024;
17494      x1a->count = 0;
17495 -    x1a->tbl = (x1node*)malloc( 
17496 +    x1a->tbl = (x1node*)malloc(
17497        (sizeof(x1node) + sizeof(x1node*))*1024 );
17498      if( x1a->tbl==0 ){
17499        free(x1a);
17500 @@ -3943,7 +3943,7 @@
17501    if( x2a ){
17502      x2a->size = 128;
17503      x2a->count = 0;
17504 -    x2a->tbl = (x2node*)malloc( 
17505 +    x2a->tbl = (x2node*)malloc(
17506        (sizeof(x2node) + sizeof(x2node*))*128 );
17507      if( x2a->tbl==0 ){
17508        free(x2a);
17509 @@ -4149,7 +4149,7 @@
17510    if( x3a ){
17511      x3a->size = 128;
17512      x3a->count = 0;
17513 -    x3a->tbl = (x3node*)malloc( 
17514 +    x3a->tbl = (x3node*)malloc(
17515        (sizeof(x3node) + sizeof(x3node*))*128 );
17516      if( x3a->tbl==0 ){
17517        free(x3a);
17518 @@ -4295,7 +4295,7 @@
17519    if( x4a ){
17520      x4a->size = 64;
17521      x4a->count = 0;
17522 -    x4a->tbl = (x4node*)malloc( 
17523 +    x4a->tbl = (x4node*)malloc(
17524        (sizeof(x4node) + sizeof(x4node*))*64 );
17525      if( x4a->tbl==0 ){
17526        free(x4a);
17527 --- ../lighttpd-1.4.11/src/lempar.c     2005-08-11 01:26:40.000000000 +0300
17528 +++ lighttpd-1.5.0/src/lempar.c 2006-07-16 00:26:03.000000000 +0300
17529 @@ -8,10 +8,10 @@
17530  /* Next is all token values, in a form suitable for use by makeheaders.
17531  ** This section will be null unless lemon is run with the -m switch.
17532  */
17533 -/* 
17534 +/*
17535  ** These constants (all generated automatically by the parser generator)
17536  ** specify the various kinds of tokens (terminals) that the parser
17537 -** understands. 
17538 +** understands.
17539  **
17540  ** Each symbol here is a terminal symbol in the grammar.
17541  */
17542 @@ -29,7 +29,7 @@
17543  **                       and nonterminals.  "int" is used otherwise.
17544  **    YYNOCODE           is a number of type YYCODETYPE which corresponds
17545  **                       to no legal terminal or nonterminal number.  This
17546 -**                       number is used to fill in empty slots of the hash 
17547 +**                       number is used to fill in empty slots of the hash
17548  **                       table.
17549  **    YYFALLBACK         If defined, this indicates that one or more tokens
17550  **                       have fall-back values which should be used if the
17551 @@ -38,7 +38,7 @@
17552  **                       and nonterminal numbers.  "unsigned char" is
17553  **                       used if there are fewer than 250 rules and
17554  **                       states combined.  "int" is used otherwise.
17555 -**    ParseTOKENTYPE     is the data type used for minor tokens given 
17556 +**    ParseTOKENTYPE     is the data type used for minor tokens given
17557  **                       directly to the parser from the tokenizer.
17558  **    YYMINORTYPE        is the data type used for all minor tokens.
17559  **                       This is typically a union of many types, one of
17560 @@ -62,7 +62,7 @@
17561  /* Next are that tables used to determine what action to take based on the
17562  ** current state and lookahead token.  These tables are used to implement
17563  ** functions that take a state number and lookahead value and return an
17564 -** action integer.  
17565 +** action integer.
17566  **
17567  ** Suppose the action integer is N.  Then the action is determined as
17568  ** follows
17569 @@ -87,7 +87,7 @@
17570  ** If the index value yy_shift_ofst[S]+X is out of range or if the value
17571  ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
17572  ** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
17573 -** and that yy_default[S] should be used instead.  
17574 +** and that yy_default[S] should be used instead.
17575  **
17576  ** The formula above is for computing the action when the lookahead is
17577  ** a terminal symbol.  If the lookahead is a non-terminal (as occurs after
17578 @@ -111,7 +111,7 @@
17579  
17580  /* The next table maps tokens into fallback tokens.  If a construct
17581  ** like the following:
17582 -** 
17583 +**
17584  **      %fallback ID X Y Z.
17585  **
17586  ** appears in the grammer, then ID becomes a fallback token for X, Y,
17587 @@ -163,10 +163,10 @@
17588  #endif /* NDEBUG */
17589  
17590  #ifndef NDEBUG
17591 -/* 
17592 +/*
17593  ** Turn parser tracing on by giving a stream to which to write the trace
17594  ** and a prompt to preface each trace message.  Tracing is turned off
17595 -** by making either argument NULL 
17596 +** by making either argument NULL
17597  **
17598  ** Inputs:
17599  ** <ul>
17600 @@ -191,7 +191,7 @@
17601  #ifndef NDEBUG
17602  /* For tracing shifts, the names of all terminals and nonterminals
17603  ** are required.  The following table supplies these names */
17604 -static const char *yyTokenName[] = { 
17605 +static const char *yyTokenName[] = {
17606  %%
17607  };
17608  #endif /* NDEBUG */
17609 @@ -220,7 +220,7 @@
17610  #endif
17611  }
17612  
17613 -/* 
17614 +/*
17615  ** This function allocates a new parser.
17616  ** The only argument is a pointer to a function which works like
17617  ** malloc.
17618 @@ -251,7 +251,7 @@
17619      /* Here is inserted the actions which take place when a
17620      ** terminal or non-terminal is destroyed.  This can happen
17621      ** when the symbol is popped from the stack during a
17622 -    ** reduce or during error processing or when a parser is 
17623 +    ** reduce or during error processing or when a parser is
17624      ** being destroyed before it is finished parsing.
17625      **
17626      ** Note: during a reduce, the only symbols destroyed are those
17627 @@ -289,7 +289,7 @@
17628    return yymajor;
17629  }
17630  
17631 -/* 
17632 +/*
17633  ** Deallocate and destroy a parser.  Destructors are all called for
17634  ** all stack elements before shutting the parser down.
17635  **
17636 @@ -325,7 +325,7 @@
17637  ){
17638    int i;
17639    int stateno = pParser->yystack[pParser->yyidx].stateno;
17640
17641 +
17642    /* if( pParser->yyidx<0 ) return YY_NO_ACTION;  */
17643    i = yy_shift_ofst[stateno];
17644    if( i==YY_SHIFT_USE_DFLT ){
17645 @@ -369,7 +369,7 @@
17646  ){
17647    int i;
17648    int stateno = pParser->yystack[pParser->yyidx].stateno;
17649
17650 +
17651    i = yy_reduce_ofst[stateno];
17652    if( i==YY_REDUCE_USE_DFLT ){
17653      return yy_default[stateno];
17654 @@ -455,7 +455,7 @@
17655    ParseARG_FETCH;
17656    yymsp = &yypParser->yystack[yypParser->yyidx];
17657  #ifndef NDEBUG
17658 -  if( yyTraceFILE && yyruleno>=0 
17659 +  if( yyTraceFILE && yyruleno>=0
17660          && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
17661      fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
17662        yyRuleName[yyruleno]);
17663 @@ -608,7 +608,7 @@
17664  #ifdef YYERRORSYMBOL
17665        /* A syntax error has occurred.
17666        ** The response to an error depends upon whether or not the
17667 -      ** grammar defines an error token "ERROR".  
17668 +      ** grammar defines an error token "ERROR".
17669        **
17670        ** This is what we do if the grammar does define ERROR:
17671        **
17672 --- ../lighttpd-1.4.11/src/log.c        2005-11-07 15:01:35.000000000 +0200
17673 +++ lighttpd-1.5.0/src/log.c    2006-07-18 13:03:40.000000000 +0300
17674 @@ -5,7 +5,6 @@
17675  #include <errno.h>
17676  #include <fcntl.h>
17677  #include <time.h>
17678 -#include <unistd.h>
17679  #include <string.h>
17680  #include <stdlib.h>
17681  
17682 @@ -16,6 +15,10 @@
17683  #include "config.h"
17684  #endif
17685  
17686 +#ifdef _WIN32
17687 +#undef HAVE_SYSLOG_H
17688 +#endif
17689 +
17690  #ifdef HAVE_SYSLOG_H
17691  #include <syslog.h>
17692  #endif
17693 @@ -23,6 +26,8 @@
17694  #include "log.h"
17695  #include "array.h"
17696  
17697 +#include "sys-files.h"
17698 +
17699  #ifdef HAVE_VALGRIND_VALGRIND_H
17700  #include <valgrind/valgrind.h>
17701  #endif
17702 @@ -31,55 +36,114 @@
17703  # define O_LARGEFILE 0
17704  #endif
17705  
17706 -/** 
17707 +/**
17708   * open the errorlog
17709 - * 
17710 + *
17711   * we have 3 possibilities:
17712   * - stderr (default)
17713 - * - syslog 
17714 + * - syslog
17715   * - logfile
17716 - * 
17717 + *
17718   * if the open failed, report to the user and die
17719 - * 
17720 + *
17721   */
17722  
17723 -int log_error_open(server *srv) {
17724 +
17725 +typedef struct {
17726 +       buffer *file;
17727 +       unsigned short use_syslog;
17728 +
17729 +       /* the errorlog */
17730         int fd;
17731 -       int close_stderr = 1;
17732 +       enum { ERRORLOG_STDERR, ERRORLOG_FILE, ERRORLOG_SYSLOG } mode;
17733 +       buffer *buf;
17734 +
17735 +       time_t cached_ts;
17736 +       buffer *cached_ts_str;
17737 +} errorlog;
17738 +
17739 +errorlog *myconfig = NULL;
17740 +
17741 +void log_init(void) {
17742 +       /* use syslog */
17743 +       errorlog *err;
17744 +
17745 +       err = calloc(1, sizeof(*err));
17746         
17747 +       err->fd = -1;
17748 +       err->mode = ERRORLOG_STDERR;
17749 +       err->buf = buffer_init();
17750 +       err->cached_ts_str = buffer_init();
17751 +
17752 +       myconfig = err;
17753 +}
17754 +
17755 +void log_free(void) {
17756 +       errorlog *err = myconfig;
17757 +
17758 +       if (!err) return;
17759 +
17760 +       TRACE("%s", "server stopped");
17761 +
17762 +       switch(err->mode) {
17763 +       case ERRORLOG_FILE:
17764 +               close(err->fd);
17765 +               break;
17766 +       case ERRORLOG_SYSLOG:
17767 +#ifdef HAVE_SYSLOG_H
17768 +               closelog();
17769 +#endif
17770 +               break;
17771 +       case ERRORLOG_STDERR:
17772 +               break;
17773 +       }
17774 +
17775 +       buffer_free(err->buf);
17776 +       buffer_free(err->cached_ts_str);
17777 +       if (err->file) buffer_free(err->file);
17778 +
17779 +       free(err);
17780 +
17781 +       myconfig = NULL;
17782 +}
17783 +
17784 +int log_error_open(buffer *file, int use_syslog) {
17785 +       int fd;
17786 +       int close_stderr = 1;
17787 +
17788 +       errorlog *err = myconfig;
17789 +
17790  #ifdef HAVE_SYSLOG_H
17791         /* perhaps someone wants to use syslog() */
17792         openlog("lighttpd", LOG_CONS | LOG_PID, LOG_DAEMON);
17793  #endif
17794 -       srv->errorlog_mode = ERRORLOG_STDERR;
17795 -       
17796 -       if (srv->srvconf.errorlog_use_syslog) {
17797 -               srv->errorlog_mode = ERRORLOG_SYSLOG;
17798 -       } else if (!buffer_is_empty(srv->srvconf.errorlog_file)) {
17799 -               const char *logfile = srv->srvconf.errorlog_file->ptr;
17800 -               
17801 -               if (-1 == (srv->errorlog_fd = open(logfile, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
17802 -                       log_error_write(srv, __FILE__, __LINE__, "SSSS", 
17803 -                                       "opening errorlog '", logfile,
17804 +       err->mode = ERRORLOG_STDERR;
17805 +
17806 +       if (use_syslog) {
17807 +               err->mode = ERRORLOG_SYSLOG;
17808 +       } else if (!buffer_is_empty(file)) {
17809 +               if (-1 == (err->fd = open(file->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
17810 +                       log_error_write(NULL, __FILE__, __LINE__, "SBSS",
17811 +                                       "opening errorlog '", file,
17812                                         "' failed: ", strerror(errno));
17813 -                       
17814 +
17815                         return -1;
17816                 }
17817  #ifdef FD_CLOEXEC
17818                 /* close fd on exec (cgi) */
17819 -               fcntl(srv->errorlog_fd, F_SETFD, FD_CLOEXEC);
17820 +               fcntl(err->fd, F_SETFD, FD_CLOEXEC);
17821  #endif
17822 -               srv->errorlog_mode = ERRORLOG_FILE;
17823 +               err->mode = ERRORLOG_FILE;
17824         }
17825 -       
17826 -       log_error_write(srv, __FILE__, __LINE__, "s", "server started");
17827 -       
17828 +
17829 +       TRACE("%s", "server started");
17830 +
17831  #ifdef HAVE_VALGRIND_VALGRIND_H
17832         /* don't close stderr for debugging purposes if run in valgrind */
17833         if (RUNNING_ON_VALGRIND) close_stderr = 0;
17834  #endif
17835 -       if (srv->errorlog_mode == ERRORLOG_STDERR) close_stderr = 0;
17836 -       
17837 +       if (err->mode == ERRORLOG_STDERR) close_stderr = 0;
17838 +
17839         /* move stderr to /dev/null */
17840         if (close_stderr &&
17841             -1 != (fd = open("/dev/null", O_WRONLY))) {
17842 @@ -90,167 +154,202 @@
17843         return 0;
17844  }
17845  
17846 -/** 
17847 +/**
17848   * open the errorlog
17849 - * 
17850 + *
17851   * if the open failed, report to the user and die
17852   * if no filename is given, use syslog instead
17853 - * 
17854 + *
17855   */
17856  
17857 -int log_error_cycle(server *srv) {
17858 +int log_error_cycle(void) {
17859         /* only cycle if we are not in syslog-mode */
17860 -       
17861 -       if (srv->errorlog_mode == ERRORLOG_FILE) {
17862 -               const char *logfile = srv->srvconf.errorlog_file->ptr;
17863 +
17864 +       errorlog *err = myconfig;
17865 +
17866 +       if (err->mode == ERRORLOG_FILE) {
17867 +               buffer *file = err->file;
17868                 /* already check of opening time */
17869 -               
17870 +
17871                 int new_fd;
17872 -               
17873 -               if (-1 == (new_fd = open(logfile, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
17874 +
17875 +               if (-1 == (new_fd = open(file->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
17876                         /* write to old log */
17877 -                       log_error_write(srv, __FILE__, __LINE__, "SSSSS", 
17878 -                                       "cycling errorlog '", logfile,
17879 +                       log_error_write(NULL, __FILE__, __LINE__, "SBSSS",
17880 +                                       "cycling errorlog '", file,
17881                                         "' failed: ", strerror(errno),
17882                                         ", falling back to syslog()");
17883 -                       
17884 -                       close(srv->errorlog_fd);
17885 -                       srv->errorlog_fd = -1;
17886 -#ifdef HAVE_SYSLOG_H   
17887 -                       srv->errorlog_mode = ERRORLOG_SYSLOG;
17888 +
17889 +                       close(err->fd);
17890 +                       err->fd = -1;
17891 +#ifdef HAVE_SYSLOG_H
17892 +                       err->mode = ERRORLOG_SYSLOG;
17893  #endif
17894                 } else {
17895                         /* ok, new log is open, close the old one */
17896 -                       close(srv->errorlog_fd);
17897 -                       srv->errorlog_fd = new_fd;
17898 +                       close(err->fd);
17899 +                       err->fd = new_fd;
17900                 }
17901         }
17902 -       
17903 -       log_error_write(srv, __FILE__, __LINE__, "s", "logfiles cycled");
17904 -       
17905 -       return 0;
17906 -}
17907  
17908 -int log_error_close(server *srv) {
17909 -       log_error_write(srv, __FILE__, __LINE__, "s", "server stopped");
17910 -       
17911 -       switch(srv->errorlog_mode) {
17912 -       case ERRORLOG_FILE:
17913 -               close(srv->errorlog_fd);
17914 -               break;
17915 -       case ERRORLOG_SYSLOG:
17916 -#ifdef HAVE_SYSLOG_H
17917 -               closelog();
17918 -#endif
17919 -               break;
17920 -       case ERRORLOG_STDERR:
17921 -               break;
17922 -       }
17923 -       
17924 +       TRACE("%s", "logfiles cycled");
17925 +
17926         return 0;
17927  }
17928  
17929 -int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...) {
17930 +int log_error_write(void *srv, const char *filename, unsigned int line, const char *fmt, ...) {
17931         va_list ap;
17932 -       
17933 -       switch(srv->errorlog_mode) {
17934 +       time_t t;
17935 +
17936 +       errorlog *err = myconfig;
17937 +
17938 +       switch(err->mode) {
17939         case ERRORLOG_FILE:
17940         case ERRORLOG_STDERR:
17941                 /* cache the generated timestamp */
17942 -               if (srv->cur_ts != srv->last_generated_debug_ts) {
17943 -                       buffer_prepare_copy(srv->ts_debug_str, 255);
17944 -                       strftime(srv->ts_debug_str->ptr, srv->ts_debug_str->size - 1, "%Y-%m-%d %H:%M:%S", localtime(&(srv->cur_ts)));
17945 -                       srv->ts_debug_str->used = strlen(srv->ts_debug_str->ptr) + 1;
17946 -                       
17947 -                       srv->last_generated_debug_ts = srv->cur_ts;
17948 +               t = time(NULL);
17949 +               
17950 +               if (t != err->cached_ts) {
17951 +                       buffer_prepare_copy(err->cached_ts_str, 255);
17952 +                       strftime(err->cached_ts_str->ptr, err->cached_ts_str->size - 1, "%Y-%m-%d %H:%M:%S", localtime(&(t)));
17953 +                       err->cached_ts_str->used = strlen(err->cached_ts_str->ptr) + 1;
17954 +                       err->cached_ts = t;
17955                 }
17956  
17957 -               buffer_copy_string_buffer(srv->errorlog_buf, srv->ts_debug_str);
17958 -               BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, ": (");
17959 +               buffer_copy_string_buffer(err->buf, err->cached_ts_str);
17960 +               BUFFER_APPEND_STRING_CONST(err->buf, ": (");
17961                 break;
17962         case ERRORLOG_SYSLOG:
17963                 /* syslog is generating its own timestamps */
17964 -               BUFFER_COPY_STRING_CONST(srv->errorlog_buf, "(");
17965 +               BUFFER_COPY_STRING_CONST(err->buf, "(");
17966                 break;
17967         }
17968 -       
17969 -       buffer_append_string(srv->errorlog_buf, filename);
17970 -       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, ".");
17971 -       buffer_append_long(srv->errorlog_buf, line);
17972 -       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, ") ");
17973 -       
17974 -       
17975 +
17976 +       buffer_append_string(err->buf, filename);
17977 +       BUFFER_APPEND_STRING_CONST(err->buf, ".");
17978 +       buffer_append_long(err->buf, line);
17979 +       BUFFER_APPEND_STRING_CONST(err->buf, ") ");
17980 +
17981         for(va_start(ap, fmt); *fmt; fmt++) {
17982                 int d;
17983                 char *s;
17984                 buffer *b;
17985                 off_t o;
17986 -               
17987 +
17988                 switch(*fmt) {
17989                 case 's':           /* string */
17990                         s = va_arg(ap, char *);
17991 -                       buffer_append_string(srv->errorlog_buf, s);
17992 -                       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
17993 +                       buffer_append_string(err->buf, s);
17994 +                       BUFFER_APPEND_STRING_CONST(err->buf, " ");
17995                         break;
17996                 case 'b':           /* buffer */
17997                         b = va_arg(ap, buffer *);
17998 -                       buffer_append_string_buffer(srv->errorlog_buf, b);
17999 -                       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
18000 +                       buffer_append_string_buffer(err->buf, b);
18001 +                       BUFFER_APPEND_STRING_CONST(err->buf, " ");
18002                         break;
18003                 case 'd':           /* int */
18004                         d = va_arg(ap, int);
18005 -                       buffer_append_long(srv->errorlog_buf, d);
18006 -                       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
18007 +                       buffer_append_long(err->buf, d);
18008 +                       BUFFER_APPEND_STRING_CONST(err->buf, " ");
18009                         break;
18010                 case 'o':           /* off_t */
18011                         o = va_arg(ap, off_t);
18012 -                       buffer_append_off_t(srv->errorlog_buf, o);
18013 -                       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
18014 +                       buffer_append_off_t(err->buf, o);
18015 +                       BUFFER_APPEND_STRING_CONST(err->buf, " ");
18016                         break;
18017                 case 'x':           /* int (hex) */
18018                         d = va_arg(ap, int);
18019 -                       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, "0x");
18020 -                       buffer_append_long_hex(srv->errorlog_buf, d);
18021 -                       BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
18022 +                       BUFFER_APPEND_STRING_CONST(err->buf, "0x");
18023 +                       buffer_append_long_hex(err->buf, d);
18024 +                       BUFFER_APPEND_STRING_CONST(err->buf, " ");
18025                         break;
18026                 case 'S':           /* string */
18027                         s = va_arg(ap, char *);
18028 -                       buffer_append_string(srv->errorlog_buf, s);
18029 +                       buffer_append_string(err->buf, s);
18030                         break;
18031                 case 'B':           /* buffer */
18032                         b = va_arg(ap, buffer *);
18033 -                       buffer_append_string_buffer(srv->errorlog_buf, b);
18034 +                       buffer_append_string_buffer(err->buf, b);
18035                         break;
18036                 case 'D':           /* int */
18037                         d = va_arg(ap, int);
18038 -                       buffer_append_long(srv->errorlog_buf, d);
18039 +                       buffer_append_long(err->buf, d);
18040                         break;
18041                 case '(':
18042                 case ')':
18043 -               case '<':       
18044 +               case '<':
18045                 case '>':
18046                 case ',':
18047                 case ' ':
18048 -                       buffer_append_string_len(srv->errorlog_buf, fmt, 1);
18049 +                       buffer_append_string_len(err->buf, fmt, 1);
18050                         break;
18051                 }
18052         }
18053         va_end(ap);
18054 -       
18055 -       switch(srv->errorlog_mode) {
18056 +
18057 +       switch(err->mode) {
18058         case ERRORLOG_FILE:
18059 -               BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, "\n");
18060 -               write(srv->errorlog_fd, srv->errorlog_buf->ptr, srv->errorlog_buf->used - 1);
18061 +               BUFFER_APPEND_STRING_CONST(err->buf, "\n");
18062 +               write(err->fd, err->buf->ptr, err->buf->used - 1);
18063                 break;
18064         case ERRORLOG_STDERR:
18065 -               BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, "\n");
18066 -               write(STDERR_FILENO, srv->errorlog_buf->ptr, srv->errorlog_buf->used - 1);
18067 +               BUFFER_APPEND_STRING_CONST(err->buf, "\n");
18068 +               write(STDERR_FILENO, err->buf->ptr, err->buf->used - 1);
18069                 break;
18070 +#ifdef HAVE_SYSLOG_H
18071 +       case ERRORLOG_SYSLOG:
18072 +               syslog(LOG_ERR, "%s", err->buf->ptr);
18073 +               break;
18074 +#endif
18075 +       }
18076 +
18077 +       return 0;
18078 +}
18079 +
18080 +static int log_trace_write(const char *fmt, va_list ap) {
18081 +       buffer *b;
18082 +       int l;
18083 +       errorlog *err = myconfig;
18084 +       
18085 +       b = buffer_init();
18086 +       buffer_prepare_copy(b, 1024);
18087 +       l = vsnprintf(b->ptr, b->size - 1, fmt, ap);
18088 +       if (l > 0) {
18089 +               b->used = (l > b->size - 1) ? b->size : l + 1;
18090 +       }
18091 +
18092 +       /* write b */
18093 +       switch(err->mode) {
18094 +       case ERRORLOG_FILE:
18095 +               buffer_append_string(b, "\r\n");
18096 +               write(err->fd, b->ptr, b->used - 1);
18097 +               break;
18098 +       case ERRORLOG_STDERR:
18099 +               buffer_append_string(b, "\r\n");
18100 +               write(STDERR_FILENO, b->ptr, b->used - 1);
18101 +               break;
18102 +#ifdef HAVE_SYSLOG_H
18103         case ERRORLOG_SYSLOG:
18104 -               syslog(LOG_ERR, "%s", srv->errorlog_buf->ptr);
18105 +               syslog(LOG_ERR, "%s", b->ptr);
18106                 break;
18107 +#endif
18108         }
18109         
18110 +       buffer_free(b);
18111 +
18112 +       return 0;
18113 +}
18114 +
18115 +int log_trace(const char *fmt, ...) {
18116 +       va_list ap;
18117 +
18118 +       va_start(ap, fmt);
18119 +
18120 +       log_trace_write(fmt, ap);
18121 +
18122 +       va_end(ap);
18123 +
18124         return 0;
18125  }
18126  
18127 +
18128 --- ../lighttpd-1.4.11/src/log.h        2005-08-11 01:26:36.000000000 +0300
18129 +++ lighttpd-1.5.0/src/log.h    2006-07-18 13:03:40.000000000 +0300
18130 @@ -1,13 +1,22 @@
18131  #ifndef _LOG_H_
18132  #define _LOG_H_
18133  
18134 -#include "server.h"
18135 +#include "buffer.h"
18136  
18137 -#define WP() log_error_write(srv, __FILE__, __LINE__, "");
18138 +void log_init(void); 
18139 +void log_free(void); 
18140  
18141 -int log_error_open(server *srv);
18142 -int log_error_close(server *srv);
18143 -int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...);
18144 -int log_error_cycle(server *srv);
18145 -       
18146 +int log_error_open(buffer *file, int use_syslog);
18147 +int log_error_close();
18148 +int log_error_write(void *srv, const char *filename, unsigned int line, const char *fmt, ...);
18149 +int log_error_cycle();
18150 +
18151 +#define ERROR(fmt, ...) \
18152 +       log_trace("%s.%d: (error) "fmt, __FILE__, __LINE__, __VA_ARGS__)
18153 +
18154 +#define TRACE(fmt, ...) \
18155 +       log_trace("%s.%d: (trace) "fmt, __FILE__, __LINE__, __VA_ARGS__)
18156 +
18157 +#define SEGFAULT() do { ERROR("%s", "Ooh, Ooh, Ooh. Something is not good ... going down"); abort(); } while(0)
18158 +int log_trace(const char *fmt, ...);
18159  #endif
18160 --- ../lighttpd-1.4.11/src/md5.h        2005-11-17 16:20:40.000000000 +0200
18161 +++ lighttpd-1.5.0/src/md5.h    2006-07-16 00:26:04.000000000 +0300
18162 @@ -30,9 +30,15 @@
18163  # include <inttypes.h>
18164  #endif
18165  
18166 +#ifdef _WIN32
18167 +#define UINT4 unsigned __int32
18168 +#define UINT2 unsigned __int16
18169 +#define POINTER unsigned char *
18170 +#else
18171  #define UINT4 uint32_t
18172  #define UINT2 uint16_t
18173  #define POINTER unsigned char *
18174 +#endif
18175  
18176  /* MD5 context. */
18177  typedef struct {
18178 --- ../lighttpd-1.4.11/src/mod_access.c 2006-01-14 19:44:54.000000000 +0200
18179 +++ lighttpd-1.5.0/src/mod_access.c     2006-07-16 00:26:04.000000000 +0300
18180 @@ -8,126 +8,125 @@
18181  
18182  #include "plugin.h"
18183  
18184 +#include "sys-strings.h"
18185 +
18186  typedef struct {
18187         array *access_deny;
18188  } plugin_config;
18189  
18190  typedef struct {
18191         PLUGIN_DATA;
18192 -       
18193 +
18194         plugin_config **config_storage;
18195 -       
18196 -       plugin_config conf; 
18197 +
18198 +       plugin_config conf;
18199  } plugin_data;
18200  
18201  INIT_FUNC(mod_access_init) {
18202         plugin_data *p;
18203 -       
18204 +
18205         p = calloc(1, sizeof(*p));
18206 -       
18207 +
18208         return p;
18209  }
18210  
18211  FREE_FUNC(mod_access_free) {
18212         plugin_data *p = p_d;
18213 -       
18214 +
18215         UNUSED(srv);
18216  
18217         if (!p) return HANDLER_GO_ON;
18218 -       
18219 +
18220         if (p->config_storage) {
18221                 size_t i;
18222                 for (i = 0; i < srv->config_context->used; i++) {
18223                         plugin_config *s = p->config_storage[i];
18224 -                       
18225 +
18226                         array_free(s->access_deny);
18227 -                       
18228 +
18229                         free(s);
18230                 }
18231                 free(p->config_storage);
18232         }
18233 -       
18234 +
18235         free(p);
18236 -       
18237 +
18238         return HANDLER_GO_ON;
18239  }
18240  
18241  SETDEFAULTS_FUNC(mod_access_set_defaults) {
18242         plugin_data *p = p_d;
18243         size_t i = 0;
18244 -       
18245 -       config_values_t cv[] = { 
18246 +
18247 +       config_values_t cv[] = {
18248                 { "url.access-deny",             NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
18249                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
18250         };
18251 -       
18252 +
18253         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
18254 -       
18255 +
18256         for (i = 0; i < srv->config_context->used; i++) {
18257                 plugin_config *s;
18258 -               
18259 +
18260                 s = calloc(1, sizeof(plugin_config));
18261                 s->access_deny    = array_init();
18262 -               
18263 +
18264                 cv[0].destination = s->access_deny;
18265 -               
18266 +
18267                 p->config_storage[i] = s;
18268 -       
18269 +
18270                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
18271                         return HANDLER_ERROR;
18272                 }
18273         }
18274 -       
18275 +
18276         return HANDLER_GO_ON;
18277  }
18278  
18279 -#define PATCH(x) \
18280 -       p->conf.x = s->x;
18281  static int mod_access_patch_connection(server *srv, connection *con, plugin_data *p) {
18282         size_t i, j;
18283         plugin_config *s = p->config_storage[0];
18284  
18285 -       PATCH(access_deny);
18286 -       
18287 +       PATCH_OPTION(access_deny);
18288 +
18289         /* skip the first, the global context */
18290         for (i = 1; i < srv->config_context->used; i++) {
18291                 data_config *dc = (data_config *)srv->config_context->data[i];
18292                 s = p->config_storage[i];
18293 -               
18294 +
18295                 /* condition didn't match */
18296                 if (!config_check_cond(srv, con, dc)) continue;
18297 -               
18298 +
18299                 /* merge config */
18300                 for (j = 0; j < dc->value->used; j++) {
18301                         data_unset *du = dc->value->data[j];
18302 -                       
18303 +
18304                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.access-deny"))) {
18305 -                               PATCH(access_deny);
18306 +                               PATCH_OPTION(access_deny);
18307                         }
18308                 }
18309         }
18310 -       
18311 +
18312         return 0;
18313  }
18314 -#undef PATCH
18315  
18316  URIHANDLER_FUNC(mod_access_uri_handler) {
18317         plugin_data *p = p_d;
18318         int s_len;
18319         size_t k;
18320 -       
18321 +
18322         if (con->uri.path->used == 0) return HANDLER_GO_ON;
18323 -       
18324 +
18325         mod_access_patch_connection(srv, con, p);
18326 -       
18327 +
18328         s_len = con->uri.path->used - 1;
18329 -       
18330 +
18331         for (k = 0; k < p->conf.access_deny->used; k++) {
18332                 data_string *ds = (data_string *)p->conf.access_deny->data[k];
18333                 int ct_len = ds->value->used - 1;
18334 -               
18335 +
18336                 if (ct_len > s_len) continue;
18337 -               
18338 +
18339                 if (ds->value->used == 0) continue;
18340  
18341                 /* if we have a case-insensitive FS we have to lower-case the URI here too */
18342 @@ -135,18 +134,18 @@
18343                 if (con->conf.force_lowercase_filenames) {
18344                         if (0 == strncasecmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
18345                                 con->http_status = 403;
18346 -                       
18347 +
18348                                 return HANDLER_FINISHED;
18349                         }
18350                 } else {
18351                         if (0 == strncmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
18352                                 con->http_status = 403;
18353 -                       
18354 +
18355                                 return HANDLER_FINISHED;
18356                         }
18357                 }
18358         }
18359 -       
18360 +
18361         /* not found */
18362         return HANDLER_GO_ON;
18363  }
18364 @@ -155,13 +154,13 @@
18365  int mod_access_plugin_init(plugin *p) {
18366         p->version     = LIGHTTPD_VERSION_ID;
18367         p->name        = buffer_init_string("access");
18368 -       
18369 +
18370         p->init        = mod_access_init;
18371         p->set_defaults = mod_access_set_defaults;
18372         p->handle_uri_clean  = mod_access_uri_handler;
18373         p->cleanup     = mod_access_free;
18374 -       
18375 +
18376         p->data        = NULL;
18377 -       
18378 +
18379         return 0;
18380  }
18381 --- ../lighttpd-1.4.11/src/mod_accesslog.c      2006-01-31 14:01:43.000000000 +0200
18382 +++ lighttpd-1.5.0/src/mod_accesslog.c  2006-09-07 00:57:05.000000000 +0300
18383 @@ -6,8 +6,7 @@
18384  #include <ctype.h>
18385  #include <stdlib.h>
18386  #include <string.h>
18387 -#include <fcntl.h>
18388 -#include <unistd.h>
18389 +#include <fcntl.h> /* only the defines on windows */
18390  #include <errno.h>
18391  #include <time.h>
18392  
18393 @@ -22,6 +21,7 @@
18394  #include "inet_ntop_cache.h"
18395  
18396  #include "sys-socket.h"
18397 +#include "sys-files.h"
18398  
18399  #ifdef HAVE_SYSLOG_H
18400  # include <syslog.h>
18401 @@ -29,7 +29,7 @@
18402  
18403  typedef struct {
18404         char key;
18405 -       enum { 
18406 +       enum {
18407                 FORMAT_UNSET,
18408                         FORMAT_UNSUPPORTED,
18409                         FORMAT_PERCENT,
18410 @@ -41,7 +41,7 @@
18411                         FORMAT_STATUS,
18412                         FORMAT_BYTES_OUT_NO_HEADER,
18413                         FORMAT_HEADER,
18414 -                       
18415 +
18416                         FORMAT_REMOTE_ADDR,
18417                         FORMAT_LOCAL_ADDR,
18418                         FORMAT_COOKIE,
18419 @@ -59,20 +59,20 @@
18420                         FORMAT_CONNECTION_STATUS,
18421                         FORMAT_BYTES_IN,
18422                         FORMAT_BYTES_OUT,
18423 -                       
18424 +
18425                         FORMAT_RESPONSE_HEADER
18426         } type;
18427  } format_mapping;
18428  
18429  /**
18430 - * 
18431 - * 
18432 + *
18433 + *
18434   * "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""
18435 - * 
18436 + *
18437   */
18438  
18439 -const format_mapping fmap[] = 
18440 -{ 
18441 +const format_mapping fmap[] =
18442 +{
18443         { '%', FORMAT_PERCENT },
18444         { 'h', FORMAT_REMOTE_HOST },
18445         { 'l', FORMAT_REMOTE_IDENT },
18446 @@ -82,7 +82,7 @@
18447         { 's', FORMAT_STATUS },
18448         { 'b', FORMAT_BYTES_OUT_NO_HEADER },
18449         { 'i', FORMAT_HEADER },
18450 -       
18451 +
18452         { 'a', FORMAT_REMOTE_ADDR },
18453         { 'A', FORMAT_LOCAL_ADDR },
18454         { 'B', FORMAT_BYTES_OUT_NO_HEADER },
18455 @@ -103,23 +103,23 @@
18456         { 'X', FORMAT_CONNECTION_STATUS },
18457         { 'I', FORMAT_BYTES_IN },
18458         { 'O', FORMAT_BYTES_OUT },
18459 -       
18460 +
18461         { 'o', FORMAT_RESPONSE_HEADER },
18462 -       
18463 +
18464         { '\0', FORMAT_UNSET }
18465  };
18466  
18467  
18468  typedef struct {
18469         enum { FIELD_UNSET, FIELD_STRING, FIELD_FORMAT } type;
18470 -       
18471 +
18472         buffer *string;
18473         int field;
18474  } format_field;
18475  
18476  typedef struct {
18477         format_field **ptr;
18478 -       
18479 +
18480         size_t used;
18481         size_t size;
18482  } format_fields;
18483 @@ -128,39 +128,39 @@
18484         buffer *access_logfile;
18485         buffer *format;
18486         unsigned short use_syslog;
18487 -       
18488 -       
18489 +
18490 +
18491         int    log_access_fd;
18492         time_t last_generated_accesslog_ts;
18493         time_t *last_generated_accesslog_ts_ptr;
18494 -       
18495 -       
18496 +
18497 +
18498         buffer *access_logbuffer;
18499         buffer *ts_accesslog_str;
18500 -       
18501 +
18502         format_fields *parsed_format;
18503  } plugin_config;
18504  
18505  typedef struct {
18506         PLUGIN_DATA;
18507 -       
18508 +
18509         plugin_config **config_storage;
18510 -       plugin_config conf; 
18511 +       plugin_config conf;
18512  } plugin_data;
18513  
18514  INIT_FUNC(mod_accesslog_init) {
18515         plugin_data *p;
18516 -       
18517 +
18518         p = calloc(1, sizeof(*p));
18519 -       
18520 +
18521         return p;
18522  }
18523  
18524  int accesslog_parse_format(server *srv, format_fields *fields, buffer *format) {
18525         size_t i, j, k = 0, start = 0;
18526 -       
18527 +
18528         for (i = 0; i < format->used - 1; i++) {
18529 -               
18530 +
18531                 switch(format->ptr[i]) {
18532                 case '%':
18533                         if (start != i) {
18534 @@ -173,19 +173,19 @@
18535                                         fields->size += 16;
18536                                         fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_fields * ));
18537                                 }
18538 -                               
18539 +
18540                                 fields->ptr[fields->used] = malloc(sizeof(format_fields));
18541                                 fields->ptr[fields->used]->type = FIELD_STRING;
18542                                 fields->ptr[fields->used]->string = buffer_init();
18543 -                               
18544 +
18545                                 buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + start, i - start);
18546 -                               
18547 +
18548                                 fields->used++;
18549                         }
18550 -                       
18551 -                       
18552 +
18553 +
18554                         /* we need a new field */
18555 -                       
18556 +
18557                         if (fields->size == 0) {
18558                                 fields->size = 16;
18559                                 fields->used = 0;
18560 @@ -194,43 +194,43 @@
18561                                 fields->size += 16;
18562                                 fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_fields * ));
18563                         }
18564 -                       
18565 +
18566                         /* search for the terminating command */
18567                         switch (format->ptr[i+1]) {
18568                         case '>':
18569                         case '<':
18570                                 /* only for s */
18571 -                               
18572 +
18573                                 for (j = 0; fmap[j].key != '\0'; j++) {
18574                                         if (fmap[j].key != format->ptr[i+2]) continue;
18575 -                                       
18576 +
18577                                         /* found key */
18578 -                                               
18579 +
18580                                         fields->ptr[fields->used] = malloc(sizeof(format_fields));
18581                                         fields->ptr[fields->used]->type = FIELD_FORMAT;
18582                                         fields->ptr[fields->used]->field = fmap[j].type;
18583                                         fields->ptr[fields->used]->string = NULL;
18584 -                                       
18585 +
18586                                         fields->used++;
18587 -                                       
18588 +
18589                                         break;
18590                                 }
18591 -                               
18592 +
18593                                 if (fmap[j].key == '\0') {
18594                                         log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
18595                                         return -1;
18596                                 }
18597 -                               
18598 +
18599                                 start = i + 3;
18600 -                               
18601 +
18602                                 break;
18603                         case '{':
18604                                 /* go forward to } */
18605 -                               
18606 +
18607                                 for (k = i+2; k < format->used - 1; k++) {
18608                                         if (format->ptr[k] == '}') break;
18609                                 }
18610 -                               
18611 +
18612                                 if (k == format->used - 1) {
18613                                         log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
18614                                         return -1;
18615 @@ -239,62 +239,62 @@
18616                                         log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
18617                                         return -1;
18618                                 }
18619 -                               
18620 +
18621                                 for (j = 0; fmap[j].key != '\0'; j++) {
18622                                         if (fmap[j].key != format->ptr[k+1]) continue;
18623 -                                       
18624 +
18625                                         /* found key */
18626 -                                               
18627 +
18628                                         fields->ptr[fields->used] = malloc(sizeof(format_fields));
18629                                         fields->ptr[fields->used]->type = FIELD_FORMAT;
18630                                         fields->ptr[fields->used]->field = fmap[j].type;
18631                                         fields->ptr[fields->used]->string = buffer_init();
18632 -                                       
18633 +
18634                                         buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + i + 2, k - (i + 2));
18635 -                                       
18636 +
18637                                         fields->used++;
18638 -                                       
18639 +
18640                                         break;
18641                                 }
18642 -                               
18643 +
18644                                 if (fmap[j].key == '\0') {
18645                                         log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
18646                                         return -1;
18647                                 }
18648 -                               
18649 +
18650                                 start = k + 2;
18651 -                               
18652 +
18653                                 break;
18654                         default:
18655                                 for (j = 0; fmap[j].key != '\0'; j++) {
18656                                         if (fmap[j].key != format->ptr[i+1]) continue;
18657 -                                       
18658 +
18659                                         /* found key */
18660 -                                               
18661 +
18662                                         fields->ptr[fields->used] = malloc(sizeof(format_fields));
18663                                         fields->ptr[fields->used]->type = FIELD_FORMAT;
18664                                         fields->ptr[fields->used]->field = fmap[j].type;
18665                                         fields->ptr[fields->used]->string = NULL;
18666 -                                       
18667 +
18668                                         fields->used++;
18669 -                                       
18670 +
18671                                         break;
18672                                 }
18673 -                               
18674 +
18675                                 if (fmap[j].key == '\0') {
18676                                         log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
18677                                         return -1;
18678                                 }
18679 -                               
18680 +
18681                                 start = i + 2;
18682 -                               
18683 +
18684                                 break;
18685                         }
18686 -                       
18687 +
18688                         break;
18689                 }
18690         }
18691 -       
18692 +
18693         if (start < i) {
18694                 /* copy the string */
18695                 if (fields->size == 0) {
18696 @@ -305,32 +305,32 @@
18697                         fields->size += 16;
18698                         fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_fields * ));
18699                 }
18700 -               
18701 +
18702                 fields->ptr[fields->used] = malloc(sizeof(format_fields));
18703                 fields->ptr[fields->used]->type = FIELD_STRING;
18704                 fields->ptr[fields->used]->string = buffer_init();
18705 -               
18706 +
18707                 buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + start, i - start);
18708 -               
18709 +
18710                 fields->used++;
18711         }
18712 -       
18713 +
18714         return 0;
18715  }
18716  
18717  FREE_FUNC(mod_accesslog_free) {
18718         plugin_data *p = p_d;
18719         size_t i;
18720 -       
18721 +
18722         if (!p) return HANDLER_GO_ON;
18723 -       
18724 +
18725         if (p->config_storage) {
18726 -               
18727 +
18728                 for (i = 0; i < srv->config_context->used; i++) {
18729                         plugin_config *s = p->config_storage[i];
18730  
18731                         if (!s) continue;
18732 -                       
18733 +
18734                         if (s->access_logbuffer->used) {
18735                                 if (s->use_syslog) {
18736  # ifdef HAVE_SYSLOG_H
18737 @@ -342,14 +342,14 @@
18738                                         write(s->log_access_fd, s->access_logbuffer->ptr, s->access_logbuffer->used - 1);
18739                                 }
18740                         }
18741 -                       
18742 +
18743                         if (s->log_access_fd != -1) close(s->log_access_fd);
18744 -                       
18745 +
18746                         buffer_free(s->ts_accesslog_str);
18747                         buffer_free(s->access_logbuffer);
18748                         buffer_free(s->format);
18749                         buffer_free(s->access_logfile);
18750 -                       
18751 +
18752                         if (s->parsed_format) {
18753                                 size_t j;
18754                                 for (j = 0; j < s->parsed_format->used; j++) {
18755 @@ -359,36 +359,36 @@
18756                                 free(s->parsed_format->ptr);
18757                                 free(s->parsed_format);
18758                         }
18759 -                       
18760 +
18761                         free(s);
18762                 }
18763 -       
18764 +
18765                 free(p->config_storage);
18766         }
18767 -       
18768 +
18769         free(p);
18770 -       
18771 +
18772         return HANDLER_GO_ON;
18773  }
18774  
18775  SETDEFAULTS_FUNC(log_access_open) {
18776         plugin_data *p = p_d;
18777         size_t i = 0;
18778 -       
18779 -       config_values_t cv[] = { 
18780 +
18781 +       config_values_t cv[] = {
18782                 { "accesslog.filename",             NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
18783                 { "accesslog.use-syslog",           NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
18784                 { "accesslog.format",               NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
18785                 { NULL,                             NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
18786         };
18787 -       
18788 +
18789         if (!p) return HANDLER_ERROR;
18790 -       
18791 +
18792         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
18793 -       
18794 +
18795         for (i = 0; i < srv->config_context->used; i++) {
18796                 plugin_config *s;
18797 -               
18798 +
18799                 s = calloc(1, sizeof(plugin_config));
18800                 s->access_logfile = buffer_init();
18801                 s->format = buffer_init();
18802 @@ -397,44 +397,44 @@
18803                 s->log_access_fd = -1;
18804                 s->last_generated_accesslog_ts = 0;
18805                 s->last_generated_accesslog_ts_ptr = &(s->last_generated_accesslog_ts);
18806 -               
18807 -       
18808 +
18809 +
18810                 cv[0].destination = s->access_logfile;
18811                 cv[1].destination = &(s->use_syslog);
18812                 cv[2].destination = s->format;
18813 -       
18814 +
18815                 p->config_storage[i] = s;
18816 -               
18817 +
18818                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
18819                         return HANDLER_ERROR;
18820                 }
18821 -               
18822 +
18823                 if (i == 0 && buffer_is_empty(s->format)) {
18824                         /* set a default logfile string */
18825 -                       
18826 +
18827                         buffer_copy_string(s->format, "%h %V %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"");
18828                 }
18829 -               
18830 +
18831                 /* parse */
18832 -               
18833 +
18834                 if (s->format->used) {
18835                         s->parsed_format = calloc(1, sizeof(*(s->parsed_format)));
18836 -                       
18837 +
18838                         if (-1 == accesslog_parse_format(srv, s->parsed_format, s->format)) {
18839  
18840 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
18841 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
18842                                                 "parsing accesslog-definition failed:", s->format);
18843  
18844                                 return HANDLER_ERROR;
18845                         }
18846  #if 0
18847 -                       /* debugging */                 
18848 +                       /* debugging */
18849                         for (j = 0; j < s->parsed_format->used; j++) {
18850                                 switch (s->parsed_format->ptr[j]->type) {
18851                                 case FIELD_FORMAT:
18852 -                                       log_error_write(srv, __FILE__, __LINE__, "ssds", 
18853 +                                       log_error_write(srv, __FILE__, __LINE__, "ssds",
18854                                                         "config:", "format", s->parsed_format->ptr[j]->field,
18855 -                                                       s->parsed_format->ptr[j]->string ? 
18856 +                                                       s->parsed_format->ptr[j]->string ?
18857                                                         s->parsed_format->ptr[j]->string->ptr : "" );
18858                                         break;
18859                                 case FIELD_STRING:
18860 @@ -446,52 +446,52 @@
18861                         }
18862  #endif
18863                 }
18864 -               
18865 +
18866                 if (s->use_syslog) {
18867                         /* ignore the next checks */
18868                         continue;
18869                 }
18870 -               
18871 +
18872                 if (buffer_is_empty(s->access_logfile)) continue;
18873 -               
18874 +
18875                 if (s->access_logfile->ptr[0] == '|') {
18876  #ifdef HAVE_FORK
18877                         /* create write pipe and spawn process */
18878 -                       
18879 +
18880                         int to_log_fds[2];
18881                         pid_t pid;
18882 -                       
18883 +
18884                         if (pipe(to_log_fds)) {
18885                                 log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed: ", strerror(errno));
18886                                 return HANDLER_ERROR;
18887                         }
18888 -                       
18889 +
18890                         /* fork, execve */
18891                         switch (pid = fork()) {
18892 -                       case 0: 
18893 +                       case 0:
18894                                 /* child */
18895 -                               
18896 +
18897                                 close(STDIN_FILENO);
18898                                 dup2(to_log_fds[0], STDIN_FILENO);
18899                                 close(to_log_fds[0]);
18900                                 /* not needed */
18901                                 close(to_log_fds[1]);
18902 -                               
18903 +
18904                                 /* we don't need the client socket */
18905                                 for (i = 3; i < 256; i++) {
18906                                         close(i);
18907                                 }
18908 -                               
18909 -                               /* exec the log-process (skip the | ) 
18910 -                                * 
18911 +
18912 +                               /* exec the log-process (skip the | )
18913 +                                *
18914                                  */
18915 -                               
18916 +
18917                                 execl("/bin/sh", "sh", "-c", s->access_logfile->ptr + 1, NULL);
18918  
18919 -                               log_error_write(srv, __FILE__, __LINE__, "sss", 
18920 -                                               "spawning log-process failed: ", strerror(errno), 
18921 +                               log_error_write(srv, __FILE__, __LINE__, "sss",
18922 +                                               "spawning log-process failed: ", strerror(errno),
18923                                                 s->access_logfile->ptr + 1);
18924 -                               
18925 +
18926                                 exit(-1);
18927                                 break;
18928                         case -1:
18929 @@ -500,27 +500,28 @@
18930                                 break;
18931                         default:
18932                                 close(to_log_fds[0]);
18933 -                               
18934 +
18935                                 s->log_access_fd = to_log_fds[1];
18936 -                               
18937 +
18938                                 break;
18939                         }
18940  #else
18941                         return -1;
18942  #endif
18943 -               } else if (-1 == (s->log_access_fd = 
18944 +               } else if (-1 == (s->log_access_fd =
18945                                   open(s->access_logfile->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
18946 -                       
18947 -                       log_error_write(srv, __FILE__, __LINE__, "ssb", 
18948 -                                       "opening access-log failed:", 
18949 +
18950 +                       log_error_write(srv, __FILE__, __LINE__, "ssb",
18951 +                                       "opening access-log failed:",
18952                                         strerror(errno), s->access_logfile);
18953 -                       
18954 +
18955                         return HANDLER_ERROR;
18956                 }
18957 +#ifndef _WIN32
18958                 fcntl(s->log_access_fd, F_SETFD, FD_CLOEXEC);
18959 -       
18960 +#endif
18961         }
18962 -       
18963 +
18964         return HANDLER_GO_ON;
18965  }
18966  
18967 @@ -529,7 +530,7 @@
18968         size_t i;
18969  
18970         if (!p->config_storage) return HANDLER_GO_ON;
18971 -               
18972 +
18973         for (i = 0; i < srv->config_context->used; i++) {
18974                 plugin_config *s = p->config_storage[i];
18975  
18976 @@ -544,90 +545,87 @@
18977                         } else if (s->log_access_fd != -1) {
18978                                 write(s->log_access_fd, s->access_logbuffer->ptr, s->access_logbuffer->used - 1);
18979                         }
18980 -                       
18981 +
18982                         buffer_reset(s->access_logbuffer);
18983                 }
18984 -               
18985 +
18986                 if (s->use_syslog == 0 &&
18987                     !buffer_is_empty(s->access_logfile) &&
18988                     s->access_logfile->ptr[0] != '|') {
18989 -                       
18990 +
18991                         close(s->log_access_fd);
18992 -                       
18993 -                       if (-1 == (s->log_access_fd = 
18994 +
18995 +                       if (-1 == (s->log_access_fd =
18996                                    open(s->access_logfile->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
18997 -                               
18998 +
18999                                 log_error_write(srv, __FILE__, __LINE__, "ss", "cycling access-log failed:", strerror(errno));
19000 -                               
19001 +
19002                                 return HANDLER_ERROR;
19003                         }
19004                 }
19005         }
19006 -       
19007 +
19008         return HANDLER_GO_ON;
19009  }
19010  
19011 -#define PATCH(x) \
19012 -       p->conf.x = s->x;
19013  static int mod_accesslog_patch_connection(server *srv, connection *con, plugin_data *p) {
19014         size_t i, j;
19015         plugin_config *s = p->config_storage[0];
19016 -       
19017 -       PATCH(access_logfile);
19018 -       PATCH(format);
19019 -       PATCH(log_access_fd);
19020 -       PATCH(last_generated_accesslog_ts_ptr);
19021 -       PATCH(access_logbuffer);
19022 -       PATCH(ts_accesslog_str);
19023 -       PATCH(parsed_format);
19024 -       PATCH(use_syslog);
19025 -       
19026 +
19027 +       PATCH_OPTION(access_logfile);
19028 +       PATCH_OPTION(format);
19029 +       PATCH_OPTION(log_access_fd);
19030 +       PATCH_OPTION(last_generated_accesslog_ts_ptr);
19031 +       PATCH_OPTION(access_logbuffer);
19032 +       PATCH_OPTION(ts_accesslog_str);
19033 +       PATCH_OPTION(parsed_format);
19034 +       PATCH_OPTION(use_syslog);
19035 +
19036         /* skip the first, the global context */
19037         for (i = 1; i < srv->config_context->used; i++) {
19038                 data_config *dc = (data_config *)srv->config_context->data[i];
19039                 s = p->config_storage[i];
19040 -               
19041 +
19042                 /* condition didn't match */
19043                 if (!config_check_cond(srv, con, dc)) continue;
19044 -               
19045 +
19046                 /* merge config */
19047                 for (j = 0; j < dc->value->used; j++) {
19048                         data_unset *du = dc->value->data[j];
19049 -                       
19050 +
19051                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.filename"))) {
19052 -                               PATCH(access_logfile);
19053 -                               PATCH(log_access_fd);
19054 -                               PATCH(last_generated_accesslog_ts_ptr);
19055 -                               PATCH(access_logbuffer);
19056 -                               PATCH(ts_accesslog_str);
19057 +                               PATCH_OPTION(access_logfile);
19058 +                               PATCH_OPTION(log_access_fd);
19059 +                               PATCH_OPTION(last_generated_accesslog_ts_ptr);
19060 +                               PATCH_OPTION(access_logbuffer);
19061 +                               PATCH_OPTION(ts_accesslog_str);
19062                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.format"))) {
19063 -                               PATCH(format);
19064 -                               PATCH(parsed_format);
19065 +                               PATCH_OPTION(format);
19066 +                               PATCH_OPTION(parsed_format);
19067                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.use-syslog"))) {
19068 -                               PATCH(use_syslog);
19069 +                               PATCH_OPTION(use_syslog);
19070                         }
19071                 }
19072         }
19073 -       
19074 +
19075         return 0;
19076  }
19077 -#undef PATCH
19078  
19079  REQUESTDONE_FUNC(log_access_write) {
19080         plugin_data *p = p_d;
19081         buffer *b;
19082         size_t j;
19083 -       
19084 +
19085         int newts = 0;
19086         data_string *ds;
19087 -       
19088 +
19089         mod_accesslog_patch_connection(srv, con, p);
19090 -       
19091 +
19092         b = p->conf.access_logbuffer;
19093         if (b->used == 0) {
19094                 buffer_copy_string(b, "");
19095         }
19096 -       
19097 +
19098         for (j = 0; j < p->conf.parsed_format->used; j++) {
19099                 switch(p->conf.parsed_format->ptr[j]->type) {
19100                 case FIELD_STRING:
19101 @@ -636,14 +634,14 @@
19102                 case FIELD_FORMAT:
19103                         switch(p->conf.parsed_format->ptr[j]->field) {
19104                         case FORMAT_TIMESTAMP:
19105 -                               
19106 +
19107                                 /* cache the generated timestamp */
19108                                 if (srv->cur_ts != *(p->conf.last_generated_accesslog_ts_ptr)) {
19109                                         struct tm tm;
19110  #if defined(HAVE_STRUCT_TM_GMTOFF)
19111                                         long scd, hrs, min;
19112  #endif
19113 -               
19114 +
19115                                         buffer_prepare_copy(p->conf.ts_accesslog_str, 255);
19116  #if defined(HAVE_STRUCT_TM_GMTOFF)
19117  # ifdef HAVE_LOCALTIME_R
19118 @@ -653,17 +651,17 @@
19119                                         strftime(p->conf.ts_accesslog_str->ptr, p->conf.ts_accesslog_str->size - 1, "[%d/%b/%Y:%H:%M:%S ", localtime_r(&(srv->cur_ts)));
19120  # endif
19121                                         p->conf.ts_accesslog_str->used = strlen(p->conf.ts_accesslog_str->ptr) + 1;
19122 -                                       
19123 +
19124                                         buffer_append_string(p->conf.ts_accesslog_str, tm.tm_gmtoff >= 0 ? "+" : "-");
19125 -                                       
19126 +
19127                                         scd = abs(tm.tm_gmtoff);
19128                                         hrs = scd / 3600;
19129                                         min = (scd % 3600) / 60;
19130 -                                       
19131 +
19132                                         /* hours */
19133                                         if (hrs < 10) buffer_append_string(p->conf.ts_accesslog_str, "0");
19134                                         buffer_append_long(p->conf.ts_accesslog_str, hrs);
19135 -                                       
19136 +
19137                                         if (min < 10) buffer_append_string(p->conf.ts_accesslog_str, "0");
19138                                         buffer_append_long(p->conf.ts_accesslog_str, min);
19139                                         BUFFER_APPEND_STRING_CONST(p->conf.ts_accesslog_str, "]");
19140 @@ -676,20 +674,20 @@
19141  #endif
19142                                         p->conf.ts_accesslog_str->used = strlen(p->conf.ts_accesslog_str->ptr) + 1;
19143  #endif
19144 -                                       
19145 +
19146                                         *(p->conf.last_generated_accesslog_ts_ptr) = srv->cur_ts;
19147                                         newts = 1;
19148                                 }
19149 -                               
19150 +
19151                                 buffer_append_string_buffer(b, p->conf.ts_accesslog_str);
19152 -                               
19153 +
19154                                 break;
19155                         case FORMAT_REMOTE_HOST:
19156 -       
19157 +
19158                                 /* handle inet_ntop cache */
19159 -       
19160 +
19161                                 buffer_append_string(b, inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
19162 -                               
19163 +
19164                                 break;
19165                         case FORMAT_REMOTE_IDENT:
19166                                 /* ident */
19167 @@ -703,17 +701,20 @@
19168                                 }
19169                                 break;
19170                         case FORMAT_REQUEST_LINE:
19171 -                               if (con->request.request_line->used) {
19172 -                                       buffer_append_string_buffer(b, con->request.request_line);
19173 -                               }
19174 +                               buffer_append_string(b, get_http_method_name(con->request.http_method));
19175 +                               buffer_append_string(b, " ");
19176 +                               buffer_append_string_buffer(b, con->request.orig_uri);
19177 +                               buffer_append_string(b, " ");
19178 +                               buffer_append_string(b, get_http_version_name(con->request.http_version));
19179 +
19180                                 break;
19181                         case FORMAT_STATUS:
19182                                 buffer_append_long(b, con->http_status);
19183                                 break;
19184 -       
19185 +
19186                         case FORMAT_BYTES_OUT_NO_HEADER:
19187                                 if (con->bytes_written > 0) {
19188 -                                       buffer_append_off_t(b, 
19189 +                                       buffer_append_off_t(b,
19190                                                             con->bytes_written - con->bytes_header <= 0 ? 0 : con->bytes_written - con->bytes_header);
19191                                 } else {
19192                                         BUFFER_APPEND_STRING_CONST(b, "-");
19193 @@ -772,7 +773,7 @@
19194                                 }
19195                                 break;
19196                         case FORMAT_REQUEST_PROTOCOL:
19197 -                               buffer_append_string(b, 
19198 +                               buffer_append_string(b,
19199                                                      con->request.http_version == HTTP_VERSION_1_1 ? "HTTP/1.1" : "HTTP/1.0");
19200                                 break;
19201                         case FORMAT_REQUEST_METHOD:
19202 @@ -801,7 +802,7 @@
19203                                  { 'D', FORMAT_TIME_USED_MS },
19204                                  { 'e', FORMAT_ENV },
19205                                  */
19206 -                               
19207 +
19208                                 break;
19209                         }
19210                         break;
19211 @@ -809,7 +810,7 @@
19212                         break;
19213                 }
19214         }
19215 -       
19216 +
19217         BUFFER_APPEND_STRING_CONST(b, "\n");
19218  
19219         if (p->conf.use_syslog ||  /* syslog doesn't cache */
19220 @@ -828,7 +829,7 @@
19221                 }
19222                 buffer_reset(b);
19223         }
19224 -       
19225 +
19226         return HANDLER_GO_ON;
19227  }
19228  
19229 @@ -836,15 +837,15 @@
19230  int mod_accesslog_plugin_init(plugin *p) {
19231         p->version     = LIGHTTPD_VERSION_ID;
19232         p->name        = buffer_init_string("accesslog");
19233 -       
19234 +
19235         p->init        = mod_accesslog_init;
19236         p->set_defaults= log_access_open;
19237         p->cleanup     = mod_accesslog_free;
19238 -       
19239 -       p->handle_request_done  = log_access_write;
19240 -       p->handle_sighup        = log_access_cycle;
19241 -       
19242 +
19243 +       p->handle_response_done  = log_access_write;
19244 +       p->handle_sighup         = log_access_cycle;
19245 +
19246         p->data        = NULL;
19247 -       
19248 +
19249         return 0;
19250  }
19251 --- ../lighttpd-1.4.11/src/mod_alias.c  2006-03-01 23:18:51.000000000 +0200
19252 +++ lighttpd-1.5.0/src/mod_alias.c      2006-07-16 00:26:03.000000000 +0300
19253 @@ -8,6 +8,7 @@
19254  #include "buffer.h"
19255  
19256  #include "plugin.h"
19257 +#include "sys-strings.h"
19258  
19259  /* plugin config for all request/connections */
19260  typedef struct {
19261 @@ -16,44 +17,44 @@
19262  
19263  typedef struct {
19264         PLUGIN_DATA;
19265 -       
19266 +
19267         plugin_config **config_storage;
19268 -       
19269 -       plugin_config conf; 
19270 +
19271 +       plugin_config conf;
19272  } plugin_data;
19273  
19274  /* init the plugin data */
19275  INIT_FUNC(mod_alias_init) {
19276         plugin_data *p;
19277 -       
19278 +
19279         p = calloc(1, sizeof(*p));
19280 -       
19281 -       
19282 -       
19283 +
19284 +
19285 +
19286         return p;
19287  }
19288  
19289  /* detroy the plugin data */
19290  FREE_FUNC(mod_alias_free) {
19291         plugin_data *p = p_d;
19292 -       
19293 +
19294         if (!p) return HANDLER_GO_ON;
19295 -       
19296 +
19297         if (p->config_storage) {
19298                 size_t i;
19299 -               
19300 +
19301                 for (i = 0; i < srv->config_context->used; i++) {
19302                         plugin_config *s = p->config_storage[i];
19303 -                       
19304 +
19305                         array_free(s->alias);
19306 -                       
19307 +
19308                         free(s);
19309                 }
19310                 free(p->config_storage);
19311         }
19312 -       
19313 +
19314         free(p);
19315 -       
19316 +
19317         return HANDLER_GO_ON;
19318  }
19319  
19320 @@ -62,25 +63,25 @@
19321  SETDEFAULTS_FUNC(mod_alias_set_defaults) {
19322         plugin_data *p = p_d;
19323         size_t i = 0;
19324 -       
19325 -       config_values_t cv[] = { 
19326 +
19327 +       config_values_t cv[] = {
19328                 { "alias.url",                  NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
19329                 { NULL,                         NULL, T_CONFIG_UNSET,  T_CONFIG_SCOPE_UNSET }
19330         };
19331 -       
19332 +
19333         if (!p) return HANDLER_ERROR;
19334 -       
19335 +
19336         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
19337 -       
19338 +
19339         for (i = 0; i < srv->config_context->used; i++) {
19340                 plugin_config *s;
19341 -               
19342 +
19343                 s = calloc(1, sizeof(plugin_config));
19344 -               s->alias = array_init();        
19345 +               s->alias = array_init();
19346                 cv[0].destination = s->alias;
19347 -               
19348 +
19349                 p->config_storage[i] = s;
19350 -               
19351 +
19352                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
19353                         return HANDLER_ERROR;
19354                 }
19355 @@ -110,76 +111,73 @@
19356                         }
19357                 }
19358         }
19359 -       
19360 +
19361         return HANDLER_GO_ON;
19362  }
19363  
19364 -#define PATCH(x) \
19365 -       p->conf.x = s->x;
19366  static int mod_alias_patch_connection(server *srv, connection *con, plugin_data *p) {
19367         size_t i, j;
19368         plugin_config *s = p->config_storage[0];
19369 -       
19370 -       PATCH(alias);
19371 -       
19372 +
19373 +       PATCH_OPTION(alias);
19374 +
19375         /* skip the first, the global context */
19376         for (i = 1; i < srv->config_context->used; i++) {
19377                 data_config *dc = (data_config *)srv->config_context->data[i];
19378                 s = p->config_storage[i];
19379 -               
19380 +
19381                 /* condition didn't match */
19382                 if (!config_check_cond(srv, con, dc)) continue;
19383 -               
19384 +
19385                 /* merge config */
19386                 for (j = 0; j < dc->value->used; j++) {
19387                         data_unset *du = dc->value->data[j];
19388 -                       
19389 +
19390                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("alias.url"))) {
19391 -                               PATCH(alias);
19392 +                               PATCH_OPTION(alias);
19393                         }
19394                 }
19395         }
19396 -       
19397 +
19398         return 0;
19399  }
19400 -#undef PATCH
19401  
19402  PHYSICALPATH_FUNC(mod_alias_physical_handler) {
19403         plugin_data *p = p_d;
19404         int uri_len, basedir_len;
19405         char *uri_ptr;
19406         size_t k;
19407 -       
19408 +
19409         if (con->physical.path->used == 0) return HANDLER_GO_ON;
19410 -       
19411 +
19412         mod_alias_patch_connection(srv, con, p);
19413 -       
19414 +
19415         /* not to include the tailing slash */
19416         basedir_len = (con->physical.basedir->used - 1) - 1;
19417         uri_len = con->physical.path->used - 1 - basedir_len;
19418         uri_ptr = con->physical.path->ptr + basedir_len;
19419 -       
19420 +
19421         for (k = 0; k < p->conf.alias->used; k++) {
19422                 data_string *ds = (data_string *)p->conf.alias->data[k];
19423                 int alias_len = ds->key->used - 1;
19424 -               
19425 +
19426                 if (alias_len > uri_len) continue;
19427                 if (ds->key->used == 0) continue;
19428 -               
19429 +
19430                 if (0 == (con->conf.force_lowercase_filenames ?
19431                                         strncasecmp(uri_ptr, ds->key->ptr, alias_len) :
19432                                         strncmp(uri_ptr, ds->key->ptr, alias_len))) {
19433                         /* matched */
19434 -                       
19435 +
19436                         buffer_copy_string_buffer(con->physical.basedir, ds->value);
19437                         buffer_copy_string_buffer(srv->tmp_buf, ds->value);
19438                         buffer_append_string(srv->tmp_buf, uri_ptr + alias_len);
19439                         buffer_copy_string_buffer(con->physical.path, srv->tmp_buf);
19440 -                       
19441 +
19442                         return HANDLER_GO_ON;
19443                 }
19444         }
19445 -       
19446 +
19447         /* not found */
19448         return HANDLER_GO_ON;
19449  }
19450 @@ -189,13 +187,13 @@
19451  int mod_alias_plugin_init(plugin *p) {
19452         p->version     = LIGHTTPD_VERSION_ID;
19453         p->name        = buffer_init_string("alias");
19454 -       
19455 +
19456         p->init           = mod_alias_init;
19457         p->handle_physical= mod_alias_physical_handler;
19458         p->set_defaults   = mod_alias_set_defaults;
19459         p->cleanup        = mod_alias_free;
19460 -       
19461 +
19462         p->data        = NULL;
19463 -       
19464 +
19465         return 0;
19466  }
19467 --- ../lighttpd-1.4.11/src/mod_auth.c   2006-02-15 20:01:31.000000000 +0200
19468 +++ lighttpd-1.5.0/src/mod_auth.c       2006-07-18 13:03:40.000000000 +0300
19469 @@ -5,168 +5,167 @@
19470  #include <string.h>
19471  #include <errno.h>
19472  #include <fcntl.h>
19473 -#include <unistd.h>
19474  
19475  #include "plugin.h"
19476  #include "http_auth.h"
19477  #include "log.h"
19478  #include "response.h"
19479  
19480 +#include "sys-strings.h"
19481 +#include "sys-files.h"
19482 +
19483  handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s);
19484  
19485  
19486  /**
19487   * the basic and digest auth framework
19488 - * 
19489 + *
19490   * - config handling
19491   * - protocol handling
19492 - * 
19493 - * http_auth.c 
19494 - * http_auth_digest.c 
19495 - * 
19496 + *
19497 + * http_auth.c
19498 + * http_auth_digest.c
19499 + *
19500   * do the real work
19501   */
19502  
19503  INIT_FUNC(mod_auth_init) {
19504         mod_auth_plugin_data *p;
19505 -       
19506 +
19507         p = calloc(1, sizeof(*p));
19508 -       
19509 +
19510         p->tmp_buf = buffer_init();
19511 -       
19512 +
19513         p->auth_user = buffer_init();
19514  #ifdef USE_LDAP
19515         p->ldap_filter = buffer_init();
19516  #endif
19517 -       
19518 +
19519         return p;
19520  }
19521  
19522  FREE_FUNC(mod_auth_free) {
19523         mod_auth_plugin_data *p = p_d;
19524 -       
19525 +
19526         UNUSED(srv);
19527  
19528         if (!p) return HANDLER_GO_ON;
19529 -       
19530 +
19531         buffer_free(p->tmp_buf);
19532         buffer_free(p->auth_user);
19533  #ifdef USE_LDAP
19534         buffer_free(p->ldap_filter);
19535  #endif
19536 -       
19537 +
19538         if (p->config_storage) {
19539                 size_t i;
19540                 for (i = 0; i < srv->config_context->used; i++) {
19541                         mod_auth_plugin_config *s = p->config_storage[i];
19542 -                       
19543 +
19544                         if (!s) continue;
19545 -                       
19546 +
19547                         array_free(s->auth_require);
19548                         buffer_free(s->auth_plain_groupfile);
19549                         buffer_free(s->auth_plain_userfile);
19550                         buffer_free(s->auth_htdigest_userfile);
19551                         buffer_free(s->auth_htpasswd_userfile);
19552                         buffer_free(s->auth_backend_conf);
19553 -                       
19554 +
19555                         buffer_free(s->auth_ldap_hostname);
19556                         buffer_free(s->auth_ldap_basedn);
19557                         buffer_free(s->auth_ldap_binddn);
19558                         buffer_free(s->auth_ldap_bindpw);
19559                         buffer_free(s->auth_ldap_filter);
19560                         buffer_free(s->auth_ldap_cafile);
19561 -                       
19562 +
19563  #ifdef USE_LDAP
19564                         buffer_free(s->ldap_filter_pre);
19565                         buffer_free(s->ldap_filter_post);
19566 -                       
19567 +
19568                         if (s->ldap) ldap_unbind_s(s->ldap);
19569  #endif
19570 -                       
19571 +
19572                         free(s);
19573                 }
19574                 free(p->config_storage);
19575         }
19576 -       
19577 +
19578         free(p);
19579 -       
19580 +
19581         return HANDLER_GO_ON;
19582  }
19583  
19584 -#define PATCH(x) \
19585 -       p->conf.x = s->x;
19586  static int mod_auth_patch_connection(server *srv, connection *con, mod_auth_plugin_data *p) {
19587         size_t i, j;
19588         mod_auth_plugin_config *s = p->config_storage[0];
19589  
19590 -       PATCH(auth_backend);
19591 -       PATCH(auth_plain_groupfile);
19592 -       PATCH(auth_plain_userfile);
19593 -       PATCH(auth_htdigest_userfile);
19594 -       PATCH(auth_htpasswd_userfile);
19595 -       PATCH(auth_require);
19596 -       PATCH(auth_debug);
19597 -       PATCH(auth_ldap_hostname);
19598 -       PATCH(auth_ldap_basedn);
19599 -       PATCH(auth_ldap_binddn);
19600 -       PATCH(auth_ldap_bindpw);
19601 -       PATCH(auth_ldap_filter);
19602 -       PATCH(auth_ldap_cafile);
19603 -       PATCH(auth_ldap_starttls);
19604 +       PATCH_OPTION(auth_backend);
19605 +       PATCH_OPTION(auth_plain_groupfile);
19606 +       PATCH_OPTION(auth_plain_userfile);
19607 +       PATCH_OPTION(auth_htdigest_userfile);
19608 +       PATCH_OPTION(auth_htpasswd_userfile);
19609 +       PATCH_OPTION(auth_require);
19610 +       PATCH_OPTION(auth_debug);
19611 +       PATCH_OPTION(auth_ldap_hostname);
19612 +       PATCH_OPTION(auth_ldap_basedn);
19613 +       PATCH_OPTION(auth_ldap_binddn);
19614 +       PATCH_OPTION(auth_ldap_bindpw);
19615 +       PATCH_OPTION(auth_ldap_filter);
19616 +       PATCH_OPTION(auth_ldap_cafile);
19617 +       PATCH_OPTION(auth_ldap_starttls);
19618  #ifdef USE_LDAP
19619 -       PATCH(ldap);
19620 -       PATCH(ldap_filter_pre);
19621 -       PATCH(ldap_filter_post);
19622 +       PATCH_OPTION(ldap);
19623 +       PATCH_OPTION(ldap_filter_pre);
19624 +       PATCH_OPTION(ldap_filter_post);
19625  #endif
19626 -       
19627 +
19628         /* skip the first, the global context */
19629         for (i = 1; i < srv->config_context->used; i++) {
19630                 data_config *dc = (data_config *)srv->config_context->data[i];
19631                 s = p->config_storage[i];
19632 -               
19633 +
19634                 /* condition didn't match */
19635                 if (!config_check_cond(srv, con, dc)) continue;
19636 -               
19637 +
19638                 /* merge config */
19639                 for (j = 0; j < dc->value->used; j++) {
19640                         data_unset *du = dc->value->data[j];
19641 -                       
19642 +
19643                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend"))) {
19644 -                               PATCH(auth_backend);
19645 +                               PATCH_OPTION(auth_backend);
19646                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.plain.groupfile"))) {
19647 -                               PATCH(auth_plain_groupfile);
19648 +                               PATCH_OPTION(auth_plain_groupfile);
19649                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.plain.userfile"))) {
19650 -                               PATCH(auth_plain_userfile);
19651 +                               PATCH_OPTION(auth_plain_userfile);
19652                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.htdigest.userfile"))) {
19653 -                               PATCH(auth_htdigest_userfile);
19654 +                               PATCH_OPTION(auth_htdigest_userfile);
19655                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.htpasswd.userfile"))) {
19656 -                               PATCH(auth_htpasswd_userfile);
19657 +                               PATCH_OPTION(auth_htpasswd_userfile);
19658                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.require"))) {
19659 -                               PATCH(auth_require);
19660 +                               PATCH_OPTION(auth_require);
19661                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.debug"))) {
19662 -                               PATCH(auth_debug);
19663 +                               PATCH_OPTION(auth_debug);
19664                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.hostname"))) {
19665 -                               PATCH(auth_ldap_hostname);
19666 +                               PATCH_OPTION(auth_ldap_hostname);
19667  #ifdef USE_LDAP
19668 -                               PATCH(ldap);
19669 -                               PATCH(ldap_filter_pre);
19670 -                               PATCH(ldap_filter_post);
19671 +                               PATCH_OPTION(ldap);
19672 +                               PATCH_OPTION(ldap_filter_pre);
19673 +                               PATCH_OPTION(ldap_filter_post);
19674  #endif
19675                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.base-dn"))) {
19676 -                               PATCH(auth_ldap_basedn);
19677 +                               PATCH_OPTION(auth_ldap_basedn);
19678                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.filter"))) {
19679 -                               PATCH(auth_ldap_filter);
19680 +                               PATCH_OPTION(auth_ldap_filter);
19681                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.ca-file"))) {
19682 -                               PATCH(auth_ldap_cafile);
19683 +                               PATCH_OPTION(auth_ldap_cafile);
19684                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.starttls"))) {
19685 -                               PATCH(auth_ldap_starttls);
19686 +                               PATCH_OPTION(auth_ldap_starttls);
19687                         }
19688                 }
19689         }
19690 -       
19691 +
19692         return 0;
19693  }
19694 -#undef PATCH
19695  
19696  static handler_t mod_auth_uri_handler(server *srv, connection *con, void *p_d) {
19697         size_t k;
19698 @@ -175,22 +174,22 @@
19699         data_string *ds;
19700         mod_auth_plugin_data *p = p_d;
19701         array *req;
19702 -       
19703 +
19704         /* select the right config */
19705         mod_auth_patch_connection(srv, con, p);
19706 -       
19707 +
19708         if (p->conf.auth_require == NULL) return HANDLER_GO_ON;
19709 -       
19710 +
19711         /*
19712          * AUTH
19713 -        *  
19714 +        *
19715          */
19716 -       
19717 +
19718         /* do we have to ask for auth ? */
19719 -       
19720 +
19721         auth_required = 0;
19722         auth_satisfied = 0;
19723 -       
19724 +
19725         /* search auth-directives for path */
19726         for (k = 0; k < p->conf.auth_require->used; k++) {
19727                 buffer *req = p->conf.auth_require->data[k]->key;
19728 @@ -212,76 +211,76 @@
19729                         }
19730                 }
19731         }
19732 -       
19733 +
19734         /* nothing to do for us */
19735         if (auth_required == 0) return HANDLER_GO_ON;
19736 -       
19737 +
19738         req = ((data_array *)(p->conf.auth_require->data[k]))->value;
19739 -       
19740 +
19741         /* try to get Authorization-header */
19742 -               
19743 +
19744         if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Authorization"))) {
19745                 http_authorization = ds->value->ptr;
19746         }
19747 -       
19748 +
19749         if (ds && ds->value && ds->value->used) {
19750                 char *auth_realm;
19751                 data_string *method;
19752 -               
19753 +
19754                 method = (data_string *)array_get_element(req, "method");
19755 -               
19756 +
19757                 /* parse auth-header */
19758                 if (NULL != (auth_realm = strchr(http_authorization, ' '))) {
19759                         int auth_type_len = auth_realm - http_authorization;
19760 -                       
19761 +
19762                         if ((auth_type_len == 5) &&
19763                             (0 == strncmp(http_authorization, "Basic", auth_type_len))) {
19764 -                               
19765 -                               if (0 == strcmp(method->value->ptr, "basic")) {
19766 +
19767 +                               if (buffer_is_equal_string(method->value, CONST_STR_LEN("basic"))) {
19768                                         auth_satisfied = http_auth_basic_check(srv, con, p, req, con->uri.path, auth_realm+1);
19769                                 }
19770                         } else if ((auth_type_len == 6) &&
19771                                    (0 == strncmp(http_authorization, "Digest", auth_type_len))) {
19772 -                               if (0 == strcmp(method->value->ptr, "digest")) {
19773 +                               if (buffer_is_equal_string(method->value, CONST_STR_LEN("digest"))) {
19774                                         if (-1 == (auth_satisfied = http_auth_digest_check(srv, con, p, req, con->uri.path, auth_realm+1))) {
19775                                                 con->http_status = 400;
19776 -                                               
19777 +
19778                                                 /* a field was missing */
19779 -                                               
19780 +
19781                                                 return HANDLER_FINISHED;
19782                                         }
19783                                 }
19784                         } else {
19785 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
19786 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
19787                                                 "unknown authentification type:",
19788                                                 http_authorization);
19789                         }
19790                 }
19791         }
19792 -       
19793 +
19794         if (!auth_satisfied) {
19795                 data_string *method, *realm;
19796                 method = (data_string *)array_get_element(req, "method");
19797                 realm = (data_string *)array_get_element(req, "realm");
19798 -               
19799 +
19800                 con->http_status = 401;
19801 -                       
19802 -               if (0 == strcmp(method->value->ptr, "basic")) {
19803 +
19804 +               if (buffer_is_equal_string(method->value, CONST_STR_LEN("basic"))) {
19805                         buffer_copy_string(p->tmp_buf, "Basic realm=\"");
19806                         buffer_append_string_buffer(p->tmp_buf, realm->value);
19807                         buffer_append_string(p->tmp_buf, "\"");
19808 -                       
19809 +
19810                         response_header_insert(srv, con, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(p->tmp_buf));
19811 -               } else if (0 == strcmp(method->value->ptr, "digest")) {
19812 +               } else if (buffer_is_equal_string(method->value, CONST_STR_LEN("digest"))) {
19813                         char hh[33];
19814                         http_auth_digest_generate_nonce(srv, p, srv->tmp_buf, hh);
19815 -                       
19816 +
19817                         buffer_copy_string(p->tmp_buf, "Digest realm=\"");
19818                         buffer_append_string_buffer(p->tmp_buf, realm->value);
19819                         buffer_append_string(p->tmp_buf, "\", nonce=\"");
19820                         buffer_append_string(p->tmp_buf, hh);
19821                         buffer_append_string(p->tmp_buf, "\", qop=\"auth\"");
19822 -                       
19823 +
19824                         response_header_insert(srv, con, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(p->tmp_buf));
19825                 } else {
19826                         /* evil */
19827 @@ -289,18 +288,18 @@
19828                 return HANDLER_FINISHED;
19829         } else {
19830                 /* the REMOTE_USER header */
19831 -               
19832 +
19833                 buffer_copy_string_buffer(con->authed_user, p->auth_user);
19834         }
19835 -       
19836 +
19837         return HANDLER_GO_ON;
19838  }
19839  
19840  SETDEFAULTS_FUNC(mod_auth_set_defaults) {
19841         mod_auth_plugin_data *p = p_d;
19842         size_t i;
19843 -       
19844 -       config_values_t cv[] = { 
19845 +
19846 +       config_values_t cv[] = {
19847                 { "auth.backend",                   NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
19848                 { "auth.backend.plain.groupfile",   NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
19849                 { "auth.backend.plain.userfile",    NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
19850 @@ -317,7 +316,7 @@
19851                 { "auth.debug",                     NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },  /* 13 */
19852                 { NULL,                             NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
19853         };
19854 -       
19855 +
19856         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
19857  
19858         for (i = 0; i < srv->config_context->used; i++) {
19859 @@ -325,14 +324,14 @@
19860                 size_t n;
19861                 data_array *da;
19862                 array *ca;
19863 -               
19864 +
19865                 s = calloc(1, sizeof(mod_auth_plugin_config));
19866                 s->auth_plain_groupfile = buffer_init();
19867                 s->auth_plain_userfile = buffer_init();
19868                 s->auth_htdigest_userfile = buffer_init();
19869                 s->auth_htpasswd_userfile = buffer_init();
19870                 s->auth_backend_conf = buffer_init();
19871 -               
19872 +
19873                 s->auth_ldap_hostname = buffer_init();
19874                 s->auth_ldap_basedn = buffer_init();
19875                 s->auth_ldap_binddn = buffer_init();
19876 @@ -341,15 +340,15 @@
19877                 s->auth_ldap_cafile = buffer_init();
19878                 s->auth_ldap_starttls = 0;
19879                 s->auth_debug = 0;
19880 -               
19881 +
19882                 s->auth_require = array_init();
19883 -               
19884 +
19885  #ifdef USE_LDAP
19886                 s->ldap_filter_pre = buffer_init();
19887                 s->ldap_filter_post = buffer_init();
19888                 s->ldap = NULL;
19889  #endif
19890 -       
19891 +
19892                 cv[0].destination = s->auth_backend_conf;
19893                 cv[1].destination = s->auth_plain_groupfile;
19894                 cv[2].destination = s->auth_plain_userfile;
19895 @@ -364,146 +363,148 @@
19896                 cv[11].destination = s->auth_htdigest_userfile;
19897                 cv[12].destination = s->auth_htpasswd_userfile;
19898                 cv[13].destination = &(s->auth_debug);
19899 -               
19900 +
19901                 p->config_storage[i] = s;
19902                 ca = ((data_config *)srv->config_context->data[i])->value;
19903 -               
19904 +
19905                 if (0 != config_insert_values_global(srv, ca, cv)) {
19906                         return HANDLER_ERROR;
19907                 }
19908 -               
19909 -               if (s->auth_backend_conf->used) {
19910 -                       if (0 == strcmp(s->auth_backend_conf->ptr, "htpasswd")) {
19911 +
19912 +               if (!buffer_is_empty(s->auth_backend_conf)) {
19913 +                       if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("htpasswd"))) {
19914                                 s->auth_backend = AUTH_BACKEND_HTPASSWD;
19915 -                       } else if (0 == strcmp(s->auth_backend_conf->ptr, "htdigest")) {
19916 +                       } else if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("htdigest"))) {
19917                                 s->auth_backend = AUTH_BACKEND_HTDIGEST;
19918 -                       } else if (0 == strcmp(s->auth_backend_conf->ptr, "plain")) {
19919 +                       } else if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("plain"))) {
19920                                 s->auth_backend = AUTH_BACKEND_PLAIN;
19921 -                       } else if (0 == strcmp(s->auth_backend_conf->ptr, "ldap")) {
19922 +                       } else if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("ldap"))) {
19923                                 s->auth_backend = AUTH_BACKEND_LDAP;
19924                         } else {
19925                                 log_error_write(srv, __FILE__, __LINE__, "sb", "auth.backend not supported:", s->auth_backend_conf);
19926 -                               
19927 +
19928                                 return HANDLER_ERROR;
19929                         }
19930                 }
19931  
19932                 /* no auth.require for this section */
19933                 if (NULL == (da = (data_array *)array_get_element(ca, "auth.require"))) continue;
19934 -               
19935 +
19936                 if (da->type != TYPE_ARRAY) continue;
19937 -               
19938 +
19939                 for (n = 0; n < da->value->used; n++) {
19940                         size_t m;
19941                         data_array *da_file = (data_array *)da->value->data[n];
19942 -                       const char *method, *realm, *require;
19943 -                       
19944 +                       buffer *method, *realm, *require;
19945 +
19946                         if (da->value->data[n]->type != TYPE_ARRAY) {
19947 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
19948 -                                               "auth.require should contain an array as in:", 
19949 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
19950 +                                               "auth.require should contain an array as in:",
19951                                                 "auth.require = ( \"...\" => ( ..., ...) )");
19952  
19953                                 return HANDLER_ERROR;
19954                         }
19955 -                                       
19956 +
19957                         method = realm = require = NULL;
19958 -                                       
19959 +
19960                         for (m = 0; m < da_file->value->used; m++) {
19961 -                               if (da_file->value->data[m]->type == TYPE_STRING) {
19962 -                                       if (0 == strcmp(da_file->value->data[m]->key->ptr, "method")) {
19963 -                                               method = ((data_string *)(da_file->value->data[m]))->value->ptr;
19964 -                                       } else if (0 == strcmp(da_file->value->data[m]->key->ptr, "realm")) {
19965 -                                               realm = ((data_string *)(da_file->value->data[m]))->value->ptr;
19966 -                                       } else if (0 == strcmp(da_file->value->data[m]->key->ptr, "require")) {
19967 -                                               require = ((data_string *)(da_file->value->data[m]))->value->ptr;
19968 -                                       } else {
19969 -                                               log_error_write(srv, __FILE__, __LINE__, "ssbs", 
19970 -                                                       "the field is unknown in:", 
19971 +                               data_string *ds_auth_req = (data_string *)da_file->value->data[m];
19972 +
19973 +                               if (ds_auth_req->type != TYPE_STRING) {
19974 +                                       log_error_write(srv, __FILE__, __LINE__, "ssbs",
19975 +                                               "a string was expected for:",
19976 +                                               "auth.require = ( \"...\" => ( ..., -> \"",
19977 +                                               ds_auth_req->key,
19978 +                                               "\" <- => \"...\" ) )");
19979 +
19980 +                                       return HANDLER_ERROR;
19981 +                               }
19982 +
19983 +                               if (buffer_is_equal_string(ds_auth_req->key, CONST_STR_LEN("method"))) {
19984 +                                       method = ds_auth_req->value;
19985 +                               } else if (buffer_is_equal_string(ds_auth_req->key, CONST_STR_LEN("realm"))) {
19986 +                                       realm = ds_auth_req->value;
19987 +                               } else if (buffer_is_equal_string(ds_auth_req->key, CONST_STR_LEN("require"))) {
19988 +                                       require = ds_auth_req->value;
19989 +                               } else {
19990 +                                       log_error_write(srv, __FILE__, __LINE__, "ssbs",
19991 +                                                       "the field is unknown in:",
19992                                                         "auth.require = ( \"...\" => ( ..., -> \"",
19993                                                         da_file->value->data[m]->key,
19994                                                         "\" <- => \"...\" ) )");
19995  
19996 -                                               return HANDLER_ERROR;
19997 -                                       }
19998 -                               } else {
19999 -                                       log_error_write(srv, __FILE__, __LINE__, "ssbs", 
20000 -                                               "a string was expected for:", 
20001 -                                               "auth.require = ( \"...\" => ( ..., -> \"",
20002 -                                               da_file->value->data[m]->key,
20003 -                                               "\" <- => \"...\" ) )");
20004 -                                       
20005                                         return HANDLER_ERROR;
20006 +
20007                                 }
20008                         }
20009 -                                       
20010 +
20011                         if (method == NULL) {
20012 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
20013 -                                               "the require field is missing in:", 
20014 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
20015 +                                               "the require field is missing in:",
20016                                                 "auth.require = ( \"...\" => ( ..., \"method\" => \"...\" ) )");
20017                                 return HANDLER_ERROR;
20018 -                       } else {
20019 -                               if (0 != strcmp(method, "basic") &&
20020 -                                   0 != strcmp(method, "digest")) {
20021 -                                       log_error_write(srv, __FILE__, __LINE__, "ss",
20022 -                                                       "method has to be either \"basic\" or \"digest\" in",
20023 -                                                       "auth.require = ( \"...\" => ( ..., \"method\" => \"...\") )");
20024 -                                       return HANDLER_ERROR;
20025 -                               }
20026 +                       } 
20027 +                       if (!buffer_is_equal_string(method, CONST_STR_LEN("basic")) &&
20028 +                           !buffer_is_equal_string(method, CONST_STR_LEN("digest"))) {
20029 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
20030 +                                               "method has to be either \"basic\" or \"digest\" in",
20031 +                                               "auth.require = ( \"...\" => ( ..., \"method\" => \"...\") )");
20032 +                               return HANDLER_ERROR;
20033                         }
20034 -                       
20035 +
20036                         if (realm == NULL) {
20037 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
20038 -                                               "the require field is missing in:", 
20039 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
20040 +                                               "the require field is missing in:",
20041                                                 "auth.require = ( \"...\" => ( ..., \"realm\" => \"...\" ) )");
20042                                 return HANDLER_ERROR;
20043                         }
20044 -                       
20045 +
20046                         if (require == NULL) {
20047 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
20048 -                                               "the require field is missing in:", 
20049 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
20050 +                                               "the require field is missing in:",
20051                                                 "auth.require = ( \"...\" => ( ..., \"require\" => \"...\" ) )");
20052                                 return HANDLER_ERROR;
20053                         }
20054 -                       
20055 +
20056                         if (method && realm && require) {
20057                                 data_string *ds;
20058                                 data_array *a;
20059 -                               
20060 +
20061                                 a = data_array_init();
20062                                 buffer_copy_string_buffer(a->key, da_file->key);
20063 -                               
20064 +
20065                                 ds = data_string_init();
20066 -                               
20067 +
20068                                 buffer_copy_string(ds->key, "method");
20069 -                               buffer_copy_string(ds->value, method);
20070 -                               
20071 +                               buffer_copy_string_buffer(ds->value, method);
20072 +
20073                                 array_insert_unique(a->value, (data_unset *)ds);
20074 -                               
20075 +
20076                                 ds = data_string_init();
20077 -                               
20078 +
20079                                 buffer_copy_string(ds->key, "realm");
20080 -                               buffer_copy_string(ds->value, realm);
20081 -                               
20082 +                               buffer_copy_string_buffer(ds->value, realm);
20083 +
20084                                 array_insert_unique(a->value, (data_unset *)ds);
20085 -                               
20086 +
20087                                 ds = data_string_init();
20088 -                               
20089 +
20090                                 buffer_copy_string(ds->key, "require");
20091 -                               buffer_copy_string(ds->value, require);
20092 -                               
20093 +                               buffer_copy_string_buffer(ds->value, require);
20094 +
20095                                 array_insert_unique(a->value, (data_unset *)ds);
20096 -                               
20097 +
20098                                 array_insert_unique(s->auth_require, (data_unset *)a);
20099                         }
20100                 }
20101 -       
20102 +
20103                 switch(s->auth_backend) {
20104                 case AUTH_BACKEND_PLAIN:
20105                         if (s->auth_plain_userfile->used) {
20106                                 int fd;
20107                                 /* try to read */
20108                                 if (-1 == (fd = open(s->auth_plain_userfile->ptr, O_RDONLY))) {
20109 -                                       log_error_write(srv, __FILE__, __LINE__, "sbss", 
20110 +                                       log_error_write(srv, __FILE__, __LINE__, "sbss",
20111                                                         "opening auth.backend.plain.userfile:", s->auth_plain_userfile,
20112                                                         "failed:", strerror(errno));
20113                                         return HANDLER_ERROR;
20114 @@ -516,7 +517,7 @@
20115                                 int fd;
20116                                 /* try to read */
20117                                 if (-1 == (fd = open(s->auth_htpasswd_userfile->ptr, O_RDONLY))) {
20118 -                                       log_error_write(srv, __FILE__, __LINE__, "sbss", 
20119 +                                       log_error_write(srv, __FILE__, __LINE__, "sbss",
20120                                                         "opening auth.backend.htpasswd.userfile:", s->auth_htpasswd_userfile,
20121                                                         "failed:", strerror(errno));
20122                                         return HANDLER_ERROR;
20123 @@ -529,7 +530,7 @@
20124                                 int fd;
20125                                 /* try to read */
20126                                 if (-1 == (fd = open(s->auth_htdigest_userfile->ptr, O_RDONLY))) {
20127 -                                       log_error_write(srv, __FILE__, __LINE__, "sbss", 
20128 +                                       log_error_write(srv, __FILE__, __LINE__, "sbss",
20129                                                         "opening auth.backend.htdigest.userfile:", s->auth_htdigest_userfile,
20130                                                         "failed:", strerror(errno));
20131                                         return HANDLER_ERROR;
20132 @@ -554,75 +555,75 @@
20133  handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s) {
20134  #ifdef USE_LDAP
20135                         int ret;
20136 -#if 0                  
20137 +#if 0
20138                         if (s->auth_ldap_basedn->used == 0) {
20139                                 log_error_write(srv, __FILE__, __LINE__, "s", "ldap: auth.backend.ldap.base-dn has to be set");
20140 -                               
20141 +
20142                                 return HANDLER_ERROR;
20143                         }
20144  #endif
20145 -                       
20146 +
20147                         if (s->auth_ldap_filter->used) {
20148                                 char *dollar;
20149 -                               
20150 +
20151                                 /* parse filter */
20152 -                       
20153 +
20154                                 if (NULL == (dollar = strchr(s->auth_ldap_filter->ptr, '$'))) {
20155                                         log_error_write(srv, __FILE__, __LINE__, "s", "ldap: auth.backend.ldap.filter is missing a replace-operator '$'");
20156 -                                       
20157 +
20158                                         return HANDLER_ERROR;
20159                                 }
20160 -                               
20161 +
20162                                 buffer_copy_string_len(s->ldap_filter_pre, s->auth_ldap_filter->ptr, dollar - s->auth_ldap_filter->ptr);
20163                                 buffer_copy_string(s->ldap_filter_post, dollar+1);
20164                         }
20165 -                       
20166 +
20167                         if (s->auth_ldap_hostname->used) {
20168                                 if (NULL == (s->ldap = ldap_init(s->auth_ldap_hostname->ptr, LDAP_PORT))) {
20169                                         log_error_write(srv, __FILE__, __LINE__, "ss", "ldap ...", strerror(errno));
20170 -                                       
20171 +
20172                                         return HANDLER_ERROR;
20173                                 }
20174 -                               
20175 +
20176                                 ret = LDAP_VERSION3;
20177                                 if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(s->ldap, LDAP_OPT_PROTOCOL_VERSION, &ret))) {
20178                                         log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
20179 -                               
20180 +
20181                                         return HANDLER_ERROR;
20182                                 }
20183  
20184                                 if (s->auth_ldap_starttls) {
20185 -                                       /* if no CA file is given, it is ok, as we will use encryption 
20186 +                                       /* if no CA file is given, it is ok, as we will use encryption
20187                                          * if the server requires a CAfile it will tell us */
20188                                         if (!buffer_is_empty(s->auth_ldap_cafile)) {
20189 -                                               if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, 
20190 +                                               if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
20191                                                                                 s->auth_ldap_cafile->ptr))) {
20192 -                                                       log_error_write(srv, __FILE__, __LINE__, "ss", 
20193 +                                                       log_error_write(srv, __FILE__, __LINE__, "ss",
20194                                                                         "Loading CA certificate failed:", ldap_err2string(ret));
20195 -                                               
20196 +
20197                                                         return HANDLER_ERROR;
20198                                                 }
20199                                         }
20200 -       
20201 +
20202                                         if (LDAP_OPT_SUCCESS != (ret = ldap_start_tls_s(s->ldap, NULL,  NULL))) {
20203                                                 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap startTLS failed:", ldap_err2string(ret));
20204 -                                               
20205 +
20206                                                 return HANDLER_ERROR;
20207                                         }
20208                                 }
20209 -                               
20210 -                               
20211 +
20212 +
20213                                 /* 1. */
20214                                 if (s->auth_ldap_binddn->used) {
20215                                         if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(s->ldap, s->auth_ldap_binddn->ptr, s->auth_ldap_bindpw->ptr))) {
20216                                                 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
20217 -                                               
20218 +
20219                                                 return HANDLER_ERROR;
20220                                         }
20221                                 } else {
20222                                         if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(s->ldap, NULL, NULL))) {
20223                                                 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
20224 -                                               
20225 +
20226                                                 return HANDLER_ERROR;
20227                                         }
20228                                 }
20229 @@ -641,8 +642,8 @@
20230         p->set_defaults = mod_auth_set_defaults;
20231         p->handle_uri_clean = mod_auth_uri_handler;
20232         p->cleanup     = mod_auth_free;
20233 -       
20234 +
20235         p->data        = NULL;
20236 -       
20237 +
20238         return 0;
20239  }
20240 --- ../lighttpd-1.4.11/src/mod_cgi.c    2006-02-22 15:15:10.000000000 +0200
20241 +++ lighttpd-1.5.0/src/mod_cgi.c        2006-09-07 00:57:05.000000000 +0300
20242 @@ -1,21 +1,8 @@
20243  #include <sys/types.h>
20244 -#ifdef __WIN32
20245 -#include <winsock2.h>
20246 -#else
20247 -#include <sys/socket.h>
20248 -#include <sys/wait.h>
20249 -#include <sys/mman.h>
20250 -
20251 -#include <netinet/in.h>
20252 -
20253 -#include <arpa/inet.h>
20254 -#endif
20255  
20256 -#include <unistd.h>
20257  #include <errno.h>
20258  #include <stdlib.h>
20259  #include <string.h>
20260 -#include <fdevent.h>
20261  #include <signal.h>
20262  #include <ctype.h>
20263  #include <assert.h>
20264 @@ -28,9 +15,16 @@
20265  #include "log.h"
20266  #include "connections.h"
20267  #include "joblist.h"
20268 -#include "http_chunk.h"
20269 +#include "fdevent.h"
20270  
20271  #include "plugin.h"
20272 +#include "http_resp.h"
20273 +
20274 +#include "sys-files.h"
20275 +#include "sys-mmap.h"
20276 +#include "sys-socket.h"
20277 +#include "sys-strings.h"
20278 +#include "sys-process.h"
20279  
20280  #ifdef HAVE_SYS_FILIO_H
20281  # include <sys/filio.h>
20282 @@ -40,11 +34,12 @@
20283  
20284  typedef struct {
20285         char **ptr;
20286 -       
20287 +
20288         size_t size;
20289         size_t used;
20290  } char_array;
20291  
20292 +#define pid_t int
20293  typedef struct {
20294         pid_t *ptr;
20295         size_t used;
20296 @@ -58,57 +53,68 @@
20297  typedef struct {
20298         PLUGIN_DATA;
20299         buffer_pid_t cgi_pid;
20300 -       
20301 +
20302         buffer *tmp_buf;
20303 -       buffer *parse_response;
20304 -       
20305 +
20306 +       http_resp *resp;
20307 +
20308         plugin_config **config_storage;
20309 -       
20310 -       plugin_config conf; 
20311 +
20312 +       plugin_config conf;
20313  } plugin_data;
20314  
20315 +typedef enum {
20316 +       CGI_STATE_UNSET,
20317 +       CGI_STATE_CONNECTING,
20318 +       CGI_STATE_READ_RESPONSE_HEADER,
20319 +       CGI_STATE_READ_RESPONSE_CONTENT
20320 +} cgi_state_t;
20321 +
20322  typedef struct {
20323         pid_t pid;
20324 -       int fd;
20325 -       int fde_ndx; /* index into the fd-event buffer */
20326 -       
20327 -       connection *remote_conn;  /* dumb pointer */
20328 -       plugin_data *plugin_data; /* dumb pointer */
20329 -       
20330 -       buffer *response;
20331 -       buffer *response_header;
20332 -} handler_ctx;
20333  
20334 -static handler_ctx * cgi_handler_ctx_init() {
20335 -       handler_ctx *hctx = calloc(1, sizeof(*hctx));
20336 +       iosocket *sock;
20337  
20338 -       assert(hctx);
20339 -       
20340 -       hctx->response = buffer_init();
20341 -       hctx->response_header = buffer_init();
20342 -       
20343 -       return hctx;
20344 -}
20345 +       chunkqueue *rb;
20346 +       chunkqueue *wb;
20347  
20348 -static void cgi_handler_ctx_free(handler_ctx *hctx) {
20349 -       buffer_free(hctx->response);
20350 -       buffer_free(hctx->response_header);
20351 -       
20352 -       free(hctx);
20353 +       cgi_state_t state;
20354 +
20355 +       connection *remote_con;  /* dumb pointer */
20356 +} cgi_session;
20357 +
20358 +static cgi_session * cgi_session_init() {
20359 +       cgi_session *sess = calloc(1, sizeof(*sess));
20360 +       assert(sess);
20361 +
20362 +       sess->sock = iosocket_init();
20363 +       sess->wb = chunkqueue_init();
20364 +       sess->rb = chunkqueue_init();
20365 +
20366 +       return sess;
20367  }
20368  
20369 -enum {FDEVENT_HANDLED_UNSET, FDEVENT_HANDLED_FINISHED, FDEVENT_HANDLED_NOT_FINISHED, FDEVENT_HANDLED_ERROR};
20370 +static void cgi_session_free(cgi_session *sess) {
20371 +       if (!sess) return;
20372 +
20373 +       iosocket_free(sess->sock);
20374 +
20375 +       chunkqueue_free(sess->wb);
20376 +       chunkqueue_free(sess->rb);
20377 +
20378 +       free(sess);
20379 +}
20380  
20381  INIT_FUNC(mod_cgi_init) {
20382         plugin_data *p;
20383 -       
20384 +
20385         p = calloc(1, sizeof(*p));
20386  
20387         assert(p);
20388 -       
20389 +
20390         p->tmp_buf = buffer_init();
20391 -       p->parse_response = buffer_init();
20392 -       
20393 +       p->resp = http_response_init();
20394 +
20395         return p;
20396  }
20397  
20398 @@ -116,62 +122,62 @@
20399  FREE_FUNC(mod_cgi_free) {
20400         plugin_data *p = p_d;
20401         buffer_pid_t *r = &(p->cgi_pid);
20402 -       
20403 +
20404         UNUSED(srv);
20405 -       
20406 +
20407         if (p->config_storage) {
20408                 size_t i;
20409                 for (i = 0; i < srv->config_context->used; i++) {
20410                         plugin_config *s = p->config_storage[i];
20411 -                       
20412 +
20413                         array_free(s->cgi);
20414 -                       
20415 +
20416                         free(s);
20417                 }
20418                 free(p->config_storage);
20419         }
20420 -       
20421 +
20422  
20423         if (r->ptr) free(r->ptr);
20424 -       
20425 +
20426         buffer_free(p->tmp_buf);
20427 -       buffer_free(p->parse_response);
20428 -       
20429 +       http_response_free(p->resp);
20430 +
20431         free(p);
20432 -       
20433 +
20434         return HANDLER_GO_ON;
20435  }
20436  
20437  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
20438         plugin_data *p = p_d;
20439         size_t i = 0;
20440 -       
20441 -       config_values_t cv[] = { 
20442 +
20443 +       config_values_t cv[] = {
20444                 { "cgi.assign",                  NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
20445                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET}
20446         };
20447  
20448         if (!p) return HANDLER_ERROR;
20449 -       
20450 +
20451         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
20452 -       
20453 +
20454         for (i = 0; i < srv->config_context->used; i++) {
20455                 plugin_config *s;
20456 -               
20457 +
20458                 s = calloc(1, sizeof(plugin_config));
20459                 assert(s);
20460 -               
20461 +
20462                 s->cgi    = array_init();
20463 -               
20464 +
20465                 cv[0].destination = s->cgi;
20466 -               
20467 +
20468                 p->config_storage[i] = s;
20469 -       
20470 +
20471                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
20472                         return HANDLER_ERROR;
20473                 }
20474         }
20475 -       
20476 +
20477         return HANDLER_GO_ON;
20478  }
20479  
20480 @@ -180,13 +186,13 @@
20481         int m = -1;
20482         size_t i;
20483         buffer_pid_t *r = &(p->cgi_pid);
20484 -       
20485 +
20486         UNUSED(srv);
20487  
20488         for (i = 0; i < r->used; i++) {
20489                 if (r->ptr[i] > m) m = r->ptr[i];
20490         }
20491 -       
20492 +
20493         if (r->size == 0) {
20494                 r->size = 16;
20495                 r->ptr = malloc(sizeof(*r->ptr) * r->size);
20496 @@ -194,321 +200,179 @@
20497                 r->size += 16;
20498                 r->ptr = realloc(r->ptr, sizeof(*r->ptr) * r->size);
20499         }
20500 -       
20501 +
20502         r->ptr[r->used++] = pid;
20503 -       
20504 +
20505         return m;
20506  }
20507  
20508  static int cgi_pid_del(server *srv, plugin_data *p, pid_t pid) {
20509         size_t i;
20510         buffer_pid_t *r = &(p->cgi_pid);
20511 -       
20512 +
20513         UNUSED(srv);
20514  
20515         for (i = 0; i < r->used; i++) {
20516                 if (r->ptr[i] == pid) break;
20517         }
20518 -       
20519 +
20520         if (i != r->used) {
20521                 /* found */
20522 -               
20523 +
20524                 if (i != r->used - 1) {
20525                         r->ptr[i] = r->ptr[r->used - 1];
20526                 }
20527                 r->used--;
20528         }
20529 -       
20530 +
20531         return 0;
20532  }
20533  
20534 -static int cgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in, int eol) {
20535 -       char *ns;
20536 -       const char *s;
20537 -       int line = 0;
20538 -       
20539 -       UNUSED(srv);
20540 -       
20541 -       buffer_copy_string_buffer(p->parse_response, in);
20542 -       
20543 -       for (s = p->parse_response->ptr; 
20544 -            NULL != (ns = (eol == EOL_RN ? strstr(s, "\r\n") : strchr(s, '\n'))); 
20545 -            s = ns + (eol == EOL_RN ? 2 : 1), line++) {
20546 -               const char *key, *value;
20547 -               int key_len;
20548 -               data_string *ds;
20549 -               
20550 -               ns[0] = '\0';
20551 -               
20552 -               if (line == 0 && 
20553 -                   0 == strncmp(s, "HTTP/1.", 7)) {
20554 -                       /* non-parsed header ... we parse them anyway */
20555 -                       
20556 -                       if ((s[7] == '1' ||
20557 -                            s[7] == '0') &&
20558 -                           s[8] == ' ') {
20559 -                               int status;
20560 -                               /* after the space should be a status code for us */
20561 -                               
20562 -                               status = strtol(s+9, NULL, 10);
20563 -                               
20564 -                               if (con->http_status >= 100 &&
20565 -                                   con->http_status < 1000) {
20566 -                                       /* we expected 3 digits and didn't got them */
20567 -                                       con->parsed_response |= HTTP_STATUS;
20568 -                                       con->http_status = status;
20569 -                               }
20570 -                       }
20571 -               } else {
20572 -               
20573 -                       key = s;
20574 -                       if (NULL == (value = strchr(s, ':'))) {
20575 -                               /* we expect: "<key>: <value>\r\n" */
20576 -                               continue;
20577 -                       }
20578 -                       
20579 -                       key_len = value - key;
20580 -                       value += 1;
20581 -                       
20582 -                       /* skip LWS */
20583 -                       while (*value == ' ' || *value == '\t') value++;
20584 -                       
20585 -                       if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
20586 -                               ds = data_response_init();
20587 -                       }
20588 -                       buffer_copy_string_len(ds->key, key, key_len);
20589 -                       buffer_copy_string(ds->value, value);
20590 -                       
20591 -                       array_insert_unique(con->response.headers, (data_unset *)ds);
20592 -                       
20593 -                       switch(key_len) {
20594 -                       case 4:
20595 -                               if (0 == strncasecmp(key, "Date", key_len)) {
20596 -                                       con->parsed_response |= HTTP_DATE;
20597 -                               }
20598 -                               break;
20599 -                       case 6:
20600 -                               if (0 == strncasecmp(key, "Status", key_len)) {
20601 -                                       con->http_status = strtol(value, NULL, 10);
20602 -                                       con->parsed_response |= HTTP_STATUS;
20603 -                               }
20604 -                               break;
20605 -                       case 8:
20606 -                               if (0 == strncasecmp(key, "Location", key_len)) {
20607 -                                       con->parsed_response |= HTTP_LOCATION;
20608 -                               }
20609 -                               break;
20610 -                       case 10:
20611 -                               if (0 == strncasecmp(key, "Connection", key_len)) {
20612 -                                       con->response.keep_alive = (0 == strcasecmp(value, "Keep-Alive")) ? 1 : 0;
20613 -                                       con->parsed_response |= HTTP_CONNECTION;
20614 -                               }
20615 -                               break;
20616 -                       case 14:
20617 -                               if (0 == strncasecmp(key, "Content-Length", key_len)) {
20618 -                                       con->response.content_length = strtol(value, NULL, 10);
20619 -                                       con->parsed_response |= HTTP_CONTENT_LENGTH;
20620 -                               }
20621 -                               break;
20622 -                       default:
20623 -                               break;
20624 -                       }
20625 -               }
20626 -       }
20627 -       
20628 -       /* CGI/1.1 rev 03 - 7.2.1.2 */
20629 -       if ((con->parsed_response & HTTP_LOCATION) &&
20630 -           !(con->parsed_response & HTTP_STATUS)) {
20631 -               con->http_status = 302;
20632 +static int cgi_demux_response(server *srv, connection *con, plugin_data *p) {
20633 +       cgi_session *sess = con->plugin_ctx[p->id];
20634 +       chunk *c = NULL;
20635 +
20636 +       switch(srv->network_backend_read(srv, con, sess->sock, sess->rb)) {
20637 +       case NETWORK_STATUS_SUCCESS:
20638 +               /* we got content */
20639 +               break;
20640 +       case NETWORK_STATUS_WAIT_FOR_EVENT:
20641 +               return 0;
20642 +       case NETWORK_STATUS_CONNECTION_CLOSE:
20643 +               /* this is a bit too early */
20644 +               ERROR("%s", "cgi-connection got closed before we read the response-header (CGI died ?)");
20645 +               return -1;
20646 +       default:
20647 +               /* oops */
20648 +               ERROR("%s", "oops, read-pipe-read failed and I don't know why");
20649 +               return -1;
20650         }
20651 -       
20652 -       return 0;
20653 -}
20654  
20655 +       /* looks like we got some content
20656 +       *
20657 +       * split off the header from the incoming stream
20658 +       */
20659  
20660 -static int cgi_demux_response(server *srv, handler_ctx *hctx) {
20661 -       plugin_data *p    = hctx->plugin_data;
20662 -       connection  *con  = hctx->remote_conn;
20663 -       
20664 -       while(1) {
20665 -               int n;
20666 -               
20667 -               buffer_prepare_copy(hctx->response, 1024);
20668 -               if (-1 == (n = read(hctx->fd, hctx->response->ptr, hctx->response->size - 1))) {
20669 -                       if (errno == EAGAIN || errno == EINTR) {
20670 -                               /* would block, wait for signal */
20671 -                               return FDEVENT_HANDLED_NOT_FINISHED;
20672 -                       }
20673 -                       /* error */
20674 -                       log_error_write(srv, __FILE__, __LINE__, "sdd", strerror(errno), con->fd, hctx->fd);
20675 -                       return FDEVENT_HANDLED_ERROR;
20676 -               }
20677 -               
20678 -               if (n == 0) {
20679 -                       /* read finished */
20680 -                       
20681 -                       con->file_finished = 1;
20682 -                       
20683 -                       /* send final chunk */
20684 -                       http_chunk_append_mem(srv, con, NULL, 0);
20685 -                       joblist_append(srv, con);
20686 -                       
20687 -                       return FDEVENT_HANDLED_FINISHED;
20688 -               }
20689 -               
20690 -               hctx->response->ptr[n] = '\0';
20691 -               hctx->response->used = n+1;
20692 -               
20693 -               /* split header from body */
20694 -               
20695 -               if (con->file_started == 0) {
20696 -                       char *c;
20697 -                       int in_header = 0;
20698 -                       int header_end = 0;
20699 -                       int cp, eol = EOL_UNSET;
20700 -                       size_t used = 0;
20701 -                       
20702 -                       buffer_append_string_buffer(hctx->response_header, hctx->response);
20703 -                       
20704 -                       /* nph (non-parsed headers) */
20705 -                       if (0 == strncmp(hctx->response_header->ptr, "HTTP/1.", 7)) in_header = 1;
20706 -                       
20707 -                       /* search for the \r\n\r\n or \n\n in the string */
20708 -                       for (c = hctx->response_header->ptr, cp = 0, used = hctx->response_header->used - 1; used; c++, cp++, used--) {
20709 -                               if (*c == ':') in_header = 1;
20710 -                               else if (*c == '\n') {
20711 -                                       if (in_header == 0) {
20712 -                                               /* got a response without a response header */
20713 -                                               
20714 -                                               c = NULL;
20715 -                                               header_end = 1;
20716 -                                               break;
20717 -                                       }
20718 -                                       
20719 -                                       if (eol == EOL_UNSET) eol = EOL_N;
20720 -                                       
20721 -                                       if (*(c+1) == '\n') {
20722 -                                               header_end = 1;
20723 -                                               break;
20724 -                                       }
20725 -                                       
20726 -                               } else if (used > 1 && *c == '\r' && *(c+1) == '\n') {
20727 -                                       if (in_header == 0) {
20728 -                                               /* got a response without a response header */
20729 -                                               
20730 -                                               c = NULL;
20731 -                                               header_end = 1;
20732 -                                               break;
20733 -                                       }
20734 -                                       
20735 -                                       if (eol == EOL_UNSET) eol = EOL_RN;
20736 -                                       
20737 -                                       if (used > 3 &&
20738 -                                           *(c+2) == '\r' && 
20739 -                                           *(c+3) == '\n') {
20740 -                                               header_end = 1;
20741 -                                               break;
20742 -                                       }
20743 -                                       
20744 -                                       /* skip the \n */
20745 -                                       c++;
20746 -                                       cp++;
20747 -                                       used--;
20748 +       if (con->file_started == 0) {
20749 +               size_t i;
20750 +               int have_content_length = 0;
20751 +
20752 +               http_response_reset(p->resp);
20753 +
20754 +               /* the response header is not fully received yet,
20755 +               *
20756 +               * extract the http-response header from the rb-cq
20757 +               */
20758 +               switch (http_response_parse_cq(sess->rb, p->resp)) {
20759 +               case PARSE_ERROR:
20760 +                       /* parsing failed */
20761 +
20762 +                       TRACE("%s", "response parser failed");
20763 +
20764 +                       con->http_status = 502; /* Bad Gateway */
20765 +                       return -1;
20766 +               case PARSE_NEED_MORE:
20767 +                       return 0;
20768 +               case PARSE_SUCCESS:
20769 +                       con->http_status = p->resp->status;
20770 +
20771 +                       chunkqueue_remove_finished_chunks(sess->rb);
20772 +
20773 +                       /* copy the http-headers */
20774 +                       for (i = 0; i < p->resp->headers->used; i++) {
20775 +                               const char *ign[] = { "Status", "Connection", NULL };
20776 +                               size_t j;
20777 +                               data_string *ds;
20778 +
20779 +                               data_string *header = (data_string *)p->resp->headers->data[i];
20780 +
20781 +                               /* some headers are ignored by default */
20782 +                               for (j = 0; ign[j]; j++) {
20783 +                                       if (0 == strcasecmp(ign[j], header->key->ptr)) break;
20784                                 }
20785 -                       }
20786 -                       
20787 -                       if (header_end) {
20788 -                               if (c == NULL) {
20789 -                                       /* no header, but a body */
20790 -                                       
20791 -                                       if (con->request.http_version == HTTP_VERSION_1_1) {
20792 -                                               con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
20793 -                                       }
20794 -                                       
20795 -                                       http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used);
20796 -                                       joblist_append(srv, con);
20797 -                               } else {
20798 -                                       size_t hlen = c - hctx->response_header->ptr + (eol == EOL_RN ? 4 : 2);
20799 -                                       size_t blen = hctx->response_header->used - hlen - 1;
20800 -                               
20801 -                                       /* a small hack: terminate after at the second \r */
20802 -                                       hctx->response_header->used = hlen + 1 - (eol == EOL_RN ? 2 : 1);
20803 -                                       hctx->response_header->ptr[hlen - (eol == EOL_RN ? 2 : 1)] = '\0';
20804 -                               
20805 -                                       /* parse the response header */
20806 -                                       cgi_response_parse(srv, con, p, hctx->response_header, eol);
20807 -                                       
20808 -                                       /* enable chunked-transfer-encoding */
20809 -                                       if (con->request.http_version == HTTP_VERSION_1_1 &&
20810 -                                           !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
20811 -                                               con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
20812 -                                       }
20813 -                                       
20814 -                                       if ((hctx->response->used != hlen) && blen > 0) {
20815 -                                               http_chunk_append_mem(srv, con, c + (eol == EOL_RN ? 4: 2), blen + 1);
20816 -                                               joblist_append(srv, con);
20817 -                                       }
20818 +                               if (ign[j]) continue;
20819 +
20820 +                               if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
20821 +                                       /* CGI/1.1 rev 03 - 7.2.1.2 */
20822 +                                       if (con->http_status == 0) con->http_status = 302;
20823 +                               } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
20824 +                                       have_content_length = 1;
20825                                 }
20826                                 
20827 -                               con->file_started = 1;
20828 +                               if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
20829 +                                       ds = data_response_init();
20830 +                               }
20831 +                               buffer_copy_string_buffer(ds->key, header->key);
20832 +                               buffer_copy_string_buffer(ds->value, header->value);
20833 +
20834 +                               array_insert_unique(con->response.headers, (data_unset *)ds);
20835                         }
20836 -               } else {
20837 -                       http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used);
20838 -                       joblist_append(srv, con);
20839 +
20840 +                       con->file_started = 1;
20841 +                       sess->state = CGI_STATE_READ_RESPONSE_CONTENT;
20842 +
20843 +                       if (con->request.http_version == HTTP_VERSION_1_1 &&
20844 +                           !have_content_length) {
20845 +                               con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
20846 +                       }
20847 +
20848 +                       break;
20849                 }
20850 -               
20851 -#if 0          
20852 -               log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), b->ptr);
20853 -#endif
20854         }
20855 -       
20856 -       return FDEVENT_HANDLED_NOT_FINISHED;
20857 +
20858 +       /* FIXME: pass the response-header to the other plugins to
20859 +       * setup the filter-queue
20860 +       *
20861 +       * - use next-queue instead of con->write_queue
20862 +       */
20863 +
20864 +       /* copy the content to the next cq */
20865 +       for (c = sess->rb->first; c; c = c->next) {
20866 +               chunkqueue_append_mem(con->send, c->mem->ptr + c->offset, c->mem->used - c->offset);
20867 +
20868 +               c->offset = c->mem->used - 1;
20869 +       }
20870 +
20871 +       chunkqueue_remove_finished_chunks(sess->rb);
20872 +       joblist_append(srv, con);
20873 +
20874 +       return 0;
20875  }
20876  
20877 -static handler_t cgi_connection_close(server *srv, handler_ctx *hctx) {
20878 +static handler_t cgi_connection_close(server *srv, connection *con, plugin_data *p) {
20879 +       cgi_session *sess = con->plugin_ctx[p->id];
20880         int status;
20881         pid_t pid;
20882 -       plugin_data *p;
20883 -       connection  *con;
20884 -       
20885 -       if (NULL == hctx) return HANDLER_GO_ON;
20886 -       
20887 -       p    = hctx->plugin_data;
20888 -       con  = hctx->remote_conn;
20889 -       
20890 +
20891 +       if (NULL == sess) return HANDLER_GO_ON;
20892         if (con->mode != p->id) return HANDLER_GO_ON;
20893  
20894 -#ifndef __WIN32
20895 -       
20896 +#ifndef _WIN32
20897 +
20898         /* the connection to the browser went away, but we still have a connection
20899 -        * to the CGI script 
20900 +        * to the CGI script
20901          *
20902          * close cgi-connection
20903          */
20904 -       
20905 -       if (hctx->fd != -1) {
20906 +
20907 +       if (sess->sock->fd != -1) {
20908                 /* close connection to the cgi-script */
20909 -               fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
20910 -               fdevent_unregister(srv->ev, hctx->fd);
20911 -               
20912 -               if (close(hctx->fd)) {
20913 -                       log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno));
20914 -               }
20915 -               
20916 -               hctx->fd = -1;
20917 -               hctx->fde_ndx = -1;
20918 +               fdevent_event_del(srv->ev, sess->sock);
20919 +               fdevent_unregister(srv->ev, sess->sock);
20920         }
20921 -       
20922 -       pid = hctx->pid;
20923 -       
20924 +
20925 +       pid = sess->pid;
20926 +
20927         con->plugin_ctx[p->id] = NULL;
20928 -       
20929 +
20930         /* is this a good idea ? */
20931 -       cgi_handler_ctx_free(hctx);
20932 -       
20933 +       cgi_session_free(sess);
20934 +       sess = NULL;
20935 +
20936         /* if waitpid hasn't been called by response.c yet, do it here */
20937         if (pid) {
20938                 /* check if the CGI-script is already gone */
20939 +#ifndef _WIN32
20940                 switch(waitpid(pid, &status, WNOHANG)) {
20941                 case 0:
20942                         /* not finished yet */
20943 @@ -519,35 +383,34 @@
20944                 case -1:
20945                         /* */
20946                         if (errno == EINTR) break;
20947 -                       
20948 -                       /* 
20949 -                        * errno == ECHILD happens if _subrequest catches the process-status before 
20950 +
20951 +                       /*
20952 +                        * errno == ECHILD happens if _subrequest catches the process-status before
20953                          * we have read the response of the cgi process
20954 -                        * 
20955 +                        *
20956                          * -> catch status
20957                          * -> WAIT_FOR_EVENT
20958                          * -> read response
20959                          * -> we get here with waitpid == ECHILD
20960 -                        * 
20961 +                        *
20962                          */
20963                         if (errno == ECHILD) return HANDLER_GO_ON;
20964 -                       
20965 +
20966                         log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno));
20967                         return HANDLER_ERROR;
20968                 default:
20969                         /* Send an error if we haven't sent any data yet */
20970                         if (0 == con->file_started) {
20971 -                               connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
20972 -                               con->http_status = 500;
20973 +                               if (con->http_status == 0) con->http_status = 500;
20974                                 con->mode = DIRECT;
20975                         }
20976 -                               
20977 +
20978                         if (WIFEXITED(status)) {
20979  #if 0
20980                                 log_error_write(srv, __FILE__, __LINE__, "sd", "(debug) cgi exited fine, pid:", pid);
20981  #endif
20982                                 pid = 0;
20983 -                               
20984 +
20985                                 return HANDLER_GO_ON;
20986                         } else {
20987                                 log_error_write(srv, __FILE__, __LINE__, "sd", "cgi died, pid:", pid);
20988 @@ -555,122 +418,126 @@
20989                                 return HANDLER_GO_ON;
20990                         }
20991                 }
20992 -               
20993 -       
20994 +
20995 +
20996                 kill(pid, SIGTERM);
20997 -               
20998 +#endif
20999                 /* cgi-script is still alive, queue the PID for removal */
21000                 cgi_pid_add(srv, p, pid);
21001         }
21002 -#endif 
21003 +#endif
21004         return HANDLER_GO_ON;
21005  }
21006  
21007  static handler_t cgi_connection_close_callback(server *srv, connection *con, void *p_d) {
21008         plugin_data *p = p_d;
21009 -       
21010 -       return cgi_connection_close(srv, con->plugin_ctx[p->id]);
21011 +
21012 +       return cgi_connection_close(srv, con, p);
21013  }
21014  
21015  
21016  static handler_t cgi_handle_fdevent(void *s, void *ctx, int revents) {
21017         server      *srv  = (server *)s;
21018 -       handler_ctx *hctx = ctx;
21019 -       connection  *con  = hctx->remote_conn;
21020 -       
21021 -       joblist_append(srv, con);
21022 -       
21023 -       if (hctx->fd == -1) {
21024 -               log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), "invalid cgi-fd");
21025 -               
21026 -               return HANDLER_ERROR;
21027 -       }
21028 -       
21029 +       cgi_session *sess = ctx;
21030 +       connection  *con  = sess->remote_con;
21031 +       chunk *c;
21032 +
21033         if (revents & FDEVENT_IN) {
21034 -               switch (cgi_demux_response(srv, hctx)) {
21035 -               case FDEVENT_HANDLED_NOT_FINISHED:
21036 +               switch (sess->state) {
21037 +               case CGI_STATE_READ_RESPONSE_HEADER:
21038 +                       /* parse the header and set file-started, the demuxer will care about it */
21039 +                       joblist_append(srv, con);
21040 +
21041                         break;
21042 -               case FDEVENT_HANDLED_FINISHED:
21043 -                       /* we are done */
21044 -                       
21045 +               case CGI_STATE_READ_RESPONSE_CONTENT:
21046 +                       /* just forward the content to the out-going queue */
21047 +
21048 +                       chunkqueue_remove_finished_chunks(sess->rb);
21049 +
21050 +                       switch (srv->network_backend_read(srv, sess->remote_con, sess->sock, sess->rb)) {
21051 +                       case NETWORK_STATUS_CONNECTION_CLOSE:
21052 +                               fdevent_event_del(srv->ev, sess->sock);
21053 +
21054 +                               /* the connection is gone
21055 +                                * make the connect */
21056 +                               sess->remote_con->send->is_closed = 1;
21057  #if 0
21058 -                       log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), "finished");
21059 +                               fdevent_event_del(srv->ev, sess->sock);
21060  #endif
21061 -                       cgi_connection_close(srv, hctx);
21062 -                       
21063 -                       /* if we get a IN|HUP and have read everything don't exec the close twice */ 
21064 -                       return HANDLER_FINISHED;
21065 -               case FDEVENT_HANDLED_ERROR:
21066 -                       connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
21067 -                       con->http_status = 500;
21068 -                       con->mode = DIRECT;
21069 -                       
21070 -                       log_error_write(srv, __FILE__, __LINE__, "s", "demuxer failed: ");
21071 +                       case NETWORK_STATUS_SUCCESS:
21072 +                               /* read even more, do we have all the content */
21073 +
21074 +                               /* how much do we want to read ? */
21075 +                               
21076 +                               /* call stream-decoder (HTTP-chunked, FastCGI, ... ) */
21077 +
21078 +                               chunkqueue_remove_finished_chunks(sess->rb);
21079 +
21080 +                               /* copy the content to the next cq */
21081 +                               for (c = sess->rb->first; c; c = c->next) {
21082 +                                       if (c->mem->used == 0) continue;
21083 +
21084 +                                       http_chunk_append_mem(srv, sess->remote_con, c->mem->ptr + c->offset, c->mem->used - c->offset);
21085 +       
21086 +                                       c->offset = c->mem->used - 1;
21087 +
21088 +                               }
21089 +                               chunkqueue_remove_finished_chunks(sess->rb);
21090 +
21091 +                               if (sess->remote_con->send->is_closed) {
21092 +                                       /* send final HTTP-Chunk packet */
21093 +                                       http_chunk_append_mem(srv, sess->remote_con, NULL, 0);
21094 +                               }
21095 +                               
21096 +                               break;
21097 +                       default:
21098 +                               ERROR("%s", "oops, we failed to read");
21099 +                               break;
21100 +                       }
21101 +
21102 +                       joblist_append(srv, sess->remote_con);
21103 +                       break;
21104 +               default:
21105 +                       TRACE("unexpected state for a FDEVENT_IN: %d", sess->state);
21106                         break;
21107                 }
21108         }
21109 -       
21110 +
21111         if (revents & FDEVENT_OUT) {
21112                 /* nothing to do */
21113         }
21114 -       
21115 +
21116         /* perhaps this issue is already handled */
21117         if (revents & FDEVENT_HUP) {
21118 -               /* check if we still have a unfinished header package which is a body in reality */
21119 -               if (con->file_started == 0 &&
21120 -                   hctx->response_header->used) {
21121 -                       con->file_started = 1;
21122 -                       http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used);
21123 -                       joblist_append(srv, con);
21124 -               }
21125 -               
21126 -               if (con->file_finished == 0) {
21127 -                       http_chunk_append_mem(srv, con, NULL, 0);
21128 -                       joblist_append(srv, con);
21129 -               }
21130 -               
21131 -               con->file_finished = 1;
21132 -               
21133 -               if (chunkqueue_is_empty(con->write_queue)) {
21134 -                       /* there is nothing left to write */
21135 -                       connection_set_state(srv, con, CON_STATE_RESPONSE_END);
21136 -               } else {
21137 -                       /* used the write-handler to finish the request on demand */
21138 -                       
21139 -               }
21140 -               
21141 -# if 0
21142 -               log_error_write(srv, __FILE__, __LINE__, "sddd", "got HUP from cgi", con->fd, hctx->fd, revents);
21143 -# endif
21144 -               
21145 -               /* rtsigs didn't liked the close */
21146 -               cgi_connection_close(srv, hctx);
21147 +               con->send->is_closed = 1;
21148 +
21149 +               fdevent_event_del(srv->ev, sess->sock);
21150 +
21151 +               /* someone has to close this socket now :) */
21152 +               http_chunk_append_mem(srv, sess->remote_con, NULL, 0);
21153 +               joblist_append(srv, sess->remote_con);
21154         } else if (revents & FDEVENT_ERR) {
21155 -               con->file_finished = 1;
21156 -               
21157 +               con->send->is_closed = 1;
21158 +
21159                 /* kill all connections to the cgi process */
21160 -               cgi_connection_close(srv, hctx);
21161 -#if 1
21162 -               log_error_write(srv, __FILE__, __LINE__, "s", "cgi-FDEVENT_ERR");
21163 -#endif                 
21164 -               return HANDLER_ERROR;
21165 +               fdevent_event_del(srv->ev, sess->sock);
21166         }
21167 -       
21168 +
21169         return HANDLER_FINISHED;
21170  }
21171  
21172  
21173  static int cgi_env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) {
21174         char *dst;
21175 -       
21176 +
21177         if (!key || !val) return -1;
21178 -       
21179 +
21180         dst = malloc(key_len + val_len + 3);
21181         memcpy(dst, key, key_len);
21182         dst[key_len] = '=';
21183         /* add the \0 from the value */
21184         memcpy(dst + key_len + 1, val, val_len + 1);
21185 -       
21186 +
21187         if (env->size == 0) {
21188                 env->size = 16;
21189                 env->ptr = malloc(env->size * sizeof(*env->ptr));
21190 @@ -678,45 +545,45 @@
21191                 env->size += 16;
21192                 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
21193         }
21194 -       
21195 +
21196         env->ptr[env->used++] = dst;
21197 -       
21198 +
21199         return 0;
21200  }
21201  
21202  static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *cgi_handler) {
21203         pid_t pid;
21204 -       
21205 +
21206  #ifdef HAVE_IPV6
21207         char b2[INET6_ADDRSTRLEN + 1];
21208  #endif
21209 -       
21210 +
21211         int to_cgi_fds[2];
21212         int from_cgi_fds[2];
21213         struct stat st;
21214 -       
21215 -#ifndef __WIN32        
21216 -       
21217 +
21218 +#ifndef _WIN32
21219 +
21220         if (cgi_handler->used > 1) {
21221                 /* stat the exec file */
21222                 if (-1 == (stat(cgi_handler->ptr, &st))) {
21223 -                       log_error_write(srv, __FILE__, __LINE__, "sbss", 
21224 +                       log_error_write(srv, __FILE__, __LINE__, "sbss",
21225                                         "stat for cgi-handler", cgi_handler,
21226                                         "failed:", strerror(errno));
21227                         return -1;
21228                 }
21229         }
21230 -       
21231 +
21232         if (pipe(to_cgi_fds)) {
21233                 log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno));
21234                 return -1;
21235         }
21236 -       
21237 +
21238         if (pipe(from_cgi_fds)) {
21239                 log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno));
21240                 return -1;
21241         }
21242 -       
21243 +
21244         /* fork, execve */
21245         switch (pid = fork()) {
21246         case 0: {
21247 @@ -730,44 +597,40 @@
21248                 char *c;
21249                 const char *s;
21250                 server_socket *srv_sock = con->srv_socket;
21251 -               
21252 +
21253                 /* move stdout to from_cgi_fd[1] */
21254                 close(STDOUT_FILENO);
21255                 dup2(from_cgi_fds[1], STDOUT_FILENO);
21256                 close(from_cgi_fds[1]);
21257                 /* not needed */
21258                 close(from_cgi_fds[0]);
21259 -               
21260 +
21261                 /* move the stdin to to_cgi_fd[0] */
21262                 close(STDIN_FILENO);
21263                 dup2(to_cgi_fds[0], STDIN_FILENO);
21264                 close(to_cgi_fds[0]);
21265                 /* not needed */
21266                 close(to_cgi_fds[1]);
21267 -               
21268 -               /* HACK: 
21269 -                * this is not nice, but it works
21270 -                *
21271 -                * we feed the stderr of the CGI to our errorlog, if possible
21272 +
21273 +               /**
21274 +                * FIXME: add a event-handler for STDERR_FILENO and let it LOG()
21275                  */
21276 -               if (srv->errorlog_mode == ERRORLOG_FILE) {
21277 -                       close(STDERR_FILENO);
21278 -                       dup2(srv->errorlog_fd, STDERR_FILENO);
21279 -               }
21280 -               
21281 +
21282 +               close(STDERR_FILENO);
21283 +
21284                 /* create environment */
21285                 env.ptr = NULL;
21286                 env.size = 0;
21287                 env.used = 0;
21288 -               
21289 +
21290                 cgi_env_add(&env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION));
21291  
21292                 if (!buffer_is_empty(con->server_name)) {
21293                         cgi_env_add(&env, CONST_STR_LEN("SERVER_NAME"), CONST_BUF_LEN(con->server_name));
21294                 } else {
21295  #ifdef HAVE_IPV6
21296 -                       s = inet_ntop(srv_sock->addr.plain.sa_family, 
21297 -                                     srv_sock->addr.plain.sa_family == AF_INET6 ? 
21298 +                       s = inet_ntop(srv_sock->addr.plain.sa_family,
21299 +                                     srv_sock->addr.plain.sa_family == AF_INET6 ?
21300                                       (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
21301                                       (const void *) &(srv_sock->addr.ipv4.sin_addr),
21302                                       b2, sizeof(b2)-1);
21303 @@ -779,10 +642,10 @@
21304                 cgi_env_add(&env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
21305  
21306                 s = get_http_version_name(con->request.http_version);
21307 -               
21308 +
21309                 cgi_env_add(&env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
21310 -               
21311 -               ltostr(buf, 
21312 +
21313 +               ltostr(buf,
21314  #ifdef HAVE_IPV6
21315                         ntohs(srv_sock->addr.plain.sa_family == AF_INET6 ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
21316  #else
21317 @@ -790,10 +653,10 @@
21318  #endif
21319                         );
21320                 cgi_env_add(&env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
21321 -               
21322 +
21323  #ifdef HAVE_IPV6
21324 -               s = inet_ntop(srv_sock->addr.plain.sa_family, 
21325 -                             srv_sock->addr.plain.sa_family == AF_INET6 ? 
21326 +               s = inet_ntop(srv_sock->addr.plain.sa_family,
21327 +                             srv_sock->addr.plain.sa_family == AF_INET6 ?
21328                               (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
21329                               (const void *) &(srv_sock->addr.ipv4.sin_addr),
21330                               b2, sizeof(b2)-1);
21331 @@ -811,15 +674,18 @@
21332                 cgi_env_add(&env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200"));
21333                 if (!buffer_is_empty(con->uri.query)) {
21334                         cgi_env_add(&env, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query));
21335 +               } else {
21336 +                       /* set a empty QUERY_STRING */
21337 +                       cgi_env_add(&env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
21338                 }
21339                 if (!buffer_is_empty(con->request.orig_uri)) {
21340                         cgi_env_add(&env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
21341                 }
21342 -               
21343 -               
21344 +
21345 +
21346  #ifdef HAVE_IPV6
21347 -               s = inet_ntop(con->dst_addr.plain.sa_family, 
21348 -                             con->dst_addr.plain.sa_family == AF_INET6 ? 
21349 +               s = inet_ntop(con->dst_addr.plain.sa_family,
21350 +                             con->dst_addr.plain.sa_family == AF_INET6 ?
21351                               (const void *) &(con->dst_addr.ipv6.sin6_addr) :
21352                               (const void *) &(con->dst_addr.ipv4.sin_addr),
21353                               b2, sizeof(b2)-1);
21354 @@ -828,7 +694,7 @@
21355  #endif
21356                 cgi_env_add(&env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
21357  
21358 -               ltostr(buf, 
21359 +               ltostr(buf,
21360  #ifdef HAVE_IPV6
21361                         ntohs(con->dst_addr.plain.sa_family == AF_INET6 ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
21362  #else
21363 @@ -836,19 +702,19 @@
21364  #endif
21365                         );
21366                 cgi_env_add(&env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
21367 -               
21368 +
21369                 if (!buffer_is_empty(con->authed_user)) {
21370                         cgi_env_add(&env, CONST_STR_LEN("REMOTE_USER"),
21371                                     CONST_BUF_LEN(con->authed_user));
21372                 }
21373 -               
21374 +
21375                 /* request.content_length < SSIZE_MAX, see request.c */
21376                 ltostr(buf, con->request.content_length);
21377                 cgi_env_add(&env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
21378                 cgi_env_add(&env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path));
21379                 cgi_env_add(&env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
21380                 cgi_env_add(&env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root));
21381 -               
21382 +
21383                 /* for valgrind */
21384                 if (NULL != (s = getenv("LD_PRELOAD"))) {
21385                         cgi_env_add(&env, CONST_STR_LEN("LD_PRELOAD"), s, strlen(s));
21386 @@ -863,24 +729,24 @@
21387                         cgi_env_add(&env, CONST_STR_LEN("SYSTEMROOT"), s, strlen(s));
21388                 }
21389  #endif
21390 -               
21391 +
21392                 for (n = 0; n < con->request.headers->used; n++) {
21393                         data_string *ds;
21394 -                       
21395 +
21396                         ds = (data_string *)con->request.headers->data[n];
21397 -                       
21398 +
21399                         if (ds->value->used && ds->key->used) {
21400                                 size_t j;
21401 -                               
21402 +
21403                                 buffer_reset(p->tmp_buf);
21404 -                               
21405 +
21406                                 if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
21407                                         buffer_copy_string(p->tmp_buf, "HTTP_");
21408                                         p->tmp_buf->used--; /* strip \0 after HTTP_ */
21409                                 }
21410 -                               
21411 +
21412                                 buffer_prepare_append(p->tmp_buf, ds->key->used + 2);
21413 -                               
21414 +
21415                                 for (j = 0; j < ds->key->used - 1; j++) {
21416                                         char cr = '_';
21417                                         if (light_isalpha(ds->key->ptr[j])) {
21418 @@ -893,46 +759,46 @@
21419                                         p->tmp_buf->ptr[p->tmp_buf->used++] = cr;
21420                                 }
21421                                 p->tmp_buf->ptr[p->tmp_buf->used++] = '\0';
21422 -                               
21423 +
21424                                 cgi_env_add(&env, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value));
21425                         }
21426                 }
21427 -               
21428 +
21429                 for (n = 0; n < con->environment->used; n++) {
21430                         data_string *ds;
21431 -                       
21432 +
21433                         ds = (data_string *)con->environment->data[n];
21434 -                       
21435 +
21436                         if (ds->value->used && ds->key->used) {
21437                                 size_t j;
21438 -                               
21439 +
21440                                 buffer_reset(p->tmp_buf);
21441 -                               
21442 +
21443                                 buffer_prepare_append(p->tmp_buf, ds->key->used + 2);
21444 -                               
21445 +
21446                                 for (j = 0; j < ds->key->used - 1; j++) {
21447 -                                       p->tmp_buf->ptr[p->tmp_buf->used++] = 
21448 -                                               isalpha((unsigned char)ds->key->ptr[j]) ? 
21449 +                                       p->tmp_buf->ptr[p->tmp_buf->used++] =
21450 +                                               isalpha((unsigned char)ds->key->ptr[j]) ?
21451                                                 toupper((unsigned char)ds->key->ptr[j]) : '_';
21452                                 }
21453                                 p->tmp_buf->ptr[p->tmp_buf->used++] = '\0';
21454 -                               
21455 +
21456                                 cgi_env_add(&env, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value));
21457                         }
21458                 }
21459 -               
21460 +
21461                 if (env.size == env.used) {
21462                         env.size += 16;
21463                         env.ptr = realloc(env.ptr, env.size * sizeof(*env.ptr));
21464                 }
21465 -               
21466 +
21467                 env.ptr[env.used] = NULL;
21468 -               
21469 +
21470                 /* set up args */
21471                 argc = 3;
21472                 args = malloc(sizeof(*args) * argc);
21473                 i = 0;
21474 -               
21475 +
21476                 if (cgi_handler->used > 1) {
21477                         args[i++] = cgi_handler->ptr;
21478                 }
21479 @@ -942,7 +808,7 @@
21480                 /* search for the last / */
21481                 if (NULL != (c = strrchr(con->physical.path->ptr, '/'))) {
21482                         *c = '\0';
21483 -                       
21484 +
21485                         /* change to the physical directory */
21486                         if (-1 == chdir(con->physical.path->ptr)) {
21487                                 log_error_write(srv, __FILE__, __LINE__, "ssb", "chdir failed:", strerror(errno), con->physical.path);
21488 @@ -952,14 +818,14 @@
21489  
21490                 /* we don't need the client socket */
21491                 for (i = 3; i < 256; i++) {
21492 -                       if (i != srv->errorlog_fd) close(i);
21493 +                       close(i);
21494                 }
21495 -               
21496 +
21497                 /* exec the cgi */
21498                 execve(args[0], args, env.ptr);
21499 -               
21500 +
21501                 log_error_write(srv, __FILE__, __LINE__, "sss", "CGI failed:", strerror(errno), args[0]);
21502 -               
21503 +
21504                 /* */
21505                 SEGFAULT();
21506                 break;
21507 @@ -969,16 +835,16 @@
21508                 log_error_write(srv, __FILE__, __LINE__, "ss", "fork failed:", strerror(errno));
21509                 break;
21510         default: {
21511 -               handler_ctx *hctx;
21512 +               cgi_session *sess;
21513                 /* father */
21514  
21515                 close(from_cgi_fds[1]);
21516                 close(to_cgi_fds[0]);
21517 -               
21518 +
21519                 if (con->request.content_length) {
21520 -                       chunkqueue *cq = con->request_content_queue;
21521 +                       chunkqueue *cq = con->recv;
21522                         chunk *c;
21523 -               
21524 +
21525                         assert(chunkqueue_length(cq) == (off_t)con->request.content_length);
21526  
21527                         /* there is content to send */
21528 @@ -993,16 +859,16 @@
21529                                                 if (-1 == c->file.fd &&  /* open the file if not already open */
21530                                                     -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
21531                                                         log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
21532 -                                       
21533 +
21534                                                         close(from_cgi_fds[0]);
21535                                                         close(to_cgi_fds[1]);
21536                                                         return -1;
21537                                                 }
21538  
21539                                                 c->file.mmap.length = c->file.length;
21540 -                               
21541 +
21542                                                 if (MAP_FAILED == (c->file.mmap.start = mmap(0,  c->file.mmap.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
21543 -                                                       log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ", 
21544 +                                                       log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
21545                                                                         strerror(errno), c->file.name,  c->file.fd);
21546  
21547                                                         close(from_cgi_fds[0]);
21548 @@ -1012,7 +878,7 @@
21549  
21550                                                 close(c->file.fd);
21551                                                 c->file.fd = -1;
21552 -       
21553 +
21554                                                 /* chunk_reset() or chunk_free() will cleanup for us */
21555                                         }
21556  
21557 @@ -1020,7 +886,7 @@
21558                                                 switch(errno) {
21559                                                 case ENOSPC:
21560                                                         con->http_status = 507;
21561 -               
21562 +
21563                                                         break;
21564                                                 default:
21565                                                         con->http_status = 403;
21566 @@ -1033,7 +899,7 @@
21567                                                 switch(errno) {
21568                                                 case ENOSPC:
21569                                                         con->http_status = 507;
21570 -               
21571 +
21572                                                         break;
21573                                                 default:
21574                                                         con->http_status = 403;
21575 @@ -1056,103 +922,95 @@
21576                 }
21577  
21578                 close(to_cgi_fds[1]);
21579 -                               
21580 +
21581                 /* register PID and wait for them asyncronously */
21582                 con->mode = p->id;
21583                 buffer_reset(con->physical.path);
21584 -               
21585 -               hctx = cgi_handler_ctx_init();
21586 -               
21587 -               hctx->remote_conn = con;
21588 -               hctx->plugin_data = p;
21589 -               hctx->pid = pid;
21590 -               hctx->fd = from_cgi_fds[0];
21591 -               hctx->fde_ndx = -1;
21592 -               
21593 -               con->plugin_ctx[p->id] = hctx;
21594 -               
21595 -               fdevent_register(srv->ev, hctx->fd, cgi_handle_fdevent, hctx);
21596 -               fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
21597 -               
21598 -               if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
21599 +
21600 +               sess = cgi_session_init();
21601 +
21602 +               sess->remote_con = con;
21603 +               sess->pid = pid;
21604 +
21605 +               assert(sess->sock);
21606 +
21607 +               sess->sock->fd = from_cgi_fds[0];
21608 +               sess->sock->type = IOSOCKET_TYPE_PIPE;
21609 +
21610 +               if (-1 == fdevent_fcntl_set(srv->ev, sess->sock)) {
21611                         log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
21612 -                       
21613 -                       fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
21614 -                       fdevent_unregister(srv->ev, hctx->fd);
21615 -                       
21616 -                       log_error_write(srv, __FILE__, __LINE__, "sd", "cgi close:", hctx->fd);
21617 -                       
21618 -                       close(hctx->fd);
21619 -                       
21620 -                       cgi_handler_ctx_free(hctx);
21621 -                       
21622 -                       con->plugin_ctx[p->id] = NULL;
21623 -                       
21624 +
21625 +                       cgi_session_free(sess);
21626 +
21627                         return -1;
21628                 }
21629 -               
21630 +
21631 +               con->plugin_ctx[p->id] = sess;
21632 +
21633 +               fdevent_register(srv->ev, sess->sock, cgi_handle_fdevent, sess);
21634 +               fdevent_event_add(srv->ev, sess->sock, FDEVENT_IN);
21635 +
21636 +               sess->state = CGI_STATE_READ_RESPONSE_HEADER;
21637 +
21638                 break;
21639         }
21640         }
21641 -       
21642 +
21643         return 0;
21644  #else
21645         return -1;
21646  #endif
21647  }
21648  
21649 -#define PATCH(x) \
21650 -       p->conf.x = s->x;
21651  static int mod_cgi_patch_connection(server *srv, connection *con, plugin_data *p) {
21652         size_t i, j;
21653         plugin_config *s = p->config_storage[0];
21654 -       
21655 -       PATCH(cgi);
21656 -       
21657 +
21658 +       PATCH_OPTION(cgi);
21659 +
21660         /* skip the first, the global context */
21661         for (i = 1; i < srv->config_context->used; i++) {
21662                 data_config *dc = (data_config *)srv->config_context->data[i];
21663                 s = p->config_storage[i];
21664 -               
21665 +
21666                 /* condition didn't match */
21667                 if (!config_check_cond(srv, con, dc)) continue;
21668 -               
21669 +
21670                 /* merge config */
21671                 for (j = 0; j < dc->value->used; j++) {
21672                         data_unset *du = dc->value->data[j];
21673 -                       
21674 +
21675                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.assign"))) {
21676 -                               PATCH(cgi);
21677 +                               PATCH_OPTION(cgi);
21678                         }
21679                 }
21680         }
21681 -       
21682 +
21683         return 0;
21684  }
21685 -#undef PATCH
21686  
21687  URIHANDLER_FUNC(cgi_is_handled) {
21688         size_t k, s_len;
21689         plugin_data *p = p_d;
21690         buffer *fn = con->physical.path;
21691 -       
21692 +
21693         if (fn->used == 0) return HANDLER_GO_ON;
21694 -       
21695 +
21696         mod_cgi_patch_connection(srv, con, p);
21697 -       
21698 +
21699         s_len = fn->used - 1;
21700 -       
21701 +
21702         for (k = 0; k < p->conf.cgi->used; k++) {
21703                 data_string *ds = (data_string *)p->conf.cgi->data[k];
21704                 size_t ct_len = ds->key->used - 1;
21705 -               
21706 +
21707                 if (ds->key->used == 0) continue;
21708                 if (s_len < ct_len) continue;
21709 -               
21710 +
21711                 if (0 == strncmp(fn->ptr + s_len - ct_len, ds->key->ptr, ct_len)) {
21712                         if (cgi_create_env(srv, con, p, ds->value)) {
21713                                 con->http_status = 500;
21714 -                               
21715 +
21716                                 buffer_reset(con->physical.path);
21717                                 return HANDLER_FINISHED;
21718                         }
21719 @@ -1160,7 +1018,7 @@
21720                         break;
21721                 }
21722         }
21723 -       
21724 +
21725         return HANDLER_GO_ON;
21726  }
21727  
21728 @@ -1168,11 +1026,11 @@
21729         plugin_data *p = p_d;
21730         size_t ndx;
21731         /* the trigger handle only cares about lonely PID which we have to wait for */
21732 -#ifndef __WIN32
21733 +#ifndef _WIN32
21734  
21735         for (ndx = 0; ndx < p->cgi_pid.used; ndx++) {
21736                 int status;
21737 -               
21738 +
21739                 switch(waitpid(p->cgi_pid.ptr[ndx], &status, WNOHANG)) {
21740                 case 0:
21741                         /* not finished yet */
21742 @@ -1182,7 +1040,7 @@
21743                         break;
21744                 case -1:
21745                         log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno));
21746 -                       
21747 +
21748                         return HANDLER_ERROR;
21749                 default:
21750  
21751 @@ -1193,96 +1051,104 @@
21752                         } else {
21753                                 log_error_write(srv, __FILE__, __LINE__, "s", "cgi died ?");
21754                         }
21755 -                       
21756 +
21757                         cgi_pid_del(srv, p, p->cgi_pid.ptr[ndx]);
21758 -                       /* del modified the buffer structure 
21759 +                       /* del modified the buffer structure
21760                          * and copies the last entry to the current one
21761                          * -> recheck the current index
21762                          */
21763                         ndx--;
21764                 }
21765         }
21766 -#endif 
21767 +#endif
21768         return HANDLER_GO_ON;
21769  }
21770  
21771  SUBREQUEST_FUNC(mod_cgi_handle_subrequest) {
21772         int status;
21773         plugin_data *p = p_d;
21774 -       handler_ctx *hctx = con->plugin_ctx[p->id];
21775 -       
21776 +       cgi_session *sess = con->plugin_ctx[p->id];
21777 +
21778         if (con->mode != p->id) return HANDLER_GO_ON;
21779 -       if (NULL == hctx) return HANDLER_GO_ON;
21780 -       
21781 +       if (NULL == sess) return HANDLER_GO_ON;
21782 +
21783 +       switch (cgi_demux_response(srv, con, p)) {
21784 +       case 0:
21785 +               break;
21786 +       case 1:
21787 +               cgi_connection_close(srv, con, p);
21788 +
21789 +               /* if we get a IN|HUP and have read everything don't exec the close twice */
21790 +               return HANDLER_FINISHED;
21791 +       case -1:
21792 +               cgi_connection_close(srv, con, p);
21793 +
21794 +               if (0 == con->http_status) con->http_status = 500;
21795 +               con->mode = DIRECT;
21796 +
21797 +               return HANDLER_FINISHED;
21798 +       }
21799 +
21800  #if 0
21801 -       log_error_write(srv, __FILE__, __LINE__, "sdd", "subrequest, pid =", hctx, hctx->pid);
21802 -#endif 
21803 -       if (hctx->pid == 0) return HANDLER_FINISHED;
21804 -#ifndef __WIN32        
21805 -       switch(waitpid(hctx->pid, &status, WNOHANG)) {
21806 +       log_error_write(srv, __FILE__, __LINE__, "sdd", "subrequest, pid =", sess, sess->pid);
21807 +#endif
21808 +       if (sess->pid == 0) return HANDLER_FINISHED;
21809 +#ifndef _WIN32
21810 +       switch(waitpid(sess->pid, &status, WNOHANG)) {
21811         case 0:
21812                 /* we only have for events here if we don't have the header yet,
21813                  * otherwise the event-handler will send us the incoming data */
21814 -               if (con->file_started) return HANDLER_FINISHED;
21815  
21816 -               return HANDLER_WAIT_FOR_EVENT;
21817 +               if (!con->file_started) return HANDLER_WAIT_FOR_EVENT;
21818 +               if (con->send->is_closed) return HANDLER_FINISHED;
21819 +
21820 +               return HANDLER_GO_ON;
21821         case -1:
21822                 if (errno == EINTR) return HANDLER_WAIT_FOR_EVENT;
21823 -               
21824 +
21825                 if (errno == ECHILD && con->file_started == 0) {
21826                         /*
21827 -                        * second round but still not response 
21828 +                        * second round but still not response
21829                          */
21830 -                       return HANDLER_WAIT_FOR_EVENT; 
21831 +                       return HANDLER_WAIT_FOR_EVENT;
21832                 }
21833 -               
21834 +
21835                 log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno));
21836                 con->mode = DIRECT;
21837                 con->http_status = 500;
21838 -               
21839 -               hctx->pid = 0;
21840 -               
21841 -               fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
21842 -               fdevent_unregister(srv->ev, hctx->fd);
21843 -               
21844 -               if (close(hctx->fd)) {
21845 -                       log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno));
21846 -               }
21847 -               
21848 -               cgi_handler_ctx_free(hctx);
21849 -               
21850 +
21851 +               sess->pid = 0;
21852 +
21853 +               fdevent_event_del(srv->ev, sess->sock);
21854 +               fdevent_unregister(srv->ev, sess->sock);
21855 +
21856 +               cgi_session_free(sess);
21857 +               sess = NULL;
21858 +
21859                 con->plugin_ctx[p->id] = NULL;
21860 -               
21861 +
21862                 return HANDLER_FINISHED;
21863         default:
21864 -               /* cgi process exited cleanly 
21865 -                * 
21866 -                * check if we already got the response 
21867 -                */
21868 -               
21869 -               if (!con->file_started) return HANDLER_WAIT_FOR_EVENT;
21870 -               
21871 +               con->send->is_closed = 1;
21872 +
21873                 if (WIFEXITED(status)) {
21874                         /* nothing */
21875                 } else {
21876                         log_error_write(srv, __FILE__, __LINE__, "s", "cgi died ?");
21877 -                       
21878 +
21879                         con->mode = DIRECT;
21880                         con->http_status = 500;
21881 -                       
21882 +
21883                 }
21884 -               
21885 -               hctx->pid = 0;
21886 -               
21887 -               fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
21888 -               fdevent_unregister(srv->ev, hctx->fd);
21889 -               
21890 -               if (close(hctx->fd)) {
21891 -                       log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno));
21892 -               }
21893 -               
21894 -               cgi_handler_ctx_free(hctx);
21895 -               
21896 +
21897 +               sess->pid = 0;
21898 +
21899 +               fdevent_event_del(srv->ev, sess->sock);
21900 +               fdevent_unregister(srv->ev, sess->sock);
21901 +
21902 +               cgi_session_free(sess);
21903 +               sess = NULL;
21904 +
21905                 con->plugin_ctx[p->id] = NULL;
21906                 return HANDLER_FINISHED;
21907         }
21908 @@ -1297,17 +1163,15 @@
21909         p->name        = buffer_init_string("cgi");
21910  
21911         p->connection_reset = cgi_connection_close_callback;
21912 -       p->handle_subrequest_start = cgi_is_handled;
21913 -       p->handle_subrequest = mod_cgi_handle_subrequest;
21914 -#if 0
21915 -       p->handle_fdevent = cgi_handle_fdevent;
21916 -#endif
21917 +       p->handle_start_backend = cgi_is_handled;
21918 +       p->handle_send_request_content = mod_cgi_handle_subrequest;
21919 +
21920         p->handle_trigger = cgi_trigger;
21921         p->init           = mod_cgi_init;
21922         p->cleanup        = mod_cgi_free;
21923         p->set_defaults   = mod_fastcgi_set_defaults;
21924 -       
21925 +
21926         p->data        = NULL;
21927 -       
21928 +
21929         return 0;
21930  }
21931 --- ../lighttpd-1.4.11/src/mod_cml.c    2006-01-30 13:51:48.000000000 +0200
21932 +++ lighttpd-1.5.0/src/mod_cml.c        2006-09-07 00:57:05.000000000 +0300
21933 @@ -4,7 +4,6 @@
21934  #include <stdlib.h>
21935  #include <string.h>
21936  #include <errno.h>
21937 -#include <unistd.h>
21938  #include <stdio.h>
21939  
21940  #include "buffer.h"
21941 @@ -20,50 +19,50 @@
21942  /* init the plugin data */
21943  INIT_FUNC(mod_cml_init) {
21944         plugin_data *p;
21945 -       
21946 +
21947         p = calloc(1, sizeof(*p));
21948 -       
21949 +
21950         p->basedir         = buffer_init();
21951         p->baseurl         = buffer_init();
21952         p->trigger_handler = buffer_init();
21953 -       
21954 +
21955         return p;
21956  }
21957  
21958  /* detroy the plugin data */
21959  FREE_FUNC(mod_cml_free) {
21960         plugin_data *p = p_d;
21961 -       
21962 +
21963         UNUSED(srv);
21964  
21965         if (!p) return HANDLER_GO_ON;
21966 -       
21967 +
21968         if (p->config_storage) {
21969                 size_t i;
21970                 for (i = 0; i < srv->config_context->used; i++) {
21971                         plugin_config *s = p->config_storage[i];
21972 -                       
21973 +
21974                         buffer_free(s->ext);
21975 -                       
21976 +
21977                         buffer_free(s->mc_namespace);
21978                         buffer_free(s->power_magnet);
21979                         array_free(s->mc_hosts);
21980 -                       
21981 +
21982  #if defined(HAVE_MEMCACHE_H)
21983                         if (s->mc) mc_free(s->mc);
21984  #endif
21985 -                       
21986 +
21987                         free(s);
21988                 }
21989                 free(p->config_storage);
21990         }
21991 -       
21992 +
21993         buffer_free(p->trigger_handler);
21994         buffer_free(p->basedir);
21995         buffer_free(p->baseurl);
21996 -       
21997 +
21998         free(p);
21999 -       
22000 +
22001         return HANDLER_GO_ON;
22002  }
22003  
22004 @@ -72,22 +71,22 @@
22005  SETDEFAULTS_FUNC(mod_cml_set_defaults) {
22006         plugin_data *p = p_d;
22007         size_t i = 0;
22008 -       
22009 -       config_values_t cv[] = { 
22010 +
22011 +       config_values_t cv[] = {
22012                 { "cml.extension",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
22013                 { "cml.memcache-hosts",         NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },        /* 1 */
22014                 { "cml.memcache-namespace",     NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
22015                 { "cml.power-magnet",           NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 3 */
22016                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
22017         };
22018 -       
22019 +
22020         if (!p) return HANDLER_ERROR;
22021 -       
22022 +
22023         p->config_storage = malloc(srv->config_context->used * sizeof(specific_config *));
22024 -       
22025 +
22026         for (i = 0; i < srv->config_context->used; i++) {
22027                 plugin_config *s;
22028 -               
22029 +
22030                 s = malloc(sizeof(plugin_config));
22031                 s->ext    = buffer_init();
22032                 s->mc_hosts       = array_init();
22033 @@ -96,87 +95,84 @@
22034  #if defined(HAVE_MEMCACHE_H)
22035                 s->mc = NULL;
22036  #endif
22037 -               
22038 +
22039                 cv[0].destination = s->ext;
22040                 cv[1].destination = s->mc_hosts;
22041                 cv[2].destination = s->mc_namespace;
22042                 cv[3].destination = s->power_magnet;
22043 -               
22044 +
22045                 p->config_storage[i] = s;
22046 -       
22047 +
22048                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
22049                         return HANDLER_ERROR;
22050                 }
22051 -               
22052 +
22053                 if (s->mc_hosts->used) {
22054  #if defined(HAVE_MEMCACHE_H)
22055                         size_t k;
22056                         s->mc = mc_new();
22057 -               
22058 +
22059                         for (k = 0; k < s->mc_hosts->used; k++) {
22060                                 data_string *ds = (data_string *)s->mc_hosts->data[k];
22061 -                               
22062 +
22063                                 if (0 != mc_server_add4(s->mc, ds->value->ptr)) {
22064 -                                       log_error_write(srv, __FILE__, __LINE__, "sb", 
22065 -                                                       "connection to host failed:", 
22066 +                                       log_error_write(srv, __FILE__, __LINE__, "sb",
22067 +                                                       "connection to host failed:",
22068                                                         ds->value);
22069 -                                       
22070 +
22071                                         return HANDLER_ERROR;
22072                                 }
22073                         }
22074  #else
22075 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
22076 +                       log_error_write(srv, __FILE__, __LINE__, "s",
22077                                         "memcache support is not compiled in but cml.memcache-hosts is set, aborting");
22078                         return HANDLER_ERROR;
22079  #endif
22080                 }
22081         }
22082 -       
22083 +
22084         return HANDLER_GO_ON;
22085  }
22086  
22087 -#define PATCH(x) \
22088 -       p->conf.x = s->x;
22089  static int mod_cml_patch_connection(server *srv, connection *con, plugin_data *p) {
22090         size_t i, j;
22091         plugin_config *s = p->config_storage[0];
22092 -       
22093 -       PATCH(ext);
22094 +
22095 +       PATCH_OPTION(ext);
22096  #if defined(HAVE_MEMCACHE_H)
22097 -       PATCH(mc);
22098 +       PATCH_OPTION(mc);
22099  #endif
22100 -       PATCH(mc_namespace);
22101 -       PATCH(power_magnet);
22102 -       
22103 +       PATCH_OPTION(mc_namespace);
22104 +       PATCH_OPTION(power_magnet);
22105 +
22106         /* skip the first, the global context */
22107         for (i = 1; i < srv->config_context->used; i++) {
22108                 data_config *dc = (data_config *)srv->config_context->data[i];
22109                 s = p->config_storage[i];
22110 -               
22111 +
22112                 /* condition didn't match */
22113                 if (!config_check_cond(srv, con, dc)) continue;
22114 -               
22115 +
22116                 /* merge config */
22117                 for (j = 0; j < dc->value->used; j++) {
22118                         data_unset *du = dc->value->data[j];
22119 -                       
22120 +
22121                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.extension"))) {
22122 -                               PATCH(ext);
22123 +                               PATCH_OPTION(ext);
22124                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.memcache-hosts"))) {
22125  #if defined(HAVE_MEMCACHE_H)
22126 -                               PATCH(mc);
22127 +                               PATCH_OPTION(mc);
22128  #endif
22129                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.memcache-namespace"))) {
22130 -                               PATCH(mc_namespace);
22131 +                               PATCH_OPTION(mc_namespace);
22132                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.power-magnet"))) {
22133 -                               PATCH(power_magnet);
22134 +                               PATCH_OPTION(power_magnet);
22135                         }
22136                 }
22137         }
22138 -       
22139 +
22140         return 0;
22141  }
22142 -#undef PATCH
22143  
22144  int cache_call_lua(server *srv, connection *con, plugin_data *p, buffer *cml_file) {
22145         buffer *b;
22146 @@ -187,57 +183,57 @@
22147         b = p->baseurl;
22148         buffer_copy_string_buffer(b, con->uri.path);
22149         for (c = b->ptr + b->used - 1; c > b->ptr && *c != '/'; c--);
22150 -       
22151 +
22152         if (*c == '/') {
22153                 b->used = c - b->ptr + 2;
22154                 *(c+1) = '\0';
22155         }
22156 -       
22157 +
22158         b = p->basedir;
22159         buffer_copy_string_buffer(b, con->physical.path);
22160         for (c = b->ptr + b->used - 1; c > b->ptr && *c != '/'; c--);
22161 -       
22162 +
22163         if (*c == '/') {
22164                 b->used = c - b->ptr + 2;
22165                 *(c+1) = '\0';
22166         }
22167 -       
22168 +
22169  
22170         /* prepare variables
22171          *   - cookie-based
22172          *   - get-param-based
22173          */
22174 -       
22175 +
22176         return cache_parse_lua(srv, con, p, cml_file);
22177 -       
22178 +
22179  }
22180  
22181  URIHANDLER_FUNC(mod_cml_power_magnet) {
22182         plugin_data *p = p_d;
22183 -       
22184 +
22185         mod_cml_patch_connection(srv, con, p);
22186 -       
22187 +
22188         buffer_reset(p->basedir);
22189         buffer_reset(p->baseurl);
22190         buffer_reset(p->trigger_handler);
22191  
22192         if (buffer_is_empty(p->conf.power_magnet)) return HANDLER_GO_ON;
22193 -       
22194 -       /* 
22195 +
22196 +       /*
22197          * power-magnet:
22198          * cml.power-magnet = server.docroot + "/rewrite.cml"
22199          *
22200          * is called on EACH request, take the original REQUEST_URI and modifies the
22201 -        * request header as neccesary. 
22202 +        * request header as neccesary.
22203          *
22204          * First use:
22205          * if file_exists("/maintainance.html") {
22206          *   output_include = ( "/maintainance.html" )
22207 -        *   return CACHE_HIT 
22208 +        *   return CACHE_HIT
22209          * }
22210          *
22211          * as we only want to rewrite HTML like requests we should cover it in a conditional
22212 -        * 
22213 +        *
22214          * */
22215  
22216         switch(cache_call_lua(srv, con, p, p->conf.power_magnet)) {
22217 @@ -266,20 +262,20 @@
22218  
22219  URIHANDLER_FUNC(mod_cml_is_handled) {
22220         plugin_data *p = p_d;
22221 -       
22222 +
22223         if (buffer_is_empty(con->physical.path)) return HANDLER_ERROR;
22224 -       
22225 +
22226         mod_cml_patch_connection(srv, con, p);
22227 -       
22228 +
22229         buffer_reset(p->basedir);
22230         buffer_reset(p->baseurl);
22231         buffer_reset(p->trigger_handler);
22232  
22233         if (buffer_is_empty(p->conf.ext)) return HANDLER_GO_ON;
22234 -       
22235 +
22236         if (!buffer_is_equal_right_len(con->physical.path, p->conf.ext, p->conf.ext->used - 1)) {
22237                 return HANDLER_GO_ON;
22238 -       } 
22239 +       }
22240  
22241         switch(cache_call_lua(srv, con, p, con->physical.path)) {
22242         case -1:
22243 @@ -311,15 +307,15 @@
22244  int mod_cml_plugin_init(plugin *p) {
22245         p->version     = LIGHTTPD_VERSION_ID;
22246         p->name        = buffer_init_string("cache");
22247 -       
22248 +
22249         p->init        = mod_cml_init;
22250         p->cleanup     = mod_cml_free;
22251         p->set_defaults  = mod_cml_set_defaults;
22252 -       
22253 -       p->handle_subrequest_start = mod_cml_is_handled;
22254 +
22255 +       p->handle_start_backend    = mod_cml_is_handled;
22256         p->handle_physical         = mod_cml_power_magnet;
22257 -       
22258 +
22259         p->data        = NULL;
22260 -       
22261 +
22262         return 0;
22263  }
22264 --- ../lighttpd-1.4.11/src/mod_cml.h    2006-01-30 13:51:35.000000000 +0200
22265 +++ lighttpd-1.5.0/src/mod_cml.h        2006-07-16 00:26:03.000000000 +0300
22266 @@ -16,10 +16,10 @@
22267  
22268  typedef struct {
22269         buffer *ext;
22270 -       
22271 +
22272         array  *mc_hosts;
22273         buffer *mc_namespace;
22274 -#if defined(HAVE_MEMCACHE_H) 
22275 +#if defined(HAVE_MEMCACHE_H)
22276         struct memcache *mc;
22277  #endif
22278         buffer *power_magnet;
22279 @@ -27,15 +27,15 @@
22280  
22281  typedef struct {
22282         PLUGIN_DATA;
22283 -       
22284 +
22285         buffer *basedir;
22286         buffer *baseurl;
22287 -       
22288 +
22289         buffer *trigger_handler;
22290 -       
22291 +
22292         plugin_config **config_storage;
22293 -       
22294 -       plugin_config conf; 
22295 +
22296 +       plugin_config conf;
22297  } plugin_data;
22298  
22299  int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn);
22300 --- ../lighttpd-1.4.11/src/mod_cml_funcs.c      2005-11-17 16:15:08.000000000 +0200
22301 +++ lighttpd-1.5.0/src/mod_cml_funcs.c  2006-07-16 00:26:04.000000000 +0300
22302 @@ -4,8 +4,7 @@
22303  #include <stdlib.h>
22304  #include <string.h>
22305  #include <errno.h>
22306 -#include <unistd.h>
22307 -#include <dirent.h>
22308 +
22309  #include <stdio.h>
22310  
22311  #include "buffer.h"
22312 @@ -13,6 +12,7 @@
22313  #include "log.h"
22314  #include "plugin.h"
22315  #include "response.h"
22316 +#include "sys-files.h"
22317  
22318  #include "mod_cml.h"
22319  #include "mod_cml_funcs.h"
22320 @@ -30,7 +30,7 @@
22321  #ifdef USE_OPENSSL
22322  #define IN const
22323  #else
22324 -#define IN 
22325 +#define IN
22326  #endif
22327  #define OUT
22328  
22329 @@ -42,29 +42,29 @@
22330         buffer b;
22331         char hex[33];
22332         int n = lua_gettop(L);
22333 -       
22334 +
22335         b.ptr = hex;
22336         b.used = 0;
22337         b.size = sizeof(hex);
22338 -       
22339 +
22340         if (n != 1) {
22341                 lua_pushstring(L, "md5: expected one argument");
22342                 lua_error(L);
22343         }
22344 -       
22345 +
22346         if (!lua_isstring(L, 1)) {
22347                 lua_pushstring(L, "md5: argument has to be a string");
22348                 lua_error(L);
22349         }
22350 -       
22351 +
22352         MD5_Init(&Md5Ctx);
22353         MD5_Update(&Md5Ctx, (unsigned char *)lua_tostring(L, 1), lua_strlen(L, 1));
22354         MD5_Final(HA1, &Md5Ctx);
22355 -       
22356 +
22357         buffer_copy_string_hex(&b, (char *)HA1, 16);
22358 -       
22359 +
22360         lua_pushstring(L, b.ptr);
22361 -       
22362 +
22363         return 1;
22364  }
22365  
22366 @@ -72,37 +72,37 @@
22367  int f_file_mtime(lua_State *L) {
22368         struct stat st;
22369         int n = lua_gettop(L);
22370 -       
22371 +
22372         if (n != 1) {
22373                 lua_pushstring(L, "file_mtime: expected one argument");
22374                 lua_error(L);
22375         }
22376 -       
22377 +
22378         if (!lua_isstring(L, 1)) {
22379                 lua_pushstring(L, "file_mtime: argument has to be a string");
22380                 lua_error(L);
22381         }
22382 -       
22383 +
22384         if (-1 == stat(lua_tostring(L, 1), &st)) {
22385                 lua_pushnil(L);
22386                 return 1;
22387         }
22388 -       
22389 +
22390         lua_pushnumber(L, st.st_mtime);
22391 -       
22392 +
22393         return 1;
22394  }
22395 -
22396 +#ifndef _WIN32
22397  int f_dir_files_iter(lua_State *L) {
22398         DIR *d;
22399         struct dirent *de;
22400 -       
22401 +
22402         d = lua_touserdata(L, lua_upvalueindex(1));
22403 -       
22404 +
22405         if (NULL == (de = readdir(d))) {
22406                 /* EOF */
22407                 closedir(d);
22408 -               
22409 +
22410                 return 0;
22411         } else {
22412                 lua_pushstring(L, de->d_name);
22413 @@ -113,75 +113,75 @@
22414  int f_dir_files(lua_State *L) {
22415         DIR *d;
22416         int n = lua_gettop(L);
22417 -       
22418 +
22419         if (n != 1) {
22420                 lua_pushstring(L, "dir_files: expected one argument");
22421                 lua_error(L);
22422         }
22423 -       
22424 +
22425         if (!lua_isstring(L, 1)) {
22426                 lua_pushstring(L, "dir_files: argument has to be a string");
22427                 lua_error(L);
22428         }
22429 -       
22430 -       /* check if there is a valid DIR handle on the stack */ 
22431 +
22432 +       /* check if there is a valid DIR handle on the stack */
22433         if (NULL == (d = opendir(lua_tostring(L, 1)))) {
22434                 lua_pushnil(L);
22435                 return 1;
22436         }
22437 -       
22438 +
22439         /* push d into registry */
22440         lua_pushlightuserdata(L, d);
22441         lua_pushcclosure(L, f_dir_files_iter, 1);
22442 -       
22443 +
22444         return 1;
22445  }
22446 -
22447 +#endif
22448  int f_file_isreg(lua_State *L) {
22449         struct stat st;
22450         int n = lua_gettop(L);
22451 -       
22452 +
22453         if (n != 1) {
22454                 lua_pushstring(L, "file_isreg: expected one argument");
22455                 lua_error(L);
22456         }
22457 -       
22458 +
22459         if (!lua_isstring(L, 1)) {
22460                 lua_pushstring(L, "file_isreg: argument has to be a string");
22461                 lua_error(L);
22462         }
22463 -       
22464 +
22465         if (-1 == stat(lua_tostring(L, 1), &st)) {
22466                 lua_pushnil(L);
22467                 return 1;
22468         }
22469 -       
22470 +
22471         lua_pushnumber(L, S_ISREG(st.st_mode));
22472 -       
22473 +
22474         return 1;
22475  }
22476  
22477  int f_file_isdir(lua_State *L) {
22478         struct stat st;
22479         int n = lua_gettop(L);
22480 -       
22481 +
22482         if (n != 1) {
22483                 lua_pushstring(L, "file_isreg: expected one argument");
22484                 lua_error(L);
22485         }
22486 -       
22487 +
22488         if (!lua_isstring(L, 1)) {
22489                 lua_pushstring(L, "file_isreg: argument has to be a string");
22490                 lua_error(L);
22491         }
22492 -       
22493 +
22494         if (-1 == stat(lua_tostring(L, 1), &st)) {
22495                 lua_pushnil(L);
22496                 return 1;
22497         }
22498 -       
22499 +
22500         lua_pushnumber(L, S_ISDIR(st.st_mode));
22501 -       
22502 +
22503         return 1;
22504  }
22505  
22506 @@ -192,33 +192,33 @@
22507         char *r;
22508         int n = lua_gettop(L);
22509         struct memcache *mc;
22510 -       
22511 +
22512         if (!lua_islightuserdata(L, lua_upvalueindex(1))) {
22513                 lua_pushstring(L, "where is my userdata ?");
22514                 lua_error(L);
22515         }
22516 -       
22517 +
22518         mc = lua_touserdata(L, lua_upvalueindex(1));
22519 -       
22520 +
22521         if (n != 1) {
22522                 lua_pushstring(L, "expected one argument");
22523                 lua_error(L);
22524         }
22525 -       
22526 +
22527         if (!lua_isstring(L, 1)) {
22528                 lua_pushstring(L, "argument has to be a string");
22529                 lua_error(L);
22530         }
22531 -       
22532 -       if (NULL == (r = mc_aget(mc, 
22533 +
22534 +       if (NULL == (r = mc_aget(mc,
22535                                  lua_tostring(L, 1), lua_strlen(L, 1)))) {
22536 -                               
22537 +
22538                 lua_pushboolean(L, 0);
22539                 return 1;
22540         }
22541 -       
22542 +
22543         free(r);
22544 -       
22545 +
22546         lua_pushboolean(L, 1);
22547         return 1;
22548  }
22549 @@ -226,74 +226,74 @@
22550  int f_memcache_get_string(lua_State *L) {
22551         char *r;
22552         int n = lua_gettop(L);
22553 -       
22554 +
22555         struct memcache *mc;
22556 -       
22557 +
22558         if (!lua_islightuserdata(L, lua_upvalueindex(1))) {
22559                 lua_pushstring(L, "where is my userdata ?");
22560                 lua_error(L);
22561         }
22562 -       
22563 +
22564         mc = lua_touserdata(L, lua_upvalueindex(1));
22565 -       
22566 -       
22567 +
22568 +
22569         if (n != 1) {
22570                 lua_pushstring(L, "expected one argument");
22571                 lua_error(L);
22572         }
22573 -       
22574 +
22575         if (!lua_isstring(L, 1)) {
22576                 lua_pushstring(L, "argument has to be a string");
22577                 lua_error(L);
22578         }
22579 -       
22580 -       if (NULL == (r = mc_aget(mc, 
22581 +
22582 +       if (NULL == (r = mc_aget(mc,
22583                                  lua_tostring(L, 1), lua_strlen(L, 1)))) {
22584                 lua_pushnil(L);
22585                 return 1;
22586         }
22587 -       
22588 +
22589         lua_pushstring(L, r);
22590 -       
22591 +
22592         free(r);
22593 -       
22594 +
22595         return 1;
22596  }
22597  
22598  int f_memcache_get_long(lua_State *L) {
22599         char *r;
22600         int n = lua_gettop(L);
22601 -       
22602 +
22603         struct memcache *mc;
22604 -       
22605 +
22606         if (!lua_islightuserdata(L, lua_upvalueindex(1))) {
22607                 lua_pushstring(L, "where is my userdata ?");
22608                 lua_error(L);
22609         }
22610 -       
22611 +
22612         mc = lua_touserdata(L, lua_upvalueindex(1));
22613 -       
22614 -       
22615 +
22616 +
22617         if (n != 1) {
22618                 lua_pushstring(L, "expected one argument");
22619                 lua_error(L);
22620         }
22621 -       
22622 +
22623         if (!lua_isstring(L, 1)) {
22624                 lua_pushstring(L, "argument has to be a string");
22625                 lua_error(L);
22626         }
22627 -       
22628 -       if (NULL == (r = mc_aget(mc, 
22629 +
22630 +       if (NULL == (r = mc_aget(mc,
22631                                  lua_tostring(L, 1), lua_strlen(L, 1)))) {
22632                 lua_pushnil(L);
22633                 return 1;
22634         }
22635 -       
22636 +
22637         lua_pushnumber(L, strtol(r, NULL, 10));
22638 -       
22639 +
22640         free(r);
22641 -       
22642 +
22643         return 1;
22644  }
22645  #endif
22646 --- ../lighttpd-1.4.11/src/mod_cml_lua.c        2006-01-30 13:56:40.000000000 +0200
22647 +++ lighttpd-1.5.0/src/mod_cml_lua.c    2006-09-07 00:57:05.000000000 +0300
22648 @@ -23,7 +23,7 @@
22649  #ifdef USE_OPENSSL
22650  #define IN const
22651  #else
22652 -#define IN 
22653 +#define IN
22654  #endif
22655  #define OUT
22656  
22657 @@ -31,6 +31,7 @@
22658  
22659  #include <lua.h>
22660  #include <lualib.h>
22661 +#include <lauxlib.h>
22662  
22663  typedef struct {
22664         stream st;
22665 @@ -39,11 +40,11 @@
22666  
22667  static const char * load_file(lua_State *L, void *data, size_t *size) {
22668         readme *rm = data;
22669 -       
22670 +
22671         UNUSED(L);
22672 -       
22673 +
22674         if (rm->done) return 0;
22675 -       
22676 +
22677         *size = rm->st.size;
22678         rm->done = 1;
22679         return rm->st.start;
22680 @@ -51,47 +52,47 @@
22681  
22682  static int lua_to_c_get_string(lua_State *L, const char *varname, buffer *b) {
22683         int curelem;
22684 -       
22685 +
22686         lua_pushstring(L, varname);
22687 -       
22688 +
22689         curelem = lua_gettop(L);
22690         lua_gettable(L, LUA_GLOBALSINDEX);
22691 -       
22692 +
22693         /* it should be a table */
22694         if (!lua_isstring(L, curelem)) {
22695                 lua_settop(L, curelem - 1);
22696 -               
22697 +
22698                 return -1;
22699         }
22700 -       
22701 +
22702         buffer_copy_string(b, lua_tostring(L, curelem));
22703 -       
22704 +
22705         lua_pop(L, 1);
22706 -       
22707 +
22708         assert(curelem - 1 == lua_gettop(L));
22709 -       
22710 +
22711         return 0;
22712  }
22713  
22714  static int lua_to_c_is_table(lua_State *L, const char *varname) {
22715         int curelem;
22716 -       
22717 +
22718         lua_pushstring(L, varname);
22719 -       
22720 +
22721         curelem = lua_gettop(L);
22722         lua_gettable(L, LUA_GLOBALSINDEX);
22723 -       
22724 +
22725         /* it should be a table */
22726         if (!lua_istable(L, curelem)) {
22727                 lua_settop(L, curelem - 1);
22728 -               
22729 +
22730                 return 0;
22731         }
22732 -       
22733 +
22734         lua_settop(L, curelem - 1);
22735 -       
22736 +
22737         assert(curelem - 1 == lua_gettop(L));
22738 -       
22739 +
22740         return 1;
22741  }
22742  
22743 @@ -99,7 +100,7 @@
22744         lua_pushlstring(L, key, key_len);
22745         lua_pushlstring(L, val, val_len);
22746         lua_settable(L, tbl);
22747 -       
22748 +
22749         return 0;
22750  }
22751  
22752 @@ -108,21 +109,21 @@
22753         size_t is_key = 1;
22754         size_t i;
22755         char *key = NULL, *val = NULL;
22756 -       
22757 +
22758         key = qrystr->ptr;
22759 -       
22760 +
22761         /* we need the \0 */
22762         for (i = 0; i < qrystr->used; i++) {
22763                 switch(qrystr->ptr[i]) {
22764                 case '=':
22765                         if (is_key) {
22766                                 val = qrystr->ptr + i + 1;
22767 -                               
22768 +
22769                                 qrystr->ptr[i] = '\0';
22770 -                               
22771 +
22772                                 is_key = 0;
22773                         }
22774 -                       
22775 +
22776                         break;
22777                 case '&':
22778                 case '\0': /* fin symbol */
22779 @@ -131,19 +132,19 @@
22780  
22781                                 /* terminate the value */
22782                                 qrystr->ptr[i] = '\0';
22783 -                               
22784 -                               c_to_lua_push(L, tbl, 
22785 +
22786 +                               c_to_lua_push(L, tbl,
22787                                               key, strlen(key),
22788                                               val, strlen(val));
22789                         }
22790 -                       
22791 +
22792                         key = qrystr->ptr + i + 1;
22793                         val = NULL;
22794                         is_key = 1;
22795                         break;
22796                 }
22797         }
22798 -       
22799 +
22800         return 0;
22801  }
22802  #if 0
22803 @@ -151,21 +152,21 @@
22804         data_unset *d;
22805  
22806         UNUSED(srv);
22807 -       
22808 +
22809         if (NULL != (d = array_get_element(con->request.headers, "Cookie"))) {
22810                 data_string *ds = (data_string *)d;
22811                 size_t key = 0, value = 0;
22812                 size_t is_key = 1, is_sid = 0;
22813                 size_t i;
22814 -               
22815 +
22816                 /* found COOKIE */
22817                 if (!DATA_IS_STRING(d)) return -1;
22818                 if (ds->value->used == 0) return -1;
22819 -                       
22820 +
22821                 if (ds->value->ptr[0] == '\0' ||
22822                     ds->value->ptr[0] == '=' ||
22823                     ds->value->ptr[0] == ';') return -1;
22824 -               
22825 +
22826                 buffer_reset(p->session_id);
22827                 for (i = 0; i < ds->value->used; i++) {
22828                         switch(ds->value->ptr[i]) {
22829 @@ -176,16 +177,16 @@
22830                                                 is_sid = 1;
22831                                         }
22832                                         value = i + 1;
22833 -                               
22834 +
22835                                         is_key = 0;
22836                                 }
22837 -                               
22838 +
22839                                 break;
22840                         case ';':
22841                                 if (is_sid) {
22842                                         buffer_copy_string_len(p->session_id, ds->value->ptr + value, i - value);
22843                                 }
22844 -                               
22845 +
22846                                 is_sid = 0;
22847                                 key = i + 1;
22848                                 value = 0;
22849 @@ -204,48 +205,43 @@
22850                         }
22851                 }
22852         }
22853 -       
22854 +
22855         return 0;
22856  }
22857  #endif
22858  
22859  int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
22860 -       lua_State *L; 
22861 +       lua_State *L;
22862         readme rm;
22863         int ret = -1;
22864         buffer *b = buffer_init();
22865         int header_tbl = 0;
22866 -       
22867 +
22868         rm.done = 0;
22869         stream_open(&rm.st, fn);
22870 -       
22871 +
22872         /* push the lua file to the interpreter and see what happends */
22873 -       L = lua_open();
22874 -       
22875 -       luaopen_base(L);
22876 -       luaopen_table(L);
22877 -       luaopen_string(L);
22878 -       luaopen_math(L);
22879 -       luaopen_io(L);
22880 -       
22881 +       L = luaL_newstate();
22882 +       luaL_openlibs(L);
22883 +
22884         /* register functions */
22885         lua_register(L, "md5", f_crypto_md5);
22886         lua_register(L, "file_mtime", f_file_mtime);
22887         lua_register(L, "file_isreg", f_file_isreg);
22888         lua_register(L, "file_isdir", f_file_isreg);
22889         lua_register(L, "dir_files", f_dir_files);
22890 -       
22891 +
22892  #ifdef HAVE_MEMCACHE_H
22893         lua_pushliteral(L, "memcache_get_long");
22894         lua_pushlightuserdata(L, p->conf.mc);
22895         lua_pushcclosure(L, f_memcache_get_long, 1);
22896         lua_settable(L, LUA_GLOBALSINDEX);
22897 -       
22898 +
22899         lua_pushliteral(L, "memcache_get_string");
22900         lua_pushlightuserdata(L, p->conf.mc);
22901         lua_pushcclosure(L, f_memcache_get_string, 1);
22902         lua_settable(L, LUA_GLOBALSINDEX);
22903 -       
22904 +
22905         lua_pushliteral(L, "memcache_exists");
22906         lua_pushlightuserdata(L, p->conf.mc);
22907         lua_pushcclosure(L, f_memcache_exists, 1);
22908 @@ -255,11 +251,11 @@
22909         lua_pushliteral(L, "request");
22910         lua_newtable(L);
22911         lua_settable(L, LUA_GLOBALSINDEX);
22912 -       
22913 +
22914         lua_pushliteral(L, "request");
22915         header_tbl = lua_gettop(L);
22916         lua_gettable(L, LUA_GLOBALSINDEX);
22917 -       
22918 +
22919         c_to_lua_push(L, header_tbl, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
22920         c_to_lua_push(L, header_tbl, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
22921         c_to_lua_push(L, header_tbl, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path));
22922 @@ -267,84 +263,84 @@
22923         if (!buffer_is_empty(con->request.pathinfo)) {
22924                 c_to_lua_push(L, header_tbl, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
22925         }
22926 -       
22927 +
22928         c_to_lua_push(L, header_tbl, CONST_STR_LEN("CWD"), CONST_BUF_LEN(p->basedir));
22929         c_to_lua_push(L, header_tbl, CONST_STR_LEN("BASEURL"), CONST_BUF_LEN(p->baseurl));
22930 -       
22931 +
22932         /* register GET parameter */
22933         lua_pushliteral(L, "get");
22934         lua_newtable(L);
22935         lua_settable(L, LUA_GLOBALSINDEX);
22936 -       
22937 +
22938         lua_pushliteral(L, "get");
22939         header_tbl = lua_gettop(L);
22940         lua_gettable(L, LUA_GLOBALSINDEX);
22941 -       
22942 +
22943         buffer_copy_string_buffer(b, con->uri.query);
22944         cache_export_get_params(L, header_tbl, b);
22945         buffer_reset(b);
22946  
22947 -       /* 2 default constants */       
22948 +       /* 2 default constants */
22949         lua_pushliteral(L, "CACHE_HIT");
22950         lua_pushboolean(L, 0);
22951         lua_settable(L, LUA_GLOBALSINDEX);
22952 -       
22953 +
22954         lua_pushliteral(L, "CACHE_MISS");
22955         lua_pushboolean(L, 1);
22956         lua_settable(L, LUA_GLOBALSINDEX);
22957 -       
22958 +
22959         /* load lua program */
22960         if (lua_load(L, load_file, &rm, fn->ptr) || lua_pcall(L,0,1,0)) {
22961                 log_error_write(srv, __FILE__, __LINE__, "s",
22962                                 lua_tostring(L,-1));
22963 -               
22964 +
22965                 goto error;
22966         }
22967 -       
22968 +
22969         /* get return value */
22970         ret = (int)lua_tonumber(L, -1);
22971         lua_pop(L, 1);
22972 -       
22973 -       /* fetch the data from lua */ 
22974 +
22975 +       /* fetch the data from lua */
22976         lua_to_c_get_string(L, "trigger_handler", p->trigger_handler);
22977 -       
22978 +
22979         if (0 == lua_to_c_get_string(L, "output_contenttype", b)) {
22980                 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(b));
22981         }
22982 -       
22983 +
22984         if (ret == 0) {
22985                 /* up to now it is a cache-hit, check if all files exist */
22986 -               
22987 +
22988                 int curelem;
22989                 time_t mtime = 0;
22990 -       
22991 +
22992                 if (!lua_to_c_is_table(L, "output_include")) {
22993                         log_error_write(srv, __FILE__, __LINE__, "s",
22994                                 "output_include is missing or not a table");
22995                         ret = -1;
22996 -               
22997 +
22998                         goto error;
22999                 }
23000 -               
23001 +
23002                 lua_pushstring(L, "output_include");
23003 -               
23004 +
23005                 curelem = lua_gettop(L);
23006                 lua_gettable(L, LUA_GLOBALSINDEX);
23007  
23008                 /* HOW-TO build a etag ?
23009 -                * as we don't just have one file we have to take the stat() 
23010 +                * as we don't just have one file we have to take the stat()
23011                  * from all base files, merge them and build the etag from
23012                  * it later.
23013 -                * 
23014 +                *
23015                  * The mtime of the content is the mtime of the freshest base file
23016 -                * 
23017 +                *
23018                  * */
23019 -               
23020 +
23021                 lua_pushnil(L);  /* first key */
23022                 while (lua_next(L, curelem) != 0) {
23023                         stat_cache_entry *sce = NULL;
23024                         /* key' is at index -2 and value' at index -1 */
23025 -                       
23026 +
23027                         if (lua_isstring(L, -1)) {
23028                                 const char *s = lua_tostring(L, -1);
23029  
23030 @@ -364,18 +360,18 @@
23031                                                 /* a file is missing, call the handler to generate it */
23032                                                 if (!buffer_is_empty(p->trigger_handler)) {
23033                                                         ret = 1; /* cache-miss */
23034 -                                                       
23035 +
23036                                                         log_error_write(srv, __FILE__, __LINE__, "s",
23037                                                                         "a file is missing, calling handler");
23038 -                                                       
23039 +
23040                                                         break;
23041                                                 } else {
23042                                                         /* handler not set -> 500 */
23043                                                         ret = -1;
23044 -                                                       
23045 +
23046                                                         log_error_write(srv, __FILE__, __LINE__, "s",
23047                                                                         "a file missing and no handler set");
23048 -                                                       
23049 +
23050                                                         break;
23051                                                 }
23052                                                 break;
23053 @@ -383,7 +379,7 @@
23054                                                 break;
23055                                         }
23056                                 } else {
23057 -                                       chunkqueue_append_file(con->write_queue, b, 0, sce->st.st_size);
23058 +                                       chunkqueue_append_file(con->send, b, 0, sce->st.st_size);
23059                                         if (sce->st.st_mtime > mtime) mtime = sce->st.st_mtime;
23060                                 }
23061                         } else {
23062 @@ -393,26 +389,26 @@
23063                                                 "not a string");
23064                                 break;
23065                         }
23066 -               
23067 +
23068                         lua_pop(L, 1);  /* removes value'; keeps key' for next iteration */
23069                 }
23070 -               
23071 +
23072                 lua_settop(L, curelem - 1);
23073 -               
23074 +
23075                 if (ret == 0) {
23076                         data_string *ds;
23077                         char timebuf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
23078                         buffer tbuf;
23079  
23080 -                       con->file_finished = 1;
23081 +                       con->send->is_closed = 1;
23082  
23083                         ds = (data_string *)array_get_element(con->response.headers, "Last-Modified");
23084  
23085                         /* no Last-Modified specified */
23086                         if ((mtime) && (NULL == ds)) {
23087 -               
23088 +
23089                                 strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&mtime));
23090 -                               
23091 +
23092                                 response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), timebuf, sizeof(timebuf) - 1);
23093  
23094  
23095 @@ -428,36 +424,36 @@
23096                                 tbuf.used = 0;
23097                                 tbuf.ptr = NULL;
23098                         }
23099 -                       
23100 +
23101                         if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, &tbuf)) {
23102 -                               /* ok, the client already has our content, 
23103 +                               /* ok, the client already has our content,
23104                                  * no need to send it again */
23105  
23106 -                               chunkqueue_reset(con->write_queue);
23107 +                               chunkqueue_reset(con->send);
23108                                 ret = 0; /* cache-hit */
23109                         }
23110                 } else {
23111 -                       chunkqueue_reset(con->write_queue);
23112 +                       chunkqueue_reset(con->send);
23113                 }
23114         }
23115 -       
23116 +
23117         if (ret == 1 && !buffer_is_empty(p->trigger_handler)) {
23118                 /* cache-miss */
23119                 buffer_copy_string_buffer(con->uri.path, p->baseurl);
23120                 buffer_append_string_buffer(con->uri.path, p->trigger_handler);
23121 -       
23122 +
23123                 buffer_copy_string_buffer(con->physical.path, p->basedir);
23124                 buffer_append_string_buffer(con->physical.path, p->trigger_handler);
23125 -               
23126 -               chunkqueue_reset(con->write_queue);
23127 +
23128 +               chunkqueue_reset(con->send);
23129         }
23130 -       
23131 +
23132  error:
23133         lua_close(L);
23134 -       
23135 +
23136         stream_close(&rm.st);
23137         buffer_free(b);
23138 -       
23139 +
23140         return ret /* cache-error */;
23141  }
23142  #else
23143 --- ../lighttpd-1.4.11/src/mod_compress.c       2005-11-18 13:49:14.000000000 +0200
23144 +++ lighttpd-1.5.0/src/mod_compress.c   2006-09-07 00:57:05.000000000 +0300
23145 @@ -2,7 +2,6 @@
23146  #include <sys/stat.h>
23147  
23148  #include <fcntl.h>
23149 -#include <unistd.h>
23150  #include <ctype.h>
23151  #include <stdlib.h>
23152  #include <string.h>
23153 @@ -33,6 +32,7 @@
23154  #endif
23155  
23156  #include "sys-mmap.h"
23157 +#include "sys-files.h"
23158  
23159  /* request: accept-encoding */
23160  #define HTTP_ACCEPT_ENCODING_IDENTITY BV(0)
23161 @@ -55,97 +55,127 @@
23162         PLUGIN_DATA;
23163         buffer *ofn;
23164         buffer *b;
23165 -       
23166 +
23167         plugin_config **config_storage;
23168 -       plugin_config conf; 
23169 +       plugin_config conf;
23170  } plugin_data;
23171  
23172  INIT_FUNC(mod_compress_init) {
23173         plugin_data *p;
23174 -       
23175 +
23176         p = calloc(1, sizeof(*p));
23177 -       
23178 +
23179         p->ofn = buffer_init();
23180         p->b = buffer_init();
23181 -       
23182 +
23183         return p;
23184  }
23185  
23186  FREE_FUNC(mod_compress_free) {
23187         plugin_data *p = p_d;
23188 -       
23189 +
23190         UNUSED(srv);
23191  
23192         if (!p) return HANDLER_GO_ON;
23193 -       
23194 +
23195         buffer_free(p->ofn);
23196         buffer_free(p->b);
23197 -       
23198 +
23199         if (p->config_storage) {
23200                 size_t i;
23201                 for (i = 0; i < srv->config_context->used; i++) {
23202                         plugin_config *s = p->config_storage[i];
23203  
23204                         if (!s) continue;
23205 -                       
23206 +
23207                         array_free(s->compress);
23208                         buffer_free(s->compress_cache_dir);
23209 -                       
23210 +
23211                         free(s);
23212                 }
23213                 free(p->config_storage);
23214         }
23215 -       
23216 -       
23217 +
23218 +
23219         free(p);
23220 -       
23221 +
23222         return HANDLER_GO_ON;
23223  }
23224  
23225 +void mkdir_recursive(const char *dir) {
23226 +
23227 +       char dir_copy[256];
23228 +       char *p = dir_copy;
23229 +
23230 +       if (!dir || !dir[0])
23231 +               return;
23232 +
23233 +       strncpy(dir_copy, dir, sizeof(dir_copy) / sizeof(dir_copy[0]));
23234 +
23235 +       while ((p = strchr(p + 1, '/')) != NULL) {
23236 +
23237 +               *p = '\0';
23238 +               if ((mkdir(dir_copy, 0700) != 0) && (errno != EEXIST))
23239 +                       return;
23240 +
23241 +               *p++ = '/';
23242 +       }
23243 +
23244 +       mkdir(dir, 0700);
23245 +}
23246 +
23247  SETDEFAULTS_FUNC(mod_compress_setdefaults) {
23248         plugin_data *p = p_d;
23249         size_t i = 0;
23250 -       
23251 -       config_values_t cv[] = { 
23252 +
23253 +       config_values_t cv[] = {
23254                 { "compress.cache-dir",             NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
23255                 { "compress.filetype",              NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
23256                 { "compress.max-filesize",          NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
23257                 { NULL,                             NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
23258         };
23259 -       
23260 +
23261         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
23262 -       
23263 +
23264         for (i = 0; i < srv->config_context->used; i++) {
23265                 plugin_config *s;
23266 -               
23267 +
23268                 s = calloc(1, sizeof(plugin_config));
23269                 s->compress_cache_dir = buffer_init();
23270                 s->compress = array_init();
23271                 s->compress_max_filesize = 0;
23272 -               
23273 +
23274                 cv[0].destination = s->compress_cache_dir;
23275                 cv[1].destination = s->compress;
23276                 cv[2].destination = &(s->compress_max_filesize);
23277 -               
23278 +
23279                 p->config_storage[i] = s;
23280 -       
23281 +
23282                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
23283                         return HANDLER_ERROR;
23284                 }
23285 -               
23286 +
23287                 if (!buffer_is_empty(s->compress_cache_dir)) {
23288                         struct stat st;
23289                         if (0 != stat(s->compress_cache_dir->ptr, &st)) {
23290 -                               log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir", 
23291 +
23292 +                               log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir, attempting to create",
23293                                                 s->compress_cache_dir, strerror(errno));
23294 -                               
23295 -                               return HANDLER_ERROR;
23296 +                               mkdir_recursive(s->compress_cache_dir->ptr);
23297 +
23298 +                               if (0 != stat(s->compress_cache_dir->ptr, &st)) {
23299 +
23300 +                                       log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir, create failed",
23301 +                                                                       s->compress_cache_dir, strerror(errno));
23302 +
23303 +                                       return HANDLER_ERROR;
23304 +                               }
23305                         }
23306                 }
23307         }
23308 -       
23309 +
23310         return HANDLER_GO_ON;
23311 -       
23312 +
23313  }
23314  
23315  #ifdef USE_ZLIB
23316 @@ -153,32 +183,32 @@
23317         unsigned char *c;
23318         unsigned long crc;
23319         z_stream z;
23320 -       
23321 +
23322         UNUSED(srv);
23323         UNUSED(con);
23324  
23325         z.zalloc = Z_NULL;
23326         z.zfree = Z_NULL;
23327         z.opaque = Z_NULL;
23328 -       
23329 -       if (Z_OK != deflateInit2(&z, 
23330 +
23331 +       if (Z_OK != deflateInit2(&z,
23332                                  Z_DEFAULT_COMPRESSION,
23333 -                                Z_DEFLATED, 
23334 +                                Z_DEFLATED,
23335                                  -MAX_WBITS,  /* supress zlib-header */
23336                                  8,
23337                                  Z_DEFAULT_STRATEGY)) {
23338                 return -1;
23339         }
23340 -               
23341 +
23342         z.next_in = (unsigned char *)start;
23343         z.avail_in = st_size;
23344         z.total_in = 0;
23345 -               
23346 -                       
23347 +
23348 +
23349         buffer_prepare_copy(p->b, (z.avail_in * 1.1) + 12 + 18);
23350 -               
23351 +
23352         /* write gzip header */
23353 -               
23354 +
23355         c = (unsigned char *)p->b->ptr;
23356         c[0] = 0x1f;
23357         c[1] = 0x8b;
23358 @@ -190,24 +220,24 @@
23359         c[7] = (mtime >> 24) & 0xff;
23360         c[8] = 0x00; /* extra flags */
23361         c[9] = 0x03; /* UNIX */
23362 -       
23363 +
23364         p->b->used = 10;
23365         z.next_out = (unsigned char *)p->b->ptr + p->b->used;
23366         z.avail_out = p->b->size - p->b->used - 8;
23367         z.total_out = 0;
23368 -       
23369 +
23370         if (Z_STREAM_END != deflate(&z, Z_FINISH)) {
23371                 deflateEnd(&z);
23372                 return -1;
23373         }
23374 -       
23375 +
23376         /* trailer */
23377         p->b->used += z.total_out;
23378 -       
23379 +
23380         crc = generate_crc32c(start, st_size);
23381 -               
23382 +
23383         c = (unsigned char *)p->b->ptr + p->b->used;
23384 -               
23385 +
23386         c[0] = (crc >>  0) & 0xff;
23387         c[1] = (crc >>  8) & 0xff;
23388         c[2] = (crc >> 16) & 0xff;
23389 @@ -221,51 +251,51 @@
23390         if (Z_OK != deflateEnd(&z)) {
23391                 return -1;
23392         }
23393 -       
23394 +
23395         return 0;
23396  }
23397  
23398  static int deflate_file_to_buffer_deflate(server *srv, connection *con, plugin_data *p, unsigned char *start, off_t st_size) {
23399         z_stream z;
23400 -       
23401 +
23402         UNUSED(srv);
23403         UNUSED(con);
23404  
23405         z.zalloc = Z_NULL;
23406         z.zfree = Z_NULL;
23407         z.opaque = Z_NULL;
23408 -       
23409 -       if (Z_OK != deflateInit2(&z, 
23410 +
23411 +       if (Z_OK != deflateInit2(&z,
23412                                  Z_DEFAULT_COMPRESSION,
23413 -                                Z_DEFLATED, 
23414 +                                Z_DEFLATED,
23415                                  -MAX_WBITS,  /* supress zlib-header */
23416                                  8,
23417                                  Z_DEFAULT_STRATEGY)) {
23418                 return -1;
23419         }
23420 -               
23421 +
23422         z.next_in = start;
23423         z.avail_in = st_size;
23424         z.total_in = 0;
23425 -               
23426 +
23427         buffer_prepare_copy(p->b, (z.avail_in * 1.1) + 12);
23428 -       
23429 +
23430         z.next_out = (unsigned char *)p->b->ptr;
23431         z.avail_out = p->b->size;
23432         z.total_out = 0;
23433 -       
23434 +
23435         if (Z_STREAM_END != deflate(&z, Z_FINISH)) {
23436                 deflateEnd(&z);
23437                 return -1;
23438         }
23439 -       
23440 +
23441         /* trailer */
23442         p->b->used += z.total_out;
23443 -       
23444 +
23445         if (Z_OK != deflateEnd(&z)) {
23446                 return -1;
23447         }
23448 -       
23449 +
23450         return 0;
23451  }
23452  
23453 @@ -274,48 +304,48 @@
23454  #ifdef USE_BZ2LIB
23455  static int deflate_file_to_buffer_bzip2(server *srv, connection *con, plugin_data *p, unsigned char *start, off_t st_size) {
23456         bz_stream bz;
23457 -       
23458 +
23459         UNUSED(srv);
23460         UNUSED(con);
23461  
23462         bz.bzalloc = NULL;
23463         bz.bzfree = NULL;
23464         bz.opaque = NULL;
23465 -       
23466 -       if (BZ_OK != BZ2_bzCompressInit(&bz, 
23467 +
23468 +       if (BZ_OK != BZ2_bzCompressInit(&bz,
23469                                         9, /* blocksize = 900k */
23470                                         0, /* no output */
23471                                         0)) { /* workFactor: default */
23472                 return -1;
23473         }
23474 -               
23475 +
23476         bz.next_in = (char *)start;
23477         bz.avail_in = st_size;
23478         bz.total_in_lo32 = 0;
23479         bz.total_in_hi32 = 0;
23480 -               
23481 +
23482         buffer_prepare_copy(p->b, (bz.avail_in * 1.1) + 12);
23483 -       
23484 +
23485         bz.next_out = p->b->ptr;
23486         bz.avail_out = p->b->size;
23487         bz.total_out_lo32 = 0;
23488         bz.total_out_hi32 = 0;
23489 -       
23490 +
23491         if (BZ_STREAM_END != BZ2_bzCompress(&bz, BZ_FINISH)) {
23492                 BZ2_bzCompressEnd(&bz);
23493                 return -1;
23494         }
23495 -       
23496 +
23497         /* file is too large for now */
23498         if (bz.total_out_hi32) return -1;
23499 -       
23500 +
23501         /* trailer */
23502         p->b->used = bz.total_out_lo32;
23503 -       
23504 +
23505         if (BZ_OK != BZ2_bzCompressEnd(&bz)) {
23506                 return -1;
23507         }
23508 -       
23509 +
23510         return 0;
23511  }
23512  #endif
23513 @@ -326,47 +356,50 @@
23514         void *start;
23515         const char *filename = fn->ptr;
23516         ssize_t r;
23517 -       
23518 +       stat_cache_entry *compressed_sce = NULL;
23519 +
23520 +       if (buffer_is_empty(p->conf.compress_cache_dir)) return -1;
23521 +
23522         /* overflow */
23523         if ((off_t)(sce->st.st_size * 1.1) < sce->st.st_size) return -1;
23524 -       
23525 -       /* don't mmap files > 128Mb 
23526 -        * 
23527 +
23528 +       /* don't mmap files > 128Mb
23529 +        *
23530          * we could use a sliding window, but currently there is no need for it
23531          */
23532 -       
23533 +
23534         if (sce->st.st_size > 128 * 1024 * 1024) return -1;
23535 -       
23536 +
23537         buffer_reset(p->ofn);
23538         buffer_copy_string_buffer(p->ofn, p->conf.compress_cache_dir);
23539 -       BUFFER_APPEND_SLASH(p->ofn);
23540 -       
23541 +       PATHNAME_APPEND_SLASH(p->ofn);
23542 +
23543         if (0 == strncmp(con->physical.path->ptr, con->physical.doc_root->ptr, con->physical.doc_root->used-1)) {
23544                 size_t offset = p->ofn->used - 1;
23545                 char *dir, *nextdir;
23546 -               
23547 +
23548                 buffer_append_string(p->ofn, con->physical.path->ptr + con->physical.doc_root->used - 1);
23549 -               
23550 +
23551                 buffer_copy_string_buffer(p->b, p->ofn);
23552 -               
23553 +
23554                 /* mkdir -p ... */
23555                 for (dir = p->b->ptr + offset; NULL != (nextdir = strchr(dir, '/')); dir = nextdir + 1) {
23556                         *nextdir = '\0';
23557 -                       
23558 +
23559                         if (-1 == mkdir(p->b->ptr, 0700)) {
23560                                 if (errno != EEXIST) {
23561                                         log_error_write(srv, __FILE__, __LINE__, "sbss", "creating cache-directory", p->b, "failed", strerror(errno));
23562 -                                       
23563 +
23564                                         return -1;
23565                                 }
23566                         }
23567 -                       
23568 +
23569                         *nextdir = '/';
23570                 }
23571         } else {
23572                 buffer_append_string_buffer(p->ofn, con->uri.path);
23573         }
23574 -       
23575 +
23576         switch(type) {
23577         case HTTP_ACCEPT_ENCODING_GZIP:
23578                 buffer_append_string(p->ofn, "-gzip-");
23579 @@ -381,55 +414,64 @@
23580                 log_error_write(srv, __FILE__, __LINE__, "sd", "unknown compression type", type);
23581                 return -1;
23582         }
23583 -       
23584 +
23585         buffer_append_string_buffer(p->ofn, sce->etag);
23586 -       
23587 +
23588 +
23589 +       if (HANDLER_ERROR != stat_cache_get_entry(srv, con, p->ofn, &compressed_sce)) {
23590 +               /* file exists */
23591 +
23592 +               chunkqueue_append_file(con->send_raw, p->ofn, 0, compressed_sce->st.st_size);
23593 +               con->send->is_closed = 1;
23594 +
23595 +               return 0;
23596 +       }
23597 +
23598         if (-1 == (ofd = open(p->ofn->ptr, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0600))) {
23599                 if (errno == EEXIST) {
23600                         /* cache-entry exists */
23601 -#if 0
23602 -                       log_error_write(srv, __FILE__, __LINE__, "bs", p->ofn, "compress-cache hit");
23603 -#endif
23604 -                       buffer_copy_string_buffer(con->physical.path, p->ofn);
23605 -                       
23606 -                       return 0;
23607 +
23608                 }
23609 -               
23610 -               log_error_write(srv, __FILE__, __LINE__, "sbss", "creating cachefile", p->ofn, "failed", strerror(errno));
23611 -               
23612 +
23613 +               log_error_write(srv, __FILE__, __LINE__, "sbss",
23614 +                               "creating cachefile", p->ofn,
23615 +                               "failed", strerror(errno));
23616 +
23617                 return -1;
23618         }
23619 -#if 0
23620 -       log_error_write(srv, __FILE__, __LINE__, "bs", p->ofn, "compress-cache miss");
23621 -#endif 
23622 +
23623         if (-1 == (ifd = open(filename, O_RDONLY | O_BINARY))) {
23624 -               log_error_write(srv, __FILE__, __LINE__, "sbss", "opening plain-file", fn, "failed", strerror(errno));
23625 -               
23626 +               log_error_write(srv, __FILE__, __LINE__, "sbss",
23627 +                               "opening plain-file", fn,
23628 +                               "failed", strerror(errno));
23629 +
23630                 close(ofd);
23631 -               
23632 +
23633                 return -1;
23634         }
23635 -       
23636 -       
23637 +
23638 +
23639         if (MAP_FAILED == (start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
23640 -               log_error_write(srv, __FILE__, __LINE__, "sbss", "mmaping", fn, "failed", strerror(errno));
23641 -               
23642 +               log_error_write(srv, __FILE__, __LINE__, "sbss",
23643 +                               "mmaping", fn,
23644 +                               "failed", strerror(errno));
23645 +
23646                 close(ofd);
23647                 close(ifd);
23648                 return -1;
23649         }
23650 -       
23651 +
23652         switch(type) {
23653  #ifdef USE_ZLIB
23654 -       case HTTP_ACCEPT_ENCODING_GZIP: 
23655 +       case HTTP_ACCEPT_ENCODING_GZIP:
23656                 ret = deflate_file_to_buffer_gzip(srv, con, p, start, sce->st.st_size, sce->st.st_mtime);
23657                 break;
23658 -       case HTTP_ACCEPT_ENCODING_DEFLATE: 
23659 +       case HTTP_ACCEPT_ENCODING_DEFLATE:
23660                 ret = deflate_file_to_buffer_deflate(srv, con, p, start, sce->st.st_size);
23661                 break;
23662  #endif
23663  #ifdef USE_BZ2LIB
23664 -       case HTTP_ACCEPT_ENCODING_BZIP2: 
23665 +       case HTTP_ACCEPT_ENCODING_BZIP2:
23666                 ret = deflate_file_to_buffer_bzip2(srv, con, p, start, sce->st.st_size);
23667                 break;
23668  #endif
23669 @@ -437,26 +479,27 @@
23670                 ret = -1;
23671                 break;
23672         }
23673 -       
23674 +
23675         if (-1 == (r = write(ofd, p->b->ptr, p->b->used))) {
23676 -               munmap(start, sce->st.st_size); 
23677 +               munmap(start, sce->st.st_size);
23678                 close(ofd);
23679                 close(ifd);
23680                 return -1;
23681         }
23682 -       
23683 +
23684         if ((size_t)r != p->b->used) {
23685 -               
23686 +
23687         }
23688 -               
23689 +
23690         munmap(start, sce->st.st_size);
23691         close(ofd);
23692         close(ifd);
23693 -       
23694 +
23695         if (ret != 0) return -1;
23696 -       
23697 -       buffer_copy_string_buffer(con->physical.path, p->ofn);
23698 -       
23699 +
23700 +       chunkqueue_append_file(con->send_raw, p->ofn, 0, r);
23701 +       con->send->is_closed = 1;
23702 +
23703         return 0;
23704  }
23705  
23706 @@ -465,43 +508,44 @@
23707         int ret = -1;
23708         void *start;
23709         buffer *b;
23710 -       
23711 +
23712         /* overflow */
23713         if ((off_t)(sce->st.st_size * 1.1) < sce->st.st_size) return -1;
23714 -       
23715 +
23716         /* don't mmap files > 128M
23717 -        * 
23718 +        *
23719          * we could use a sliding window, but currently there is no need for it
23720          */
23721 -       
23722 +
23723         if (sce->st.st_size > 128 * 1024 * 1024) return -1;
23724 -       
23725 -       
23726 +
23727         if (-1 == (ifd = open(fn->ptr, O_RDONLY | O_BINARY))) {
23728                 log_error_write(srv, __FILE__, __LINE__, "sbss", "opening plain-file", fn, "failed", strerror(errno));
23729 -               
23730 +
23731                 return -1;
23732         }
23733 -       
23734 -       
23735 -       if (MAP_FAILED == (start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
23736 +
23737 +       start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0);
23738 +
23739 +       close(ifd);
23740 +
23741 +       if (MAP_FAILED == start) {
23742                 log_error_write(srv, __FILE__, __LINE__, "sbss", "mmaping", fn, "failed", strerror(errno));
23743 -               
23744 -               close(ifd);
23745 +
23746                 return -1;
23747         }
23748 -       
23749 +
23750         switch(type) {
23751  #ifdef USE_ZLIB
23752 -       case HTTP_ACCEPT_ENCODING_GZIP: 
23753 +       case HTTP_ACCEPT_ENCODING_GZIP:
23754                 ret = deflate_file_to_buffer_gzip(srv, con, p, start, sce->st.st_size, sce->st.st_mtime);
23755                 break;
23756 -       case HTTP_ACCEPT_ENCODING_DEFLATE: 
23757 +       case HTTP_ACCEPT_ENCODING_DEFLATE:
23758                 ret = deflate_file_to_buffer_deflate(srv, con, p, start, sce->st.st_size);
23759                 break;
23760  #endif
23761  #ifdef USE_BZ2LIB
23762 -       case HTTP_ACCEPT_ENCODING_BZIP2: 
23763 +       case HTTP_ACCEPT_ENCODING_BZIP2:
23764                 ret = deflate_file_to_buffer_bzip2(srv, con, p, start, sce->st.st_size);
23765                 break;
23766  #endif
23767 @@ -509,69 +553,64 @@
23768                 ret = -1;
23769                 break;
23770         }
23771 -               
23772 +
23773         munmap(start, sce->st.st_size);
23774 -       close(ifd);
23775 -       
23776 +
23777         if (ret != 0) return -1;
23778 -       
23779 -       chunkqueue_reset(con->write_queue);
23780 -       b = chunkqueue_get_append_buffer(con->write_queue);
23781 +
23782 +       chunkqueue_reset(con->send);
23783 +       b = chunkqueue_get_append_buffer(con->send);
23784         buffer_copy_memory(b, p->b->ptr, p->b->used + 1);
23785 -       
23786 +
23787         buffer_reset(con->physical.path);
23788 -       
23789 -       con->file_finished = 1;
23790 +
23791 +       con->send->is_closed = 1;
23792         con->file_started  = 1;
23793 -       
23794 +
23795         return 0;
23796  }
23797  
23798 -
23799 -#define PATCH(x) \
23800 -       p->conf.x = s->x;
23801  static int mod_compress_patch_connection(server *srv, connection *con, plugin_data *p) {
23802         size_t i, j;
23803         plugin_config *s = p->config_storage[0];
23804  
23805 -       PATCH(compress_cache_dir);
23806 -       PATCH(compress);
23807 -       PATCH(compress_max_filesize);
23808 -       
23809 +       PATCH_OPTION(compress_cache_dir);
23810 +       PATCH_OPTION(compress);
23811 +       PATCH_OPTION(compress_max_filesize);
23812 +
23813         /* skip the first, the global context */
23814         for (i = 1; i < srv->config_context->used; i++) {
23815                 data_config *dc = (data_config *)srv->config_context->data[i];
23816                 s = p->config_storage[i];
23817 -               
23818 +
23819                 /* condition didn't match */
23820                 if (!config_check_cond(srv, con, dc)) continue;
23821 -               
23822 +
23823                 /* merge config */
23824                 for (j = 0; j < dc->value->used; j++) {
23825                         data_unset *du = dc->value->data[j];
23826 -                       
23827 +
23828                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.cache-dir"))) {
23829 -                               PATCH(compress_cache_dir);
23830 +                               PATCH_OPTION(compress_cache_dir);
23831                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.filetype"))) {
23832 -                               PATCH(compress);
23833 +                               PATCH_OPTION(compress);
23834                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.max-filesize"))) {
23835 -                               PATCH(compress_max_filesize);
23836 +                               PATCH_OPTION(compress_max_filesize);
23837                         }
23838                 }
23839         }
23840 -       
23841 +
23842         return 0;
23843  }
23844 -#undef PATCH
23845  
23846  PHYSICALPATH_FUNC(mod_compress_physical) {
23847         plugin_data *p = p_d;
23848         size_t m;
23849         off_t max_fsize;
23850         stat_cache_entry *sce = NULL;
23851 -       
23852 +
23853         /* only GET and POST can get compressed */
23854 -       if (con->request.http_method != HTTP_METHOD_GET && 
23855 +       if (con->request.http_method != HTTP_METHOD_GET &&
23856             con->request.http_method != HTTP_METHOD_POST) {
23857                 return HANDLER_GO_ON;
23858         }
23859 @@ -579,46 +618,49 @@
23860         if (buffer_is_empty(con->physical.path)) {
23861                 return HANDLER_GO_ON;
23862         }
23863 -       
23864 +
23865         mod_compress_patch_connection(srv, con, p);
23866 -       
23867 +
23868         max_fsize = p->conf.compress_max_filesize;
23869  
23870         stat_cache_get_entry(srv, con, con->physical.path, &sce);
23871  
23872         /* don't compress files that are too large as we need to much time to handle them */
23873         if (max_fsize && (sce->st.st_size >> 10) > max_fsize) return HANDLER_GO_ON;
23874 -               
23875 +
23876 +       /* compressing the file might lead to larger files instead */
23877 +       if (sce->st.st_size < 128) return HANDLER_GO_ON;
23878 +
23879         /* check if mimetype is in compress-config */
23880         for (m = 0; m < p->conf.compress->used; m++) {
23881                 data_string *compress_ds = (data_string *)p->conf.compress->data[m];
23882 -                       
23883 +
23884                 if (!compress_ds) {
23885                         log_error_write(srv, __FILE__, __LINE__, "sbb", "evil", con->physical.path, con->uri.path);
23886 -                       
23887 +
23888                         return HANDLER_GO_ON;
23889                 }
23890 -               
23891 +
23892                 if (buffer_is_equal(compress_ds->value, sce->content_type)) {
23893                         /* mimetype found */
23894                         data_string *ds;
23895 -                               
23896 +
23897                         /* the response might change according to Accept-Encoding */
23898                         response_header_insert(srv, con, CONST_STR_LEN("Vary"), CONST_STR_LEN("Accept-Encoding"));
23899 -                               
23900 +
23901                         if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Accept-Encoding"))) {
23902                                 int accept_encoding = 0;
23903                                 char *value = ds->value->ptr;
23904                                 int srv_encodings = 0;
23905                                 int matched_encodings = 0;
23906 -                               
23907 +
23908                                 /* get client side support encodings */
23909                                 if (NULL != strstr(value, "gzip")) accept_encoding |= HTTP_ACCEPT_ENCODING_GZIP;
23910                                 if (NULL != strstr(value, "deflate")) accept_encoding |= HTTP_ACCEPT_ENCODING_DEFLATE;
23911                                 if (NULL != strstr(value, "compress")) accept_encoding |= HTTP_ACCEPT_ENCODING_COMPRESS;
23912                                 if (NULL != strstr(value, "bzip2")) accept_encoding |= HTTP_ACCEPT_ENCODING_BZIP2;
23913                                 if (NULL != strstr(value, "identity")) accept_encoding |= HTTP_ACCEPT_ENCODING_IDENTITY;
23914 -                               
23915 +
23916                                 /* get server side supported ones */
23917  #ifdef USE_BZ2LIB
23918                                 srv_encodings |= HTTP_ACCEPT_ENCODING_BZIP2;
23919 @@ -627,18 +669,31 @@
23920                                 srv_encodings |= HTTP_ACCEPT_ENCODING_GZIP;
23921                                 srv_encodings |= HTTP_ACCEPT_ENCODING_DEFLATE;
23922  #endif
23923 -                               
23924 +
23925                                 /* find matching entries */
23926                                 matched_encodings = accept_encoding & srv_encodings;
23927 -                               
23928 +
23929                                 if (matched_encodings) {
23930                                         const char *dflt_gzip = "gzip";
23931                                         const char *dflt_deflate = "deflate";
23932                                         const char *dflt_bzip2 = "bzip2";
23933 -                                       
23934 +
23935                                         const char *compression_name = NULL;
23936                                         int compression_type = 0;
23937 -                                       
23938 +                                       buffer *mtime;
23939 +
23940 +                                       mtime = strftime_cache_get(srv, sce->st.st_mtime);
23941 +                                       etag_mutate(con->physical.etag, sce->etag);
23942 +
23943 +                                       response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
23944 +                                       response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
23945 +
23946 +                                       /* perhaps we don't even have to compress the file as the browser still has the
23947 +                                        * current version */
23948 +                                       if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) {
23949 +                                               return HANDLER_FINISHED;
23950 +                                       }
23951 +
23952                                         /* select best matching encoding */
23953                                         if (matched_encodings & HTTP_ACCEPT_ENCODING_BZIP2) {
23954                                                 compression_type = HTTP_ACCEPT_ENCODING_BZIP2;
23955 @@ -650,31 +705,21 @@
23956                                                 compression_type = HTTP_ACCEPT_ENCODING_DEFLATE;
23957                                                 compression_name = dflt_deflate;
23958                                         }
23959 -                                       
23960 -                                       /* deflate it */
23961 -                                       if (p->conf.compress_cache_dir->used) {
23962 -                                               if (0 == deflate_file_to_file(srv, con, p,
23963 -                                                                             con->physical.path, sce, compression_type)) {
23964 -                                                       buffer *mtime;
23965 -                                                       
23966 -                                                       response_header_overwrite(srv, con, CONST_STR_LEN("Content-Encoding"), compression_name, strlen(compression_name));
23967 -                                                       
23968 -                                                       mtime = strftime_cache_get(srv, sce->st.st_mtime);
23969 -                                                       response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
23970 -
23971 -                                                       etag_mutate(con->physical.etag, sce->etag);
23972 -                                                       response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
23973 -
23974 -                                                       response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
23975 -
23976 -                                                       return HANDLER_GO_ON;
23977 -                                               }
23978 -                                       } else if (0 == deflate_file_to_buffer(srv, con, p,
23979 -                                                                              con->physical.path, sce, compression_type)) {
23980 -                                                       
23981 -                                               response_header_overwrite(srv, con, CONST_STR_LEN("Content-Encoding"), compression_name, strlen(compression_name));
23982 -                                               response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
23983 -                                               
23984 +
23985 +                                       /* deflate it to file (cached) or to memory */
23986 +                                       if (0 == deflate_file_to_file(srv, con, p,
23987 +                                                       con->physical.path, sce, compression_type) ||
23988 +                                           0 == deflate_file_to_buffer(srv, con, p,
23989 +                                                       con->physical.path, sce, compression_type)) {
23990 +
23991 +                                               response_header_overwrite(srv, con,
23992 +                                                               CONST_STR_LEN("Content-Encoding"),
23993 +                                                               compression_name, strlen(compression_name));
23994 +
23995 +                                               response_header_overwrite(srv, con,
23996 +                                                               CONST_STR_LEN("Content-Type"),
23997 +                                                               CONST_BUF_LEN(sce->content_type));
23998 +
23999                                                 return HANDLER_FINISHED;
24000                                         }
24001                                         break;
24002 @@ -682,20 +727,23 @@
24003                         }
24004                 }
24005         }
24006 -       
24007 +
24008         return HANDLER_GO_ON;
24009  }
24010  
24011  int mod_compress_plugin_init(plugin *p) {
24012         p->version     = LIGHTTPD_VERSION_ID;
24013         p->name        = buffer_init_string("compress");
24014 -       
24015 +
24016         p->init        = mod_compress_init;
24017         p->set_defaults = mod_compress_setdefaults;
24018 -       p->handle_subrequest_start  = mod_compress_physical;
24019 +
24020 +       /* we have to hook into the response-header settings */
24021 +       p->handle_response_header  = mod_compress_physical;
24022 +
24023         p->cleanup     = mod_compress_free;
24024 -       
24025 +
24026         p->data        = NULL;
24027 -       
24028 +
24029         return 0;
24030  }
24031 --- ../lighttpd-1.4.11/src/mod_dirlisting.c     2006-01-13 00:00:45.000000000 +0200
24032 +++ lighttpd-1.5.0/src/mod_dirlisting.c 2006-09-07 00:57:05.000000000 +0300
24033 @@ -1,11 +1,9 @@
24034  #include <ctype.h>
24035  #include <stdlib.h>
24036  #include <string.h>
24037 -#include <dirent.h>
24038  #include <assert.h>
24039  #include <errno.h>
24040  #include <stdio.h>
24041 -#include <unistd.h>
24042  #include <time.h>
24043  
24044  #include "base.h"
24045 @@ -17,6 +15,9 @@
24046  #include "response.h"
24047  #include "stat_cache.h"
24048  #include "stream.h"
24049 +#include "etag.h"
24050 +
24051 +#include "sys-strings.h"
24052  
24053  /**
24054   * this is a dirlisting for a lighttpd plugin
24055 @@ -27,10 +28,13 @@
24056  #include <sys/syslimits.h>
24057  #endif
24058  
24059 -#ifdef HAVE_ATTR_ATTRIBUTES_H
24060 +#ifdef HAVE_XATTR
24061  #include <attr/attributes.h>
24062  #endif
24063  
24064 +#include "sys-files.h"
24065 +#include "sys-strings.h"
24066 +
24067  /* plugin config for all request/connections */
24068  
24069  typedef struct {
24070 @@ -54,7 +58,7 @@
24071         unsigned short hide_readme_file;
24072         unsigned short show_header;
24073         unsigned short hide_header_file;
24074 -       
24075 +
24076         excludes_buffer *excludes;
24077  
24078         buffer *external_css;
24079 @@ -63,13 +67,14 @@
24080  
24081  typedef struct {
24082         PLUGIN_DATA;
24083 -       
24084 +
24085         buffer *tmp_buf;
24086         buffer *content_charset;
24087 -       
24088 +       buffer *path;
24089 +
24090         plugin_config **config_storage;
24091 -       
24092 -       plugin_config conf; 
24093 +
24094 +       plugin_config conf;
24095  } plugin_data;
24096  
24097  excludes_buffer *excludes_buffer_init(void) {
24098 @@ -146,44 +151,46 @@
24099  /* init the plugin data */
24100  INIT_FUNC(mod_dirlisting_init) {
24101         plugin_data *p;
24102 -       
24103 +
24104         p = calloc(1, sizeof(*p));
24105  
24106         p->tmp_buf = buffer_init();
24107         p->content_charset = buffer_init();
24108 -       
24109 +       p->path = buffer_init();
24110 +
24111         return p;
24112  }
24113  
24114  /* detroy the plugin data */
24115  FREE_FUNC(mod_dirlisting_free) {
24116         plugin_data *p = p_d;
24117 -       
24118 +
24119         UNUSED(srv);
24120  
24121         if (!p) return HANDLER_GO_ON;
24122 -       
24123 +
24124         if (p->config_storage) {
24125                 size_t i;
24126                 for (i = 0; i < srv->config_context->used; i++) {
24127                         plugin_config *s = p->config_storage[i];
24128 -                       
24129 +
24130                         if (!s) continue;
24131 -                       
24132 +
24133                         excludes_buffer_free(s->excludes);
24134                         buffer_free(s->external_css);
24135                         buffer_free(s->encoding);
24136 -                       
24137 +
24138                         free(s);
24139                 }
24140                 free(p->config_storage);
24141         }
24142 -       
24143 +
24144         buffer_free(p->tmp_buf);
24145 +       buffer_free(p->path);
24146         buffer_free(p->content_charset);
24147 -       
24148 +
24149         free(p);
24150 -       
24151 +
24152         return HANDLER_GO_ON;
24153  }
24154  
24155 @@ -215,10 +222,10 @@
24156                         if (0 != excludes_buffer_append(s->excludes,
24157                                     ((data_string *)(da->value->data[j]))->value)) {
24158  #ifdef HAVE_PCRE_H
24159 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
24160 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
24161                                                 "pcre-compile failed for", ((data_string *)(da->value->data[j]))->value);
24162  #else
24163 -                               log_error_write(srv, __FILE__, __LINE__, "s", 
24164 +                               log_error_write(srv, __FILE__, __LINE__, "s",
24165                                                 "pcre support is missing, please install libpcre and the headers");
24166  #endif
24167                         }
24168 @@ -233,8 +240,8 @@
24169  SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) {
24170         plugin_data *p = p_d;
24171         size_t i = 0;
24172 -       
24173 -       config_values_t cv[] = { 
24174 +
24175 +       config_values_t cv[] = {
24176                 { "dir-listing.exclude",          NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION },   /* 0 */
24177                 { "dir-listing.activate",         NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
24178                 { "dir-listing.hide-dotfiles",    NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
24179 @@ -245,18 +252,18 @@
24180                 { "dir-listing.show-header",      NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
24181                 { "dir-listing.hide-header-file", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
24182                 { "server.dir-listing",           NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 9 */
24183 -               
24184 +
24185                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
24186         };
24187 -       
24188 +
24189         if (!p) return HANDLER_ERROR;
24190 -       
24191 +
24192         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
24193 -       
24194 +
24195         for (i = 0; i < srv->config_context->used; i++) {
24196                 plugin_config *s;
24197                 array *ca;
24198 -               
24199 +
24200                 s = calloc(1, sizeof(plugin_config));
24201                 s->excludes = excludes_buffer_init();
24202                 s->dir_listing = 0;
24203 @@ -267,7 +274,7 @@
24204                 s->show_header = 0;
24205                 s->hide_header_file = 0;
24206                 s->encoding = buffer_init();
24207 -               
24208 +
24209                 cv[0].destination = s->excludes;
24210                 cv[1].destination = &(s->dir_listing);
24211                 cv[2].destination = &(s->hide_dot_files);
24212 @@ -292,60 +299,57 @@
24213         return HANDLER_GO_ON;
24214  }
24215  
24216 -#define PATCH(x) \
24217 -       p->conf.x = s->x;
24218  static int mod_dirlisting_patch_connection(server *srv, connection *con, plugin_data *p) {
24219         size_t i, j;
24220         plugin_config *s = p->config_storage[0];
24221  
24222 -       PATCH(dir_listing);
24223 -       PATCH(external_css);
24224 -       PATCH(hide_dot_files);
24225 -       PATCH(encoding);
24226 -       PATCH(show_readme);
24227 -       PATCH(hide_readme_file);
24228 -       PATCH(show_header);
24229 -       PATCH(hide_header_file);
24230 -       PATCH(excludes);
24231 -       
24232 +       PATCH_OPTION(dir_listing);
24233 +       PATCH_OPTION(external_css);
24234 +       PATCH_OPTION(hide_dot_files);
24235 +       PATCH_OPTION(encoding);
24236 +       PATCH_OPTION(show_readme);
24237 +       PATCH_OPTION(hide_readme_file);
24238 +       PATCH_OPTION(show_header);
24239 +       PATCH_OPTION(hide_header_file);
24240 +       PATCH_OPTION(excludes);
24241 +
24242         /* skip the first, the global context */
24243         for (i = 1; i < srv->config_context->used; i++) {
24244                 data_config *dc = (data_config *)srv->config_context->data[i];
24245                 s = p->config_storage[i];
24246 -               
24247 +
24248                 /* condition didn't match */
24249                 if (!config_check_cond(srv, con, dc)) continue;
24250 -               
24251 +
24252                 /* merge config */
24253                 for (j = 0; j < dc->value->used; j++) {
24254                         data_unset *du = dc->value->data[j];
24255 -                       
24256 +
24257                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.activate")) ||
24258                             buffer_is_equal_string(du->key, CONST_STR_LEN("server.dir-listing"))) {
24259 -                               PATCH(dir_listing);
24260 +                               PATCH_OPTION(dir_listing);
24261                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.hide-dotfiles"))) {
24262 -                               PATCH(hide_dot_files);
24263 +                               PATCH_OPTION(hide_dot_files);
24264                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.external-css"))) {
24265 -                               PATCH(external_css);
24266 +                               PATCH_OPTION(external_css);
24267                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.encoding"))) {
24268 -                               PATCH(encoding);
24269 +                               PATCH_OPTION(encoding);
24270                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.show-readme"))) {
24271 -                               PATCH(show_readme);
24272 +                               PATCH_OPTION(show_readme);
24273                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.hide-readme-file"))) {
24274 -                               PATCH(hide_readme_file);
24275 +                               PATCH_OPTION(hide_readme_file);
24276                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.show-header"))) {
24277 -                               PATCH(show_header);
24278 +                               PATCH_OPTION(show_header);
24279                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.hide-header-file"))) {
24280 -                               PATCH(hide_header_file);
24281 +                               PATCH_OPTION(hide_header_file);
24282                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.excludes"))) {
24283 -                               PATCH(excludes);
24284 +                               PATCH_OPTION(excludes);
24285                         }
24286                 }
24287         }
24288 -       
24289 +
24290         return 0;
24291  }
24292 -#undef PATCH
24293  
24294  typedef struct {
24295         size_t  namelen;
24296 @@ -432,7 +436,7 @@
24297  
24298  static void http_list_directory_header(server *srv, connection *con, plugin_data *p, buffer *out) {
24299         UNUSED(srv);
24300 -       
24301 +
24302         BUFFER_APPEND_STRING_CONST(out,
24303                 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
24304                 "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n"
24305 @@ -492,11 +496,11 @@
24306         if (p->conf.show_header) {
24307                 stream s;
24308                 /* if we have a HEADER file, display it in <pre class="header"></pre> */
24309 -               
24310 +
24311                 buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
24312 -               BUFFER_APPEND_SLASH(p->tmp_buf);
24313 +               PATHNAME_APPEND_SLASH(p->tmp_buf);
24314                 BUFFER_APPEND_STRING_CONST(p->tmp_buf, "HEADER.txt");
24315 -               
24316 +
24317                 if (-1 != stream_open(&s, p->tmp_buf)) {
24318                         BUFFER_APPEND_STRING_CONST(out, "<pre class=\"header\">");
24319                         buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML);
24320 @@ -531,21 +535,21 @@
24321  
24322  static void http_list_directory_footer(server *srv, connection *con, plugin_data *p, buffer *out) {
24323         UNUSED(srv);
24324 -       
24325 +
24326         BUFFER_APPEND_STRING_CONST(out,
24327                 "</tbody>\n"
24328                 "</table>\n"
24329                 "</div>\n"
24330         );
24331 -       
24332 +
24333         if (p->conf.show_readme) {
24334                 stream s;
24335                 /* if we have a README file, display it in <pre class="readme"></pre> */
24336 -               
24337 +
24338                 buffer_copy_string_buffer(p->tmp_buf,  con->physical.path);
24339 -               BUFFER_APPEND_SLASH(p->tmp_buf);
24340 +               PATHNAME_APPEND_SLASH(p->tmp_buf);
24341                 BUFFER_APPEND_STRING_CONST(p->tmp_buf, "README.txt");
24342 -               
24343 +
24344                 if (-1 != stream_open(&s, p->tmp_buf)) {
24345                         BUFFER_APPEND_STRING_CONST(out, "<pre class=\"readme\">");
24346                         buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML);
24347 @@ -553,7 +557,7 @@
24348                 }
24349                 stream_close(&s);
24350         }
24351 -       
24352 +
24353         BUFFER_APPEND_STRING_CONST(out,
24354                 "<div class=\"foot\">"
24355         );
24356 @@ -576,7 +580,6 @@
24357         buffer *out;
24358         struct dirent *dent;
24359         struct stat st;
24360 -       char *path, *path_file;
24361         size_t i;
24362         int hide_dotfiles = p->conf.hide_dot_files;
24363         dirls_list_t dirs, files, *list;
24364 @@ -586,6 +589,7 @@
24365         size_t k;
24366         const char *content_type;
24367         long name_max;
24368 +
24369  #ifdef HAVE_XATTR
24370         char attrval[128];
24371         int attrlen;
24372 @@ -594,10 +598,10 @@
24373         struct tm tm;
24374  #endif
24375  
24376 -       if (dir->used == 0) return -1;
24377 -       
24378 -       i = dir->used - 1;
24379 +       /* empty pathname, never ... */
24380 +       if (buffer_is_empty(dir)) return -1;
24381  
24382 +       /* max-length for the opendir */
24383  #ifdef HAVE_PATHCONF
24384         if (-1 == (name_max = pathconf(dir->ptr, _PC_NAME_MAX))) {
24385  #ifdef NAME_MAX
24386 @@ -606,22 +610,24 @@
24387                 name_max = 256; /* stupid default */
24388  #endif
24389         }
24390 -#elif defined __WIN32
24391 +#elif defined _WIN32
24392         name_max = FILENAME_MAX;
24393  #else
24394         name_max = NAME_MAX;
24395  #endif
24396 -       
24397 -       path = malloc(dir->used + name_max);
24398 -       assert(path);
24399 -       strcpy(path, dir->ptr);
24400 -       path_file = path + i;
24401  
24402 -       if (NULL == (dp = opendir(path))) {
24403 -               log_error_write(srv, __FILE__, __LINE__, "sbs", 
24404 +       buffer_copy_string_buffer(p->path, dir);
24405 +       PATHNAME_APPEND_SLASH(p->path);
24406 +
24407 +#ifdef _WIN32
24408 +       /* append *.* to the path */
24409 +       buffer_append_string(path, "*.*");
24410 +#endif
24411 +
24412 +       if (NULL == (dp = opendir(p->path->ptr))) {
24413 +               log_error_write(srv, __FILE__, __LINE__, "sbs",
24414                         "opendir failed:", dir, strerror(errno));
24415  
24416 -               free(path);
24417                 return -1;
24418         }
24419  
24420 @@ -633,7 +639,7 @@
24421         assert(files.ent);
24422         files.size = DIRLIST_BLOB_SIZE;
24423         files.used = 0;
24424 -       
24425 +
24426         while ((dent = readdir(dp)) != NULL) {
24427                 unsigned short exclude_match = 0;
24428  
24429 @@ -686,15 +692,21 @@
24430  #endif
24431  
24432                 i = strlen(dent->d_name);
24433 -               
24434 +
24435                 /* NOTE: the manual says, d_name is never more than NAME_MAX
24436                  *       so this should actually not be a buffer-overflow-risk
24437                  */
24438                 if (i > (size_t)name_max) continue;
24439 -               
24440 -               memcpy(path_file, dent->d_name, i + 1);
24441 -               if (stat(path, &st) != 0)
24442 +
24443 +               /* build the dirname */
24444 +               buffer_copy_string_buffer(p->path, dir);
24445 +               PATHNAME_APPEND_SLASH(p->path);
24446 +               buffer_append_string(p->path, dent->d_name);
24447 +
24448 +               if (stat(p->path->ptr, &st) != 0) {
24449 +                       fprintf(stderr, "%s.%d: %s, %s\r\n", __FILE__, __LINE__, p->path->ptr, strerror(errno));
24450                         continue;
24451 +               }
24452  
24453                 list = &files;
24454                 if (S_ISDIR(st.st_mode))
24455 @@ -720,7 +732,7 @@
24456  
24457         if (files.used) http_dirls_sort(files.ent, files.used);
24458  
24459 -       out = chunkqueue_get_append_buffer(con->write_queue);
24460 +       out = chunkqueue_get_append_buffer(con->send);
24461         BUFFER_COPY_STRING_CONST(out, "<?xml version=\"1.0\" encoding=\"");
24462         if (buffer_is_empty(p->conf.encoding)) {
24463                 BUFFER_APPEND_STRING_CONST(out, "iso-8859-1");
24464 @@ -740,7 +752,7 @@
24465  #else
24466                 strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", localtime(&(tmp->mtime)));
24467  #endif
24468 -               
24469 +
24470                 BUFFER_APPEND_STRING_CONST(out, "<tr><td class=\"n\"><a href=\"");
24471                 buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_REL_URI_PART);
24472                 BUFFER_APPEND_STRING_CONST(out, "/\">");
24473 @@ -757,18 +769,22 @@
24474                 tmp = files.ent[i];
24475  
24476                 content_type = NULL;
24477 +
24478  #ifdef HAVE_XATTR
24479 -               
24480                 if (con->conf.use_xattr) {
24481 -                       memcpy(path_file, DIRLIST_ENT_NAME(tmp), tmp->namelen + 1);
24482 +                       /* build the dirname */
24483 +                       buffer_copy_string_buffer(p->path, dir);
24484 +                       PATHNAME_APPEND_SLASH(p->path);
24485 +                       buffer_append_string_len(p->path, DIRLIST_ENT_NAME(tmp), tmp->namelen);
24486 +
24487                         attrlen = sizeof(attrval) - 1;
24488 -                       if (attr_get(path, "Content-Type", attrval, &attrlen, 0) == 0) {
24489 +                       if (attr_get(p->path->ptr, "Content-Type", attrval, &attrlen, 0) == 0) {
24490                                 attrval[attrlen] = '\0';
24491                                 content_type = attrval;
24492                         }
24493                 }
24494  #endif
24495 -               
24496 +
24497                 if (content_type == NULL) {
24498                         content_type = "application/octet-stream";
24499                         for (k = 0; k < con->conf.mimetypes->used; k++) {
24500 @@ -788,7 +804,7 @@
24501                                 }
24502                         }
24503                 }
24504 -                       
24505 +
24506  #ifdef HAVE_LOCALTIME_R
24507                 localtime_r(&(tmp->mtime), &tm);
24508                 strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", &tm);
24509 @@ -814,7 +830,6 @@
24510  
24511         free(files.ent);
24512         free(dirs.ent);
24513 -       free(path);
24514  
24515         http_list_directory_footer(srv, con, p, out);
24516  
24517 @@ -827,7 +842,7 @@
24518                 response_header_insert(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(p->content_charset));
24519         }
24520  
24521 -       con->file_finished = 1;
24522 +       con->send->is_closed = 1;
24523  
24524         return 0;
24525  }
24526 @@ -837,36 +852,55 @@
24527  URIHANDLER_FUNC(mod_dirlisting_subrequest) {
24528         plugin_data *p = p_d;
24529         stat_cache_entry *sce = NULL;
24530 -       
24531 -       UNUSED(srv);
24532 -       
24533 -       if (con->physical.path->used == 0) return HANDLER_GO_ON;
24534 -       if (con->uri.path->used == 0) return HANDLER_GO_ON;
24535 +       buffer *mtime;
24536 +       data_string *ds;
24537 +
24538 +       if (con->uri.path->used < 2) return HANDLER_GO_ON;
24539         if (con->uri.path->ptr[con->uri.path->used - 2] != '/') return HANDLER_GO_ON;
24540 -       
24541 +       if (con->physical.path->used == 0) return HANDLER_GO_ON;
24542 +
24543         mod_dirlisting_patch_connection(srv, con, p);
24544  
24545         if (!p->conf.dir_listing) return HANDLER_GO_ON;
24546 -       
24547 +
24548 +       if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
24549 +               /* just a second ago the file was still there */
24550 +               return HANDLER_GO_ON;
24551 +       }
24552 +
24553 +       if (!S_ISDIR(sce->st.st_mode)) return HANDLER_GO_ON;
24554 +
24555         if (con->conf.log_request_handling) {
24556                 log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling the request as Dir-Listing");
24557                 log_error_write(srv, __FILE__, __LINE__,  "sb", "URI          :", con->uri.path);
24558         }
24559 -       
24560 -       if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
24561 -               fprintf(stderr, "%s.%d: %s\n", __FILE__, __LINE__, con->physical.path->ptr);
24562 -               SEGFAULT();
24563 +
24564 +       /* perhaps this a cachable request
24565 +        * - we use the etag of the directory
24566 +        * */
24567 +
24568 +       etag_mutate(con->physical.etag, sce->etag);
24569 +       response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
24570 +
24571 +       /* prepare header */
24572 +       if (NULL == (ds = (data_string *)array_get_element(con->response.headers, "Last-Modified"))) {
24573 +               mtime = strftime_cache_get(srv, sce->st.st_mtime);
24574 +               response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
24575 +       } else {
24576 +               mtime = ds->value;
24577         }
24578 -       
24579 -       if (!S_ISDIR(sce->st.st_mode)) return HANDLER_GO_ON;
24580 -       
24581 +
24582 +       if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) {
24583 +               return HANDLER_FINISHED;
24584 +       }
24585 +
24586         if (http_list_directory(srv, con, p, con->physical.path)) {
24587                 /* dirlisting failed */
24588                 con->http_status = 403;
24589         }
24590 -       
24591 +
24592         buffer_reset(con->physical.path);
24593 -       
24594 +
24595         /* not found */
24596         return HANDLER_FINISHED;
24597  }
24598 @@ -876,13 +910,13 @@
24599  int mod_dirlisting_plugin_init(plugin *p) {
24600         p->version     = LIGHTTPD_VERSION_ID;
24601         p->name        = buffer_init_string("dirlisting");
24602 -       
24603 +
24604         p->init        = mod_dirlisting_init;
24605 -       p->handle_subrequest_start  = mod_dirlisting_subrequest;
24606 +       p->handle_start_backend  = mod_dirlisting_subrequest;
24607         p->set_defaults  = mod_dirlisting_set_defaults;
24608         p->cleanup     = mod_dirlisting_free;
24609 -       
24610 +
24611         p->data        = NULL;
24612 -       
24613 +
24614         return 0;
24615  }
24616 --- ../lighttpd-1.4.11/src/mod_evasive.c        2006-01-04 15:24:51.000000000 +0200
24617 +++ lighttpd-1.5.0/src/mod_evasive.c    2006-09-07 00:57:05.000000000 +0300
24618 @@ -31,100 +31,97 @@
24619  
24620  typedef struct {
24621         PLUGIN_DATA;
24622 -       
24623 +
24624         plugin_config **config_storage;
24625 -       
24626 -       plugin_config conf; 
24627 +
24628 +       plugin_config conf;
24629  } plugin_data;
24630  
24631  INIT_FUNC(mod_evasive_init) {
24632         plugin_data *p;
24633 -       
24634 +
24635         p = calloc(1, sizeof(*p));
24636 -       
24637 +
24638         return p;
24639  }
24640  
24641  FREE_FUNC(mod_evasive_free) {
24642         plugin_data *p = p_d;
24643 -       
24644 +
24645         UNUSED(srv);
24646  
24647         if (!p) return HANDLER_GO_ON;
24648 -       
24649 +
24650         if (p->config_storage) {
24651                 size_t i;
24652                 for (i = 0; i < srv->config_context->used; i++) {
24653                         plugin_config *s = p->config_storage[i];
24654 -                                               
24655 +
24656                         free(s);
24657                 }
24658                 free(p->config_storage);
24659         }
24660 -       
24661 +
24662         free(p);
24663 -       
24664 +
24665         return HANDLER_GO_ON;
24666  }
24667  
24668  SETDEFAULTS_FUNC(mod_evasive_set_defaults) {
24669         plugin_data *p = p_d;
24670         size_t i = 0;
24671 -       
24672 -       config_values_t cv[] = { 
24673 +
24674 +       config_values_t cv[] = {
24675                 { "evasive.max-conns-per-ip",    NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
24676                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
24677         };
24678 -       
24679 +
24680         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
24681 -       
24682 +
24683         for (i = 0; i < srv->config_context->used; i++) {
24684                 plugin_config *s;
24685 -               
24686 +
24687                 s = calloc(1, sizeof(plugin_config));
24688                 s->max_conns       = 0;
24689 -               
24690 +
24691                 cv[0].destination = &(s->max_conns);
24692 -               
24693 +
24694                 p->config_storage[i] = s;
24695 -       
24696 +
24697                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
24698                         return HANDLER_ERROR;
24699                 }
24700         }
24701 -       
24702 +
24703         return HANDLER_GO_ON;
24704  }
24705  
24706 -#define PATCH(x) \
24707 -       p->conf.x = s->x;
24708  static int mod_evasive_patch_connection(server *srv, connection *con, plugin_data *p) {
24709         size_t i, j;
24710         plugin_config *s = p->config_storage[0];
24711  
24712 -       PATCH(max_conns);
24713 -       
24714 +       PATCH_OPTION(max_conns);
24715 +
24716         /* skip the first, the global context */
24717         for (i = 1; i < srv->config_context->used; i++) {
24718                 data_config *dc = (data_config *)srv->config_context->data[i];
24719                 s = p->config_storage[i];
24720 -               
24721 +
24722                 /* condition didn't match */
24723                 if (!config_check_cond(srv, con, dc)) continue;
24724 -               
24725 +
24726                 /* merge config */
24727                 for (j = 0; j < dc->value->used; j++) {
24728                         data_unset *du = dc->value->data[j];
24729 -                       
24730 +
24731                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("evasive.max-conns-per-ip"))) {
24732 -                               PATCH(max_conns);
24733 +                               PATCH_OPTION(max_conns);
24734                         }
24735                 }
24736         }
24737 -       
24738 +
24739         return 0;
24740  }
24741 -#undef PATCH
24742  
24743  URIHANDLER_FUNC(mod_evasive_uri_handler) {
24744         plugin_data *p = p_d;
24745 @@ -132,10 +129,10 @@
24746         size_t j;
24747  
24748         if (con->uri.path->used == 0) return HANDLER_GO_ON;
24749 -       
24750 +
24751         mod_evasive_patch_connection(srv, con, p);
24752 -       
24753 -       /* no limit set, nothing to block */    
24754 +
24755 +       /* no limit set, nothing to block */
24756         if (p->conf.max_conns == 0) return HANDLER_GO_ON;
24757  
24758         for (j = 0; j < srv->conns->used; j++) {
24759 @@ -145,9 +142,9 @@
24760                  * we can only ban connections which are already behind the 'read request' state
24761                  * */
24762                 if (c->dst_addr.ipv4.sin_addr.s_addr == con->dst_addr.ipv4.sin_addr.s_addr &&
24763 -                   c->state > CON_STATE_REQUEST_END) {
24764 +                   c->state > CON_STATE_HANDLE_REQUEST_HEADER) {
24765                         conns_by_ip++;
24766 -       
24767 +
24768                         if (conns_by_ip > p->conf.max_conns) {
24769                                 log_error_write(srv, __FILE__, __LINE__, "ss",
24770                                         inet_ntop_cache_get_ip(srv, &(con->dst_addr)),
24771 @@ -158,7 +155,7 @@
24772                         }
24773                 }
24774         }
24775 -       
24776 +
24777         return HANDLER_GO_ON;
24778  }
24779  
24780 @@ -166,13 +163,13 @@
24781  int mod_evasive_plugin_init(plugin *p) {
24782         p->version     = LIGHTTPD_VERSION_ID;
24783         p->name        = buffer_init_string("evasive");
24784 -       
24785 +
24786         p->init        = mod_evasive_init;
24787         p->set_defaults = mod_evasive_set_defaults;
24788         p->handle_uri_clean  = mod_evasive_uri_handler;
24789         p->cleanup     = mod_evasive_free;
24790 -       
24791 +
24792         p->data        = NULL;
24793 -       
24794 +
24795         return 0;
24796  }
24797 --- ../lighttpd-1.4.11/src/mod_evhost.c 2005-08-17 10:42:03.000000000 +0300
24798 +++ lighttpd-1.5.0/src/mod_evhost.c     2006-07-16 00:26:03.000000000 +0300
24799 @@ -7,10 +7,12 @@
24800  #include "response.h"
24801  #include "stat_cache.h"
24802  
24803 +#include "sys-files.h"
24804 +
24805  typedef struct {
24806         /* unparsed pieces */
24807         buffer *path_pieces_raw;
24808 -       
24809 +
24810         /* pieces for path creation */
24811         size_t len;
24812         buffer **path_pieces;
24813 @@ -21,14 +23,14 @@
24814         buffer *tmp_buf;
24815  
24816         plugin_config **config_storage;
24817 -       plugin_config conf; 
24818 +       plugin_config conf;
24819  } plugin_data;
24820  
24821  INIT_FUNC(mod_evhost_init) {
24822         plugin_data *p;
24823 -       
24824 +
24825         p = calloc(1, sizeof(*p));
24826 -       
24827 +
24828         p->tmp_buf = buffer_init();
24829  
24830         return p;
24831 @@ -36,34 +38,34 @@
24832  
24833  FREE_FUNC(mod_evhost_free) {
24834         plugin_data *p = p_d;
24835 -       
24836 +
24837         UNUSED(srv);
24838  
24839         if (!p) return HANDLER_GO_ON;
24840 -       
24841 +
24842         if (p->config_storage) {
24843                 size_t i;
24844                 for (i = 0; i < srv->config_context->used; i++) {
24845                         plugin_config *s = p->config_storage[i];
24846  
24847                         if (!s) continue;
24848 -                       
24849 +
24850                         if(s->path_pieces) {
24851                                 size_t j;
24852                                 for (j = 0; j < s->len; j++) {
24853                                         buffer_free(s->path_pieces[j]);
24854                                 }
24855 -                               
24856 +
24857                                 free(s->path_pieces);
24858                         }
24859 -                       
24860 +
24861                         buffer_free(s->path_pieces_raw);
24862 -                       
24863 +
24864                         free(s);
24865                 }
24866                 free(p->config_storage);
24867         }
24868 -       
24869 +
24870         buffer_free(p->tmp_buf);
24871  
24872         free(p);
24873 @@ -73,30 +75,30 @@
24874  
24875  static void mod_evhost_parse_pattern(plugin_config *s) {
24876         char *ptr = s->path_pieces_raw->ptr,*pos;
24877 -       
24878 +
24879         s->path_pieces = NULL;
24880 -       
24881 +
24882         for(pos=ptr;*ptr;ptr++) {
24883                 if(*ptr == '%') {
24884                         s->path_pieces = realloc(s->path_pieces,(s->len+2) * sizeof(*s->path_pieces));
24885                         s->path_pieces[s->len] = buffer_init();
24886                         s->path_pieces[s->len+1] = buffer_init();
24887 -                       
24888 +
24889                         buffer_copy_string_len(s->path_pieces[s->len],pos,ptr-pos);
24890                         pos = ptr + 2;
24891 -                       
24892 +
24893                         buffer_copy_string_len(s->path_pieces[s->len+1],ptr++,2);
24894 -                       
24895 +
24896                         s->len += 2;
24897                 }
24898         }
24899 -       
24900 +
24901         if(*pos != '\0') {
24902                 s->path_pieces = realloc(s->path_pieces,(s->len+1) * sizeof(*s->path_pieces));
24903                 s->path_pieces[s->len] = buffer_init();
24904 -               
24905 +
24906                 buffer_append_memory(s->path_pieces[s->len],pos,ptr-pos);
24907 -               
24908 +
24909                 s->len += 1;
24910         }
24911  }
24912 @@ -104,9 +106,9 @@
24913  SETDEFAULTS_FUNC(mod_evhost_set_defaults) {
24914         plugin_data *p = p_d;
24915         size_t i;
24916 -       
24917 +
24918         /**
24919 -        * 
24920 +        *
24921          * #
24922          * # define a pattern for the host url finding
24923          * # %% => % sign
24924 @@ -117,39 +119,39 @@
24925          * # %4 => subdomain 2 name
24926          * #
24927          * evhost.path-pattern = "/home/ckruse/dev/www/%3/htdocs/"
24928 -        * 
24929 +        *
24930          */
24931 -       
24932 -       config_values_t cv[] = { 
24933 +
24934 +       config_values_t cv[] = {
24935                 { "evhost.path-pattern",            NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
24936                 { NULL,                             NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
24937         };
24938 -       
24939 +
24940         if (!p) return HANDLER_ERROR;
24941 -       
24942 +
24943         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
24944 -       
24945 +
24946         for (i = 0; i < srv->config_context->used; i++) {
24947                 plugin_config *s;
24948 -               
24949 +
24950                 s = calloc(1, sizeof(plugin_config));
24951                 s->path_pieces_raw = buffer_init();
24952                 s->path_pieces     = NULL;
24953                 s->len             = 0;
24954 -       
24955 +
24956                 cv[0].destination = s->path_pieces_raw;
24957 -               
24958 +
24959                 p->config_storage[i] = s;
24960 -               
24961 +
24962                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value,  cv)) {
24963                         return HANDLER_ERROR;
24964                 }
24965 -               
24966 +
24967                 if (s->path_pieces_raw->used != 0) {
24968                         mod_evhost_parse_pattern(s);
24969                 }
24970         }
24971 -       
24972 +
24973         return HANDLER_GO_ON;
24974  }
24975  
24976 @@ -158,7 +160,7 @@
24977   * - %0 - full hostname (authority w/o port)
24978   * - %1 - tld
24979   * - %2 - domain.tld
24980 - * - %3 - 
24981 + * - %3 -
24982   */
24983  
24984  static int mod_evhost_parse_host(connection *con,array *host) {
24985 @@ -168,7 +170,7 @@
24986         int first = 1;
24987         data_string *ds;
24988         int i;
24989 -       
24990 +
24991         /* first, find the domain + tld */
24992         for(;ptr > con->uri.authority->ptr;ptr--) {
24993                 if(*ptr == '.') {
24994 @@ -179,18 +181,18 @@
24995                         first = 1;
24996                 }
24997         }
24998 -       
24999 +
25000         ds = data_string_init();
25001         buffer_copy_string(ds->key,"%0");
25002 -       
25003 +
25004         /* if we stopped at a dot, skip the dot */
25005         if (*ptr == '.') ptr++;
25006         buffer_copy_string_len(ds->value, ptr, colon-ptr);
25007 -       
25008 +
25009         array_insert_unique(host,(data_unset *)ds);
25010 -       
25011 +
25012         /* if the : is not the start of the authority, go on parsing the hostname */
25013 -       
25014 +
25015         if (colon != con->uri.authority->ptr) {
25016                 for(ptr = colon - 1, i = 1; ptr > con->uri.authority->ptr; ptr--) {
25017                         if(*ptr == '.') {
25018 @@ -200,59 +202,55 @@
25019                                         buffer_copy_string(ds->key,"%");
25020                                         buffer_append_long(ds->key, i++);
25021                                         buffer_copy_string_len(ds->value,ptr+1,colon-ptr-1);
25022 -                                       
25023 +
25024                                         array_insert_unique(host,(data_unset *)ds);
25025                                 }
25026                                 colon = ptr;
25027                         }
25028                 }
25029 -               
25030 +
25031                 /* if the . is not the first charactor of the hostname */
25032                 if (colon != ptr) {
25033                         ds = data_string_init();
25034                         buffer_copy_string(ds->key,"%");
25035                         buffer_append_long(ds->key, i++);
25036                         buffer_copy_string_len(ds->value,ptr,colon-ptr);
25037 -                       
25038 +
25039                         array_insert_unique(host,(data_unset *)ds);
25040                 }
25041         }
25042 -       
25043 +
25044         return 0;
25045  }
25046  
25047 -#define PATCH(x) \
25048 -       p->conf.x = s->x;
25049  static int mod_evhost_patch_connection(server *srv, connection *con, plugin_data *p) {
25050         size_t i, j;
25051         plugin_config *s = p->config_storage[0];
25052 -       
25053 -       PATCH(path_pieces);
25054 -       PATCH(len);
25055 -       
25056 +
25057 +       PATCH_OPTION(path_pieces);
25058 +       PATCH_OPTION(len);
25059 +
25060         /* skip the first, the global context */
25061         for (i = 1; i < srv->config_context->used; i++) {
25062                 data_config *dc = (data_config *)srv->config_context->data[i];
25063                 s = p->config_storage[i];
25064 -               
25065 +
25066                 /* condition didn't match */
25067                 if (!config_check_cond(srv, con, dc)) continue;
25068 -               
25069 +
25070                 /* merge config */
25071                 for (j = 0; j < dc->value->used; j++) {
25072                         data_unset *du = dc->value->data[j];
25073 -                       
25074 +
25075                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("evhost.path-pattern"))) {
25076 -                               PATCH(path_pieces);
25077 -                               PATCH(len);
25078 +                               PATCH_OPTION(path_pieces);
25079 +                               PATCH_OPTION(len);
25080                         }
25081                 }
25082         }
25083 -       
25084 +
25085         return 0;
25086  }
25087 -#undef PATCH
25088 -
25089  
25090  static handler_t mod_evhost_uri_handler(server *srv, connection *con, void *p_d) {
25091         plugin_data *p = p_d;
25092 @@ -261,29 +259,29 @@
25093         register char *ptr;
25094         int not_good = 0;
25095         stat_cache_entry *sce = NULL;
25096 -       
25097 +
25098         /* not authority set */
25099         if (con->uri.authority->used == 0) return HANDLER_GO_ON;
25100 -       
25101 +
25102         mod_evhost_patch_connection(srv, con, p);
25103 -       
25104 +
25105         /* missing even default(global) conf */
25106         if (0 == p->conf.len) {
25107                 return HANDLER_GO_ON;
25108         }
25109  
25110         parsed_host = array_init();
25111 -       
25112 +
25113         mod_evhost_parse_host(con, parsed_host);
25114 -       
25115 +
25116         /* build document-root */
25117         buffer_reset(p->tmp_buf);
25118 -       
25119 +
25120         for (i = 0; i < p->conf.len; i++) {
25121                 ptr = p->conf.path_pieces[i]->ptr;
25122                 if (*ptr == '%') {
25123                         data_string *ds;
25124 -                       
25125 +
25126                         if (*(ptr+1) == '%') {
25127                                 /* %% */
25128                                 BUFFER_APPEND_STRING_CONST(p->tmp_buf,"%");
25129 @@ -298,11 +296,11 @@
25130                         buffer_append_string_buffer(p->tmp_buf,p->conf.path_pieces[i]);
25131                 }
25132         }
25133 -       
25134 -       BUFFER_APPEND_SLASH(p->tmp_buf);
25135 -       
25136 +
25137 +       PATHNAME_APPEND_SLASH(p->tmp_buf);
25138 +
25139         array_free(parsed_host);
25140 -       
25141 +
25142         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
25143                 log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->tmp_buf);
25144                 not_good = 1;
25145 @@ -310,11 +308,11 @@
25146                 log_error_write(srv, __FILE__, __LINE__, "sb", "not a directory:", p->tmp_buf);
25147                 not_good = 1;
25148         }
25149 -       
25150 +
25151         if (!not_good) {
25152                 buffer_copy_string_buffer(con->physical.doc_root, p->tmp_buf);
25153         }
25154 -       
25155 +
25156         return HANDLER_GO_ON;
25157  }
25158  
25159 @@ -325,9 +323,9 @@
25160         p->set_defaults            = mod_evhost_set_defaults;
25161         p->handle_docroot          = mod_evhost_uri_handler;
25162         p->cleanup                 = mod_evhost_free;
25163 -       
25164 +
25165         p->data                    = NULL;
25166 -       
25167 +
25168         return 0;
25169  }
25170  
25171 --- ../lighttpd-1.4.11/src/mod_expire.c 2005-11-03 09:52:13.000000000 +0200
25172 +++ lighttpd-1.5.0/src/mod_expire.c     2006-09-07 00:57:05.000000000 +0300
25173 @@ -12,8 +12,8 @@
25174  #include "stat_cache.h"
25175  
25176  /**
25177 - * this is a expire module for a lighttpd 
25178 - * 
25179 + * this is a expire module for a lighttpd
25180 + *
25181   * set 'Expires:' HTTP Headers on demand
25182   */
25183  
25184 @@ -27,51 +27,51 @@
25185  
25186  typedef struct {
25187         PLUGIN_DATA;
25188 -       
25189 +
25190         buffer *expire_tstmp;
25191 -       
25192 +
25193         plugin_config **config_storage;
25194 -       
25195 -       plugin_config conf; 
25196 +
25197 +       plugin_config conf;
25198  } plugin_data;
25199  
25200  /* init the plugin data */
25201  INIT_FUNC(mod_expire_init) {
25202         plugin_data *p;
25203 -       
25204 +
25205         p = calloc(1, sizeof(*p));
25206 -       
25207 +
25208         p->expire_tstmp = buffer_init();
25209 -       
25210 +
25211         buffer_prepare_copy(p->expire_tstmp, 255);
25212 -       
25213 +
25214         return p;
25215  }
25216  
25217  /* detroy the plugin data */
25218  FREE_FUNC(mod_expire_free) {
25219         plugin_data *p = p_d;
25220 -       
25221 +
25222         UNUSED(srv);
25223  
25224         if (!p) return HANDLER_GO_ON;
25225 -       
25226 +
25227         buffer_free(p->expire_tstmp);
25228 -       
25229 +
25230         if (p->config_storage) {
25231                 size_t i;
25232                 for (i = 0; i < srv->config_context->used; i++) {
25233                         plugin_config *s = p->config_storage[i];
25234 -                       
25235 +
25236                         array_free(s->expire_url);
25237 -                       
25238 +
25239                         free(s);
25240                 }
25241                 free(p->config_storage);
25242         }
25243 -       
25244 +
25245         free(p);
25246 -       
25247 +
25248         return HANDLER_GO_ON;
25249  }
25250  
25251 @@ -79,25 +79,25 @@
25252         char *ts;
25253         int type = -1;
25254         int retts = 0;
25255 -               
25256 +
25257         UNUSED(p);
25258  
25259 -       /* 
25260 +       /*
25261          * parse
25262 -        * 
25263 +        *
25264          * '(access|modification) [plus] {<num> <type>}*'
25265 -        * 
25266 +        *
25267          * e.g. 'access 1 years'
25268          */
25269 -       
25270 +
25271         if (expire->used == 0) {
25272 -               log_error_write(srv, __FILE__, __LINE__, "s", 
25273 +               log_error_write(srv, __FILE__, __LINE__, "s",
25274                                 "empty:");
25275                 return -1;
25276         }
25277 -       
25278 +
25279         ts = expire->ptr;
25280 -       
25281 +
25282         if (0 == strncmp(ts, "access ", 7)) {
25283                 type  = 0;
25284                 ts   += 7;
25285 @@ -110,39 +110,39 @@
25286                                 "invalid <base>:", ts);
25287                 return -1;
25288         }
25289 -       
25290 +
25291         if (0 == strncmp(ts, "plus ", 5)) {
25292                 /* skip the optional plus */
25293                 ts   += 5;
25294         }
25295 -       
25296 +
25297         /* the rest is just <number> (years|months|days|hours|minutes|seconds) */
25298         while (1) {
25299                 char *space, *err;
25300                 int num;
25301 -               
25302 +
25303                 if (NULL == (space = strchr(ts, ' '))) {
25304 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
25305 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
25306                                         "missing space after <num>:", ts);
25307                         return -1;
25308                 }
25309 -               
25310 +
25311                 num = strtol(ts, &err, 10);
25312                 if (*err != ' ') {
25313 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
25314 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
25315                                         "missing <type> after <num>:", ts);
25316                         return -1;
25317                 }
25318 -               
25319 +
25320                 ts = space + 1;
25321 -               
25322 +
25323                 if (NULL != (space = strchr(ts, ' '))) {
25324                         int slen;
25325                         /* */
25326 -                       
25327 +
25328                         slen = space - ts;
25329 -                       
25330 -                       if (slen == 5 && 
25331 +
25332 +                       if (slen == 5 &&
25333                             0 == strncmp(ts, "years", slen)) {
25334                                 num *= 60 * 60 * 24 * 30 * 12;
25335                         } else if (slen == 6 &&
25336 @@ -161,13 +161,13 @@
25337                                    0 == strncmp(ts, "seconds", slen)) {
25338                                 num *= 1;
25339                         } else {
25340 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
25341 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
25342                                                 "unknown type:", ts);
25343                                 return -1;
25344                         }
25345 -                       
25346 +
25347                         retts += num;
25348 -                       
25349 +
25350                         ts = space + 1;
25351                 } else {
25352                         if (0 == strcmp(ts, "years")) {
25353 @@ -183,19 +183,19 @@
25354                         } else if (0 == strcmp(ts, "seconds")) {
25355                                 num *= 1;
25356                         } else {
25357 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
25358 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
25359                                                 "unknown type:", ts);
25360                                 return -1;
25361                         }
25362 -                       
25363 +
25364                         retts += num;
25365 -                       
25366 +
25367                         break;
25368                 }
25369         }
25370 -       
25371 +
25372         if (offset != NULL) *offset = retts;
25373 -       
25374 +
25375         return type;
25376  }
25377  
25378 @@ -205,102 +205,99 @@
25379  SETDEFAULTS_FUNC(mod_expire_set_defaults) {
25380         plugin_data *p = p_d;
25381         size_t i = 0, k;
25382 -       
25383 -       config_values_t cv[] = { 
25384 +
25385 +       config_values_t cv[] = {
25386                 { "expire.url",                 NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
25387                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
25388         };
25389 -       
25390 +
25391         if (!p) return HANDLER_ERROR;
25392 -       
25393 +
25394         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
25395 -       
25396 +
25397         for (i = 0; i < srv->config_context->used; i++) {
25398                 plugin_config *s;
25399 -               
25400 +
25401                 s = calloc(1, sizeof(plugin_config));
25402                 s->expire_url    = array_init();
25403 -               
25404 +
25405                 cv[0].destination = s->expire_url;
25406 -               
25407 +
25408                 p->config_storage[i] = s;
25409 -       
25410 +
25411                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
25412                         return HANDLER_ERROR;
25413                 }
25414 -       
25415 +
25416                 for (k = 0; k < s->expire_url->used; k++) {
25417                         data_string *ds = (data_string *)s->expire_url->data[k];
25418 -                       
25419 +
25420                         /* parse lines */
25421                         if (-1 == mod_expire_get_offset(srv, p, ds->value, NULL)) {
25422 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
25423 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
25424                                                 "parsing expire.url failed:", ds->value);
25425                                 return HANDLER_ERROR;
25426                         }
25427                 }
25428         }
25429 -       
25430 -       
25431 +
25432 +
25433         return HANDLER_GO_ON;
25434  }
25435  
25436 -#define PATCH(x) \
25437 -       p->conf.x = s->x;
25438  static int mod_expire_patch_connection(server *srv, connection *con, plugin_data *p) {
25439         size_t i, j;
25440         plugin_config *s = p->config_storage[0];
25441 -       
25442 -       PATCH(expire_url);
25443 -       
25444 +
25445 +       PATCH_OPTION(expire_url);
25446 +
25447         /* skip the first, the global context */
25448         for (i = 1; i < srv->config_context->used; i++) {
25449                 data_config *dc = (data_config *)srv->config_context->data[i];
25450                 s = p->config_storage[i];
25451 -               
25452 +
25453                 /* condition didn't match */
25454                 if (!config_check_cond(srv, con, dc)) continue;
25455 -               
25456 +
25457                 /* merge config */
25458                 for (j = 0; j < dc->value->used; j++) {
25459                         data_unset *du = dc->value->data[j];
25460 -                       
25461 +
25462                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("expire.url"))) {
25463 -                               PATCH(expire_url);
25464 +                               PATCH_OPTION(expire_url);
25465                         }
25466                 }
25467         }
25468 -       
25469 +
25470         return 0;
25471  }
25472 -#undef PATCH
25473  
25474  URIHANDLER_FUNC(mod_expire_path_handler) {
25475         plugin_data *p = p_d;
25476         int s_len;
25477         size_t k;
25478 -       
25479 +
25480         if (con->uri.path->used == 0) return HANDLER_GO_ON;
25481 -       
25482 +
25483         mod_expire_patch_connection(srv, con, p);
25484 -       
25485 +
25486         s_len = con->uri.path->used - 1;
25487 -       
25488 +
25489         for (k = 0; k < p->conf.expire_url->used; k++) {
25490                 data_string *ds = (data_string *)p->conf.expire_url->data[k];
25491                 int ct_len = ds->key->used - 1;
25492 -               
25493 +
25494                 if (ct_len > s_len) continue;
25495                 if (ds->key->used == 0) continue;
25496 -               
25497 +
25498                 if (0 == strncmp(con->uri.path->ptr, ds->key->ptr, ct_len)) {
25499                         int ts;
25500                         time_t t;
25501                         size_t len;
25502                         stat_cache_entry *sce = NULL;
25503 -               
25504 +
25505                         stat_cache_get_entry(srv, con, con->physical.path, &sce);
25506 -                       
25507 +
25508                         switch(mod_expire_get_offset(srv, p, ds->value, &ts)) {
25509                         case 0:
25510                                 /* access */
25511 @@ -308,38 +305,38 @@
25512                                 break;
25513                         case 1:
25514                                 /* modification */
25515 -                               
25516 +
25517                                 t = (ts + sce->st.st_mtime);
25518                                 break;
25519                         default:
25520                                 /* -1 is handled at parse-time */
25521                                 break;
25522                         }
25523 -                       
25524 -                       
25525 -                       if (0 == (len = strftime(p->expire_tstmp->ptr, p->expire_tstmp->size - 1, 
25526 +
25527 +
25528 +                       if (0 == (len = strftime(p->expire_tstmp->ptr, p->expire_tstmp->size - 1,
25529                                            "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(t))))) {
25530                                 /* could not set expire header, out of mem */
25531 -                               
25532 +
25533                                 return HANDLER_GO_ON;
25534 -                               
25535 +
25536                         }
25537 -                           
25538 +
25539                         p->expire_tstmp->used = len + 1;
25540 -               
25541 -                       /* HTTP/1.0 */  
25542 +
25543 +                       /* HTTP/1.0 */
25544                         response_header_overwrite(srv, con, CONST_STR_LEN("Expires"), CONST_BUF_LEN(p->expire_tstmp));
25545  
25546 -                       /* HTTP/1.1 */  
25547 +                       /* HTTP/1.1 */
25548                         buffer_copy_string(p->expire_tstmp, "max-age=");
25549                         buffer_append_long(p->expire_tstmp, ts);
25550 -                       
25551 +
25552                         response_header_overwrite(srv, con, CONST_STR_LEN("Cache-Control"), CONST_BUF_LEN(p->expire_tstmp));
25553 -                       
25554 +
25555                         return HANDLER_GO_ON;
25556                 }
25557         }
25558 -       
25559 +
25560         /* not found */
25561         return HANDLER_GO_ON;
25562  }
25563 @@ -349,13 +346,13 @@
25564  int mod_expire_plugin_init(plugin *p) {
25565         p->version     = LIGHTTPD_VERSION_ID;
25566         p->name        = buffer_init_string("expire");
25567 -       
25568 +
25569         p->init        = mod_expire_init;
25570 -       p->handle_subrequest_start = mod_expire_path_handler;
25571 +       p->handle_response_header = mod_expire_path_handler;
25572         p->set_defaults  = mod_expire_set_defaults;
25573         p->cleanup     = mod_expire_free;
25574 -       
25575 +
25576         p->data        = NULL;
25577 -       
25578 +
25579         return 0;
25580  }
25581 --- ../lighttpd-1.4.11/src/mod_fastcgi.c        2006-03-09 13:18:39.000000000 +0200
25582 +++ lighttpd-1.5.0/src/mod_fastcgi.c    2006-09-07 00:57:05.000000000 +0300
25583 @@ -1,5 +1,4 @@
25584  #include <sys/types.h>
25585 -#include <unistd.h>
25586  #include <errno.h>
25587  #include <fcntl.h>
25588  #include <string.h>
25589 @@ -13,18 +12,18 @@
25590  #include "keyvalue.h"
25591  #include "log.h"
25592  
25593 -#include "http_chunk.h"
25594  #include "fdevent.h"
25595  #include "connections.h"
25596  #include "response.h"
25597  #include "joblist.h"
25598 +#include "status_counter.h"
25599  
25600  #include "plugin.h"
25601  
25602  #include "inet_ntop_cache.h"
25603  #include "stat_cache.h"
25604  
25605 -#include <fastcgi.h>
25606 +#include "fastcgi.h"
25607  #include <stdio.h>
25608  
25609  #ifdef HAVE_SYS_FILIO_H
25610 @@ -32,7 +31,11 @@
25611  #endif
25612  
25613  #include "sys-socket.h"
25614 +#include "sys-files.h"
25615 +#include "sys-strings.h"
25616 +#include "sys-process.h"
25617  
25618 +#include "http_resp.h"
25619  
25620  #ifndef UNIX_PATH_MAX
25621  # define UNIX_PATH_MAX 108
25622 @@ -45,14 +48,13 @@
25623  #include <sys/wait.h>
25624  #endif
25625  
25626 -
25627  /*
25628 - * 
25629 + *
25630   * TODO:
25631 - * 
25632 + *
25633   * - add timeout for a connect to a non-fastcgi process
25634   *   (use state_timestamp + state)
25635 - * 
25636 + *
25637   */
25638  
25639  typedef struct fcgi_proc {
25640 @@ -61,7 +63,7 @@
25641         unsigned port;  /* config.port + pno */
25642  
25643         buffer *connection_name; /* either tcp:<host>:<port> or unix:<socket> for debuggin purposes */
25644 -       
25645 +
25646         pid_t pid;   /* PID of the spawned process (0 if not spawned locally) */
25647  
25648  
25649 @@ -70,20 +72,20 @@
25650         time_t last_used; /* see idle_timeout */
25651         size_t requests;  /* see max_requests */
25652         struct fcgi_proc *prev, *next; /* see first */
25653 -       
25654 +
25655         time_t disabled_until; /* this proc is disabled until, use something else until than */
25656 -       
25657 +
25658         int is_local;
25659  
25660 -       enum { 
25661 +       enum {
25662                 PROC_STATE_UNSET,    /* init-phase */
25663                 PROC_STATE_RUNNING,  /* alive */
25664 -               PROC_STATE_OVERLOADED, /* listen-queue is full, 
25665 +               PROC_STATE_OVERLOADED, /* listen-queue is full,
25666                                           don't send something to this proc for the next 2 seconds */
25667                 PROC_STATE_DIED_WAIT_FOR_PID, /* */
25668                 PROC_STATE_DIED,     /* marked as dead, should be restarted */
25669                 PROC_STATE_KILLED    /* was killed as we don't have the load anymore */
25670 -       } state; 
25671 +       } state;
25672  } fcgi_proc;
25673  
25674  typedef struct {
25675 @@ -94,20 +96,20 @@
25676          * sorted by lowest load
25677          *
25678          * whenever a job is done move it up in the list
25679 -        * until it is sorted, move it down as soon as the 
25680 +        * until it is sorted, move it down as soon as the
25681          * job is started
25682          */
25683 -       fcgi_proc *first; 
25684 -       fcgi_proc *unused_procs; 
25685 +       fcgi_proc *first;
25686 +       fcgi_proc *unused_procs;
25687  
25688 -       /* 
25689 +       /*
25690          * spawn at least min_procs, at max_procs.
25691          *
25692 -        * as soon as the load of the first entry 
25693 +        * as soon as the load of the first entry
25694          * is max_load_per_proc we spawn a new one
25695 -        * and add it to the first entry and give it 
25696 +        * and add it to the first entry and give it
25697          * the load
25698 -        * 
25699 +        *
25700          */
25701  
25702         unsigned short min_procs;
25703 @@ -119,44 +121,44 @@
25704  
25705         /*
25706          * kick the process from the list if it was not
25707 -        * used for idle_timeout until min_procs is 
25708 +        * used for idle_timeout until min_procs is
25709          * reached. this helps to get the processlist
25710          * small again we had a small peak load.
25711          *
25712          */
25713 -       
25714 +
25715         unsigned short idle_timeout;
25716 -       
25717 +
25718         /*
25719          * time after a disabled remote connection is tried to be re-enabled
25720 -        * 
25721 -        * 
25722 +        *
25723 +        *
25724          */
25725 -       
25726 +
25727         unsigned short disable_time;
25728  
25729         /*
25730          * same fastcgi processes get a little bit larger
25731 -        * than wanted. max_requests_per_proc kills a 
25732 +        * than wanted. max_requests_per_proc kills a
25733          * process after a number of handled requests.
25734          *
25735          */
25736         size_t max_requests_per_proc;
25737 -       
25738 +
25739  
25740         /* config */
25741  
25742 -       /* 
25743 -        * host:port 
25744 +       /*
25745 +        * host:port
25746          *
25747 -        * if host is one of the local IP adresses the 
25748 +        * if host is one of the local IP adresses the
25749          * whole connection is local
25750          *
25751          * if tcp/ip should be used host AND port have
25752 -        * to be specified 
25753 -        * 
25754 -        */ 
25755 -       buffer *host; 
25756 +        * to be specified
25757 +        *
25758 +        */
25759 +       buffer *host;
25760         unsigned short port;
25761  
25762         /*
25763 @@ -169,7 +171,7 @@
25764          */
25765         buffer *unixsocket;
25766  
25767 -       /* if socket is local we can start the fastcgi 
25768 +       /* if socket is local we can start the fastcgi
25769          * process ourself
25770          *
25771          * bin-path is the path to the binary
25772 @@ -177,19 +179,19 @@
25773          * check min_procs and max_procs for the number
25774          * of process to start-up
25775          */
25776 -       buffer *bin_path; 
25777 -       
25778 -       /* bin-path is set bin-environment is taken to 
25779 +       buffer *bin_path;
25780 +
25781 +       /* bin-path is set bin-environment is taken to
25782          * create the environement before starting the
25783          * FastCGI process
25784 -        * 
25785 +        *
25786          */
25787         array *bin_env;
25788 -       
25789 +
25790         array *bin_env_copy;
25791 -       
25792 +
25793         /*
25794 -        * docroot-translation between URL->phys and the 
25795 +        * docroot-translation between URL->phys and the
25796          * remote host
25797          *
25798          * reasons:
25799 @@ -208,7 +210,7 @@
25800         unsigned short mode;
25801  
25802         /*
25803 -        * check_local tell you if the phys file is stat()ed 
25804 +        * check_local tell you if the phys file is stat()ed
25805          * or not. FastCGI doesn't care if the service is
25806          * remote. If the web-server side doesn't contain
25807          * the fastcgi-files we should not stat() for them
25808 @@ -218,11 +220,11 @@
25809  
25810         /*
25811          * append PATH_INFO to SCRIPT_FILENAME
25812 -        * 
25813 +        *
25814          * php needs this if cgi.fix_pathinfo is provied
25815 -        * 
25816 +        *
25817          */
25818 -       
25819 +
25820         unsigned short break_scriptfilename_for_php;
25821  
25822         /*
25823 @@ -231,12 +233,12 @@
25824          *
25825          */
25826         unsigned short allow_xsendfile;
25827 -               
25828 +
25829         ssize_t load; /* replace by host->load */
25830  
25831         size_t max_id; /* corresponds most of the time to
25832         num_procs.
25833 -       
25834 +
25835         only if a process is killed max_id waits for the process itself
25836         to die and decrements its afterwards */
25837  
25838 @@ -245,17 +247,17 @@
25839  
25840  /*
25841   * one extension can have multiple hosts assigned
25842 - * one host can spawn additional processes on the same 
25843 + * one host can spawn additional processes on the same
25844   *   socket (if we control it)
25845   *
25846   * ext -> host -> procs
25847   *    1:n     1:n
25848   *
25849 - * if the fastcgi process is remote that whole goes down 
25850 + * if the fastcgi process is remote that whole goes down
25851   * to
25852   *
25853   * ext -> host -> procs
25854 - *    1:n     1:1 
25855 + *    1:n     1:1
25856   *
25857   * in case of PHP and FCGI_CHILDREN we have again a procs
25858   * but we don't control it directly.
25859 @@ -268,7 +270,7 @@
25860         int note_is_sent;
25861  
25862         fcgi_extension_host **hosts;
25863 -       
25864 +
25865         size_t used;
25866         size_t size;
25867  } fcgi_extension;
25868 @@ -282,10 +284,10 @@
25869  
25870  
25871  typedef struct {
25872 -       fcgi_exts *exts; 
25873 +       fcgi_exts *exts;
25874  
25875         array *ext_mapping;
25876 -       
25877 +
25878         int debug;
25879  } plugin_config;
25880  
25881 @@ -297,7 +299,7 @@
25882  
25883  typedef struct {
25884         char **ptr;
25885 -       
25886 +
25887         size_t size;
25888         size_t used;
25889  } char_array;
25890 @@ -306,55 +308,54 @@
25891  typedef struct {
25892         PLUGIN_DATA;
25893         buffer_uint fcgi_request_id;
25894 -       
25895 +
25896         buffer *fcgi_env;
25897 -       
25898 +
25899         buffer *path;
25900 -       buffer *parse_response;
25901  
25902         buffer *statuskey;
25903 -       
25904 +
25905 +       http_resp *resp;
25906 +
25907         plugin_config **config_storage;
25908 -       
25909 +
25910         plugin_config conf; /* this is only used as long as no handler_ctx is setup */
25911  } plugin_data;
25912  
25913  /* connection specific data */
25914 -typedef enum { 
25915 +typedef enum {
25916         FCGI_STATE_UNSET,
25917 -       FCGI_STATE_INIT, 
25918 -       FCGI_STATE_CONNECT_DELAYED, 
25919 -       FCGI_STATE_PREPARE_WRITE, 
25920 -       FCGI_STATE_WRITE, 
25921 -       FCGI_STATE_READ 
25922 +       FCGI_STATE_INIT,
25923 +       FCGI_STATE_CONNECT_DELAYED,
25924 +       FCGI_STATE_PREPARE_WRITE,
25925 +       FCGI_STATE_WRITE,
25926 +       FCGI_STATE_READ
25927  } fcgi_connection_state_t;
25928  
25929  typedef struct {
25930         fcgi_proc *proc;
25931         fcgi_extension_host *host;
25932         fcgi_extension *ext;
25933 -       
25934 +
25935         fcgi_connection_state_t state;
25936         time_t   state_timestamp;
25937 -       
25938 +
25939         int      reconnects; /* number of reconnect attempts */
25940 -       
25941 -       chunkqueue *rb; /* read queue */
25942 +
25943 +       chunkqueue *rb; /* the raw fcgi read-queue */
25944 +       chunkqueue *http_rb; /* the decoded read-queue for http-parsing */
25945         chunkqueue *wb; /* write queue */
25946 -       
25947 -       buffer   *response_header;
25948 -       
25949 +
25950         size_t    request_id;
25951 -       int       fd;        /* fd to the fastcgi process */
25952 -       int       fde_ndx;   /* index into the fd-event buffer */
25953 +       iosocket *sock;
25954  
25955         pid_t     pid;
25956         int       got_proc;
25957  
25958         int       send_content_body;
25959 -       
25960 +
25961         plugin_config conf;
25962 -       
25963 +
25964         connection *remote_conn;  /* dumb pointer */
25965         plugin_data *plugin_data; /* dumb pointer */
25966  } handler_ctx;
25967 @@ -363,49 +364,6 @@
25968  /* ok, we need a prototype */
25969  static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents);
25970  
25971 -data_integer *status_counter_get_counter(server *srv, const char *s, size_t len) {
25972 -       data_integer *di;
25973 -
25974 -       if (NULL == (di = (data_integer *)array_get_element(srv->status, s))) {
25975 -               /* not found, create it */
25976 -
25977 -               if (NULL == (di = (data_integer *)array_get_unused_element(srv->status, TYPE_INTEGER))) {
25978 -                       di = data_integer_init();
25979 -               }
25980 -               buffer_copy_string_len(di->key, s, len);
25981 -               di->value = 0;
25982 -
25983 -               array_insert_unique(srv->status, (data_unset *)di);
25984 -       }
25985 -       return di;
25986 -}
25987 -
25988 -/* dummies of the statistic framework functions 
25989 - * they will be moved to a statistics.c later */
25990 -int status_counter_inc(server *srv, const char *s, size_t len) {
25991 -       data_integer *di = status_counter_get_counter(srv, s, len);
25992 -
25993 -       di->value++;
25994 -
25995 -       return 0;
25996 -}
25997 -
25998 -int status_counter_dec(server *srv, const char *s, size_t len) {
25999 -       data_integer *di = status_counter_get_counter(srv, s, len);
26000 -
26001 -       if (di->value > 0) di->value--;
26002 -
26003 -       return 0;
26004 -}
26005 -
26006 -int status_counter_set(server *srv, const char *s, size_t len, int val) {
26007 -       data_integer *di = status_counter_get_counter(srv, s, len);
26008 -
26009 -       di->value = val;
26010 -
26011 -       return 0;
26012 -}
26013 -
26014  int fastcgi_status_copy_procname(buffer *b, fcgi_extension_host *host, fcgi_proc *proc) {
26015         buffer_copy_string(b, "fastcgi.backend.");
26016         buffer_append_string_buffer(b, host->id);
26017 @@ -421,7 +379,7 @@
26018  #define CLEAN(x) \
26019         fastcgi_status_copy_procname(b, host, proc); \
26020         buffer_append_string(b, x); \
26021 -       status_counter_set(srv, CONST_BUF_LEN(b), 0);
26022 +       status_counter_set(CONST_BUF_LEN(b), 0);
26023  
26024         CLEAN(".disabled");
26025         CLEAN(".died");
26026 @@ -429,42 +387,39 @@
26027         CLEAN(".connected");
26028         CLEAN(".load");
26029  
26030 -#undef CLEAN   
26031 +#undef CLEAN
26032  
26033  #define CLEAN(x) \
26034         fastcgi_status_copy_procname(b, host, NULL); \
26035         buffer_append_string(b, x); \
26036 -       status_counter_set(srv, CONST_BUF_LEN(b), 0);
26037 +       status_counter_set(CONST_BUF_LEN(b), 0);
26038  
26039         CLEAN(".load");
26040  
26041 -#undef CLEAN   
26042 +#undef CLEAN
26043  
26044         return 0;
26045  }
26046  
26047  static handler_ctx * handler_ctx_init() {
26048         handler_ctx * hctx;
26049 -       
26050 +
26051         hctx = calloc(1, sizeof(*hctx));
26052         assert(hctx);
26053 -       
26054 -       hctx->fde_ndx = -1;
26055 -       
26056 -       hctx->response_header = buffer_init();
26057 -       
26058 +
26059         hctx->request_id = 0;
26060         hctx->state = FCGI_STATE_INIT;
26061         hctx->proc = NULL;
26062 -       
26063 -       hctx->fd = -1;
26064 -       
26065 +
26066 +       hctx->sock = iosocket_init();
26067 +
26068         hctx->reconnects = 0;
26069         hctx->send_content_body = 1;
26070  
26071         hctx->rb = chunkqueue_init();
26072 +       hctx->http_rb = chunkqueue_init();
26073         hctx->wb = chunkqueue_init();
26074 -       
26075 +
26076         return hctx;
26077  }
26078  
26079 @@ -473,12 +428,13 @@
26080                 hctx->host->load--;
26081                 hctx->host = NULL;
26082         }
26083 -       
26084 -       buffer_free(hctx->response_header);
26085  
26086         chunkqueue_free(hctx->rb);
26087 +       chunkqueue_free(hctx->http_rb);
26088         chunkqueue_free(hctx->wb);
26089  
26090 +       iosocket_free(hctx->sock);
26091 +
26092         free(hctx);
26093  }
26094  
26095 @@ -488,21 +444,21 @@
26096         f = calloc(1, sizeof(*f));
26097         f->unixsocket = buffer_init();
26098         f->connection_name = buffer_init();
26099 -       
26100 +
26101         f->prev = NULL;
26102         f->next = NULL;
26103 -       
26104 +
26105         return f;
26106  }
26107  
26108  void fastcgi_process_free(fcgi_proc *f) {
26109         if (!f) return;
26110 -       
26111 +
26112         fastcgi_process_free(f->next);
26113 -       
26114 +
26115         buffer_free(f->unixsocket);
26116         buffer_free(f->connection_name);
26117 -       
26118 +
26119         free(f);
26120  }
26121  
26122 @@ -519,13 +475,13 @@
26123         f->bin_env = array_init();
26124         f->bin_env_copy = array_init();
26125         f->strip_request_uri = buffer_init();
26126 -       
26127 +
26128         return f;
26129  }
26130  
26131  void fastcgi_host_free(fcgi_extension_host *h) {
26132         if (!h) return;
26133 -       
26134 +
26135         buffer_free(h->id);
26136         buffer_free(h->host);
26137         buffer_free(h->unixsocket);
26138 @@ -534,49 +490,49 @@
26139         buffer_free(h->strip_request_uri);
26140         array_free(h->bin_env);
26141         array_free(h->bin_env_copy);
26142 -       
26143 +
26144         fastcgi_process_free(h->first);
26145         fastcgi_process_free(h->unused_procs);
26146 -       
26147 +
26148         free(h);
26149 -       
26150 +
26151  }
26152  
26153  fcgi_exts *fastcgi_extensions_init() {
26154         fcgi_exts *f;
26155  
26156         f = calloc(1, sizeof(*f));
26157 -       
26158 +
26159         return f;
26160  }
26161  
26162  void fastcgi_extensions_free(fcgi_exts *f) {
26163         size_t i;
26164 -       
26165 +
26166         if (!f) return;
26167 -       
26168 +
26169         for (i = 0; i < f->used; i++) {
26170                 fcgi_extension *fe;
26171                 size_t j;
26172 -               
26173 +
26174                 fe = f->exts[i];
26175 -               
26176 +
26177                 for (j = 0; j < fe->used; j++) {
26178                         fcgi_extension_host *h;
26179 -                       
26180 +
26181                         h = fe->hosts[j];
26182 -                       
26183 +
26184                         fastcgi_host_free(h);
26185                 }
26186 -               
26187 +
26188                 buffer_free(fe->key);
26189                 free(fe->hosts);
26190 -               
26191 +
26192                 free(fe);
26193         }
26194 -       
26195 +
26196         free(f->exts);
26197 -       
26198 +
26199         free(f);
26200  }
26201  
26202 @@ -625,24 +581,25 @@
26203                 assert(fe->hosts);
26204         }
26205  
26206 -       fe->hosts[fe->used++] = fh; 
26207 +       fe->hosts[fe->used++] = fh;
26208  
26209         return 0;
26210 -       
26211 +
26212  }
26213  
26214  INIT_FUNC(mod_fastcgi_init) {
26215         plugin_data *p;
26216 -       
26217 +
26218         p = calloc(1, sizeof(*p));
26219 -       
26220 +
26221         p->fcgi_env = buffer_init();
26222 -       
26223 +
26224         p->path = buffer_init();
26225 -       p->parse_response = buffer_init();
26226 +
26227 +       p->resp = http_response_init();
26228  
26229         p->statuskey = buffer_init();
26230 -       
26231 +
26232         return p;
26233  }
26234  
26235 @@ -650,81 +607,82 @@
26236  FREE_FUNC(mod_fastcgi_free) {
26237         plugin_data *p = p_d;
26238         buffer_uint *r = &(p->fcgi_request_id);
26239 -       
26240 +
26241         UNUSED(srv);
26242  
26243         if (r->ptr) free(r->ptr);
26244 -       
26245 +
26246         buffer_free(p->fcgi_env);
26247         buffer_free(p->path);
26248 -       buffer_free(p->parse_response);
26249         buffer_free(p->statuskey);
26250 -       
26251 +
26252 +       http_response_free(p->resp);
26253 +
26254         if (p->config_storage) {
26255                 size_t i, j, n;
26256                 for (i = 0; i < srv->config_context->used; i++) {
26257                         plugin_config *s = p->config_storage[i];
26258                         fcgi_exts *exts;
26259 -                       
26260 +
26261                         if (!s) continue;
26262 -                       
26263 +
26264                         exts = s->exts;
26265  
26266                         for (j = 0; j < exts->used; j++) {
26267                                 fcgi_extension *ex;
26268 -                               
26269 +
26270                                 ex = exts->exts[j];
26271 -                               
26272 +
26273                                 for (n = 0; n < ex->used; n++) {
26274                                         fcgi_proc *proc;
26275                                         fcgi_extension_host *host;
26276 -                                       
26277 +
26278                                         host = ex->hosts[n];
26279 -                                       
26280 +
26281                                         for (proc = host->first; proc; proc = proc->next) {
26282                                                 if (proc->pid != 0) kill(proc->pid, SIGTERM);
26283 -                                               
26284 -                                               if (proc->is_local && 
26285 +
26286 +                                               if (proc->is_local &&
26287                                                     !buffer_is_empty(proc->unixsocket)) {
26288                                                         unlink(proc->unixsocket->ptr);
26289                                                 }
26290                                         }
26291 -                                       
26292 +
26293                                         for (proc = host->unused_procs; proc; proc = proc->next) {
26294                                                 if (proc->pid != 0) kill(proc->pid, SIGTERM);
26295 -                                               
26296 -                                               if (proc->is_local && 
26297 +
26298 +                                               if (proc->is_local &&
26299                                                     !buffer_is_empty(proc->unixsocket)) {
26300                                                         unlink(proc->unixsocket->ptr);
26301                                                 }
26302                                         }
26303                                 }
26304                         }
26305 -                       
26306 +
26307                         fastcgi_extensions_free(s->exts);
26308                         array_free(s->ext_mapping);
26309 -                       
26310 +
26311                         free(s);
26312                 }
26313                 free(p->config_storage);
26314         }
26315 -       
26316 +
26317         free(p);
26318 -       
26319 +
26320         return HANDLER_GO_ON;
26321  }
26322  
26323  static int env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) {
26324         char *dst;
26325 -       
26326 +
26327         if (!key || !val) return -1;
26328 -       
26329 +
26330         dst = malloc(key_len + val_len + 3);
26331         memcpy(dst, key, key_len);
26332         dst[key_len] = '=';
26333         /* add the \0 from the value */
26334         memcpy(dst + key_len + 1, val, val_len + 1);
26335 -       
26336 +
26337         if (env->size == 0) {
26338                 env->size = 16;
26339                 env->ptr = malloc(env->size * sizeof(*env->ptr));
26340 @@ -732,9 +690,9 @@
26341                 env->size += 16;
26342                 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
26343         }
26344 -       
26345 +
26346         env->ptr[env->used++] = dst;
26347 -       
26348 +
26349         return 0;
26350  }
26351  
26352 @@ -753,15 +711,15 @@
26353                         if (env->size == 0) {
26354                                 env->size = 16;
26355                                 env->ptr = malloc(env->size * sizeof(*env->ptr));
26356 -                       } else if (env->size == env->used) { 
26357 +                       } else if (env->size == env->used) {
26358                                 env->size += 16;
26359                                 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
26360                         }
26361 -                       
26362 +
26363                         b->ptr[i] = '\0';
26364  
26365                         env->ptr[env->used++] = start;
26366 -                       
26367 +
26368                         start = b->ptr + i + 1;
26369                         break;
26370                 default:
26371 @@ -794,7 +752,7 @@
26372         return 0;
26373  }
26374  
26375 -static int fcgi_spawn_connection(server *srv, 
26376 +static int fcgi_spawn_connection(server *srv,
26377                                  plugin_data *p,
26378                                  fcgi_extension_host *host,
26379                                  fcgi_proc *proc) {
26380 @@ -806,31 +764,27 @@
26381  #endif
26382         struct sockaddr_in fcgi_addr_in;
26383         struct sockaddr *fcgi_addr;
26384 -       
26385 +
26386         socklen_t servlen;
26387 -       
26388 +
26389  #ifndef HAVE_FORK
26390         return -1;
26391  #endif
26392 -       
26393 +
26394         if (p->conf.debug) {
26395                 log_error_write(srv, __FILE__, __LINE__, "sdb",
26396                                 "new proc, socket:", proc->port, proc->unixsocket);
26397         }
26398 -               
26399 +
26400         if (!buffer_is_empty(proc->unixsocket)) {
26401                 memset(&fcgi_addr, 0, sizeof(fcgi_addr));
26402 -               
26403 +
26404  #ifdef HAVE_SYS_UN_H
26405                 fcgi_addr_un.sun_family = AF_UNIX;
26406                 strcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr);
26407 -               
26408 -#ifdef SUN_LEN
26409 +
26410                 servlen = SUN_LEN(&fcgi_addr_un);
26411 -#else
26412 -               /* stevens says: */
26413 -               servlen = proc->unixsocket->used + sizeof(fcgi_addr_un.sun_family);
26414 -#endif
26415 +
26416                 socket_type = AF_UNIX;
26417                 fcgi_addr = (struct sockaddr *) &fcgi_addr_un;
26418  
26419 @@ -844,108 +798,108 @@
26420  #endif
26421         } else {
26422                 fcgi_addr_in.sin_family = AF_INET;
26423 -               
26424 +
26425                 if (buffer_is_empty(host->host)) {
26426                         fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
26427                 } else {
26428                         struct hostent *he;
26429 -                       
26430 +
26431                         /* set a usefull default */
26432                         fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
26433 -                       
26434 -                       
26435 +
26436 +
26437                         if (NULL == (he = gethostbyname(host->host->ptr))) {
26438 -                               log_error_write(srv, __FILE__, __LINE__, 
26439 -                                               "sdb", "gethostbyname failed: ", 
26440 +                               log_error_write(srv, __FILE__, __LINE__,
26441 +                                               "sdb", "gethostbyname failed: ",
26442                                                 h_errno, host->host);
26443                                 return -1;
26444                         }
26445 -                       
26446 +
26447                         if (he->h_addrtype != AF_INET) {
26448                                 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype);
26449                                 return -1;
26450                         }
26451 -                       
26452 +
26453                         if (he->h_length != sizeof(struct in_addr)) {
26454                                 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length);
26455                                 return -1;
26456                         }
26457 -                       
26458 +
26459                         memcpy(&(fcgi_addr_in.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
26460 -                       
26461 +
26462                 }
26463                 fcgi_addr_in.sin_port = htons(proc->port);
26464                 servlen = sizeof(fcgi_addr_in);
26465 -               
26466 +
26467                 socket_type = AF_INET;
26468                 fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
26469 -               
26470 +
26471                 buffer_copy_string(proc->connection_name, "tcp:");
26472                 buffer_append_string_buffer(proc->connection_name, host->host);
26473                 buffer_append_string(proc->connection_name, ":");
26474                 buffer_append_long(proc->connection_name, proc->port);
26475         }
26476 -       
26477 +
26478         if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
26479 -               log_error_write(srv, __FILE__, __LINE__, "ss", 
26480 +               log_error_write(srv, __FILE__, __LINE__, "ss",
26481                                 "failed:", strerror(errno));
26482                 return -1;
26483         }
26484 -       
26485 +
26486         if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
26487                 /* server is not up, spawn in  */
26488                 pid_t child;
26489                 int val;
26490 -               
26491 -               if (errno != ENOENT && 
26492 +
26493 +               if (errno != ENOENT &&
26494                     !buffer_is_empty(proc->unixsocket)) {
26495                         unlink(proc->unixsocket->ptr);
26496                 }
26497 -               
26498 +
26499                 close(fcgi_fd);
26500 -               
26501 +
26502                 /* reopen socket */
26503                 if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
26504 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
26505 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
26506                                 "socket failed:", strerror(errno));
26507                         return -1;
26508                 }
26509 -               
26510 +
26511                 val = 1;
26512                 if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
26513 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
26514 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
26515                                         "socketsockopt failed:", strerror(errno));
26516                         return -1;
26517                 }
26518 -               
26519 +
26520                 /* create socket */
26521                 if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) {
26522 -                       log_error_write(srv, __FILE__, __LINE__, "sbs", 
26523 -                               "bind failed for:", 
26524 +                       log_error_write(srv, __FILE__, __LINE__, "sbs",
26525 +                               "bind failed for:",
26526                                 proc->connection_name,
26527                                 strerror(errno));
26528                         return -1;
26529                 }
26530 -               
26531 +
26532                 if (-1 == listen(fcgi_fd, 1024)) {
26533 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
26534 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
26535                                 "listen failed:", strerror(errno));
26536                         return -1;
26537                 }
26538 -               
26539 -#ifdef HAVE_FORK       
26540 +
26541 +#ifndef _WIN32
26542                 switch ((child = fork())) {
26543                 case 0: {
26544                         size_t i = 0;
26545                         char *c;
26546                         char_array env;
26547                         char_array arg;
26548 -                       
26549 +
26550                         /* create environment */
26551                         env.ptr = NULL;
26552                         env.size = 0;
26553                         env.used = 0;
26554 -                       
26555 +
26556                         arg.ptr = NULL;
26557                         arg.size = 0;
26558                         arg.used = 0;
26559 @@ -955,18 +909,18 @@
26560                                 dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO);
26561                                 close(fcgi_fd);
26562                         }
26563 -                       
26564 +
26565                         /* we don't need the client socket */
26566                         for (i = 3; i < 256; i++) {
26567                                 close(i);
26568                         }
26569 -                       
26570 +
26571                         /* build clean environment */
26572                         if (host->bin_env_copy->used) {
26573                                 for (i = 0; i < host->bin_env_copy->used; i++) {
26574                                         data_string *ds = (data_string *)host->bin_env_copy->data[i];
26575                                         char *ge;
26576 -                                       
26577 +
26578                                         if (NULL != (ge = getenv(ds->value->ptr))) {
26579                                                 env_add(&env, CONST_BUF_LEN(ds->value), ge, strlen(ge));
26580                                         }
26581 @@ -974,39 +928,39 @@
26582                         } else {
26583                                 for (i = 0; environ[i]; i++) {
26584                                         char *eq;
26585 -                                       
26586 +
26587                                         if (NULL != (eq = strchr(environ[i], '='))) {
26588                                                 env_add(&env, environ[i], eq - environ[i], eq+1, strlen(eq+1));
26589                                         }
26590                                 }
26591                         }
26592 -                       
26593 +
26594                         /* create environment */
26595                         for (i = 0; i < host->bin_env->used; i++) {
26596                                 data_string *ds = (data_string *)host->bin_env->data[i];
26597 -                               
26598 +
26599                                 env_add(&env, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
26600                         }
26601 -                       
26602 +
26603                         for (i = 0; i < env.used; i++) {
26604                                 /* search for PHP_FCGI_CHILDREN */
26605                                 if (0 == strncmp(env.ptr[i], "PHP_FCGI_CHILDREN=", sizeof("PHP_FCGI_CHILDREN=") - 1)) break;
26606                         }
26607 -                       
26608 +
26609                         /* not found, add a default */
26610                         if (i == env.used) {
26611                                 env_add(&env, CONST_STR_LEN("PHP_FCGI_CHILDREN"), CONST_STR_LEN("1"));
26612                         }
26613 -                       
26614 +
26615                         env.ptr[env.used] = NULL;
26616  
26617                         parse_binpath(&arg, host->bin_path);
26618 -                       
26619 +
26620                         /* chdir into the base of the bin-path,
26621                          * search for the last / */
26622                         if (NULL != (c = strrchr(arg.ptr[0], '/'))) {
26623                                 *c = '\0';
26624 -                       
26625 +
26626                                 /* change to the physical directory */
26627                                 if (-1 == chdir(arg.ptr[0])) {
26628                                         *c = '/';
26629 @@ -1018,12 +972,12 @@
26630  
26631                         /* exec the cgi */
26632                         execve(arg.ptr[0], arg.ptr, env.ptr);
26633 -                       
26634 -                       log_error_write(srv, __FILE__, __LINE__, "sbs", 
26635 +
26636 +                       log_error_write(srv, __FILE__, __LINE__, "sbs",
26637                                         "execve failed for:", host->bin_path, strerror(errno));
26638 -                       
26639 +
26640                         exit(errno);
26641 -                       
26642 +
26643                         break;
26644                 }
26645                 case -1:
26646 @@ -1031,17 +985,17 @@
26647                         break;
26648                 default:
26649                         /* father */
26650 -                       
26651 +
26652                         /* wait */
26653                         select(0, NULL, NULL, NULL, &tv);
26654 -                       
26655 +
26656                         switch (waitpid(child, &status, WNOHANG)) {
26657                         case 0:
26658                                 /* child still running after timeout, good */
26659                                 break;
26660                         case -1:
26661                                 /* no PID found ? should never happen */
26662 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
26663 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
26664                                                 "pid not found:", strerror(errno));
26665                                 return -1;
26666                         default:
26667 @@ -1049,10 +1003,10 @@
26668                                                 "the fastcgi-backend", host->bin_path, "failed to start:");
26669                                 /* the child should not terminate at all */
26670                                 if (WIFEXITED(status)) {
26671 -                                       log_error_write(srv, __FILE__, __LINE__, "sdb", 
26672 -                                                       "child exited with status", 
26673 +                                       log_error_write(srv, __FILE__, __LINE__, "sdb",
26674 +                                                       "child exited with status",
26675                                                         WEXITSTATUS(status), host->bin_path);
26676 -                                       log_error_write(srv, __FILE__, __LINE__, "s", 
26677 +                                       log_error_write(srv, __FILE__, __LINE__, "s",
26678                                                         "if you try do run PHP as FastCGI backend make sure you use the FastCGI enabled version.\n"
26679                                                         "You can find out if it is the right one by executing 'php -v' and it should display '(cgi-fcgi)' "
26680                                                         "in the output, NOT (cgi) NOR (cli)\n"
26681 @@ -1060,8 +1014,8 @@
26682                                         log_error_write(srv, __FILE__, __LINE__, "s",
26683                                                         "If this is PHP on Gentoo add fastcgi to the USE flags");
26684                                 } else if (WIFSIGNALED(status)) {
26685 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
26686 -                                                       "terminated by signal:", 
26687 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
26688 +                                                       "terminated by signal:",
26689                                                         WTERMSIG(status));
26690  
26691                                         if (WTERMSIG(status) == 11) {
26692 @@ -1071,8 +1025,8 @@
26693                                                                 "If this is PHP try to remove the byte-code caches for now and try again.");
26694                                         }
26695                                 } else {
26696 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
26697 -                                                       "child died somehow:", 
26698 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
26699 +                                                       "child died somehow:",
26700                                                         status);
26701                                 }
26702                                 return -1;
26703 @@ -1082,26 +1036,26 @@
26704                         proc->pid = child;
26705                         proc->last_used = srv->cur_ts;
26706                         proc->is_local = 1;
26707 -                                               
26708 +
26709                         break;
26710                 }
26711  #endif
26712         } else {
26713                 proc->is_local = 0;
26714                 proc->pid = 0;
26715 -               
26716 +
26717                 if (p->conf.debug) {
26718                         log_error_write(srv, __FILE__, __LINE__, "sb",
26719                                         "(debug) socket is already used, won't spawn:",
26720                                         proc->connection_name);
26721                 }
26722         }
26723 -       
26724 +
26725         proc->state = PROC_STATE_RUNNING;
26726         host->active_procs++;
26727 -       
26728 +
26729         close(fcgi_fd);
26730 -       
26731 +
26732         return 0;
26733  }
26734  
26735 @@ -1111,93 +1065,93 @@
26736         data_unset *du;
26737         size_t i = 0;
26738         buffer *fcgi_mode = buffer_init();
26739 -       
26740 -       config_values_t cv[] = { 
26741 +
26742 +       config_values_t cv[] = {
26743                 { "fastcgi.server",              NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
26744                 { "fastcgi.debug",               NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
26745                 { "fastcgi.map-extensions",      NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
26746                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
26747         };
26748 -       
26749 +
26750         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
26751 -       
26752 +
26753         for (i = 0; i < srv->config_context->used; i++) {
26754                 plugin_config *s;
26755                 array *ca;
26756 -               
26757 +
26758                 s = malloc(sizeof(plugin_config));
26759                 s->exts          = fastcgi_extensions_init();
26760                 s->debug         = 0;
26761                 s->ext_mapping   = array_init();
26762 -               
26763 +
26764                 cv[0].destination = s->exts;
26765                 cv[1].destination = &(s->debug);
26766                 cv[2].destination = s->ext_mapping;
26767 -               
26768 +
26769                 p->config_storage[i] = s;
26770                 ca = ((data_config *)srv->config_context->data[i])->value;
26771 -       
26772 +
26773                 if (0 != config_insert_values_global(srv, ca, cv)) {
26774                         return HANDLER_ERROR;
26775                 }
26776 -               
26777 -               /* 
26778 +
26779 +               /*
26780                  * <key> = ( ... )
26781                  */
26782 -               
26783 +
26784                 if (NULL != (du = array_get_element(ca, "fastcgi.server"))) {
26785                         size_t j;
26786                         data_array *da = (data_array *)du;
26787 -                       
26788 +
26789                         if (du->type != TYPE_ARRAY) {
26790 -                               log_error_write(srv, __FILE__, __LINE__, "sss", 
26791 +                               log_error_write(srv, __FILE__, __LINE__, "sss",
26792                                                 "unexpected type for key: ", "fastcgi.server", "array of strings");
26793 -                               
26794 +
26795                                 return HANDLER_ERROR;
26796                         }
26797 -                       
26798 -                       
26799 -                       /* 
26800 -                        * fastcgi.server = ( "<ext>" => ( ... ), 
26801 +
26802 +
26803 +                       /*
26804 +                        * fastcgi.server = ( "<ext>" => ( ... ),
26805                          *                    "<ext>" => ( ... ) )
26806                          */
26807 -                       
26808 +
26809                         for (j = 0; j < da->value->used; j++) {
26810                                 size_t n;
26811                                 data_array *da_ext = (data_array *)da->value->data[j];
26812 -                               
26813 +
26814                                 if (da->value->data[j]->type != TYPE_ARRAY) {
26815 -                                       log_error_write(srv, __FILE__, __LINE__, "sssbs", 
26816 -                                                       "unexpected type for key: ", "fastcgi.server", 
26817 +                                       log_error_write(srv, __FILE__, __LINE__, "sssbs",
26818 +                                                       "unexpected type for key: ", "fastcgi.server",
26819                                                         "[", da->value->data[j]->key, "](string)");
26820 -                                       
26821 +
26822                                         return HANDLER_ERROR;
26823                                 }
26824 -                               
26825 -                               /* 
26826 -                                * da_ext->key == name of the extension 
26827 +
26828 +                               /*
26829 +                                * da_ext->key == name of the extension
26830                                  */
26831 -                               
26832 -                               /* 
26833 -                                * fastcgi.server = ( "<ext>" => 
26834 -                                *                     ( "<host>" => ( ... ), 
26835 +
26836 +                               /*
26837 +                                * fastcgi.server = ( "<ext>" =>
26838 +                                *                     ( "<host>" => ( ... ),
26839                                  *                       "<host>" => ( ... )
26840 -                                *                     ), 
26841 +                                *                     ),
26842                                  *                    "<ext>" => ... )
26843                                  */
26844 -                                       
26845 +
26846                                 for (n = 0; n < da_ext->value->used; n++) {
26847                                         data_array *da_host = (data_array *)da_ext->value->data[n];
26848 -                                       
26849 +
26850                                         fcgi_extension_host *host;
26851 -                                       
26852 -                                       config_values_t fcv[] = { 
26853 +
26854 +                                       config_values_t fcv[] = {
26855                                                 { "host",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
26856                                                 { "docroot",           NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
26857                                                 { "mode",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
26858                                                 { "socket",            NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 3 */
26859                                                 { "bin-path",          NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 4 */
26860 -                                               
26861 +
26862                                                 { "check-local",       NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },      /* 5 */
26863                                                 { "port",              NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 6 */
26864                                                 { "min-procs-not-working",         NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 7 this is broken for now */
26865 @@ -1205,28 +1159,28 @@
26866                                                 { "max-load-per-proc", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 9 */
26867                                                 { "idle-timeout",      NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 10 */
26868                                                 { "disable-time",      NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 11 */
26869 -                                               
26870 +
26871                                                 { "bin-environment",   NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },        /* 12 */
26872                                                 { "bin-copy-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },     /* 13 */
26873 -                                               
26874 +
26875                                                 { "broken-scriptfilename", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },  /* 14 */
26876                                                 { "allow-x-send-file", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },      /* 15 */
26877                                                 { "strip-request-uri",  NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },      /* 16 */
26878 -                                               
26879 +
26880                                                 { NULL,                NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
26881                                         };
26882 -                                       
26883 +
26884                                         if (da_host->type != TYPE_ARRAY) {
26885 -                                               log_error_write(srv, __FILE__, __LINE__, "ssSBS", 
26886 -                                                               "unexpected type for key:", 
26887 -                                                               "fastcgi.server", 
26888 +                                               log_error_write(srv, __FILE__, __LINE__, "ssSBS",
26889 +                                                               "unexpected type for key:",
26890 +                                                               "fastcgi.server",
26891                                                                 "[", da_host->key, "](string)");
26892 -                                               
26893 +
26894                                                 return HANDLER_ERROR;
26895                                         }
26896 -                                       
26897 +
26898                                         host = fastcgi_host_init();
26899 -                                       
26900 +
26901                                         buffer_copy_string_buffer(host->id, da_host->key);
26902  
26903                                         host->check_local  = 1;
26904 @@ -1238,13 +1192,13 @@
26905                                         host->disable_time = 60;
26906                                         host->break_scriptfilename_for_php = 0;
26907                                         host->allow_xsendfile = 0; /* handle X-LIGHTTPD-send-file */
26908 -                                       
26909 +
26910                                         fcv[0].destination = host->host;
26911                                         fcv[1].destination = host->docroot;
26912                                         fcv[2].destination = fcgi_mode;
26913                                         fcv[3].destination = host->unixsocket;
26914                                         fcv[4].destination = host->bin_path;
26915 -                                       
26916 +
26917                                         fcv[5].destination = &(host->check_local);
26918                                         fcv[6].destination = &(host->port);
26919                                         fcv[7].destination = &(host->min_procs);
26920 @@ -1252,35 +1206,35 @@
26921                                         fcv[9].destination = &(host->max_load_per_proc);
26922                                         fcv[10].destination = &(host->idle_timeout);
26923                                         fcv[11].destination = &(host->disable_time);
26924 -                                       
26925 +
26926                                         fcv[12].destination = host->bin_env;
26927                                         fcv[13].destination = host->bin_env_copy;
26928                                         fcv[14].destination = &(host->break_scriptfilename_for_php);
26929                                         fcv[15].destination = &(host->allow_xsendfile);
26930                                         fcv[16].destination = host->strip_request_uri;
26931 -                                       
26932 +
26933                                         if (0 != config_insert_values_internal(srv, da_host->value, fcv)) {
26934                                                 return HANDLER_ERROR;
26935                                         }
26936 -                                                       
26937 -                                       if ((!buffer_is_empty(host->host) || host->port) && 
26938 +
26939 +                                       if ((!buffer_is_empty(host->host) || host->port) &&
26940                                             !buffer_is_empty(host->unixsocket)) {
26941 -                                               log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", 
26942 +                                               log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
26943                                                                 "either host/port or socket have to be set in:",
26944 -                                                               da->key, "= (", 
26945 +                                                               da->key, "= (",
26946                                                                 da_ext->key, " => (",
26947                                                                 da_host->key, " ( ...");
26948  
26949                                                 return HANDLER_ERROR;
26950                                         }
26951 -                                       
26952 +
26953                                         if (!buffer_is_empty(host->unixsocket)) {
26954                                                 /* unix domain socket */
26955 -                                               
26956 +
26957                                                 if (host->unixsocket->used > UNIX_PATH_MAX - 2) {
26958 -                                                       log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", 
26959 +                                                       log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
26960                                                                         "unixsocket is too long in:",
26961 -                                                                       da->key, "= (", 
26962 +                                                                       da->key, "= (",
26963                                                                         da_ext->key, " => (",
26964                                                                         da_host->key, " ( ...");
26965  
26966 @@ -1288,37 +1242,37 @@
26967                                                 }
26968                                         } else {
26969                                                 /* tcp/ip */
26970 -                                               
26971 -                                               if (buffer_is_empty(host->host) && 
26972 +
26973 +                                               if (buffer_is_empty(host->host) &&
26974                                                     buffer_is_empty(host->bin_path)) {
26975 -                                                       log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", 
26976 +                                                       log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
26977                                                                         "host or binpath have to be set in:",
26978 -                                                                       da->key, "= (", 
26979 +                                                                       da->key, "= (",
26980                                                                         da_ext->key, " => (",
26981                                                                         da_host->key, " ( ...");
26982 -                                                       
26983 +
26984                                                         return HANDLER_ERROR;
26985                                                 } else if (host->port == 0) {
26986 -                                                       log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", 
26987 +                                                       log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
26988                                                                         "port has to be set in:",
26989 -                                                                       da->key, "= (", 
26990 +                                                                       da->key, "= (",
26991                                                                         da_ext->key, " => (",
26992                                                                         da_host->key, " ( ...");
26993  
26994                                                         return HANDLER_ERROR;
26995                                                 }
26996                                         }
26997 -                                               
26998 -                                       if (!buffer_is_empty(host->bin_path)) { 
26999 +
27000 +                                       if (!buffer_is_empty(host->bin_path)) {
27001                                                 /* a local socket + self spawning */
27002                                                 size_t pno;
27003  
27004                                                 /* HACK:  just to make sure the adaptive spawing is disabled */
27005                                                 host->min_procs = host->max_procs;
27006 -                                               
27007 +
27008                                                 if (host->min_procs > host->max_procs) host->max_procs = host->min_procs;
27009                                                 if (host->max_load_per_proc < 1) host->max_load_per_proc = 0;
27010 -                                               
27011 +
27012                                                 if (s->debug) {
27013                                                         log_error_write(srv, __FILE__, __LINE__, "ssbsdsbsdsd",
27014                                                                         "--- fastcgi spawning local",
27015 @@ -1328,7 +1282,7 @@
27016                                                                         "\n\tmin-procs:", host->min_procs,
27017                                                                         "\n\tmax-procs:", host->max_procs);
27018                                                 }
27019 -                                               
27020 +
27021                                                 for (pno = 0; pno < host->min_procs; pno++) {
27022                                                         fcgi_proc *proc;
27023  
27024 @@ -1343,7 +1297,7 @@
27025                                                                 buffer_append_string(proc->unixsocket, "-");
27026                                                                 buffer_append_long(proc->unixsocket, pno);
27027                                                         }
27028 -                                                       
27029 +
27030                                                         if (s->debug) {
27031                                                                 log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
27032                                                                                 "--- fastcgi spawning",
27033 @@ -1351,7 +1305,7 @@
27034                                                                                 "\n\tsocket", host->unixsocket,
27035                                                                                 "\n\tcurrent:", pno, "/", host->min_procs);
27036                                                         }
27037 -                                                       
27038 +
27039                                                         if (fcgi_spawn_connection(srv, p, host, proc)) {
27040                                                                 log_error_write(srv, __FILE__, __LINE__, "s",
27041                                                                                 "[ERROR]: spawning fcgi failed.");
27042 @@ -1359,35 +1313,35 @@
27043                                                         }
27044  
27045                                                         fastcgi_status_init(srv, p->statuskey, host, proc);
27046 -                                                       
27047 +
27048                                                         proc->next = host->first;
27049                                                         if (host->first)        host->first->prev = proc;
27050 -                                                       
27051 +
27052                                                         host->first = proc;
27053                                                 }
27054                                         } else {
27055                                                 fcgi_proc *proc;
27056 -                                               
27057 +
27058                                                 proc = fastcgi_process_init();
27059                                                 proc->id = host->num_procs++;
27060                                                 host->max_id++;
27061                                                 host->active_procs++;
27062                                                 proc->state = PROC_STATE_RUNNING;
27063 -                                               
27064 +
27065                                                 if (buffer_is_empty(host->unixsocket)) {
27066                                                         proc->port = host->port;
27067                                                 } else {
27068                                                         buffer_copy_string_buffer(proc->unixsocket, host->unixsocket);
27069                                                 }
27070 -                                               
27071 +
27072                                                 fastcgi_status_init(srv, p->statuskey, host, proc);
27073  
27074                                                 host->first = proc;
27075 -                                               
27076 +
27077                                                 host->min_procs = 1;
27078                                                 host->max_procs = 1;
27079                                         }
27080 -                                       
27081 +
27082                                         if (!buffer_is_empty(fcgi_mode)) {
27083                                                 if (strcmp(fcgi_mode->ptr, "responder") == 0) {
27084                                                         host->mode = FCGI_RESPONDER;
27085 @@ -1411,16 +1365,16 @@
27086                         }
27087                 }
27088         }
27089 -       
27090 +
27091         buffer_free(fcgi_mode);
27092 -       
27093 +
27094         return HANDLER_GO_ON;
27095  }
27096  
27097  static int fcgi_set_state(server *srv, handler_ctx *hctx, fcgi_connection_state_t state) {
27098         hctx->state = state;
27099         hctx->state_timestamp = srv->cur_ts;
27100 -       
27101 +
27102         return 0;
27103  }
27104  
27105 @@ -1429,13 +1383,13 @@
27106         size_t m = 0;
27107         size_t i;
27108         buffer_uint *r = &(p->fcgi_request_id);
27109 -       
27110 +
27111         UNUSED(srv);
27112  
27113         for (i = 0; i < r->used; i++) {
27114                 if (r->ptr[i] > m) m = r->ptr[i];
27115         }
27116 -       
27117 +
27118         if (r->size == 0) {
27119                 r->size = 16;
27120                 r->ptr = malloc(sizeof(*r->ptr) * r->size);
27121 @@ -1443,54 +1397,55 @@
27122                 r->size += 16;
27123                 r->ptr = realloc(r->ptr, sizeof(*r->ptr) * r->size);
27124         }
27125 -       
27126 +
27127         r->ptr[r->used++] = ++m;
27128 -       
27129 +
27130         return m;
27131  }
27132  
27133  static int fcgi_requestid_del(server *srv, plugin_data *p, size_t request_id) {
27134         size_t i;
27135         buffer_uint *r = &(p->fcgi_request_id);
27136 -       
27137 +
27138         UNUSED(srv);
27139  
27140         for (i = 0; i < r->used; i++) {
27141                 if (r->ptr[i] == request_id) break;
27142         }
27143 -       
27144 +
27145         if (i != r->used) {
27146                 /* found */
27147 -               
27148 +
27149                 if (i != r->used - 1) {
27150                         r->ptr[i] = r->ptr[r->used - 1];
27151                 }
27152                 r->used--;
27153         }
27154 -       
27155 +
27156         return 0;
27157  }
27158  void fcgi_connection_close(server *srv, handler_ctx *hctx) {
27159         plugin_data *p;
27160         connection  *con;
27161 -       
27162 +
27163         if (NULL == hctx) return;
27164 -       
27165 +
27166         p    = hctx->plugin_data;
27167         con  = hctx->remote_conn;
27168 -       
27169 +
27170         if (con->mode != p->id) {
27171 -               WP();
27172                 return;
27173         }
27174 -       
27175 -       if (hctx->fd != -1) {
27176 -               fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
27177 -               fdevent_unregister(srv->ev, hctx->fd);
27178 -               close(hctx->fd);
27179 +
27180 +       if (hctx->sock->fd != -1) {
27181 +               fdevent_event_del(srv->ev, hctx->sock);
27182 +               fdevent_unregister(srv->ev, hctx->sock);
27183 +               closesocket(hctx->sock->fd);
27184 +               hctx->sock->fd = -1;
27185 +
27186                 srv->cur_fds--;
27187         }
27188 -       
27189 +
27190         if (hctx->request_id != 0) {
27191                 fcgi_requestid_del(srv, p, hctx->request_id);
27192         }
27193 @@ -1499,111 +1454,111 @@
27194                 if (hctx->got_proc) {
27195                         /* after the connect the process gets a load */
27196                         hctx->proc->load--;
27197 -                       
27198 -                       status_counter_dec(srv, CONST_STR_LEN("fastcgi.active-requests"));
27199 +
27200 +                       status_counter_dec(CONST_STR_LEN("fastcgi.active-requests"));
27201  
27202                         fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
27203                         buffer_append_string(p->statuskey, ".load");
27204  
27205 -                       status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->proc->load);
27206 +                       status_counter_set(CONST_BUF_LEN(p->statuskey), hctx->proc->load);
27207  
27208                         if (p->conf.debug) {
27209                                 log_error_write(srv, __FILE__, __LINE__, "ssdsbsd",
27210 -                                               "released proc:", 
27211 -                                               "pid:", hctx->proc->pid, 
27212 -                                               "socket:", hctx->proc->connection_name, 
27213 +                                               "released proc:",
27214 +                                               "pid:", hctx->proc->pid,
27215 +                                               "socket:", hctx->proc->connection_name,
27216                                                 "load:", hctx->proc->load);
27217                         }
27218                 }
27219         }
27220  
27221 -       
27222 +
27223         handler_ctx_free(hctx);
27224 -       con->plugin_ctx[p->id] = NULL;  
27225 +       con->plugin_ctx[p->id] = NULL;
27226  }
27227  
27228  static int fcgi_reconnect(server *srv, handler_ctx *hctx) {
27229         plugin_data *p    = hctx->plugin_data;
27230 -       
27231 -       /* child died 
27232 -        * 
27233 -        * 1. 
27234 -        * 
27235 +
27236 +       /* child died
27237 +        *
27238 +        * 1.
27239 +        *
27240          * connect was ok, connection was accepted
27241          * but the php accept loop checks after the accept if it should die or not.
27242 -        * 
27243 -        * if yes we can only detect it at a write() 
27244 -        * 
27245 +        *
27246 +        * if yes we can only detect it at a write()
27247 +        *
27248          * next step is resetting this attemp and setup a connection again
27249 -        * 
27250 +        *
27251          * if we have more then 5 reconnects for the same request, die
27252 -        * 
27253 -        * 2. 
27254 -        * 
27255 +        *
27256 +        * 2.
27257 +        *
27258          * we have a connection but the child died by some other reason
27259 -        * 
27260 +        *
27261          */
27262  
27263 -       if (hctx->fd != -1) {
27264 -               fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
27265 -               fdevent_unregister(srv->ev, hctx->fd);
27266 -               close(hctx->fd);
27267 +       if (hctx->sock->fd != -1) {
27268 +               fdevent_event_del(srv->ev, hctx->sock);
27269 +               fdevent_unregister(srv->ev, hctx->sock);
27270 +               close(hctx->sock->fd);
27271                 srv->cur_fds--;
27272 -               hctx->fd = -1;
27273 +               hctx->sock->fd = -1;
27274         }
27275 -       
27276 +
27277         fcgi_requestid_del(srv, p, hctx->request_id);
27278 -       
27279 +
27280         fcgi_set_state(srv, hctx, FCGI_STATE_INIT);
27281 -       
27282 +
27283         hctx->request_id = 0;
27284         hctx->reconnects++;
27285 -       
27286 +
27287         if (p->conf.debug > 2) {
27288                 if (hctx->proc) {
27289                         log_error_write(srv, __FILE__, __LINE__, "sdb",
27290 -                                       "release proc for reconnect:", 
27291 +                                       "release proc for reconnect:",
27292                                         hctx->proc->pid, hctx->proc->connection_name);
27293                 } else {
27294                         log_error_write(srv, __FILE__, __LINE__, "sb",
27295 -                                       "release proc for reconnect:", 
27296 +                                       "release proc for reconnect:",
27297                                         hctx->host->unixsocket);
27298                 }
27299         }
27300  
27301 -       if (hctx->proc && hctx->got_proc) {     
27302 +       if (hctx->proc && hctx->got_proc) {
27303                 hctx->proc->load--;
27304         }
27305  
27306         /* perhaps another host gives us more luck */
27307         hctx->host->load--;
27308         hctx->host = NULL;
27309 -       
27310 +
27311         return 0;
27312  }
27313  
27314  
27315  static handler_t fcgi_connection_reset(server *srv, connection *con, void *p_d) {
27316         plugin_data *p = p_d;
27317 -       
27318 +
27319         fcgi_connection_close(srv, con->plugin_ctx[p->id]);
27320 -       
27321 +
27322         return HANDLER_GO_ON;
27323  }
27324  
27325  
27326  static int fcgi_env_add(buffer *env, const char *key, size_t key_len, const char *val, size_t val_len) {
27327         size_t len;
27328 -       
27329 +
27330         if (!key || !val) return -1;
27331 -       
27332 +
27333         len = key_len + val_len;
27334 -       
27335 +
27336         len += key_len > 127 ? 4 : 1;
27337         len += val_len > 127 ? 4 : 1;
27338 -       
27339 +
27340         buffer_prepare_append(env, len);
27341 -       
27342 +
27343         if (key_len > 127) {
27344                 env->ptr[env->used++] = ((key_len >> 24) & 0xff) | 0x80;
27345                 env->ptr[env->used++] = (key_len >> 16) & 0xff;
27346 @@ -1612,7 +1567,7 @@
27347         } else {
27348                 env->ptr[env->used++] = (key_len >> 0) & 0xff;
27349         }
27350 -       
27351 +
27352         if (val_len > 127) {
27353                 env->ptr[env->used++] = ((val_len >> 24) & 0xff) | 0x80;
27354                 env->ptr[env->used++] = (val_len >> 16) & 0xff;
27355 @@ -1621,12 +1576,12 @@
27356         } else {
27357                 env->ptr[env->used++] = (val_len >> 0) & 0xff;
27358         }
27359 -       
27360 +
27361         memcpy(env->ptr + env->used, key, key_len);
27362         env->used += key_len;
27363         memcpy(env->ptr + env->used, val, val_len);
27364         env->used += val_len;
27365 -       
27366 +
27367         return 0;
27368  }
27369  
27370 @@ -1639,11 +1594,11 @@
27371         header->contentLengthB1 = (contentLength >> 8) & 0xff;
27372         header->paddingLength = paddingLength;
27373         header->reserved = 0;
27374 -       
27375 +
27376         return 0;
27377  }
27378  /**
27379 - * 
27380 + *
27381   * returns
27382   *   -1 error
27383   *    0 connected
27384 @@ -1665,26 +1620,23 @@
27385         struct sockaddr_un fcgi_addr_un;
27386  #endif
27387         socklen_t servlen;
27388 -       
27389 +
27390         fcgi_extension_host *host = hctx->host;
27391         fcgi_proc *proc   = hctx->proc;
27392 -       int fcgi_fd       = hctx->fd;
27393 -       
27394 +       int fcgi_fd       = hctx->sock->fd;
27395 +
27396         memset(&fcgi_addr, 0, sizeof(fcgi_addr));
27397 -       
27398 +
27399         if (!buffer_is_empty(proc->unixsocket)) {
27400  #ifdef HAVE_SYS_UN_H
27401                 /* use the unix domain socket */
27402                 fcgi_addr_un.sun_family = AF_UNIX;
27403                 strcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr);
27404 -#ifdef SUN_LEN
27405 +
27406                 servlen = SUN_LEN(&fcgi_addr_un);
27407 -#else
27408 -               /* stevens says: */
27409 -               servlen = proc->unixsocket->used + sizeof(fcgi_addr_un.sun_family);
27410 -#endif
27411 +
27412                 fcgi_addr = (struct sockaddr *) &fcgi_addr_un;
27413 -       
27414 +
27415                 if (buffer_is_empty(proc->connection_name)) {
27416                         /* on remote spawing we have to set the connection-name now */
27417                         buffer_copy_string(proc->connection_name, "unix:");
27418 @@ -1695,16 +1647,18 @@
27419  #endif
27420         } else {
27421                 fcgi_addr_in.sin_family = AF_INET;
27422 +
27423                 if (0 == inet_aton(host->host->ptr, &(fcgi_addr_in.sin_addr))) {
27424 -                       log_error_write(srv, __FILE__, __LINE__, "sbs", 
27425 -                                       "converting IP-adress failed for", host->host, 
27426 +                       log_error_write(srv, __FILE__, __LINE__, "sbs",
27427 +                                       "converting IP-adress failed for", host->host,
27428                                         "\nBe sure to specify an IP address here");
27429 -                       
27430 +
27431                         return -1;
27432                 }
27433 +
27434                 fcgi_addr_in.sin_port = htons(proc->port);
27435                 servlen = sizeof(fcgi_addr_in);
27436 -               
27437 +
27438                 fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
27439  
27440                 if (buffer_is_empty(proc->connection_name)) {
27441 @@ -1715,20 +1669,20 @@
27442                         buffer_append_long(proc->connection_name, proc->port);
27443                 }
27444         }
27445 -       
27446 +
27447         if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
27448 -               if (errno == EINPROGRESS || 
27449 +               if (errno == EINPROGRESS ||
27450                     errno == EALREADY ||
27451                     errno == EINTR) {
27452                         if (hctx->conf.debug > 2) {
27453 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
27454 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
27455                                         "connect delayed, will continue later:", proc->connection_name);
27456                         }
27457 -                       
27458 +
27459                         return CONNECTION_DELAYED;
27460                 } else if (errno == EAGAIN) {
27461                         if (hctx->conf.debug) {
27462 -                               log_error_write(srv, __FILE__, __LINE__, "sbsd", 
27463 +                               log_error_write(srv, __FILE__, __LINE__, "sbsd",
27464                                         "This means that the you have more incoming requests than your fastcgi-backend can handle in parallel. "
27465                                         "Perhaps it helps to spawn more fastcgi backend or php-children, if not decrease server.max-connections."
27466                                         "The load for this fastcgi backend", proc->connection_name, "is", proc->load);
27467 @@ -1736,8 +1690,8 @@
27468  
27469                         return CONNECTION_OVERLOADED;
27470                 } else {
27471 -                       log_error_write(srv, __FILE__, __LINE__, "sssb", 
27472 -                                       "connect failed:", 
27473 +                       log_error_write(srv, __FILE__, __LINE__, "sssb",
27474 +                                       "connect failed:",
27475                                         strerror(errno), "on",
27476                                         proc->connection_name);
27477  
27478 @@ -1747,7 +1701,7 @@
27479  
27480         hctx->reconnects = 0;
27481         if (hctx->conf.debug > 1) {
27482 -               log_error_write(srv, __FILE__, __LINE__, "sd", 
27483 +               log_error_write(srv, __FILE__, __LINE__, "sd",
27484                                 "connect succeeded: ", fcgi_fd);
27485         }
27486  
27487 @@ -1756,21 +1710,21 @@
27488  
27489  static int fcgi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
27490         size_t i;
27491 -       
27492 +
27493         for (i = 0; i < con->request.headers->used; i++) {
27494                 data_string *ds;
27495 -               
27496 +
27497                 ds = (data_string *)con->request.headers->data[i];
27498 -               
27499 +
27500                 if (ds->value->used && ds->key->used) {
27501                         size_t j;
27502                         buffer_reset(srv->tmp_buf);
27503 -                       
27504 +
27505                         if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
27506                                 BUFFER_COPY_STRING_CONST(srv->tmp_buf, "HTTP_");
27507                                 srv->tmp_buf->used--;
27508                         }
27509 -                       
27510 +
27511                         buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
27512                         for (j = 0; j < ds->key->used - 1; j++) {
27513                                 char c = '_';
27514 @@ -1784,20 +1738,20 @@
27515                                 srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
27516                         }
27517                         srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
27518 -                       
27519 +
27520                         fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
27521                 }
27522         }
27523 -       
27524 +
27525         for (i = 0; i < con->environment->used; i++) {
27526                 data_string *ds;
27527 -               
27528 +
27529                 ds = (data_string *)con->environment->data[i];
27530 -               
27531 +
27532                 if (ds->value->used && ds->key->used) {
27533                         size_t j;
27534                         buffer_reset(srv->tmp_buf);
27535 -                       
27536 +
27537                         buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
27538                         for (j = 0; j < ds->key->used - 1; j++) {
27539                                 char c = '_';
27540 @@ -1811,11 +1765,11 @@
27541                                 srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
27542                         }
27543                         srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
27544 -                       
27545 +
27546                         fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
27547                 }
27548         }
27549 -       
27550 +
27551         return 0;
27552  }
27553  
27554 @@ -1824,24 +1778,24 @@
27555         FCGI_BeginRequestRecord beginRecord;
27556         FCGI_Header header;
27557         buffer *b;
27558 -       
27559 +
27560         char buf[32];
27561         const char *s;
27562  #ifdef HAVE_IPV6
27563         char b2[INET6_ADDRSTRLEN + 1];
27564  #endif
27565 -       
27566 +
27567         plugin_data *p    = hctx->plugin_data;
27568         fcgi_extension_host *host= hctx->host;
27569  
27570         connection *con   = hctx->remote_conn;
27571         server_socket *srv_sock = con->srv_socket;
27572 -       
27573 +
27574         sock_addr our_addr;
27575         socklen_t our_addr_len;
27576 -       
27577 +
27578         /* send FCGI_BEGIN_REQUEST */
27579 -       
27580 +
27581         fcgi_header(&(beginRecord.header), FCGI_BEGIN_REQUEST, request_id, sizeof(beginRecord.body), 0);
27582         beginRecord.body.roleB0 = host->mode;
27583         beginRecord.body.roleB1 = 0;
27584 @@ -1849,21 +1803,21 @@
27585         memset(beginRecord.body.reserved, 0, sizeof(beginRecord.body.reserved));
27586  
27587         b = chunkqueue_get_append_buffer(hctx->wb);
27588 -       
27589 +
27590         buffer_copy_memory(b, (const char *)&beginRecord, sizeof(beginRecord));
27591 -       
27592 +
27593         /* send FCGI_PARAMS */
27594         buffer_prepare_copy(p->fcgi_env, 1024);
27595  
27596  
27597         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION));
27598 -       
27599 +
27600         if (con->server_name->used) {
27601                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_NAME"), CONST_BUF_LEN(con->server_name));
27602         } else {
27603  #ifdef HAVE_IPV6
27604 -               s = inet_ntop(srv_sock->addr.plain.sa_family, 
27605 -                             srv_sock->addr.plain.sa_family == AF_INET6 ? 
27606 +               s = inet_ntop(srv_sock->addr.plain.sa_family,
27607 +                             srv_sock->addr.plain.sa_family == AF_INET6 ?
27608                               (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
27609                               (const void *) &(srv_sock->addr.ipv4.sin_addr),
27610                               b2, sizeof(b2)-1);
27611 @@ -1872,50 +1826,50 @@
27612  #endif
27613                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_NAME"), s, strlen(s));
27614         }
27615 -       
27616 +
27617         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
27618 -       
27619 -       ltostr(buf, 
27620 +
27621 +       ltostr(buf,
27622  #ifdef HAVE_IPV6
27623                ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
27624  #else
27625                ntohs(srv_sock->addr.ipv4.sin_port)
27626  #endif
27627                );
27628 -       
27629 +
27630         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
27631 -       
27632 +
27633         /* get the server-side of the connection to the client */
27634         our_addr_len = sizeof(our_addr);
27635 -       
27636 -       if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) {
27637 +
27638 +       if (-1 == getsockname(con->sock->fd, &(our_addr.plain), &our_addr_len)) {
27639                 s = inet_ntop_cache_get_ip(srv, &(srv_sock->addr));
27640         } else {
27641                 s = inet_ntop_cache_get_ip(srv, &(our_addr));
27642         }
27643         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
27644 -       
27645 -       ltostr(buf, 
27646 +
27647 +       ltostr(buf,
27648  #ifdef HAVE_IPV6
27649                ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
27650  #else
27651                ntohs(con->dst_addr.ipv4.sin_port)
27652  #endif
27653                );
27654 -       
27655 +
27656         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
27657 -       
27658 +
27659         s = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
27660         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
27661 -       
27662 +
27663         if (!buffer_is_empty(con->authed_user)) {
27664                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_USER"),
27665                              CONST_BUF_LEN(con->authed_user));
27666         }
27667 -       
27668 +
27669         if (con->request.content_length > 0 && host->mode != FCGI_AUTHORIZER) {
27670                 /* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */
27671 -               
27672 +
27673                 /* request.content_length < SSIZE_MAX, see request.c */
27674                 ltostr(buf, con->request.content_length);
27675                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
27676 @@ -1930,12 +1884,12 @@
27677                  */
27678  
27679                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
27680 -               
27681 +
27682                 if (!buffer_is_empty(con->request.pathinfo)) {
27683                         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
27684 -                       
27685 +
27686                         /* PATH_TRANSLATED is only defined if PATH_INFO is set */
27687 -                       
27688 +
27689                         if (!buffer_is_empty(host->docroot)) {
27690                                 buffer_copy_string_buffer(p->path, host->docroot);
27691                         } else {
27692 @@ -1957,27 +1911,27 @@
27693          */
27694  
27695         if (!buffer_is_empty(host->docroot)) {
27696 -               /* 
27697 -                * rewrite SCRIPT_FILENAME 
27698 -                * 
27699 +               /*
27700 +                * rewrite SCRIPT_FILENAME
27701 +                *
27702                  */
27703 -               
27704 +
27705                 buffer_copy_string_buffer(p->path, host->docroot);
27706                 buffer_append_string_buffer(p->path, con->uri.path);
27707 -               
27708 +
27709                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
27710                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(host->docroot));
27711         } else {
27712                 buffer_copy_string_buffer(p->path, con->physical.path);
27713 -               
27714 -               /* cgi.fix_pathinfo need a broken SCRIPT_FILENAME to find out what PATH_INFO is itself 
27715 -                * 
27716 +
27717 +               /* cgi.fix_pathinfo need a broken SCRIPT_FILENAME to find out what PATH_INFO is itself
27718 +                *
27719                  * see src/sapi/cgi_main.c, init_request_info()
27720                  */
27721                 if (host->break_scriptfilename_for_php) {
27722                         buffer_append_string_buffer(p->path, con->request.pathinfo);
27723                 }
27724 -               
27725 +
27726                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
27727                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root));
27728         }
27729 @@ -1987,7 +1941,7 @@
27730                 /**
27731                  * /app1/index/list
27732                  *
27733 -                * stripping /app1 or /app1/ should lead to 
27734 +                * stripping /app1 or /app1/ should lead to
27735                  *
27736                  * /index/list
27737                  *
27738 @@ -2001,7 +1955,7 @@
27739                     0 == strncmp(con->request.orig_uri->ptr, host->strip_request_uri->ptr, host->strip_request_uri->used - 1)) {
27740                         /* the left is the same */
27741  
27742 -                       fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"), 
27743 +                       fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"),
27744                                         con->request.orig_uri->ptr + (host->strip_request_uri->used - 2),
27745                                         con->request.orig_uri->used - (host->strip_request_uri->used - 2));
27746                 } else {
27747 @@ -2018,26 +1972,26 @@
27748         } else {
27749                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
27750         }
27751 -       
27752 +
27753         s = get_http_method_name(con->request.http_method);
27754         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
27755         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")); /* if php is compiled with --force-redirect */
27756         s = get_http_version_name(con->request.http_version);
27757         fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
27758 -       
27759 +
27760  #ifdef USE_OPENSSL
27761         if (srv_sock->is_ssl) {
27762                 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on"));
27763         }
27764  #endif
27765 -       
27766 -       
27767 +
27768 +
27769         fcgi_env_add_request_headers(srv, con, p);
27770 -       
27771 +
27772         fcgi_header(&(header), FCGI_PARAMS, request_id, p->fcgi_env->used, 0);
27773         buffer_append_memory(b, (const char *)&header, sizeof(header));
27774         buffer_append_memory(b, (const char *)p->fcgi_env->ptr, p->fcgi_env->used);
27775 -       
27776 +
27777         fcgi_header(&(header), FCGI_PARAMS, request_id, 0, 0);
27778         buffer_append_memory(b, (const char *)&header, sizeof(header));
27779  
27780 @@ -2045,7 +1999,7 @@
27781         hctx->wb->bytes_in += b->used - 1;
27782  
27783         if (con->request.content_length) {
27784 -               chunkqueue *req_cq = con->request_content_queue;
27785 +               chunkqueue *req_cq = con->recv;
27786                 chunk *req_c;
27787                 off_t offset;
27788  
27789 @@ -2057,7 +2011,7 @@
27790  
27791                         /* we announce toWrite octects
27792                          * now take all the request_content chunk that we need to fill this request
27793 -                        * */   
27794 +                        * */
27795  
27796                         b = chunkqueue_get_append_buffer(hctx->wb);
27797                         fcgi_header(&(header), FCGI_STDIN, request_id, weWant, 0);
27798 @@ -2080,16 +2034,16 @@
27799                                         if (weHave > weWant - written) weHave = weWant - written;
27800  
27801                                         if (p->conf.debug > 10) {
27802 -                                               fprintf(stderr, "%s.%d: sending %lld bytes from (%lld / %lld) %s\n", 
27803 -                                                               __FILE__, __LINE__, 
27804 -                                                               weHave, 
27805 -                                                               req_c->offset, 
27806 -                                                               req_c->file.length, 
27807 +                                               fprintf(stderr, "%s.%d: sending %lld bytes from (%lld / %lld) %s\n",
27808 +                                                               __FILE__, __LINE__,
27809 +                                                               weHave,
27810 +                                                               req_c->offset,
27811 +                                                               req_c->file.length,
27812                                                                 req_c->file.name->ptr);
27813                                         }
27814  
27815                                         assert(weHave != 0);
27816 -                                       
27817 +
27818                                         chunkqueue_append_file(hctx->wb, req_c->file.name, req_c->offset, weHave);
27819  
27820                                         req_c->offset += weHave;
27821 @@ -2104,7 +2058,7 @@
27822                                          * - we reference the tempfile from the request-content-queue several times
27823                                          *   if the req_c is larger than FCGI_MAX_LENGTH
27824                                          * - we can't simply cleanup the request-content-queue as soon as possible
27825 -                                        *   as it would remove the tempfiles 
27826 +                                        *   as it would remove the tempfiles
27827                                          * - the idea is to 'steal' the tempfiles and attach the is_temp flag to the last
27828                                          *   referencing chunk of the fastcgi-write-queue
27829                                          *
27830 @@ -2141,7 +2095,7 @@
27831                                         req_c->offset += weHave;
27832                                         req_cq->bytes_out += weHave;
27833                                         written += weHave;
27834 -                                       
27835 +
27836                                         hctx->wb->bytes_in += weHave;
27837  
27838                                         if (req_c->offset == req_c->mem->used - 1) {
27839 @@ -2155,12 +2109,12 @@
27840                                         break;
27841                                 }
27842                         }
27843 -                       
27844 +
27845                         b->used++; /* add virtual \0 */
27846                         offset += weWant;
27847                 }
27848         }
27849 -       
27850 +
27851         b = chunkqueue_get_append_buffer(hctx->wb);
27852         /* terminate STDIN */
27853         fcgi_header(&(header), FCGI_STDIN, request_id, 0, 0);
27854 @@ -2175,118 +2129,19 @@
27855                 if ((i+1) % 16 == 0) {
27856                         size_t j;
27857                         for (j = i-15; j <= i; j++) {
27858 -                               fprintf(stderr, "%c", 
27859 +                               fprintf(stderr, "%c",
27860                                         isprint((unsigned char)hctx->write_buffer->ptr[j]) ? hctx->write_buffer->ptr[j] : '.');
27861                         }
27862                         fprintf(stderr, "\n");
27863                 }
27864         }
27865  #endif
27866 -       
27867 -       return 0;
27868 -}
27869  
27870 -static int fcgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in) {
27871 -       char *s, *ns;
27872 -       
27873 -       handler_ctx *hctx = con->plugin_ctx[p->id];
27874 -       fcgi_extension_host *host= hctx->host;
27875 -       
27876 -       UNUSED(srv);
27877 -
27878 -       buffer_copy_string_buffer(p->parse_response, in);
27879 -       
27880 -       /* search for \n */
27881 -       for (s = p->parse_response->ptr; NULL != (ns = strchr(s, '\n')); s = ns + 1) {
27882 -               char *key, *value;
27883 -               int key_len;
27884 -               data_string *ds;
27885 -               
27886 -               /* a good day. Someone has read the specs and is sending a \r\n to us */
27887 -               
27888 -               if (ns > p->parse_response->ptr &&
27889 -                   *(ns-1) == '\r') {
27890 -                       *(ns-1) = '\0';
27891 -               }
27892 -               
27893 -               ns[0] = '\0';
27894 -               
27895 -               key = s;
27896 -               if (NULL == (value = strchr(s, ':'))) {
27897 -                       /* we expect: "<key>: <value>\n" */
27898 -                       continue;
27899 -               }
27900 -               
27901 -               key_len = value - key;
27902 -               
27903 -               value++;
27904 -               /* strip WS */
27905 -               while (*value == ' ' || *value == '\t') value++;
27906 -               
27907 -               if (host->mode != FCGI_AUTHORIZER ||
27908 -                   !(con->http_status == 0 ||
27909 -                     con->http_status == 200)) {
27910 -                       /* authorizers shouldn't affect the response headers sent back to the client */
27911 -                       
27912 -                       /* don't forward Status: */
27913 -                       if (0 != strncasecmp(key, "Status", key_len)) {
27914 -                               if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
27915 -                                       ds = data_response_init();
27916 -                               }
27917 -                               buffer_copy_string_len(ds->key, key, key_len);
27918 -                               buffer_copy_string(ds->value, value);
27919 -                               
27920 -                               array_insert_unique(con->response.headers, (data_unset *)ds);
27921 -                       }
27922 -               }
27923 -               
27924 -               switch(key_len) {
27925 -               case 4:
27926 -                       if (0 == strncasecmp(key, "Date", key_len)) {
27927 -                               con->parsed_response |= HTTP_DATE;
27928 -                       }
27929 -                       break;
27930 -               case 6:
27931 -                       if (0 == strncasecmp(key, "Status", key_len)) {
27932 -                               con->http_status = strtol(value, NULL, 10);
27933 -                               con->parsed_response |= HTTP_STATUS;
27934 -                       }
27935 -                       break;
27936 -               case 8:
27937 -                       if (0 == strncasecmp(key, "Location", key_len)) {
27938 -                               con->parsed_response |= HTTP_LOCATION;
27939 -                       }
27940 -                       break;
27941 -               case 10:
27942 -                       if (0 == strncasecmp(key, "Connection", key_len)) {
27943 -                               con->response.keep_alive = (0 == strcasecmp(value, "Keep-Alive")) ? 1 : 0;
27944 -                               con->parsed_response |= HTTP_CONNECTION;
27945 -                       }
27946 -                       break;
27947 -               case 14:
27948 -                       if (0 == strncasecmp(key, "Content-Length", key_len)) {
27949 -                               con->response.content_length = strtol(value, NULL, 10);
27950 -                               con->parsed_response |= HTTP_CONTENT_LENGTH;
27951 -                               
27952 -                               if (con->response.content_length < 0) con->response.content_length = 0;
27953 -                       }
27954 -                       break;
27955 -               default:
27956 -                       break;
27957 -               }
27958 -       }
27959 -       
27960 -       /* CGI/1.1 rev 03 - 7.2.1.2 */
27961 -       if ((con->parsed_response & HTTP_LOCATION) &&
27962 -           !(con->parsed_response & HTTP_STATUS)) {
27963 -               con->http_status = 302;
27964 -       }
27965 -       
27966         return 0;
27967  }
27968  
27969  typedef struct {
27970 -       buffer  *b; 
27971 +       buffer  *b;
27972         size_t   len;
27973         int      type;
27974         int      padding;
27975 @@ -2327,9 +2182,9 @@
27976                 return -1;
27977         }
27978  
27979 -       /* we have at least a header, now check how much me have to fetch */ 
27980 +       /* we have at least a header, now check how much me have to fetch */
27981         header = (FCGI_Header *)(packet->b->ptr);
27982 -                       
27983 +
27984         packet->len = (header->contentLengthB0 | (header->contentLengthB1 << 8)) + header->paddingLength;
27985         packet->request_id = (header->requestIdB0 | (header->requestIdB1 << 8));
27986         packet->type = header->type;
27987 @@ -2348,7 +2203,7 @@
27988                         size_t weHave = c->mem->used - c->offset - offset - 1;
27989  
27990                         if (weHave > weWant) weHave = weWant;
27991 -                                               
27992 +
27993                         buffer_append_string_len(packet->b, c->mem->ptr + c->offset + offset, weHave);
27994  
27995                         /* we only skipped the first 8 bytes as they are the fcgi header */
27996 @@ -2380,65 +2235,42 @@
27997         }
27998  
27999         chunkqueue_remove_finished_chunks(hctx->rb);
28000 -       
28001 +
28002         return 0;
28003  }
28004  
28005  static int fcgi_demux_response(server *srv, handler_ctx *hctx) {
28006         int fin = 0;
28007 -       int toread;
28008 -       ssize_t r;
28009 -       
28010 +
28011         plugin_data *p    = hctx->plugin_data;
28012         connection *con   = hctx->remote_conn;
28013 -       int fcgi_fd       = hctx->fd;
28014         fcgi_extension_host *host= hctx->host;
28015         fcgi_proc *proc   = hctx->proc;
28016 -       
28017 -       /* 
28018 -        * check how much we have to read 
28019 -        */
28020 -       if (ioctl(hctx->fd, FIONREAD, &toread)) {
28021 -               log_error_write(srv, __FILE__, __LINE__, "sd", 
28022 -                               "unexpected end-of-file (perhaps the fastcgi process died):",
28023 -                               fcgi_fd);
28024 -               return -1;
28025 -       }
28026 -       
28027 -       /* init read-buffer */
28028 -       
28029 -       if (toread > 0) {
28030 -               buffer *b;
28031 -
28032 -               b = chunkqueue_get_append_buffer(hctx->rb);
28033 -               buffer_prepare_copy(b, toread + 1);
28034 -
28035 -               /* append to read-buffer */
28036 -               if (-1 == (r = read(hctx->fd, b->ptr, toread))) {
28037 -                       log_error_write(srv, __FILE__, __LINE__, "sds", 
28038 -                                       "unexpected end-of-file (perhaps the fastcgi process died):",
28039 -                                       fcgi_fd, strerror(errno));
28040 -                       return -1;
28041 -               }
28042 -               
28043 -               /* this should be catched by the b > 0 above */
28044 -               assert(r);
28045 +       handler_t ret;
28046  
28047 -               b->used = r + 1; /* one extra for the fake \0 */
28048 -               b->ptr[b->used - 1] = '\0';
28049 -       } else {
28050 -               log_error_write(srv, __FILE__, __LINE__, "ssdsb", 
28051 -                               "unexpected end-of-file (perhaps the fastcgi process died):",
28052 -                               "pid:", proc->pid,
28053 -                               "socket:", proc->connection_name);
28054 -               
28055 +       /* in case we read nothing, check the return code
28056 +        * if we got something, be happy :)
28057 +        *
28058 +        * Ok, to be honest:
28059 +        * - it is fine to receive a EAGAIN on a second read() call
28060 +        * - it might be fine they we get a con-close on a second read() call */
28061 +       switch(srv->network_backend_read(srv, con, hctx->sock, hctx->rb)) {
28062 +       case NETWORK_STATUS_WAIT_FOR_EVENT:
28063 +               /* a EAGAIN after we read exactly the chunk-size */
28064 +
28065 +               ERROR("%s", "oops, got a EAGAIN even if we just got call for the event, wired");
28066 +               return -1;
28067 +       case NETWORK_STATUS_SUCCESS:
28068 +               break;
28069 +       default:
28070 +               ERROR("reading from fastcgi socket failed (fd=%d)", hctx->sock->fd);
28071                 return -1;
28072         }
28073  
28074         /*
28075          * parse the fastcgi packets and forward the content to the write-queue
28076          *
28077 -        */     
28078 +        */
28079         while (fin == 0) {
28080                 fastcgi_response_packet packet;
28081  
28082 @@ -2454,132 +2286,165 @@
28083  
28084                         /* is the header already finished */
28085                         if (0 == con->file_started) {
28086 -                               char *c;
28087 -                               size_t blen;
28088 -                               data_string *ds;
28089 -                                       
28090 -                               /* search for header terminator 
28091 -                                * 
28092 -                                * if we start with \r\n check if last packet terminated with \r\n
28093 -                                * if we start with \n check if last packet terminated with \n
28094 -                                * search for \r\n\r\n
28095 -                                * search for \n\n
28096 -                                */
28097 -
28098 -                               if (hctx->response_header->used == 0) {
28099 -                                       buffer_copy_string_buffer(hctx->response_header, packet.b);
28100 -                               } else {
28101 -                                       buffer_append_string_buffer(hctx->response_header, packet.b);
28102 -                               }
28103 -
28104 -                               if (NULL != (c = buffer_search_string_len(hctx->response_header, CONST_STR_LEN("\r\n\r\n")))) {
28105 -                                       blen = hctx->response_header->used - (c - hctx->response_header->ptr) - 4;
28106 -                                       hctx->response_header->used = (c - hctx->response_header->ptr) + 3;
28107 -                                       c += 4; /* point the the start of the response */
28108 -                               } else if (NULL != (c = buffer_search_string_len(hctx->response_header, CONST_STR_LEN("\n\n")))) {
28109 -                                       blen = hctx->response_header->used - (c - hctx->response_header->ptr) - 2;
28110 -                                       hctx->response_header->used = c - hctx->response_header->ptr + 2;
28111 -                                       c += 2; /* point the the start of the response */
28112 -                               } else {
28113 -                                       /* no luck, no header found */
28114 +                               int have_content_length = 0;
28115 +                               int need_more = 0;
28116 +                               size_t i;
28117 +
28118 +                               /* append the current packet to the chunk queue */
28119 +                               chunkqueue_append_buffer(hctx->http_rb, packet.b);
28120 +                               http_response_reset(p->resp);
28121 +
28122 +                               switch(http_response_parse_cq(hctx->http_rb, p->resp)) {
28123 +                               case PARSE_ERROR:
28124 +                                       /* parsing the response header failed */
28125 +
28126 +                                       con->http_status = 502; /* Bad Gateway */
28127 +
28128 +                                       return 1;
28129 +                               case PARSE_NEED_MORE:
28130 +                                       need_more = 1;
28131 +                                       break; /* leave the loop */
28132 +                               case PARSE_SUCCESS:
28133                                         break;
28134 +                               default:
28135 +                                       /* should not happen */
28136 +                                       SEGFAULT();
28137                                 }
28138  
28139 -                               /* parse the response header */
28140 -                               fcgi_response_parse(srv, con, p, hctx->response_header);
28141 +                               if (need_more) break;
28142  
28143 -                               con->file_started = 1;
28144 +                               chunkqueue_remove_finished_chunks(hctx->http_rb);
28145  
28146 -                               if (host->mode == FCGI_AUTHORIZER &&
28147 -                                   (con->http_status == 0 ||
28148 -                                    con->http_status == 200)) {
28149 -                                       /* a authorizer with approved the static request, ignore the content here */
28150 -                                       hctx->send_content_body = 0;
28151 -                               }
28152 -
28153 -                               if (host->allow_xsendfile &&
28154 -                                   NULL != (ds = (data_string *) array_get_element(con->response.headers, "X-LIGHTTPD-send-file"))) {
28155 -                                       stat_cache_entry *sce;
28156 -
28157 -                                       if (HANDLER_ERROR != stat_cache_get_entry(srv, con, ds->value, &sce)) {
28158 -                                               /* found */
28159 -
28160 -                                               http_chunk_append_file(srv, con, ds->value, 0, sce->st.st_size);
28161 -                                               hctx->send_content_body = 0; /* ignore the content */
28162 -                                               joblist_append(srv, con);
28163 +                               con->http_status = p->resp->status;
28164 +                               hctx->send_content_body = 1;
28165 +
28166 +                               /* handle the header fields */
28167 +                               if (host->mode == FCGI_AUTHORIZER) {
28168 +                                       /* auth mode is a bit different */
28169 +
28170 +                                       if (con->http_status == 0 ||
28171 +                                           con->http_status == 200) {
28172 +                                               /* a authorizer with approved the static request, ignore the content here */
28173 +                                               hctx->send_content_body = 0;
28174                                         }
28175                                 }
28176  
28177 +                               /* copy the http-headers */
28178 +                               for (i = 0; i < p->resp->headers->used; i++) {
28179 +                                       const char *ign[] = { "Status", NULL };
28180 +                                       size_t j;
28181 +                                       data_string *ds;
28182 +
28183 +                                       data_string *header = (data_string *)p->resp->headers->data[i];
28184 +
28185 +                                       /* ignore all headers in AUTHORIZER mode */
28186 +                                       if (host->mode == FCGI_AUTHORIZER) continue;
28187 +
28188 +                                       /* some headers are ignored by default */
28189 +                                       for (j = 0; ign[j]; j++) {
28190 +                                               if (0 == strcasecmp(ign[j], header->key->ptr)) break;
28191 +                                       }
28192 +                                       if (ign[j]) continue;
28193 +
28194 +                                       if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
28195 +                                               /* CGI/1.1 rev 03 - 7.2.1.2 */
28196 +                                               con->http_status = 302;
28197 +                                       } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
28198 +                                               have_content_length = 1;
28199 +                                       } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("X-Sendfile")) || 
28200 +                                                  0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("X-LIGHTTPD-send-file"))) {
28201                                                 
28202 -                               if (hctx->send_content_body && blen > 1) {                                              
28203 -                                       /* enable chunked-transfer-encoding */
28204 -                                       if (con->request.http_version == HTTP_VERSION_1_1 &&
28205 -                                           !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
28206 -                                               con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
28207 +                                               stat_cache_entry *sce;
28208 +                                               
28209 +                                               if (host->allow_xsendfile &&
28210 +                                                   HANDLER_ERROR != stat_cache_get_entry(srv, con, header->value, &sce)) {
28211 +                                                       chunkqueue_append_file(con->send, header->value, 0, sce->st.st_size);
28212 +                                                       hctx->send_content_body = 0; /* ignore the content */
28213 +                                       
28214 +                                                       joblist_append(srv, con);
28215 +                                               }
28216 +
28217 +                                               continue; /* ignore header */
28218                                         }
28219 +                                       
28220 +                                       if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
28221 +                                               ds = data_response_init();
28222 +                                       }
28223 +                                       buffer_copy_string_buffer(ds->key, header->key);
28224 +                                       buffer_copy_string_buffer(ds->value, header->value);
28225  
28226 -                                       http_chunk_append_mem(srv, con, c, blen);
28227 +                                       array_insert_unique(con->response.headers, (data_unset *)ds);
28228 +                               }
28229 +
28230 +                               /* header is complete ... go on with the body */
28231 +
28232 +                               con->file_started = 1;
28233 +
28234 +                               if (hctx->send_content_body) {
28235 +                                       chunk *c = hctx->http_rb->first;
28236 +
28237 +                                       /* copy the rest of the data */
28238 +                                       for (c = hctx->http_rb->first; c; c = c->next) {
28239 +                                               if (c->mem->used > 1) {
28240 +                                                       chunkqueue_append_mem(con->send, c->mem->ptr + c->offset, c->mem->used - c->offset);
28241 +                                                       c->offset = c->mem->used - 1;
28242 +                                               }
28243 +                                       }
28244 +                                       chunkqueue_remove_finished_chunks(hctx->http_rb);
28245                                         joblist_append(srv, con);
28246                                 }
28247                         } else if (hctx->send_content_body && packet.b->used > 1) {
28248 -                               if (con->request.http_version == HTTP_VERSION_1_1 &&
28249 -                                   !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
28250 -                                       /* enable chunked-transfer-encoding */
28251 -                                       con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
28252 -                               }
28253 -
28254 -                               http_chunk_append_mem(srv, con, packet.b->ptr, packet.b->used);
28255 +                               chunkqueue_append_mem(con->send, packet.b->ptr, packet.b->used);
28256                                 joblist_append(srv, con);
28257                         }
28258                         break;
28259                 case FCGI_STDERR:
28260 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
28261 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
28262                                         "FastCGI-stderr:", packet.b);
28263 -                       
28264 +
28265                         break;
28266                 case FCGI_END_REQUEST:
28267 -                       con->file_finished = 1;
28268 -                       
28269 +                       con->send->is_closed = 1;
28270 +
28271                         if (host->mode != FCGI_AUTHORIZER ||
28272                             !(con->http_status == 0 ||
28273                               con->http_status == 200)) {
28274                                 /* send chunk-end if nesseary */
28275 -                               http_chunk_append_mem(srv, con, NULL, 0);
28276                                 joblist_append(srv, con);
28277                         }
28278 -                       
28279 +
28280                         fin = 1;
28281                         break;
28282                 default:
28283 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
28284 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
28285                                         "FastCGI: header.type not handled: ", packet.type);
28286                         break;
28287                 }
28288                 buffer_free(packet.b);
28289         }
28290 -       
28291 +
28292         return fin;
28293  }
28294  
28295  static int fcgi_restart_dead_procs(server *srv, plugin_data *p, fcgi_extension_host *host) {
28296         fcgi_proc *proc;
28297 -       
28298 +
28299         for (proc = host->first; proc; proc = proc->next) {
28300                 int status;
28301  
28302                 if (p->conf.debug > 2) {
28303 -                       log_error_write(srv, __FILE__, __LINE__,  "sbdddd", 
28304 -                                       "proc:", 
28305 +                       log_error_write(srv, __FILE__, __LINE__,  "sbdddd",
28306 +                                       "proc:",
28307                                         proc->connection_name,
28308                                         proc->state,
28309                                         proc->is_local,
28310                                         proc->load,
28311                                         proc->pid);
28312                 }
28313 -               
28314 -               /* 
28315 +
28316 +               /*
28317                  * if the remote side is overloaded, we check back after <n> seconds
28318 -                * 
28319 +                *
28320                  */
28321                 switch (proc->state) {
28322                 case PROC_STATE_KILLED:
28323 @@ -2592,13 +2457,13 @@
28324                         break;
28325                 case PROC_STATE_OVERLOADED:
28326                         if (srv->cur_ts <= proc->disabled_until) break;
28327 -                       
28328 +
28329                         proc->state = PROC_STATE_RUNNING;
28330                         host->active_procs++;
28331 -                       
28332 -                       log_error_write(srv, __FILE__, __LINE__,  "sbdb", 
28333 -                                       "fcgi-server re-enabled:", 
28334 -                                       host->host, host->port, 
28335 +
28336 +                       log_error_write(srv, __FILE__, __LINE__,  "sbdb",
28337 +                                       "fcgi-server re-enabled:",
28338 +                                       host->host, host->port,
28339                                         host->unixsocket);
28340                         break;
28341                 case PROC_STATE_DIED_WAIT_FOR_PID:
28342 @@ -2606,7 +2471,7 @@
28343                         if (!proc->is_local) break;
28344  
28345                         /* the child should not terminate at all */
28346 -                       
28347 +#ifndef _WIN32
28348                         switch(waitpid(proc->pid, &status, WNOHANG)) {
28349                         case 0:
28350                                 /* child is still alive */
28351 @@ -2616,45 +2481,45 @@
28352                         default:
28353                                 if (WIFEXITED(status)) {
28354  #if 0
28355 -                                       log_error_write(srv, __FILE__, __LINE__, "sdsd", 
28356 +                                       log_error_write(srv, __FILE__, __LINE__, "sdsd",
28357                                                         "child exited, pid:", proc->pid,
28358                                                         "status:", WEXITSTATUS(status));
28359  #endif
28360                                 } else if (WIFSIGNALED(status)) {
28361 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
28362 -                                                       "child signaled:", 
28363 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
28364 +                                                       "child signaled:",
28365                                                         WTERMSIG(status));
28366                                 } else {
28367 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
28368 -                                                       "child died somehow:", 
28369 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
28370 +                                                       "child died somehow:",
28371                                                         status);
28372                                 }
28373 -                               
28374 +
28375                                 proc->state = PROC_STATE_DIED;
28376                                 break;
28377                         }
28378 -
28379 +#endif
28380                         /* fall through if we have a dead proc now */
28381                         if (proc->state != PROC_STATE_DIED) break;
28382  
28383                 case PROC_STATE_DIED:
28384 -                       /* local proc get restarted by us, 
28385 +                       /* local proc get restarted by us,
28386                          * remote ones hopefully by the admin */
28387 -                       
28388 +
28389                         if (proc->is_local) {
28390                                 /* we still have connections bound to this proc,
28391                                  * let them terminate first */
28392                                 if (proc->load != 0) break;
28393 -                       
28394 +
28395                                 /* restart the child */
28396 -                               
28397 +
28398                                 if (p->conf.debug) {
28399                                         log_error_write(srv, __FILE__, __LINE__, "ssbsdsd",
28400                                                         "--- fastcgi spawning",
28401                                                         "\n\tsocket", proc->connection_name,
28402                                                         "\n\tcurrent:", 1, "/", host->min_procs);
28403                                 }
28404 -                               
28405 +
28406                                 if (fcgi_spawn_connection(srv, p, host, proc)) {
28407                                         log_error_write(srv, __FILE__, __LINE__, "s",
28408                                                         "ERROR: spawning fcgi failed.");
28409 @@ -2662,18 +2527,18 @@
28410                                 }
28411                         } else {
28412                                 if (srv->cur_ts <= proc->disabled_until) break;
28413 -                       
28414 +
28415                                 proc->state = PROC_STATE_RUNNING;
28416                                 host->active_procs++;
28417 -                       
28418 -                               log_error_write(srv, __FILE__, __LINE__,  "sb", 
28419 -                                               "fcgi-server re-enabled:", 
28420 +
28421 +                               log_error_write(srv, __FILE__, __LINE__,  "sb",
28422 +                                               "fcgi-server re-enabled:",
28423                                                 proc->connection_name);
28424                         }
28425                         break;
28426                 }
28427         }
28428 -       
28429 +
28430         return 0;
28431  }
28432  
28433 @@ -2682,19 +2547,19 @@
28434         fcgi_extension_host *host= hctx->host;
28435         connection *con   = hctx->remote_conn;
28436         fcgi_proc  *proc;
28437 -       
28438 +
28439         int ret;
28440  
28441 -       /* sanity check */      
28442 +       /* sanity check */
28443         if (!host ||
28444             ((!host->host->used || !host->port) && !host->unixsocket->used)) {
28445 -               log_error_write(srv, __FILE__, __LINE__, "sxddd", 
28446 +               log_error_write(srv, __FILE__, __LINE__, "sxddd",
28447                                 "write-req: error",
28448                                 host,
28449                                 host->host->used,
28450                                 host->port,
28451                                 host->unixsocket->used);
28452 -                       
28453 +
28454                 hctx->proc->disabled_until = srv->cur_ts + 10;
28455                 hctx->proc->state = PROC_STATE_DIED;
28456  
28457 @@ -2705,12 +2570,12 @@
28458         if (hctx->state == FCGI_STATE_CONNECT_DELAYED) {
28459                 int socket_error;
28460                 socklen_t socket_error_len = sizeof(socket_error);
28461 -                       
28462 +
28463                 /* try to finish the connect() */
28464 -               if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
28465 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
28466 +               if (0 != getsockopt(hctx->sock->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
28467 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
28468                                         "getsockopt failed:", strerror(errno));
28469 -                       
28470 +
28471                         hctx->proc->disabled_until = srv->cur_ts + 10;
28472                         hctx->proc->state = PROC_STATE_DIED;
28473  
28474 @@ -2719,12 +2584,12 @@
28475                 if (socket_error != 0) {
28476                         if (!hctx->proc->is_local || p->conf.debug) {
28477                                 /* local procs get restarted */
28478 -                               
28479 +
28480                                 log_error_write(srv, __FILE__, __LINE__, "sssb",
28481 -                                               "establishing connection failed:", strerror(socket_error), 
28482 +                                               "establishing connection failed:", strerror(socket_error),
28483                                                 "socket:", hctx->proc->connection_name);
28484                         }
28485 -       
28486 +
28487                         hctx->proc->disabled_until = srv->cur_ts + 5;
28488  
28489                         if (hctx->proc->is_local) {
28490 @@ -2732,17 +2597,17 @@
28491                         } else {
28492                                 hctx->proc->state = PROC_STATE_DIED;
28493                         }
28494 -       
28495 +
28496                         hctx->proc->state = PROC_STATE_DIED;
28497 -               
28498 +
28499                         fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
28500                         buffer_append_string(p->statuskey, ".died");
28501  
28502 -                       status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
28503 -               
28504 +                       status_counter_inc(CONST_BUF_LEN(p->statuskey));
28505 +
28506                         return HANDLER_ERROR;
28507                 }
28508 -               /* go on with preparing the request */ 
28509 +               /* go on with preparing the request */
28510                 hctx->state = FCGI_STATE_PREPARE_WRITE;
28511         }
28512  
28513 @@ -2755,14 +2620,14 @@
28514                 /* do we have a running process for this host (max-procs) ? */
28515                 hctx->proc = NULL;
28516  
28517 -               for (proc = hctx->host->first; 
28518 -                    proc && proc->state != PROC_STATE_RUNNING; 
28519 +               for (proc = hctx->host->first;
28520 +                    proc && proc->state != PROC_STATE_RUNNING;
28521                      proc = proc->next);
28522 -                       
28523 +
28524                 /* all childs are dead */
28525                 if (proc == NULL) {
28526 -                       hctx->fde_ndx = -1;
28527 -               
28528 +                       hctx->sock->fde_ndx = -1;
28529 +
28530                         return HANDLER_ERROR;
28531                 }
28532  
28533 @@ -2775,50 +2640,50 @@
28534                 }
28535  
28536                 ret = host->unixsocket->used ? AF_UNIX : AF_INET;
28537 -               
28538 -               if (-1 == (hctx->fd = socket(ret, SOCK_STREAM, 0))) {
28539 +
28540 +               if (-1 == (hctx->sock->fd = socket(ret, SOCK_STREAM, 0))) {
28541                         if (errno == EMFILE ||
28542                             errno == EINTR) {
28543 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
28544 -                                               "wait for fd at connection:", con->fd);
28545 -                               
28546 +                               log_error_write(srv, __FILE__, __LINE__, "sd",
28547 +                                               "wait for fd at connection:", con->sock->fd);
28548 +
28549                                 return HANDLER_WAIT_FOR_FD;
28550                         }
28551 -                       
28552 -                       log_error_write(srv, __FILE__, __LINE__, "ssdd", 
28553 +
28554 +                       log_error_write(srv, __FILE__, __LINE__, "ssdd",
28555                                         "socket failed:", strerror(errno), srv->cur_fds, srv->max_fds);
28556                         return HANDLER_ERROR;
28557                 }
28558 -               hctx->fde_ndx = -1;
28559 -               
28560 +               hctx->sock->fde_ndx = -1;
28561 +
28562                 srv->cur_fds++;
28563 -               
28564 -               fdevent_register(srv->ev, hctx->fd, fcgi_handle_fdevent, hctx);
28565 -               
28566 -               if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
28567 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
28568 +
28569 +               fdevent_register(srv->ev, hctx->sock, fcgi_handle_fdevent, hctx);
28570 +
28571 +               if (-1 == fdevent_fcntl_set(srv->ev, hctx->sock)) {
28572 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
28573                                         "fcntl failed:", strerror(errno));
28574 -                       
28575 +
28576                         return HANDLER_ERROR;
28577                 }
28578 -                       
28579 +
28580                 if (hctx->proc->is_local) {
28581                         hctx->pid = hctx->proc->pid;
28582                 }
28583 -                       
28584 +
28585                 switch (fcgi_establish_connection(srv, hctx)) {
28586                 case CONNECTION_DELAYED:
28587                         /* connection is in progress, wait for an event and call getsockopt() below */
28588 -                       
28589 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
28590 -                       
28591 +
28592 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
28593 +
28594                         fcgi_set_state(srv, hctx, FCGI_STATE_CONNECT_DELAYED);
28595                         return HANDLER_WAIT_FOR_EVENT;
28596                 case CONNECTION_OVERLOADED:
28597                         /* cool down the backend, it is overloaded
28598                          * -> EAGAIN */
28599  
28600 -                       log_error_write(srv, __FILE__, __LINE__, "ssdsd", 
28601 +                       log_error_write(srv, __FILE__, __LINE__, "ssdsd",
28602                                 "backend is overloaded, we disable it for a 2 seconds and send the request to another backend instead:",
28603                                 "reconnects:", hctx->reconnects,
28604                                 "load:", host->load);
28605 @@ -2830,8 +2695,8 @@
28606                         fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
28607                         buffer_append_string(p->statuskey, ".overloaded");
28608  
28609 -                       status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
28610 -                       
28611 +                       status_counter_inc(CONST_BUF_LEN(p->statuskey));
28612 +
28613                         return HANDLER_ERROR;
28614                 case CONNECTION_DEAD:
28615                         /* we got a hard error from the backend like
28616 @@ -2840,67 +2705,67 @@
28617                          *
28618                          * for check if the host is back in 5 seconds
28619                          *  */
28620 -                       
28621 +
28622                         hctx->proc->disabled_until = srv->cur_ts + 5;
28623                         if (hctx->proc->is_local) {
28624                                 hctx->proc->state = PROC_STATE_DIED_WAIT_FOR_PID;
28625                         } else {
28626                                 hctx->proc->state = PROC_STATE_DIED;
28627                         }
28628 -       
28629 -                       log_error_write(srv, __FILE__, __LINE__, "ssdsd", 
28630 +
28631 +                       log_error_write(srv, __FILE__, __LINE__, "ssdsd",
28632                                 "backend died, we disable it for a 5 seconds and send the request to another backend instead:",
28633                                 "reconnects:", hctx->reconnects,
28634                                 "load:", host->load);
28635 -       
28636 +
28637                         fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
28638                         buffer_append_string(p->statuskey, ".died");
28639  
28640 -                       status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
28641 +                       status_counter_inc(CONST_BUF_LEN(p->statuskey));
28642  
28643                         return HANDLER_ERROR;
28644                 case CONNECTION_OK:
28645                         /* everything is ok, go on */
28646  
28647                         fcgi_set_state(srv, hctx, FCGI_STATE_PREPARE_WRITE);
28648 -                       
28649 +
28650                         break;
28651                 case CONNECTION_UNSET:
28652                         break;
28653                 }
28654 -               
28655 +
28656         case FCGI_STATE_PREPARE_WRITE:
28657                 /* ok, we have the connection */
28658 -               
28659 +
28660                 hctx->proc->load++;
28661                 hctx->proc->last_used = srv->cur_ts;
28662                 hctx->got_proc = 1;
28663 -       
28664 -               status_counter_inc(srv, CONST_STR_LEN("fastcgi.requests"));
28665 -               status_counter_inc(srv, CONST_STR_LEN("fastcgi.active-requests"));
28666 +
28667 +               status_counter_inc(CONST_STR_LEN("fastcgi.requests"));
28668 +               status_counter_inc(CONST_STR_LEN("fastcgi.active-requests"));
28669  
28670                 fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
28671                 buffer_append_string(p->statuskey, ".connected");
28672  
28673 -               status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
28674 +               status_counter_inc(CONST_BUF_LEN(p->statuskey));
28675  
28676                 /* the proc-load */
28677                 fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
28678                 buffer_append_string(p->statuskey, ".load");
28679  
28680 -               status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->proc->load);
28681 +               status_counter_set(CONST_BUF_LEN(p->statuskey), hctx->proc->load);
28682  
28683                 /* the host-load */
28684                 fastcgi_status_copy_procname(p->statuskey, hctx->host, NULL);
28685                 buffer_append_string(p->statuskey, ".load");
28686  
28687 -               status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->host->load);
28688 +               status_counter_set(CONST_BUF_LEN(p->statuskey), hctx->host->load);
28689  
28690                 if (p->conf.debug) {
28691                         log_error_write(srv, __FILE__, __LINE__, "ssdsbsd",
28692 -                                       "got proc:", 
28693 -                                       "pid:", hctx->proc->pid, 
28694 -                                       "socket:", hctx->proc->connection_name, 
28695 +                                       "got proc:",
28696 +                                       "pid:", hctx->proc->pid,
28697 +                                       "socket:", hctx->proc->connection_name,
28698                                         "load:", hctx->proc->load);
28699                 }
28700  
28701 @@ -2908,74 +2773,75 @@
28702                 if (hctx->request_id == 0) {
28703                         hctx->request_id = fcgi_requestid_new(srv, p);
28704                 } else {
28705 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
28706 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
28707                                         "fcgi-request is already in use:", hctx->request_id);
28708                 }
28709 -               
28710 +
28711                 /* fall through */
28712                 fcgi_create_env(srv, hctx, hctx->request_id);
28713 -               
28714 +
28715                 fcgi_set_state(srv, hctx, FCGI_STATE_WRITE);
28716 -               
28717 +
28718                 /* fall through */
28719         case FCGI_STATE_WRITE:
28720 -               ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb); 
28721 +               ret = srv->network_backend_write(srv, con, hctx->sock, hctx->wb);
28722  
28723                 chunkqueue_remove_finished_chunks(hctx->wb);
28724 -               
28725 +
28726                 if (ret < 0) {
28727                         switch(errno) {
28728                         case ENOTCONN:
28729 -                               /* the connection got dropped after accept() 
28730 -                                * 
28731 -                                * this is most of the time a PHP which dies 
28732 +                               /* the connection got dropped after accept()
28733 +                                *
28734 +                                * this is most of the time a PHP which dies
28735                                  * after PHP_FCGI_MAX_REQUESTS
28736 -                                * 
28737 -                                */ 
28738 +                                *
28739 +                                */
28740                                 if (hctx->wb->bytes_out == 0 &&
28741                                     hctx->reconnects < 5) {
28742 -                                       usleep(10000); /* take away the load of the webserver 
28743 -                                                       * to let the php a chance to restart 
28744 +#ifndef _WIN32
28745 +                                       usleep(10000); /* take away the load of the webserver
28746 +                                                       * to let the php a chance to restart
28747                                                         */
28748 -                                       
28749 +#endif
28750                                         fcgi_reconnect(srv, hctx);
28751 -                               
28752 +
28753                                         return HANDLER_WAIT_FOR_FD;
28754                                 }
28755 -                               
28756 +
28757                                 /* not reconnected ... why
28758 -                                * 
28759 +                                *
28760                                  * far@#lighttpd report this for FreeBSD
28761 -                                * 
28762 +                                *
28763                                  */
28764 -                               
28765 -                               log_error_write(srv, __FILE__, __LINE__, "ssdsd", 
28766 +
28767 +                               log_error_write(srv, __FILE__, __LINE__, "ssosd",
28768                                                 "[REPORT ME] connection was dropped after accept(). reconnect() denied:",
28769                                                 "write-offset:", hctx->wb->bytes_out,
28770                                                 "reconnect attempts:", hctx->reconnects);
28771 -                               
28772 +
28773                                 return HANDLER_ERROR;
28774                         case EAGAIN:
28775                         case EINTR:
28776 -                               fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
28777 -                               
28778 +                               fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
28779 +
28780                                 return HANDLER_WAIT_FOR_EVENT;
28781                         default:
28782 -                               log_error_write(srv, __FILE__, __LINE__, "ssd", 
28783 +                               log_error_write(srv, __FILE__, __LINE__, "ssd",
28784                                                 "write failed:", strerror(errno), errno);
28785 -                               
28786 +
28787                                 return HANDLER_ERROR;
28788                         }
28789                 }
28790  
28791                 if (hctx->wb->bytes_out == hctx->wb->bytes_in) {
28792                         /* we don't need the out event anymore */
28793 -                       fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
28794 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
28795 +                       fdevent_event_del(srv->ev, hctx->sock);
28796 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
28797                         fcgi_set_state(srv, hctx, FCGI_STATE_READ);
28798                 } else {
28799 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
28800 -                               
28801 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
28802 +
28803                         return HANDLER_WAIT_FOR_EVENT;
28804                 }
28805  
28806 @@ -2987,7 +2853,7 @@
28807                 log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
28808                 return HANDLER_ERROR;
28809         }
28810 -       
28811 +
28812         return HANDLER_WAIT_FOR_EVENT;
28813  }
28814  
28815 @@ -2996,18 +2862,18 @@
28816   * */
28817  SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) {
28818         plugin_data *p = p_d;
28819 -       
28820 +
28821         handler_ctx *hctx = con->plugin_ctx[p->id];
28822         fcgi_proc *proc;
28823         fcgi_extension_host *host;
28824 -       
28825 +
28826         if (NULL == hctx) return HANDLER_GO_ON;
28827 -       
28828 +
28829         /* not my job */
28830         if (con->mode != p->id) return HANDLER_GO_ON;
28831  
28832         /* we don't have a host yet, choose one
28833 -        * -> this happens in the first round 
28834 +        * -> this happens in the first round
28835          *    and when the host died and we have to select a new one */
28836         if (hctx->host == NULL) {
28837                 size_t k;
28838 @@ -3016,23 +2882,23 @@
28839                 /* get best server */
28840                 for (k = 0, ndx = -1; k < hctx->ext->used; k++) {
28841                         host = hctx->ext->hosts[k];
28842 -               
28843 +
28844                         /* we should have at least one proc that can do something */
28845                         if (host->active_procs == 0) continue;
28846  
28847                         if (used == -1 || host->load < used) {
28848                                 used = host->load;
28849 -                       
28850 +
28851                                 ndx = k;
28852                         }
28853                 }
28854 -       
28855 +
28856                 /* found a server */
28857                 if (ndx == -1) {
28858                         /* all hosts are down */
28859  
28860                         fcgi_connection_close(srv, hctx);
28861 -                       
28862 +
28863                         con->http_status = 500;
28864                         con->mode = DIRECT;
28865  
28866 @@ -3040,16 +2906,16 @@
28867                 }
28868  
28869                 host = hctx->ext->hosts[ndx];
28870 -               
28871 -               /* 
28872 -                * if check-local is disabled, use the uri.path handler 
28873 -                * 
28874 +
28875 +               /*
28876 +                * if check-local is disabled, use the uri.path handler
28877 +                *
28878                  */
28879 -               
28880 +
28881                 /* init handler-context */
28882                 hctx->host = host;
28883  
28884 -               /* we put a connection on this host, move the other new connections to other hosts 
28885 +               /* we put a connection on this host, move the other new connections to other hosts
28886                  *
28887                  * as soon as hctx->host is unassigned, decrease the load again */
28888                 hctx->host->load++;
28889 @@ -3063,7 +2929,7 @@
28890         case HANDLER_ERROR:
28891                 proc = hctx->proc;
28892                 host = hctx->host;
28893 -               
28894 +
28895                 if (hctx->state == FCGI_STATE_INIT ||
28896                     hctx->state == FCGI_STATE_CONNECT_DELAYED) {
28897                         if (proc) host->active_procs--;
28898 @@ -3078,7 +2944,7 @@
28899                                 return HANDLER_WAIT_FOR_FD;
28900                         } else {
28901                                 fcgi_connection_close(srv, hctx);
28902 -                       
28903 +
28904                                 buffer_reset(con->physical.path);
28905                                 con->mode = DIRECT;
28906                                 con->http_status = 500;
28907 @@ -3088,12 +2954,12 @@
28908                         }
28909                 } else {
28910                         fcgi_connection_close(srv, hctx);
28911 -                       
28912 +
28913                         buffer_reset(con->physical.path);
28914                         con->mode = DIRECT;
28915                         con->http_status = 503;
28916                         joblist_append(srv, con); /* really ? */
28917 -                       
28918 +
28919                         return HANDLER_FINISHED;
28920                 }
28921         case HANDLER_WAIT_FOR_EVENT:
28922 @@ -3115,7 +2981,7 @@
28923         handler_ctx *hctx = ctx;
28924         connection  *con  = hctx->remote_conn;
28925         plugin_data *p    = hctx->plugin_data;
28926 -       
28927 +
28928         fcgi_proc *proc   = hctx->proc;
28929         fcgi_extension_host *host= hctx->host;
28930  
28931 @@ -3125,8 +2991,8 @@
28932                 case 0:
28933                         break;
28934                 case 1:
28935 -                       
28936 -                       if (host->mode == FCGI_AUTHORIZER && 
28937 +
28938 +                       if (host->mode == FCGI_AUTHORIZER &&
28939                             (con->http_status == 200 ||
28940                              con->http_status == 0)) {
28941                                 /*
28942 @@ -3136,26 +3002,26 @@
28943                                  */
28944  
28945                                 buffer_copy_string_buffer(con->physical.doc_root, host->docroot);
28946 -                               
28947 +
28948                                 buffer_copy_string_buffer(con->physical.path, host->docroot);
28949                                 buffer_append_string_buffer(con->physical.path, con->uri.path);
28950                                 fcgi_connection_close(srv, hctx);
28951 -                               
28952 +
28953                                 con->mode = DIRECT;
28954                                 con->file_started = 1; /* fcgi_extension won't touch the request afterwards */
28955                         } else {
28956                                 /* we are done */
28957                                 fcgi_connection_close(srv, hctx);
28958                         }
28959 -                       
28960 +
28961                         joblist_append(srv, con);
28962                         return HANDLER_FINISHED;
28963                 case -1:
28964                         if (proc->pid && proc->state != PROC_STATE_DIED) {
28965                                 int status;
28966 -                               
28967 +
28968                                 /* only fetch the zombie if it is not already done */
28969 -                               
28970 +#ifndef _WIN32
28971                                 switch(waitpid(proc->pid, &status, WNOHANG)) {
28972                                 case 0:
28973                                         /* child is still alive */
28974 @@ -3165,137 +3031,137 @@
28975                                 default:
28976                                         /* the child should not terminate at all */
28977                                         if (WIFEXITED(status)) {
28978 -                                               log_error_write(srv, __FILE__, __LINE__, "sdsd", 
28979 +                                               log_error_write(srv, __FILE__, __LINE__, "sdsd",
28980                                                                 "child exited, pid:", proc->pid,
28981                                                                 "status:", WEXITSTATUS(status));
28982                                         } else if (WIFSIGNALED(status)) {
28983 -                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
28984 -                                                               "child signaled:", 
28985 +                                               log_error_write(srv, __FILE__, __LINE__, "sd",
28986 +                                                               "child signaled:",
28987                                                                 WTERMSIG(status));
28988                                         } else {
28989 -                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
28990 -                                                               "child died somehow:", 
28991 +                                               log_error_write(srv, __FILE__, __LINE__, "sd",
28992 +                                                               "child died somehow:",
28993                                                                 status);
28994                                         }
28995 -                                       
28996 +
28997                                         if (p->conf.debug) {
28998                                                 log_error_write(srv, __FILE__, __LINE__, "ssbsdsd",
28999                                                                 "--- fastcgi spawning",
29000                                                                 "\n\tsocket", proc->connection_name,
29001                                                                 "\n\tcurrent:", 1, "/", host->min_procs);
29002                                         }
29003 -                                       
29004 +
29005                                         if (fcgi_spawn_connection(srv, p, host, proc)) {
29006                                                 /* respawning failed, retry later */
29007                                                 proc->state = PROC_STATE_DIED;
29008  
29009 -                                               log_error_write(srv, __FILE__, __LINE__, "s", 
29010 +                                               log_error_write(srv, __FILE__, __LINE__, "s",
29011                                                                 "respawning failed, will retry later");
29012                                         }
29013 -                                       
29014 +
29015                                         break;
29016                                 }
29017 +#endif
29018                         }
29019  
29020                         if (con->file_started == 0) {
29021                                 /* nothing has been send out yet, try to use another child */
29022 -                               
29023 +
29024                                 if (hctx->wb->bytes_out == 0 &&
29025                                     hctx->reconnects < 5) {
29026                                         fcgi_reconnect(srv, hctx);
29027 -                                       
29028 -                                       log_error_write(srv, __FILE__, __LINE__, "ssbsbs", 
29029 +
29030 +                                       log_error_write(srv, __FILE__, __LINE__, "ssbsbs",
29031                                                 "response not received, request not sent",
29032 -                                               "on socket:", proc->connection_name, 
29033 +                                               "on socket:", proc->connection_name,
29034                                                 "for", con->uri.path, ", reconnecting");
29035 -                                       
29036 +
29037                                         return HANDLER_WAIT_FOR_FD;
29038                                 }
29039 -                       
29040 -                               log_error_write(srv, __FILE__, __LINE__, "sosbsbs", 
29041 +
29042 +                               log_error_write(srv, __FILE__, __LINE__, "sosbsbs",
29043                                                 "response not received, request sent:", hctx->wb->bytes_out,
29044 -                                               "on socket:", proc->connection_name, 
29045 +                                               "on socket:", proc->connection_name,
29046                                                 "for", con->uri.path, ", closing connection");
29047 -                               
29048 +
29049                                 fcgi_connection_close(srv, hctx);
29050 -                               
29051 -                               connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
29052 +
29053                                 buffer_reset(con->physical.path);
29054                                 con->http_status = 500;
29055                                 con->mode = DIRECT;
29056                         } else {
29057                                 /* response might have been already started, kill the connection */
29058                                 fcgi_connection_close(srv, hctx);
29059 -                               
29060 -                               log_error_write(srv, __FILE__, __LINE__, "ssbsbs", 
29061 +
29062 +                               log_error_write(srv, __FILE__, __LINE__, "ssbsbs",
29063                                                 "response already sent out, but backend returned error",
29064 -                                               "on socket:", proc->connection_name, 
29065 +                                               "on socket:", proc->connection_name,
29066                                                 "for", con->uri.path, ", terminating connection");
29067 -                               
29068 +
29069                                 connection_set_state(srv, con, CON_STATE_ERROR);
29070                         }
29071  
29072                         /* */
29073 -                       
29074 -                       
29075 +
29076 +
29077                         joblist_append(srv, con);
29078                         return HANDLER_FINISHED;
29079                 }
29080         }
29081 -       
29082 +
29083         if (revents & FDEVENT_OUT) {
29084                 if (hctx->state == FCGI_STATE_CONNECT_DELAYED ||
29085                     hctx->state == FCGI_STATE_WRITE) {
29086                         /* we are allowed to send something out
29087 -                        * 
29088 +                        *
29089                          * 1. in a unfinished connect() call
29090                          * 2. in a unfinished write() call (long POST request)
29091                          */
29092                         return mod_fastcgi_handle_subrequest(srv, con, p);
29093                 } else {
29094 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
29095 -                                       "got a FDEVENT_OUT and didn't know why:", 
29096 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
29097 +                                       "got a FDEVENT_OUT and didn't know why:",
29098                                         hctx->state);
29099                 }
29100         }
29101 -       
29102 +
29103         /* perhaps this issue is already handled */
29104         if (revents & FDEVENT_HUP) {
29105                 if (hctx->state == FCGI_STATE_CONNECT_DELAYED) {
29106                         /* getoptsock will catch this one (right ?)
29107 -                        * 
29108 -                        * if we are in connect we might get a EINPROGRESS 
29109 -                        * in the first call and a FDEVENT_HUP in the 
29110 +                        *
29111 +                        * if we are in connect we might get a EINPROGRESS
29112 +                        * in the first call and a FDEVENT_HUP in the
29113                          * second round
29114 -                        * 
29115 +                        *
29116                          * FIXME: as it is a bit ugly.
29117 -                        * 
29118 +                        *
29119                          */
29120                         return mod_fastcgi_handle_subrequest(srv, con, p);
29121                 } else if (hctx->state == FCGI_STATE_READ &&
29122                            hctx->proc->port == 0) {
29123                         /* FIXME:
29124 -                        * 
29125 +                        *
29126                          * ioctl says 8192 bytes to read from PHP and we receive directly a HUP for the socket
29127                          * even if the FCGI_FIN packet is not received yet
29128                          */
29129                 } else {
29130 -                       log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd", 
29131 -                                       "error: unexpected close of fastcgi connection for", 
29132 +                       log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd",
29133 +                                       "error: unexpected close of fastcgi connection for",
29134                                         con->uri.path,
29135 -                                       "(no fastcgi process on host:", 
29136 +                                       "(no fastcgi process on host:",
29137                                         host->host,
29138 -                                       ", port: ", 
29139 +                                       ", port: ",
29140                                         host->port,
29141                                         " ?)",
29142                                         hctx->state);
29143 -                       
29144 +
29145                         connection_set_state(srv, con, CON_STATE_ERROR);
29146                         fcgi_connection_close(srv, hctx);
29147                         joblist_append(srv, con);
29148                 }
29149         } else if (revents & FDEVENT_ERR) {
29150 -               log_error_write(srv, __FILE__, __LINE__, "s", 
29151 +               log_error_write(srv, __FILE__, __LINE__, "s",
29152                                 "fcgi: got a FDEVENT_ERR. Don't know why.");
29153                 /* kill all connections to the fastcgi process */
29154  
29155 @@ -3304,45 +3170,42 @@
29156                 fcgi_connection_close(srv, hctx);
29157                 joblist_append(srv, con);
29158         }
29159 -       
29160 +
29161         return HANDLER_FINISHED;
29162  }
29163 -#define PATCH(x) \
29164 -       p->conf.x = s->x;
29165 +
29166  static int fcgi_patch_connection(server *srv, connection *con, plugin_data *p) {
29167         size_t i, j;
29168         plugin_config *s = p->config_storage[0];
29169 -       
29170 -       PATCH(exts);
29171 -       PATCH(debug);
29172 -       PATCH(ext_mapping);
29173 -       
29174 +
29175 +       PATCH_OPTION(exts);
29176 +       PATCH_OPTION(debug);
29177 +       PATCH_OPTION(ext_mapping);
29178 +
29179         /* skip the first, the global context */
29180         for (i = 1; i < srv->config_context->used; i++) {
29181                 data_config *dc = (data_config *)srv->config_context->data[i];
29182                 s = p->config_storage[i];
29183 -               
29184 +
29185                 /* condition didn't match */
29186                 if (!config_check_cond(srv, con, dc)) continue;
29187 -               
29188 +
29189                 /* merge config */
29190                 for (j = 0; j < dc->value->used; j++) {
29191                         data_unset *du = dc->value->data[j];
29192 -                       
29193 +
29194                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.server"))) {
29195 -                               PATCH(exts);
29196 +                               PATCH_OPTION(exts);
29197                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.debug"))) {
29198 -                               PATCH(debug);
29199 +                               PATCH_OPTION(debug);
29200                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.map-extensions"))) {
29201 -                               PATCH(ext_mapping);
29202 +                               PATCH_OPTION(ext_mapping);
29203                         }
29204                 }
29205         }
29206 -       
29207 +
29208         return 0;
29209  }
29210 -#undef PATCH
29211 -
29212  
29213  static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, int uri_path_handler) {
29214         plugin_data *p = p_d;
29215 @@ -3351,16 +3214,16 @@
29216         buffer *fn;
29217         fcgi_extension *extension = NULL;
29218         fcgi_extension_host *host = NULL;
29219 -       
29220 +
29221         /* Possibly, we processed already this request */
29222         if (con->file_started == 1) return HANDLER_GO_ON;
29223  
29224         fn = uri_path_handler ? con->uri.path : con->physical.path;
29225  
29226         if (buffer_is_empty(fn)) return HANDLER_GO_ON;
29227 -       
29228 +
29229         s_len = fn->used - 1;
29230 -       
29231 +
29232         fcgi_patch_connection(srv, con, p);
29233  
29234         /* fastcgi.map-extensions maps extensions to existing fastcgi.server entries
29235 @@ -3368,24 +3231,24 @@
29236          * fastcgi.map-extensions = ( ".php3" => ".php" )
29237          *
29238          * fastcgi.server = ( ".php" => ... )
29239 -        * 
29240 +        *
29241          * */
29242  
29243         /* check if extension-mapping matches */
29244         for (k = 0; k < p->conf.ext_mapping->used; k++) {
29245                 data_string *ds = (data_string *)p->conf.ext_mapping->data[k];
29246                 size_t ct_len; /* length of the config entry */
29247 -               
29248 +
29249                 if (ds->key->used == 0) continue;
29250 -               
29251 +
29252                 ct_len = ds->key->used - 1;
29253 -               
29254 +
29255                 if (s_len < ct_len) continue;
29256 -               
29257 +
29258                 /* found a mapping */
29259                 if (0 == strncmp(fn->ptr + s_len - ct_len, ds->key->ptr, ct_len)) {
29260                         /* check if we know the extension */
29261 -                       
29262 +
29263                         /* we can reuse k here */
29264                         for (k = 0; k < p->conf.exts->used; k++) {
29265                                 extension = p->conf.exts->exts[k];
29266 @@ -3407,15 +3270,15 @@
29267                 /* check if extension matches */
29268                 for (k = 0; k < p->conf.exts->used; k++) {
29269                         size_t ct_len; /* length of the config entry */
29270 -               
29271 +
29272                         extension = p->conf.exts->exts[k];
29273 -               
29274 +
29275                         if (extension->key->used == 0) continue;
29276 -               
29277 +
29278                         ct_len = extension->key->used - 1;
29279 -               
29280 +
29281                         if (s_len < ct_len) continue;
29282 -               
29283 +
29284                         /* check extension in the form "/fcgi_pattern" */
29285                         if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) {
29286                                 break;
29287 @@ -3441,10 +3304,10 @@
29288                         continue;
29289                 }
29290  
29291 -               /* we found one host that is alive */ 
29292 +               /* we found one host that is alive */
29293                 break;
29294         }
29295 -       
29296 +
29297         if (!host) {
29298                 /* sorry, we don't have a server alive for this ext */
29299                 buffer_reset(con->physical.path);
29300 @@ -3459,72 +3322,72 @@
29301                                         "on", extension->key,
29302                                         "are down.");
29303                 }
29304 -               
29305 +
29306                 return HANDLER_FINISHED;
29307         }
29308  
29309         /* a note about no handler is not sent yey */
29310         extension->note_is_sent = 0;
29311  
29312 -       /* 
29313 -        * if check-local is disabled, use the uri.path handler 
29314 -        * 
29315 +       /*
29316 +        * if check-local is disabled, use the uri.path handler
29317 +        *
29318          */
29319 -       
29320 +
29321         /* init handler-context */
29322         if (uri_path_handler) {
29323                 if (host->check_local == 0) {
29324                         handler_ctx *hctx;
29325                         char *pathinfo;
29326 -                       
29327 +
29328                         hctx = handler_ctx_init();
29329 -                       
29330 +
29331                         hctx->remote_conn      = con;
29332                         hctx->plugin_data      = p;
29333                         hctx->proc             = NULL;
29334                         hctx->ext              = extension;
29335 -       
29336 +
29337  
29338                         hctx->conf.exts        = p->conf.exts;
29339                         hctx->conf.debug       = p->conf.debug;
29340 -                               
29341 +
29342                         con->plugin_ctx[p->id] = hctx;
29343 -                               
29344 +
29345                         con->mode = p->id;
29346 -                               
29347 +
29348                         if (con->conf.log_request_handling) {
29349 -                               log_error_write(srv, __FILE__, __LINE__, "s", 
29350 +                               log_error_write(srv, __FILE__, __LINE__, "s",
29351                                 "handling it in mod_fastcgi");
29352                         }
29353 -                               
29354 -                       /* the prefix is the SCRIPT_NAME, 
29355 +
29356 +                       /* the prefix is the SCRIPT_NAME,
29357                          * everthing from start to the next slash
29358                          * this is important for check-local = "disable"
29359 -                        * 
29360 +                        *
29361                          * if prefix = /admin.fcgi
29362 -                        * 
29363 +                        *
29364                          * /admin.fcgi/foo/bar
29365 -                        * 
29366 +                        *
29367                          * SCRIPT_NAME = /admin.fcgi
29368                          * PATH_INFO   = /foo/bar
29369 -                        * 
29370 +                        *
29371                          * if prefix = /fcgi-bin/
29372 -                        * 
29373 +                        *
29374                          * /fcgi-bin/foo/bar
29375 -                        * 
29376 +                        *
29377                          * SCRIPT_NAME = /fcgi-bin/foo
29378                          * PATH_INFO   = /bar
29379 -                        * 
29380 +                        *
29381                          */
29382 -                       
29383 +
29384                         /* the rewrite is only done for /prefix/? matches */
29385                         if (extension->key->ptr[0] == '/' &&
29386                             con->uri.path->used > extension->key->used &&
29387                             NULL != (pathinfo = strchr(con->uri.path->ptr + extension->key->used - 1, '/'))) {
29388 -                               /* rewrite uri.path and pathinfo */ 
29389 -                               
29390 +                               /* rewrite uri.path and pathinfo */
29391 +
29392                                 buffer_copy_string(con->request.pathinfo, pathinfo);
29393 -                               
29394 +
29395                                 con->uri.path->used -= con->request.pathinfo->used - 1;
29396                                 con->uri.path->ptr[con->uri.path->used - 1] = '\0';
29397                         }
29398 @@ -3532,19 +3395,19 @@
29399         } else {
29400                 handler_ctx *hctx;
29401                 hctx = handler_ctx_init();
29402 -               
29403 +
29404                 hctx->remote_conn      = con;
29405                 hctx->plugin_data      = p;
29406                 hctx->proc             = NULL;
29407                 hctx->ext              = extension;
29408 -               
29409 +
29410                 hctx->conf.exts        = p->conf.exts;
29411                 hctx->conf.debug       = p->conf.debug;
29412 -               
29413 +
29414                 con->plugin_ctx[p->id] = hctx;
29415 -               
29416 +
29417                 con->mode = p->id;
29418 -               
29419 +
29420                 if (con->conf.log_request_handling) {
29421                         log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_fastcgi");
29422                 }
29423 @@ -3566,19 +3429,19 @@
29424  JOBLIST_FUNC(mod_fastcgi_handle_joblist) {
29425         plugin_data *p = p_d;
29426         handler_ctx *hctx = con->plugin_ctx[p->id];
29427 -       
29428 +
29429         if (hctx == NULL) return HANDLER_GO_ON;
29430  
29431 -       if (hctx->fd != -1) {
29432 +       if (hctx->sock->fd != -1) {
29433                 switch (hctx->state) {
29434                 case FCGI_STATE_READ:
29435 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
29436 -                       
29437 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
29438 +
29439                         break;
29440                 case FCGI_STATE_CONNECT_DELAYED:
29441                 case FCGI_STATE_WRITE:
29442 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
29443 -                       
29444 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
29445 +
29446                         break;
29447                 case FCGI_STATE_INIT:
29448                         /* at reconnect */
29449 @@ -3595,7 +3458,7 @@
29450  
29451  static handler_t fcgi_connection_close_callback(server *srv, connection *con, void *p_d) {
29452         plugin_data *p = p_d;
29453 -       
29454 +
29455         fcgi_connection_close(srv, con->plugin_ctx[p->id]);
29456  
29457         return HANDLER_GO_ON;
29458 @@ -3604,16 +3467,38 @@
29459  TRIGGER_FUNC(mod_fastcgi_handle_trigger) {
29460         plugin_data *p = p_d;
29461         size_t i, j, n;
29462 -       
29463 -       
29464 +
29465 +
29466         /* perhaps we should kill a connect attempt after 10-15 seconds
29467 -        * 
29468 +        *
29469          * currently we wait for the TCP timeout which is on Linux 180 seconds
29470 -        * 
29471 -        * 
29472 -        * 
29473 +        *
29474          */
29475  
29476 +       for (i = 0; i < srv->conns->used; i++) {
29477 +               connection *con = srv->conns->ptr[i];
29478 +               handler_ctx *hctx = con->plugin_ctx[p->id];
29479 +
29480 +               /* if a connection is ours and is in handle-req for more than max-request-time
29481 +                * kill the connection */
29482 +
29483 +               if (con->mode != p->id) continue;
29484 +               if (srv->cur_ts < con->request_start + 60) continue;
29485 +
29486 +               /* the request is waiting for a FCGI_STDOUT since 60 seconds */
29487 +
29488 +               /* kill the connection */
29489 +
29490 +               log_error_write(srv, __FILE__, __LINE__, "s", "fastcgi backend didn't responded after 60 seconds");
29491 +
29492 +               fcgi_connection_close(srv, hctx);
29493 +
29494 +               con->mode = DIRECT;
29495 +               con->http_status = 500;
29496 +
29497 +               joblist_append(srv, con);
29498 +       }
29499 +
29500         /* check all childs if they are still up */
29501  
29502         for (i = 0; i < srv->config_context->used; i++) {
29503 @@ -3628,45 +3513,45 @@
29504                         fcgi_extension *ex;
29505  
29506                         ex = exts->exts[j];
29507 -                       
29508 +
29509                         for (n = 0; n < ex->used; n++) {
29510 -                               
29511 +
29512                                 fcgi_proc *proc;
29513                                 unsigned long sum_load = 0;
29514                                 fcgi_extension_host *host;
29515 -                               
29516 +
29517                                 host = ex->hosts[n];
29518 -                               
29519 +
29520                                 fcgi_restart_dead_procs(srv, p, host);
29521 -                               
29522 +
29523                                 for (proc = host->first; proc; proc = proc->next) {
29524                                         sum_load += proc->load;
29525                                 }
29526 -                               
29527 +
29528                                 if (host->num_procs &&
29529                                     host->num_procs < host->max_procs &&
29530                                     (sum_load / host->num_procs) > host->max_load_per_proc) {
29531                                         /* overload, spawn new child */
29532                                         if (p->conf.debug) {
29533 -                                               log_error_write(srv, __FILE__, __LINE__, "s", 
29534 +                                               log_error_write(srv, __FILE__, __LINE__, "s",
29535                                                                 "overload detected, spawning a new child");
29536                                         }
29537 -                                       
29538 +
29539                                         for (proc = host->unused_procs; proc && proc->pid != 0; proc = proc->next);
29540 -                                       
29541 +
29542                                         if (proc) {
29543                                                 if (proc == host->unused_procs) host->unused_procs = proc->next;
29544 -                                               
29545 +
29546                                                 if (proc->next) proc->next->prev = NULL;
29547 -                                               
29548 +
29549                                                 host->max_id++;
29550                                         } else {
29551                                                 proc = fastcgi_process_init();
29552                                                 proc->id = host->max_id++;
29553                                         }
29554 -                                       
29555 +
29556                                         host->num_procs++;
29557 -                                       
29558 +
29559                                         if (buffer_is_empty(host->unixsocket)) {
29560                                                 proc->port = host->port + proc->id;
29561                                         } else {
29562 @@ -3674,13 +3559,13 @@
29563                                                 buffer_append_string(proc->unixsocket, "-");
29564                                                 buffer_append_long(proc->unixsocket, proc->id);
29565                                         }
29566 -                                       
29567 +
29568                                         if (fcgi_spawn_connection(srv, p, host, proc)) {
29569                                                 log_error_write(srv, __FILE__, __LINE__, "s",
29570                                                                 "ERROR: spawning fcgi failed.");
29571                                                 return HANDLER_ERROR;
29572                                         }
29573 -                                       
29574 +
29575                                         proc->prev = NULL;
29576                                         proc->next = host->first;
29577                                         if (host->first) {
29578 @@ -3688,56 +3573,56 @@
29579                                         }
29580                                         host->first = proc;
29581                                 }
29582 -                               
29583 +
29584                                 for (proc = host->first; proc; proc = proc->next) {
29585                                         if (proc->load != 0) break;
29586                                         if (host->num_procs <= host->min_procs) break;
29587                                         if (proc->pid == 0) continue;
29588 -                                       
29589 +
29590                                         if (srv->cur_ts - proc->last_used > host->idle_timeout) {
29591                                                 /* a proc is idling for a long time now,
29592                                                  * terminated it */
29593 -                                               
29594 +
29595                                                 if (p->conf.debug) {
29596 -                                                       log_error_write(srv, __FILE__, __LINE__, "ssbsd", 
29597 -                                                                       "idle-timeout reached, terminating child:", 
29598 -                                                                       "socket:", proc->connection_name, 
29599 +                                                       log_error_write(srv, __FILE__, __LINE__, "ssbsd",
29600 +                                                                       "idle-timeout reached, terminating child:",
29601 +                                                                       "socket:", proc->connection_name,
29602                                                                         "pid", proc->pid);
29603                                                 }
29604 -                                               
29605 -                                               
29606 +
29607 +
29608                                                 if (proc->next) proc->next->prev = proc->prev;
29609                                                 if (proc->prev) proc->prev->next = proc->next;
29610 -                                               
29611 +
29612                                                 if (proc->prev == NULL) host->first = proc->next;
29613 -                                               
29614 +
29615                                                 proc->prev = NULL;
29616                                                 proc->next = host->unused_procs;
29617 -                                               
29618 +
29619                                                 if (host->unused_procs) host->unused_procs->prev = proc;
29620                                                 host->unused_procs = proc;
29621 -                                               
29622 +
29623                                                 kill(proc->pid, SIGTERM);
29624 -                                               
29625 +
29626                                                 proc->state = PROC_STATE_KILLED;
29627 -                                               
29628 -                                               log_error_write(srv, __FILE__, __LINE__, "ssbsd", 
29629 -                                                                       "killed:", 
29630 -                                                                       "socket:", proc->connection_name, 
29631 +
29632 +                                               log_error_write(srv, __FILE__, __LINE__, "ssbsd",
29633 +                                                                       "killed:",
29634 +                                                                       "socket:", proc->connection_name,
29635                                                                         "pid", proc->pid);
29636 -                                               
29637 +
29638                                                 host->num_procs--;
29639 -                                               
29640 +
29641                                                 /* proc is now in unused, let the next second handle the next process */
29642                                                 break;
29643 -                                       }       
29644 +                                       }
29645                                 }
29646 -                               
29647 +
29648                                 for (proc = host->unused_procs; proc; proc = proc->next) {
29649                                         int status;
29650 -                                       
29651 +
29652                                         if (proc->pid == 0) continue;
29653 -                                       
29654 +#ifndef _WIN32
29655                                         switch (waitpid(proc->pid, &status, WNOHANG)) {
29656                                         case 0:
29657                                                 /* child still running after timeout, good */
29658 @@ -3745,10 +3630,10 @@
29659                                         case -1:
29660                                                 if (errno != EINTR) {
29661                                                         /* no PID found ? should never happen */
29662 -                                                       log_error_write(srv, __FILE__, __LINE__, "sddss", 
29663 +                                                       log_error_write(srv, __FILE__, __LINE__, "sddss",
29664                                                                         "pid ", proc->pid, proc->state,
29665                                                                         "not found:", strerror(errno));
29666 -                                                       
29667 +
29668  #if 0
29669                                                         if (errno == ECHILD) {
29670                                                                 /* someone else has cleaned up for us */
29671 @@ -3762,25 +3647,26 @@
29672                                                 /* the child should not terminate at all */
29673                                                 if (WIFEXITED(status)) {
29674                                                         if (proc->state != PROC_STATE_KILLED) {
29675 -                                                               log_error_write(srv, __FILE__, __LINE__, "sdb", 
29676 -                                                                               "child exited:", 
29677 +                                                               log_error_write(srv, __FILE__, __LINE__, "sdb",
29678 +                                                                               "child exited:",
29679                                                                                 WEXITSTATUS(status), proc->connection_name);
29680                                                         }
29681                                                 } else if (WIFSIGNALED(status)) {
29682                                                         if (WTERMSIG(status) != SIGTERM) {
29683 -                                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
29684 -                                                                               "child signaled:", 
29685 +                                                               log_error_write(srv, __FILE__, __LINE__, "sd",
29686 +                                                                               "child signaled:",
29687                                                                                 WTERMSIG(status));
29688                                                         }
29689                                                 } else {
29690 -                                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
29691 -                                                                       "child died somehow:", 
29692 +                                                       log_error_write(srv, __FILE__, __LINE__, "sd",
29693 +                                                                       "child died somehow:",
29694                                                                         status);
29695                                                 }
29696                                                 proc->pid = 0;
29697                                                 proc->state = PROC_STATE_UNSET;
29698                                                 host->max_id--;
29699                                         }
29700 +#endif
29701                                 }
29702                         }
29703                 }
29704 @@ -3800,12 +3686,12 @@
29705         p->connection_reset        = fcgi_connection_reset;
29706         p->handle_connection_close = fcgi_connection_close_callback;
29707         p->handle_uri_clean        = fcgi_check_extension_1;
29708 -       p->handle_subrequest_start = fcgi_check_extension_2;
29709 -       p->handle_subrequest       = mod_fastcgi_handle_subrequest;
29710 +       p->handle_start_backend    = fcgi_check_extension_2;
29711 +       p->handle_send_request_content = mod_fastcgi_handle_subrequest;
29712         p->handle_joblist          = mod_fastcgi_handle_joblist;
29713         p->handle_trigger          = mod_fastcgi_handle_trigger;
29714 -       
29715 +
29716         p->data         = NULL;
29717 -       
29718 +
29719         return 0;
29720  }
29721 --- ../lighttpd-1.4.11/src/mod_flv_streaming.c  2006-03-07 14:06:26.000000000 +0200
29722 +++ lighttpd-1.5.0/src/mod_flv_streaming.c      2006-09-07 00:57:05.000000000 +0300
29723 @@ -6,7 +6,6 @@
29724  #include "log.h"
29725  #include "buffer.h"
29726  #include "response.h"
29727 -#include "http_chunk.h"
29728  #include "stat_cache.h"
29729  
29730  #include "plugin.h"
29731 @@ -23,35 +22,35 @@
29732  
29733  typedef struct {
29734         PLUGIN_DATA;
29735 -       
29736 +
29737         buffer *query_str;
29738         array *get_params;
29739 -       
29740 +
29741         plugin_config **config_storage;
29742 -       
29743 -       plugin_config conf; 
29744 +
29745 +       plugin_config conf;
29746  } plugin_data;
29747  
29748  /* init the plugin data */
29749  INIT_FUNC(mod_flv_streaming_init) {
29750         plugin_data *p;
29751 -       
29752 +
29753         p = calloc(1, sizeof(*p));
29754 -       
29755 +
29756         p->query_str = buffer_init();
29757         p->get_params = array_init();
29758 -       
29759 +
29760         return p;
29761  }
29762  
29763  /* detroy the plugin data */
29764  FREE_FUNC(mod_flv_streaming_free) {
29765         plugin_data *p = p_d;
29766 -       
29767 +
29768         UNUSED(srv);
29769  
29770         if (!p) return HANDLER_GO_ON;
29771 -       
29772 +
29773         if (p->config_storage) {
29774                 size_t i;
29775  
29776 @@ -59,19 +58,19 @@
29777                         plugin_config *s = p->config_storage[i];
29778  
29779                         if (!s) continue;
29780 -                       
29781 +
29782                         array_free(s->extensions);
29783 -                       
29784 +
29785                         free(s);
29786                 }
29787                 free(p->config_storage);
29788         }
29789 -       
29790 +
29791         buffer_free(p->query_str);
29792         array_free(p->get_params);
29793 -       
29794 +
29795         free(p);
29796 -       
29797 +
29798         return HANDLER_GO_ON;
29799  }
29800  
29801 @@ -80,83 +79,80 @@
29802  SETDEFAULTS_FUNC(mod_flv_streaming_set_defaults) {
29803         plugin_data *p = p_d;
29804         size_t i = 0;
29805 -       
29806 -       config_values_t cv[] = { 
29807 +
29808 +       config_values_t cv[] = {
29809                 { "flv-streaming.extensions",   NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
29810                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
29811         };
29812 -       
29813 +
29814         if (!p) return HANDLER_ERROR;
29815 -       
29816 +
29817         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
29818 -       
29819 +
29820         for (i = 0; i < srv->config_context->used; i++) {
29821                 plugin_config *s;
29822 -               
29823 +
29824                 s = calloc(1, sizeof(plugin_config));
29825                 s->extensions     = array_init();
29826 -               
29827 +
29828                 cv[0].destination = s->extensions;
29829 -               
29830 +
29831                 p->config_storage[i] = s;
29832 -       
29833 +
29834                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
29835                         return HANDLER_ERROR;
29836                 }
29837         }
29838 -       
29839 +
29840         return HANDLER_GO_ON;
29841  }
29842  
29843 -#define PATCH(x) \
29844 -       p->conf.x = s->x;
29845  static int mod_flv_streaming_patch_connection(server *srv, connection *con, plugin_data *p) {
29846         size_t i, j;
29847         plugin_config *s = p->config_storage[0];
29848 -       
29849 -       PATCH(extensions);
29850 -       
29851 +
29852 +       PATCH_OPTION(extensions);
29853 +
29854         /* skip the first, the global context */
29855         for (i = 1; i < srv->config_context->used; i++) {
29856                 data_config *dc = (data_config *)srv->config_context->data[i];
29857                 s = p->config_storage[i];
29858 -               
29859 +
29860                 /* condition didn't match */
29861                 if (!config_check_cond(srv, con, dc)) continue;
29862 -               
29863 +
29864                 /* merge config */
29865                 for (j = 0; j < dc->value->used; j++) {
29866                         data_unset *du = dc->value->data[j];
29867 -                       
29868 +
29869                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("flv-streaming.extensions"))) {
29870 -                               PATCH(extensions);
29871 +                               PATCH_OPTION(extensions);
29872                         }
29873                 }
29874         }
29875 -       
29876 +
29877         return 0;
29878  }
29879 -#undef PATCH
29880  
29881 -static int split_get_params(server *srv, connection *con, array *get_params, buffer *qrystr) {
29882 +static int split_get_params(array *get_params, buffer *qrystr) {
29883         size_t is_key = 1;
29884         size_t i;
29885         char *key = NULL, *val = NULL;
29886 -       
29887 +
29888         key = qrystr->ptr;
29889 -       
29890 +
29891         /* we need the \0 */
29892         for (i = 0; i < qrystr->used; i++) {
29893                 switch(qrystr->ptr[i]) {
29894                 case '=':
29895                         if (is_key) {
29896                                 val = qrystr->ptr + i + 1;
29897 -                               
29898 +
29899                                 qrystr->ptr[i] = '\0';
29900 -                               
29901 +
29902                                 is_key = 0;
29903                         }
29904 -                       
29905 +
29906                         break;
29907                 case '&':
29908                 case '\0': /* fin symbol */
29909 @@ -167,7 +163,7 @@
29910                                 /* terminate the value */
29911                                 qrystr->ptr[i] = '\0';
29912  
29913 -                               if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
29914 +                               if (NULL == (ds = (data_string *)array_get_unused_element(get_params, TYPE_STRING))) {
29915                                         ds = data_string_init();
29916                                 }
29917                                 buffer_copy_string_len(ds->key, key, strlen(key));
29918 @@ -175,14 +171,14 @@
29919  
29920                                 array_insert_unique(get_params, (data_unset *)ds);
29921                         }
29922 -                       
29923 +
29924                         key = qrystr->ptr + i + 1;
29925                         val = NULL;
29926                         is_key = 1;
29927                         break;
29928                 }
29929         }
29930 -       
29931 +
29932         return 0;
29933  }
29934  
29935 @@ -190,34 +186,34 @@
29936         plugin_data *p = p_d;
29937         int s_len;
29938         size_t k;
29939 -       
29940 +
29941         UNUSED(srv);
29942  
29943         if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON;
29944 -       
29945 +
29946         mod_flv_streaming_patch_connection(srv, con, p);
29947  
29948         s_len = con->physical.path->used - 1;
29949 -       
29950 +
29951         for (k = 0; k < p->conf.extensions->used; k++) {
29952                 data_string *ds = (data_string *)p->conf.extensions->data[k];
29953                 int ct_len = ds->value->used - 1;
29954 -               
29955 +
29956                 if (ct_len > s_len) continue;
29957                 if (ds->value->used == 0) continue;
29958 -               
29959 +
29960                 if (0 == strncmp(con->physical.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
29961                         data_string *get_param;
29962                         stat_cache_entry *sce = NULL;
29963                         buffer *b;
29964                         int start;
29965                         char *err = NULL;
29966 -                       /* if there is a start=[0-9]+ in the header use it as start, 
29967 +                       /* if there is a start=[0-9]+ in the header use it as start,
29968                          * otherwise send the full file */
29969  
29970                         array_reset(p->get_params);
29971                         buffer_copy_string_buffer(p->query_str, con->uri.query);
29972 -                       split_get_params(srv, con, p->get_params, p->query_str);
29973 +                       split_get_params(p->get_params, p->query_str);
29974  
29975                         if (NULL == (get_param = (data_string *)array_get_element(p->get_params, "start"))) {
29976                                 return HANDLER_GO_ON;
29977 @@ -244,19 +240,19 @@
29978                         }
29979  
29980                         /* we are safe now, let's build a flv header */
29981 -                       b = chunkqueue_get_append_buffer(con->write_queue);
29982 +                       b = chunkqueue_get_append_buffer(con->send);
29983                         BUFFER_COPY_STRING_CONST(b, "FLV\x1\x1\0\0\0\x9\0\0\0\x9");
29984  
29985 -                       http_chunk_append_file(srv, con, con->physical.path, start, sce->st.st_size - start);
29986 +                       chunkqueue_append_file(con->send, con->physical.path, start, sce->st.st_size - start);
29987  
29988                         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("video/x-flv"));
29989  
29990 -                       con->file_finished = 1;
29991 +                       con->send->is_closed = 1;
29992  
29993                         return HANDLER_FINISHED;
29994                 }
29995         }
29996 -       
29997 +
29998         /* not found */
29999         return HANDLER_GO_ON;
30000  }
30001 @@ -266,13 +262,13 @@
30002  int mod_flv_streaming_plugin_init(plugin *p) {
30003         p->version     = LIGHTTPD_VERSION_ID;
30004         p->name        = buffer_init_string("flv_streaming");
30005 -       
30006 +
30007         p->init        = mod_flv_streaming_init;
30008         p->handle_physical = mod_flv_streaming_path_handler;
30009         p->set_defaults  = mod_flv_streaming_set_defaults;
30010         p->cleanup     = mod_flv_streaming_free;
30011 -       
30012 +
30013         p->data        = NULL;
30014 -       
30015 +
30016         return 0;
30017  }
30018 --- ../lighttpd-1.4.11/src/mod_indexfile.c      2005-09-30 01:08:53.000000000 +0300
30019 +++ lighttpd-1.5.0/src/mod_indexfile.c  2006-09-07 00:57:05.000000000 +0300
30020 @@ -12,6 +12,8 @@
30021  
30022  #include "stat_cache.h"
30023  
30024 +#include "sys-strings.h"
30025 +#include "sys-files.h"
30026  /* plugin config for all request/connections */
30027  
30028  typedef struct {
30029 @@ -20,51 +22,51 @@
30030  
30031  typedef struct {
30032         PLUGIN_DATA;
30033 -       
30034 +
30035         buffer *tmp_buf;
30036 -       
30037 +
30038         plugin_config **config_storage;
30039 -       
30040 -       plugin_config conf; 
30041 +
30042 +       plugin_config conf;
30043  } plugin_data;
30044  
30045  /* init the plugin data */
30046  INIT_FUNC(mod_indexfile_init) {
30047         plugin_data *p;
30048 -       
30049 +
30050         p = calloc(1, sizeof(*p));
30051 -       
30052 +
30053         p->tmp_buf = buffer_init();
30054 -       
30055 +
30056         return p;
30057  }
30058  
30059  /* detroy the plugin data */
30060  FREE_FUNC(mod_indexfile_free) {
30061         plugin_data *p = p_d;
30062 -       
30063 +
30064         UNUSED(srv);
30065  
30066         if (!p) return HANDLER_GO_ON;
30067 -       
30068 +
30069         if (p->config_storage) {
30070                 size_t i;
30071                 for (i = 0; i < srv->config_context->used; i++) {
30072                         plugin_config *s = p->config_storage[i];
30073  
30074                         if (!s) continue;
30075 -                       
30076 +
30077                         array_free(s->indexfiles);
30078 -                       
30079 +
30080                         free(s);
30081                 }
30082                 free(p->config_storage);
30083         }
30084 -       
30085 +
30086         buffer_free(p->tmp_buf);
30087 -       
30088 +
30089         free(p);
30090 -       
30091 +
30092         return HANDLER_GO_ON;
30093  }
30094  
30095 @@ -73,131 +75,139 @@
30096  SETDEFAULTS_FUNC(mod_indexfile_set_defaults) {
30097         plugin_data *p = p_d;
30098         size_t i = 0;
30099 -       
30100 -       config_values_t cv[] = { 
30101 +
30102 +       config_values_t cv[] = {
30103                 { "index-file.names",           NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
30104                 { "server.indexfiles",          NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
30105                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
30106         };
30107 -       
30108 +
30109         if (!p) return HANDLER_ERROR;
30110 -       
30111 +
30112         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
30113 -       
30114 +
30115         for (i = 0; i < srv->config_context->used; i++) {
30116                 plugin_config *s;
30117 -               
30118 +
30119                 s = calloc(1, sizeof(plugin_config));
30120                 s->indexfiles    = array_init();
30121 -               
30122 +
30123                 cv[0].destination = s->indexfiles;
30124                 cv[1].destination = s->indexfiles; /* old name for [0] */
30125 -               
30126 +
30127                 p->config_storage[i] = s;
30128 -       
30129 +
30130                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
30131                         return HANDLER_ERROR;
30132                 }
30133         }
30134 -       
30135 +
30136         return HANDLER_GO_ON;
30137  }
30138  
30139 -#define PATCH(x) \
30140 -       p->conf.x = s->x;
30141  static int mod_indexfile_patch_connection(server *srv, connection *con, plugin_data *p) {
30142         size_t i, j;
30143         plugin_config *s = p->config_storage[0];
30144 -       
30145 -       PATCH(indexfiles);
30146 -       
30147 +
30148 +       PATCH_OPTION(indexfiles);
30149 +
30150         /* skip the first, the global context */
30151         for (i = 1; i < srv->config_context->used; i++) {
30152                 data_config *dc = (data_config *)srv->config_context->data[i];
30153                 s = p->config_storage[i];
30154 -               
30155 +
30156                 /* condition didn't match */
30157                 if (!config_check_cond(srv, con, dc)) continue;
30158 -               
30159 +
30160                 /* merge config */
30161                 for (j = 0; j < dc->value->used; j++) {
30162                         data_unset *du = dc->value->data[j];
30163 -                       
30164 +
30165                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.indexfiles"))) {
30166 -                               PATCH(indexfiles);
30167 +                               PATCH_OPTION(indexfiles);
30168                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("index-file.names"))) {
30169 -                               PATCH(indexfiles);
30170 +                               PATCH_OPTION(indexfiles);
30171                         }
30172                 }
30173         }
30174 -       
30175 +
30176         return 0;
30177  }
30178 -#undef PATCH
30179  
30180  URIHANDLER_FUNC(mod_indexfile_subrequest) {
30181         plugin_data *p = p_d;
30182         size_t k;
30183         stat_cache_entry *sce = NULL;
30184 -       
30185 +
30186         if (con->uri.path->used == 0) return HANDLER_GO_ON;
30187         if (con->uri.path->ptr[con->uri.path->used - 2] != '/') return HANDLER_GO_ON;
30188 -       
30189 +
30190         mod_indexfile_patch_connection(srv, con, p);
30191 -       
30192 +
30193 +       /* is the physical-path really a dir ? */
30194 +       if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
30195 +               return HANDLER_GO_ON;
30196 +       }
30197 +
30198 +       if (!S_ISDIR(sce->st.st_mode)) {
30199 +               return HANDLER_GO_ON;
30200 +       }
30201 +
30202         if (con->conf.log_request_handling) {
30203                 log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling the request as Indexfile");
30204                 log_error_write(srv, __FILE__, __LINE__,  "sb", "URI          :", con->uri.path);
30205         }
30206 -       
30207 +
30208 +
30209         /* indexfile */
30210         for (k = 0; k < p->conf.indexfiles->used; k++) {
30211                 data_string *ds = (data_string *)p->conf.indexfiles->data[k];
30212 -               
30213 +
30214                 if (ds->value && ds->value->ptr[0] == '/') {
30215 -                       /* if the index-file starts with a prefix as use this file as 
30216 +                       /* if the index-file starts with a prefix as use this file as
30217                          * index-generator */
30218                         buffer_copy_string_buffer(p->tmp_buf, con->physical.doc_root);
30219                 } else {
30220                         buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
30221 +                       PATHNAME_APPEND_SLASH(p->tmp_buf);
30222                 }
30223                 buffer_append_string_buffer(p->tmp_buf, ds->value);
30224 -               
30225 +
30226                 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
30227                         if (errno == EACCES) {
30228                                 con->http_status = 403;
30229                                 buffer_reset(con->physical.path);
30230 -                               
30231 +
30232                                 return HANDLER_FINISHED;
30233                         }
30234 -                       
30235 +
30236                         if (errno != ENOENT &&
30237                             errno != ENOTDIR) {
30238                                 /* we have no idea what happend. let's tell the user so. */
30239 -                               
30240 +
30241                                 con->http_status = 500;
30242 -                               
30243 +
30244                                 log_error_write(srv, __FILE__, __LINE__, "ssbsb",
30245                                                 "file not found ... or so: ", strerror(errno),
30246                                                 con->uri.path,
30247                                                 "->", con->physical.path);
30248 -                               
30249 +
30250                                 buffer_reset(con->physical.path);
30251 -                               
30252 +
30253                                 return HANDLER_FINISHED;
30254                         }
30255                         continue;
30256                 }
30257 -                       
30258 +
30259                 /* rewrite uri.path to the real path (/ -> /index.php) */
30260                 buffer_append_string_buffer(con->uri.path, ds->value);
30261                 buffer_copy_string_buffer(con->physical.path, p->tmp_buf);
30262 -               
30263 +
30264                 /* fce is already set up a few lines above */
30265 -               
30266 +
30267                 return HANDLER_GO_ON;
30268         }
30269 -       
30270 +
30271         /* not found */
30272         return HANDLER_GO_ON;
30273  }
30274 @@ -207,13 +217,13 @@
30275  int mod_indexfile_plugin_init(plugin *p) {
30276         p->version     = LIGHTTPD_VERSION_ID;
30277         p->name        = buffer_init_string("indexfile");
30278 -       
30279 +
30280         p->init        = mod_indexfile_init;
30281 -       p->handle_subrequest_start = mod_indexfile_subrequest;
30282 +       p->handle_start_backend = mod_indexfile_subrequest;
30283         p->set_defaults  = mod_indexfile_set_defaults;
30284         p->cleanup     = mod_indexfile_free;
30285 -       
30286 +
30287         p->data        = NULL;
30288 -       
30289 +
30290         return 0;
30291  }
30292 --- ../lighttpd-1.4.11/src/mod_mysql_vhost.c    2006-01-14 20:35:10.000000000 +0200
30293 +++ lighttpd-1.5.0/src/mod_mysql_vhost.c        2006-07-20 00:57:19.000000000 +0300
30294 @@ -1,13 +1,18 @@
30295 -#include <unistd.h>
30296  #include <stdio.h>
30297  #include <errno.h>
30298  #include <fcntl.h>
30299 -#include <strings.h>
30300 +#include <string.h>
30301  
30302  #ifdef HAVE_CONFIG_H
30303  #include "config.h"
30304  #endif
30305  
30306 +#ifdef HAVE_MYSQL_H 
30307 +# ifdef HAVE_LIBMYSQL
30308 +#  define HAVE_MYSQL
30309 +# endif
30310 +#endif
30311 +
30312  #ifdef HAVE_MYSQL
30313  #include <mysql.h>
30314  #endif
30315 @@ -16,61 +21,40 @@
30316  #include "log.h"
30317  
30318  #include "stat_cache.h"
30319 -#ifdef DEBUG_MOD_MYSQL_VHOST
30320 -#define DEBUG
30321 -#endif
30322 +#include "sys-files.h"
30323  
30324 -/*
30325 - * Plugin for lighttpd to use MySQL 
30326 - *   for domain to directory lookups,
30327 - *   i.e virtual hosts (vhosts).
30328 - *   
30329 - * Optionally sets fcgi_offset and fcgi_arg 
30330 - *   in preparation for fcgi.c to handle 
30331 - *   per-user fcgi chroot jails.
30332 - *
30333 - * /ada@riksnet.se 2004-12-06
30334 - */
30335 +#include "mod_sql_vhost_core.h"
30336  
30337  #ifdef HAVE_MYSQL
30338 +
30339 +#define CORE_PLUGIN "mod_sql_vhost_core"
30340 +
30341  typedef struct {
30342         MYSQL   *mysql;
30343 -       
30344 -       buffer  *mydb;
30345 -       buffer  *myuser;
30346 -       buffer  *mypass;
30347 -       buffer  *mysock;
30348 -       
30349 -       buffer  *hostname;
30350 -       unsigned short port;
30351 -       
30352 +
30353         buffer  *mysql_pre;
30354         buffer  *mysql_post;
30355 +
30356 +       mod_sql_vhost_core_plugin_config *core;
30357  } plugin_config;
30358  
30359  /* global plugin data */
30360  typedef struct {
30361         PLUGIN_DATA;
30362 -       
30363 +
30364         buffer  *tmp_buf;
30365 -       
30366 +
30367         plugin_config **config_storage;
30368 -       
30369 -       plugin_config conf; 
30370 +
30371 +       plugin_config conf;
30372  } plugin_data;
30373  
30374 -/* per connection plugin data */
30375 -typedef struct {
30376 -       buffer  *server_name;
30377 -       buffer  *document_root;
30378 -       buffer  *fcgi_arg;
30379 -       unsigned fcgi_offset;
30380 -} plugin_connection_data;
30381 +SQLVHOST_BACKEND_GETVHOST(mod_mysql_vhost_get_vhost); 
30382  
30383  /* init the plugin data */
30384  INIT_FUNC(mod_mysql_vhost_init) {
30385         plugin_data *p;
30386 -       
30387 +
30388         p = calloc(1, sizeof(*p));
30389  
30390         p->tmp_buf = buffer_init();
30391 @@ -83,144 +67,77 @@
30392         plugin_data *p = p_d;
30393  
30394         UNUSED(srv);
30395 -       
30396 -#ifdef DEBUG
30397 -       log_error_write(srv, __FILE__, __LINE__, "ss", 
30398 -               "mod_mysql_vhost_cleanup", p ? "yes" : "NO");
30399 -#endif
30400 +
30401         if (!p) return HANDLER_GO_ON;
30402 -       
30403 +
30404         if (p->config_storage) {
30405                 size_t i;
30406                 for (i = 0; i < srv->config_context->used; i++) {
30407                         plugin_config *s = p->config_storage[i];
30408  
30409                         if (!s) continue;
30410 -                       
30411 +
30412                         mysql_close(s->mysql);
30413 -                       
30414 -                       buffer_free(s->mydb);
30415 -                       buffer_free(s->myuser);
30416 -                       buffer_free(s->mypass);
30417 -                       buffer_free(s->mysock);
30418 +
30419                         buffer_free(s->mysql_pre);
30420                         buffer_free(s->mysql_post);
30421 -                       
30422 +
30423                         free(s);
30424                 }
30425                 free(p->config_storage);
30426         }
30427         buffer_free(p->tmp_buf);
30428 -       
30429 -       free(p);
30430  
30431 -       return HANDLER_GO_ON;
30432 -}
30433 -
30434 -/* handle the plugin per connection data */
30435 -static void* mod_mysql_vhost_connection_data(server *srv, connection *con, void *p_d)
30436 -{
30437 -       plugin_data *p = p_d;
30438 -       plugin_connection_data *c = con->plugin_ctx[p->id];
30439 -
30440 -       UNUSED(srv);
30441 -
30442 -#ifdef DEBUG
30443 -        log_error_write(srv, __FILE__, __LINE__, "ss", 
30444 -               "mod_mysql_connection_data", c ? "old" : "NEW");
30445 -#endif
30446 -
30447 -       if (c) return c;
30448 -       c = calloc(1, sizeof(*c));
30449 -
30450 -       c->server_name = buffer_init();
30451 -       c->document_root = buffer_init();
30452 -       c->fcgi_arg = buffer_init();
30453 -       c->fcgi_offset = 0;
30454 -
30455 -       return con->plugin_ctx[p->id] = c;
30456 -}
30457 -
30458 -/* destroy the plugin per connection data */
30459 -CONNECTION_FUNC(mod_mysql_vhost_handle_connection_close) {
30460 -       plugin_data *p = p_d;
30461 -       plugin_connection_data *c = con->plugin_ctx[p->id];
30462 -
30463 -       UNUSED(srv);
30464 -
30465 -#ifdef DEBUG
30466 -       log_error_write(srv, __FILE__, __LINE__, "ss", 
30467 -               "mod_mysql_vhost_handle_connection_close", c ? "yes" : "NO");
30468 -#endif
30469 -       
30470 -       if (!c) return HANDLER_GO_ON;
30471 -
30472 -       buffer_free(c->server_name);
30473 -       buffer_free(c->document_root);
30474 -       buffer_free(c->fcgi_arg);
30475 -       c->fcgi_offset = 0;
30476 -
30477 -       free(c);
30478 +       free(p);
30479  
30480 -       con->plugin_ctx[p->id] = NULL;
30481         return HANDLER_GO_ON;
30482  }
30483  
30484  /* set configuration values */
30485  SERVER_FUNC(mod_mysql_vhost_set_defaults) {
30486         plugin_data *p = p_d;
30487 +       mod_sql_vhost_core_plugin_data *core_config;
30488  
30489 -       char *qmark;
30490         size_t i = 0;
30491  
30492 -       config_values_t cv[] = {
30493 -               { "mysql-vhost.db",     NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER },
30494 -               { "mysql-vhost.user",   NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER },
30495 -               { "mysql-vhost.pass",   NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER },
30496 -               { "mysql-vhost.sock",   NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER },
30497 -               { "mysql-vhost.sql",    NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER },
30498 -               { "mysql-vhost.hostname", NULL, T_CONFIG_STRING,T_CONFIG_SCOPE_SERVER },
30499 -               { "mysql-vhost.port",   NULL, T_CONFIG_SHORT,   T_CONFIG_SCOPE_SERVER },
30500 -                { NULL,                        NULL, T_CONFIG_UNSET,   T_CONFIG_SCOPE_UNSET }
30501 -        };
30502 -       
30503 +       /* our very own plugin storage, one entry for each conditional
30504 +        * 
30505 +        * srv->config_context->used is the number of conditionals
30506 +        * */
30507         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
30508 -       
30509 +
30510 +       /* get the config of the core-plugin */
30511 +       core_config = plugin_get_config(srv, CORE_PLUGIN);
30512 +
30513 +
30514 +       /* walk through all conditionals and check for assignments */
30515         for (i = 0; i < srv->config_context->used; i++) {
30516                 plugin_config *s;
30517                 buffer *sel;
30518 -               
30519 -               
30520 +               char *qmark;
30521 +
30522 +               /* get the config from the core plugin for this conditional-context */
30523                 s = calloc(1, sizeof(plugin_config));
30524 -               s->mydb = buffer_init();
30525 -               s->myuser = buffer_init();
30526 -               s->mypass = buffer_init();
30527 -               s->mysock = buffer_init();
30528 -               s->hostname = buffer_init();
30529 -               s->port   = 0;               /* default port for mysql */
30530 -               sel = buffer_init();
30531 -               s->mysql = NULL;
30532 +
30533 +               s->core = core_config->config_storage[i];
30534                 
30535 +               s->mysql = NULL;
30536 +
30537                 s->mysql_pre = buffer_init();
30538                 s->mysql_post = buffer_init();
30539 -               
30540 -               cv[0].destination = s->mydb;
30541 -               cv[1].destination = s->myuser;
30542 -               cv[2].destination = s->mypass;
30543 -               cv[3].destination = s->mysock;
30544 -               cv[4].destination = sel;
30545 -               cv[5].destination = s->hostname;
30546 -               cv[6].destination = &(s->port);
30547 -               
30548 +
30549                 p->config_storage[i] = s;
30550 -               
30551 -               if (config_insert_values_global(srv, 
30552 -                       ((data_config *)srv->config_context->data[i])->value,
30553 -                       cv)) return HANDLER_ERROR;
30554 -               
30555 -               s->mysql_pre = buffer_init();
30556 -               s->mysql_post = buffer_init();
30557 -               
30558 +
30559 +               /* check if we are the plugin for this backend */
30560 +               if (!buffer_is_equal_string(s->core->backend, CONST_STR_LEN("mysql"))) continue;
30561 +
30562 +               /* attach us to the core-plugin */
30563 +               s->core->backend_data = p;
30564 +               s->core->get_vhost = mod_mysql_vhost_get_vhost;
30565 +
30566 +               sel = buffer_init();
30567 +               buffer_copy_string_buffer(sel, s->core->select_vhost);
30568 +
30569                 if (sel->used && (qmark = index(sel->ptr, '?'))) {
30570                         *qmark = '\0';
30571                         buffer_copy_string(s->mysql_pre, sel->ptr);
30572 @@ -228,35 +145,38 @@
30573                 } else {
30574                         buffer_copy_string_buffer(s->mysql_pre, sel);
30575                 }
30576 -               
30577 +               buffer_free(sel);
30578 +
30579                 /* required:
30580                  * - username
30581 -                * - database 
30582 -                * 
30583 +                * - database
30584 +                *
30585                  * optional:
30586                  * - password, default: empty
30587                  * - socket, default: mysql default
30588                  * - hostname, if set overrides socket
30589                  * - port, default: 3306
30590                  */
30591 -               
30592 +
30593                 /* all have to be set */
30594 -               if (!(buffer_is_empty(s->myuser) ||
30595 -                     buffer_is_empty(s->mydb))) {
30596 +               if (!(buffer_is_empty(s->core->user) ||
30597 +                     buffer_is_empty(s->core->db))) {
30598  
30599                         int fd;
30600 -               
30601 +
30602                         if (NULL == (s->mysql = mysql_init(NULL))) {
30603                                 log_error_write(srv, __FILE__, __LINE__, "s", "mysql_init() failed, exiting...");
30604 -                               
30605 +
30606                                 return HANDLER_ERROR;
30607                         }
30608 -#define FOO(x) (s->x->used ? s->x->ptr : NULL)
30609 -                       
30610 -                       if (!mysql_real_connect(s->mysql, FOO(hostname), FOO(myuser), FOO(mypass), 
30611 -                                               FOO(mydb), s->port, FOO(mysock), 0)) {
30612 +#define FOO(x) (s->core->x->used ? s->core->x->ptr : NULL)
30613 +
30614 +                       s->mysql->free_me = 1;
30615 +
30616 +                       if (!mysql_real_connect(s->mysql, FOO(hostname), FOO(user), FOO(pass),
30617 +                                               FOO(db), s->core->port, FOO(sock), 0)) {
30618                                 log_error_write(srv, __FILE__, __LINE__, "s", mysql_error(s->mysql));
30619 -                               
30620 +
30621                                 return HANDLER_ERROR;
30622                         }
30623  #undef FOO
30624 @@ -265,61 +185,47 @@
30625                         /* otherwise we cannot be sure that mysql is fd i-1 */
30626                         if (-1 == (fd = open("/dev/null", 0))) {
30627                                 close(fd);
30628 -                               fcntl(fd-1, F_SETFD, FD_CLOEXEC); 
30629 +                               fcntl(fd-1, F_SETFD, FD_CLOEXEC);
30630                         }
30631                 }
30632         }
30633 -       
30634 -       
30635 +
30636 +
30637  
30638          return HANDLER_GO_ON;
30639  }
30640  
30641 -#define PATCH(x) \
30642 -       p->conf.x = s->x;
30643  static int mod_mysql_vhost_patch_connection(server *srv, connection *con, plugin_data *p) {
30644 -       size_t i, j;
30645 +       size_t i;
30646         plugin_config *s = p->config_storage[0];
30647 -       
30648 -       PATCH(mysql_pre);
30649 -       PATCH(mysql_post);
30650 -#ifdef HAVE_MYSQL
30651 -       PATCH(mysql);
30652 -#endif
30653 -       
30654 +
30655 +       PATCH_OPTION(mysql_pre);
30656 +       PATCH_OPTION(mysql_post);
30657 +       PATCH_OPTION(mysql);
30658 +
30659         /* skip the first, the global context */
30660         for (i = 1; i < srv->config_context->used; i++) {
30661                 data_config *dc = (data_config *)srv->config_context->data[i];
30662                 s = p->config_storage[i];
30663 -               
30664 +
30665                 /* condition didn't match */
30666                 if (!config_check_cond(srv, con, dc)) continue;
30667 -               
30668 -               /* merge config */
30669 -               for (j = 0; j < dc->value->used; j++) {
30670 -                       data_unset *du = dc->value->data[j];
30671 -                       
30672 -                       if (buffer_is_equal_string(du->key, CONST_STR_LEN("mysql-vhost.sql"))) {
30673 -                               PATCH(mysql_pre);
30674 -                               PATCH(mysql_post);
30675 -                       }
30676 -               }
30677 -               
30678 +
30679                 if (s->mysql) {
30680 -                       PATCH(mysql);
30681 +                       PATCH_OPTION(mysql);
30682 +                       PATCH_OPTION(mysql_pre);
30683 +                       PATCH_OPTION(mysql_post);
30684                 }
30685         }
30686 -       
30687 +
30688         return 0;
30689  }
30690 -#undef PATCH
30691  
30692 -
30693 -/* handle document root request */
30694 -CONNECTION_FUNC(mod_mysql_vhost_handle_docroot) {
30695 +/**
30696 + * get the vhost info from the database 
30697 + */
30698 +SQLVHOST_BACKEND_GETVHOST(mod_mysql_vhost_get_vhost) {
30699         plugin_data *p = p_d;
30700 -       plugin_connection_data *c;
30701 -       stat_cache_entry *sce;
30702  
30703         unsigned  cols;
30704         MYSQL_ROW row;
30705 @@ -332,13 +238,6 @@
30706  
30707         if (!p->conf.mysql) return HANDLER_GO_ON;
30708  
30709 -       /* sets up connection data if not done yet */
30710 -       c = mod_mysql_vhost_connection_data(srv, con, p_d);
30711 -
30712 -       /* check if cached this connection */
30713 -       if (c->server_name->used && /* con->uri.authority->used && */
30714 -            buffer_is_equal(c->server_name, con->uri.authority)) goto GO_ON;
30715 -
30716         /* build and run SQL query */
30717         buffer_copy_string_buffer(p->tmp_buf, p->conf.mysql_pre);
30718         if (p->conf.mysql_post->used) {
30719 @@ -347,77 +246,43 @@
30720         }
30721         if (mysql_query(p->conf.mysql, p->tmp_buf->ptr)) {
30722                 log_error_write(srv, __FILE__, __LINE__, "s", mysql_error(p->conf.mysql));
30723 -               goto ERR500;
30724 +
30725 +               mysql_free_result(result);
30726 +               return HANDLER_GO_ON;
30727         }
30728         result = mysql_store_result(p->conf.mysql);
30729         cols = mysql_num_fields(result);
30730         row = mysql_fetch_row(result);
30731 +
30732         if (!row || cols < 1) {
30733                 /* no such virtual host */
30734                 mysql_free_result(result);
30735                 return HANDLER_GO_ON;
30736         }
30737  
30738 -       /* sanity check that really is a directory */
30739 -       buffer_copy_string(p->tmp_buf, row[0]);
30740 -       BUFFER_APPEND_SLASH(p->tmp_buf);
30741 -
30742 -       if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
30743 -               log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->tmp_buf);
30744 -               goto ERR500;
30745 -       }
30746 -        if (!S_ISDIR(sce->st.st_mode)) {
30747 -               log_error_write(srv, __FILE__, __LINE__, "sb", "Not a directory", p->tmp_buf);
30748 -               goto ERR500;
30749 -       }
30750 +       buffer_copy_string(docroot, row[0]);
30751  
30752 -       /* cache the data */
30753 -       buffer_copy_string_buffer(c->server_name, con->uri.authority);
30754 -       buffer_copy_string_buffer(c->document_root, p->tmp_buf);
30755 -
30756 -       /* fcgi_offset and fcgi_arg are optional */
30757 -       if (cols > 1 && row[1]) {
30758 -               c->fcgi_offset = atoi(row[1]);
30759 -               
30760 -               if (cols > 2 && row[2]) {
30761 -                       buffer_copy_string(c->fcgi_arg, row[2]);
30762 -               } else {
30763 -                       c->fcgi_arg->used = 0;
30764 -               }
30765 -       } else {
30766 -               c->fcgi_offset = c->fcgi_arg->used = 0;
30767 -       }
30768         mysql_free_result(result);
30769  
30770 -       /* fix virtual server and docroot */
30771 -GO_ON: buffer_copy_string_buffer(con->server_name, c->server_name);
30772 -       buffer_copy_string_buffer(con->physical.doc_root, c->document_root);
30773 -
30774 -#ifdef DEBUG
30775 -       log_error_write(srv, __FILE__, __LINE__, "sbbdb", 
30776 -               result ? "NOT CACHED" : "cached", 
30777 -               con->server_name, con->physical.doc_root,
30778 -               c->fcgi_offset, c->fcgi_arg);
30779 -#endif
30780 -       return HANDLER_GO_ON;   
30781 -
30782 -ERR500:        if (result) mysql_free_result(result);
30783 -       con->http_status = 500; /* Internal Error */
30784 -       return HANDLER_FINISHED;
30785 +       return HANDLER_GO_ON;
30786  }
30787  
30788  /* this function is called at dlopen() time and inits the callbacks */
30789  int mod_mysql_vhost_plugin_init(plugin *p) {
30790 +       data_string *ds;
30791 +       
30792         p->version     = LIGHTTPD_VERSION_ID;
30793         p->name                         = buffer_init_string("mysql_vhost");
30794  
30795         p->init                         = mod_mysql_vhost_init;
30796         p->cleanup                      = mod_mysql_vhost_cleanup;
30797 -       p->handle_request_done          = mod_mysql_vhost_handle_connection_close;
30798  
30799         p->set_defaults                 = mod_mysql_vhost_set_defaults;
30800 -       p->handle_docroot               = mod_mysql_vhost_handle_docroot;
30801         
30802 +       ds = data_string_init();
30803 +       buffer_copy_string(ds->value, CORE_PLUGIN);
30804 +       array_insert_unique(p->required_plugins, (data_unset *)ds);
30805 +
30806         return 0;
30807  }
30808  #else
30809 --- ../lighttpd-1.4.11/src/mod_proxy.c  2006-01-31 13:01:22.000000000 +0200
30810 +++ lighttpd-1.5.0/src/mod_proxy.c      2006-09-07 00:57:05.000000000 +0300
30811 @@ -1,6 +1,5 @@
30812  #include <sys/types.h>
30813  
30814 -#include <unistd.h>
30815  #include <errno.h>
30816  #include <fcntl.h>
30817  #include <string.h>
30818 @@ -13,7 +12,6 @@
30819  #include "keyvalue.h"
30820  #include "log.h"
30821  
30822 -#include "http_chunk.h"
30823  #include "fdevent.h"
30824  #include "connections.h"
30825  #include "response.h"
30826 @@ -23,6 +21,9 @@
30827  
30828  #include "inet_ntop_cache.h"
30829  #include "crc32.h"
30830 +#include "network.h"
30831 +
30832 +#include "http_resp.h"
30833  
30834  #include <stdio.h>
30835  
30836 @@ -31,6 +32,8 @@
30837  #endif
30838  
30839  #include "sys-socket.h"
30840 +#include "sys-files.h"
30841 +#include "sys-strings.h"
30842  
30843  #define data_proxy data_fastcgi
30844  #define data_proxy_init data_fastcgi_init
30845 @@ -38,22 +41,25 @@
30846  #define PROXY_RETRY_TIMEOUT 60
30847  
30848  /**
30849 - * 
30850 - * the proxy module is based on the fastcgi module 
30851 - * 
30852 + *
30853 + * the proxy module is based on the fastcgi module
30854 + *
30855   * 28.06.2004 Jan Kneschke     The first release
30856   * 01.07.2004 Evgeny Rodichev  Several bugfixes and cleanups
30857   *            - co-ordinate up- and downstream flows correctly (proxy_demux_response
30858   *              and proxy_handle_fdevent)
30859   *            - correctly transfer upstream http_response_status;
30860   *            - some unused structures removed.
30861 - * 
30862 + *
30863   * TODO:      - delay upstream read if write_queue is too large
30864   *              (to prevent memory eating, like in apache). Shoud be
30865   *              configurable).
30866   *            - persistent connection with upstream servers
30867   *            - HTTP/1.1
30868   */
30869 +
30870 +
30871 +
30872  typedef enum {
30873         PROXY_BALANCE_UNSET,
30874         PROXY_BALANCE_FAIR,
30875 @@ -66,26 +72,33 @@
30876         int debug;
30877  
30878         proxy_balance_t balance;
30879 +
30880 +       array *last_used_backends; /* "extension" : last_used_backend */
30881  } plugin_config;
30882  
30883  typedef struct {
30884         PLUGIN_DATA;
30885 -       
30886 +
30887         buffer *parse_response;
30888         buffer *balance_buf;
30889 -       
30890 +
30891 +       http_resp *resp;
30892 +
30893 +       array *ignore_headers;
30894 +
30895         plugin_config **config_storage;
30896 -       
30897 +
30898         plugin_config conf;
30899  } plugin_data;
30900  
30901 -typedef enum { 
30902 -       PROXY_STATE_INIT, 
30903 -       PROXY_STATE_CONNECT, 
30904 -       PROXY_STATE_PREPARE_WRITE, 
30905 -       PROXY_STATE_WRITE, 
30906 -       PROXY_STATE_READ, 
30907 -       PROXY_STATE_ERROR 
30908 +typedef enum {
30909 +       PROXY_STATE_INIT,
30910 +       PROXY_STATE_CONNECT,
30911 +       PROXY_STATE_PREPARE_WRITE,
30912 +       PROXY_STATE_WRITE,
30913 +       PROXY_STATE_RESPONSE_HEADER,
30914 +       PROXY_STATE_RESPONSE_CONTENT,
30915 +       PROXY_STATE_ERROR
30916  } proxy_connection_state_t;
30917  
30918  enum { PROXY_STDOUT, PROXY_END_REQUEST };
30919 @@ -93,19 +106,16 @@
30920  typedef struct {
30921         proxy_connection_state_t state;
30922         time_t state_timestamp;
30923 -       
30924 +
30925         data_proxy *host;
30926 -       
30927 -       buffer *response;
30928 -       buffer *response_header;
30929  
30930         chunkqueue *wb;
30931 -       
30932 -       int fd; /* fd to the proxy process */
30933 -       int fde_ndx; /* index into the fd-event buffer */
30934 +       chunkqueue *rb;
30935 +
30936 +       iosocket *sock; /* fd to the proxy process */
30937  
30938         size_t path_info_offset; /* start of path_info in uri.path */
30939 -       
30940 +
30941         connection *remote_conn;  /* dump pointer */
30942         plugin_data *plugin_data; /* dump pointer */
30943  } handler_ctx;
30944 @@ -116,69 +126,89 @@
30945  
30946  static handler_ctx * handler_ctx_init() {
30947         handler_ctx * hctx;
30948 -       
30949 +
30950  
30951         hctx = calloc(1, sizeof(*hctx));
30952 -       
30953 +
30954         hctx->state = PROXY_STATE_INIT;
30955         hctx->host = NULL;
30956 -       
30957 -       hctx->response = buffer_init();
30958 -       hctx->response_header = buffer_init();
30959  
30960         hctx->wb = chunkqueue_init();
30961 +       hctx->rb = chunkqueue_init();
30962 +
30963 +       hctx->sock = iosocket_init();
30964  
30965 -       hctx->fd = -1;
30966 -       hctx->fde_ndx = -1;
30967 -       
30968         return hctx;
30969  }
30970  
30971  static void handler_ctx_free(handler_ctx *hctx) {
30972 -       buffer_free(hctx->response);
30973 -       buffer_free(hctx->response_header);
30974         chunkqueue_free(hctx->wb);
30975 -       
30976 +       chunkqueue_free(hctx->rb);
30977 +
30978 +       iosocket_free(hctx->sock);
30979 +
30980         free(hctx);
30981  }
30982  
30983  INIT_FUNC(mod_proxy_init) {
30984         plugin_data *p;
30985 -       
30986 +       size_t i;
30987 +
30988 +       char *hop2hop_headers[] = {
30989 +               "Connection",
30990 +               "Keep-Alive",
30991 +               "Host",
30992 +               NULL
30993 +       };
30994 +
30995         p = calloc(1, sizeof(*p));
30996 -       
30997 -       p->parse_response = buffer_init();
30998 +
30999         p->balance_buf = buffer_init();
31000 -       
31001 +       p->ignore_headers = array_init();
31002 +       p->resp = http_response_init();
31003 +
31004 +       for (i = 0; hop2hop_headers[i]; i++) {
31005 +               data_string *ds;
31006 +
31007 +               if (NULL == (ds = (data_string *)array_get_unused_element(p->ignore_headers, TYPE_STRING))) {
31008 +                       ds = data_string_init();
31009 +               }
31010 +
31011 +               buffer_copy_string(ds->key, hop2hop_headers[i]);
31012 +               buffer_copy_string(ds->value, hop2hop_headers[i]);
31013 +               array_insert_unique(p->ignore_headers, (data_unset *)ds);
31014 +       }
31015 +
31016         return p;
31017  }
31018  
31019  
31020  FREE_FUNC(mod_proxy_free) {
31021         plugin_data *p = p_d;
31022 -       
31023 +
31024         UNUSED(srv);
31025  
31026 -       buffer_free(p->parse_response);
31027 -       buffer_free(p->balance_buf);
31028 -       
31029         if (p->config_storage) {
31030                 size_t i;
31031                 for (i = 0; i < srv->config_context->used; i++) {
31032                         plugin_config *s = p->config_storage[i];
31033 -                       
31034 +
31035                         if (s) {
31036 -                       
31037                                 array_free(s->extensions);
31038 -                       
31039 +                               array_free(s->last_used_backends);
31040 +
31041                                 free(s);
31042                         }
31043                 }
31044                 free(p->config_storage);
31045         }
31046 -       
31047 +
31048 +       array_free(p->ignore_headers);
31049 +       buffer_free(p->balance_buf);
31050 +       http_response_free(p->resp);
31051 +
31052         free(p);
31053 -       
31054 +
31055         return HANDLER_GO_ON;
31056  }
31057  
31058 @@ -186,37 +216,38 @@
31059         plugin_data *p = p_d;
31060         data_unset *du;
31061         size_t i = 0;
31062 -       
31063 -       config_values_t cv[] = { 
31064 +
31065 +       config_values_t cv[] = {
31066                 { "proxy.server",              NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
31067                 { "proxy.debug",               NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
31068                 { "proxy.balance",             NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },      /* 2 */
31069                 { NULL,                        NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
31070         };
31071 -       
31072 +
31073         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
31074 -       
31075 +
31076         for (i = 0; i < srv->config_context->used; i++) {
31077                 plugin_config *s;
31078                 array *ca;
31079 -               
31080 +
31081                 s = malloc(sizeof(plugin_config));
31082 -               s->extensions    = array_init();
31083 +               s->extensions         = array_init();
31084 +               s->last_used_backends = array_init();
31085                 s->debug         = 0;
31086 -               
31087 +
31088                 cv[0].destination = s->extensions;
31089                 cv[1].destination = &(s->debug);
31090                 cv[2].destination = p->balance_buf;
31091  
31092                 buffer_reset(p->balance_buf);
31093 -               
31094 +
31095                 p->config_storage[i] = s;
31096                 ca = ((data_config *)srv->config_context->data[i])->value;
31097 -       
31098 +
31099                 if (0 != config_insert_values_global(srv, ca, cv)) {
31100                         return HANDLER_ERROR;
31101                 }
31102 -       
31103 +
31104                 if (buffer_is_empty(p->balance_buf)) {
31105                         s->balance = PROXY_BALANCE_FAIR;
31106                 } else if (buffer_is_equal_string(p->balance_buf, CONST_STR_LEN("fair"))) {
31107 @@ -226,99 +257,99 @@
31108                 } else if (buffer_is_equal_string(p->balance_buf, CONST_STR_LEN("hash"))) {
31109                         s->balance = PROXY_BALANCE_HASH;
31110                 } else {
31111 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
31112 -                                       "proxy.balance has to be one of: fair, round-robin, hash, but not:", p->balance_buf);
31113 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
31114 +                               "proxy.balance has to be one of: fair, round-robin, hash, but not:", p->balance_buf);
31115                         return HANDLER_ERROR;
31116                 }
31117  
31118                 if (NULL != (du = array_get_element(ca, "proxy.server"))) {
31119                         size_t j;
31120                         data_array *da = (data_array *)du;
31121 -                       
31122 +
31123                         if (du->type != TYPE_ARRAY) {
31124 -                               log_error_write(srv, __FILE__, __LINE__, "sss", 
31125 +                               log_error_write(srv, __FILE__, __LINE__, "sss",
31126                                                 "unexpected type for key: ", "proxy.server", "array of strings");
31127 -                               
31128 +
31129                                 return HANDLER_ERROR;
31130                         }
31131 -                       
31132 -                       /* 
31133 +
31134 +                       /*
31135                          * proxy.server = ( "<ext>" => ...,
31136                          *                  "<ext>" => ... )
31137                          */
31138 -                       
31139 +
31140                         for (j = 0; j < da->value->used; j++) {
31141                                 data_array *da_ext = (data_array *)da->value->data[j];
31142                                 size_t n;
31143 -                               
31144 +
31145                                 if (da_ext->type != TYPE_ARRAY) {
31146 -                                       log_error_write(srv, __FILE__, __LINE__, "sssbs", 
31147 -                                                       "unexpected type for key: ", "proxy.server", 
31148 +                                       log_error_write(srv, __FILE__, __LINE__, "sssbs",
31149 +                                                       "unexpected type for key: ", "proxy.server",
31150                                                         "[", da->value->data[j]->key, "](string)");
31151 -                                       
31152 +
31153                                         return HANDLER_ERROR;
31154                                 }
31155 -                               
31156 -                               /* 
31157 -                                * proxy.server = ( "<ext>" => 
31158 -                                *                     ( "<host>" => ( ... ), 
31159 +
31160 +                               /*
31161 +                                * proxy.server = ( "<ext>" =>
31162 +                                *                     ( "<host>" => ( ... ),
31163                                  *                       "<host>" => ( ... )
31164 -                                *                     ), 
31165 +                                *                     ),
31166                                  *                    "<ext>" => ... )
31167                                  */
31168 -                               
31169 +
31170                                 for (n = 0; n < da_ext->value->used; n++) {
31171                                         data_array *da_host = (data_array *)da_ext->value->data[n];
31172 -                                       
31173 +
31174                                         data_proxy *df;
31175                                         data_array *dfa;
31176 -                                       
31177 -                                       config_values_t pcv[] = { 
31178 +
31179 +                                       config_values_t pcv[] = {
31180                                                 { "host",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },      /* 0 */
31181                                                 { "port",              NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
31182                                                 { NULL,                NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
31183                                         };
31184 -                                       
31185 +
31186                                         if (da_host->type != TYPE_ARRAY) {
31187 -                                               log_error_write(srv, __FILE__, __LINE__, "ssSBS", 
31188 -                                                               "unexpected type for key:", 
31189 -                                                               "proxy.server", 
31190 +                                               log_error_write(srv, __FILE__, __LINE__, "ssSBS",
31191 +                                                               "unexpected type for key:",
31192 +                                                               "proxy.server",
31193                                                                 "[", da_ext->value->data[n]->key, "](string)");
31194 -                                               
31195 +
31196                                                 return HANDLER_ERROR;
31197                                         }
31198 -                                       
31199 +
31200                                         df = data_proxy_init();
31201 -                                       
31202 +
31203                                         df->port = 80;
31204 -                                       
31205 +
31206                                         buffer_copy_string_buffer(df->key, da_host->key);
31207 -                                       
31208 +
31209                                         pcv[0].destination = df->host;
31210                                         pcv[1].destination = &(df->port);
31211 -                                       
31212 +
31213                                         if (0 != config_insert_values_internal(srv, da_host->value, pcv)) {
31214                                                 return HANDLER_ERROR;
31215                                         }
31216 -                                       
31217 +
31218                                         if (buffer_is_empty(df->host)) {
31219 -                                               log_error_write(srv, __FILE__, __LINE__, "sbbbs", 
31220 -                                                               "missing key (string):", 
31221 +                                               log_error_write(srv, __FILE__, __LINE__, "sbbbs",
31222 +                                                               "missing key (string):",
31223                                                                 da->key,
31224                                                                 da_ext->key,
31225                                                                 da_host->key,
31226                                                                 "host");
31227 -                                               
31228 +
31229                                                 return HANDLER_ERROR;
31230                                         }
31231 -                                       
31232 +
31233                                         /* if extension already exists, take it */
31234 -                                       
31235 +
31236                                         if (NULL == (dfa = (data_array *)array_get_element(s->extensions, da_ext->key->ptr))) {
31237                                                 dfa = data_array_init();
31238 -                                               
31239 +
31240                                                 buffer_copy_string_buffer(dfa->key, da_ext->key);
31241 -                                               
31242 +
31243                                                 array_insert_unique(dfa->value, (data_unset *)df);
31244                                                 array_insert_unique(s->extensions, (data_unset *)dfa);
31245                                         } else {
31246 @@ -328,67 +359,76 @@
31247                         }
31248                 }
31249         }
31250 -       
31251 +
31252         return HANDLER_GO_ON;
31253  }
31254  
31255  void proxy_connection_close(server *srv, handler_ctx *hctx) {
31256         plugin_data *p;
31257         connection *con;
31258 -       
31259 +
31260         if (NULL == hctx) return;
31261 -       
31262 +
31263         p    = hctx->plugin_data;
31264         con  = hctx->remote_conn;
31265 -       
31266 -       if (hctx->fd != -1) {
31267 -               fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
31268 -               fdevent_unregister(srv->ev, hctx->fd);
31269  
31270 -               close(hctx->fd);
31271 +       if (hctx->sock->fd != -1) {
31272 +               fdevent_event_del(srv->ev, hctx->sock);
31273 +               fdevent_unregister(srv->ev, hctx->sock);
31274 +
31275 +               close(hctx->sock->fd);
31276                 srv->cur_fds--;
31277         }
31278 -       
31279 +
31280         handler_ctx_free(hctx);
31281 -       con->plugin_ctx[p->id] = NULL;  
31282 +       con->plugin_ctx[p->id] = NULL;
31283  }
31284  
31285  static int proxy_establish_connection(server *srv, handler_ctx *hctx) {
31286         struct sockaddr *proxy_addr;
31287         struct sockaddr_in proxy_addr_in;
31288         socklen_t servlen;
31289 -       
31290 +
31291         plugin_data *p    = hctx->plugin_data;
31292         data_proxy *host= hctx->host;
31293 -       int proxy_fd       = hctx->fd;
31294 -       
31295 +       int proxy_fd       = hctx->sock->fd;
31296 +
31297         memset(&proxy_addr, 0, sizeof(proxy_addr));
31298 -       
31299 +
31300         proxy_addr_in.sin_family = AF_INET;
31301         proxy_addr_in.sin_addr.s_addr = inet_addr(host->host->ptr);
31302         proxy_addr_in.sin_port = htons(host->port);
31303         servlen = sizeof(proxy_addr_in);
31304 -               
31305 +
31306         proxy_addr = (struct sockaddr *) &proxy_addr_in;
31307 -       
31308 +
31309         if (-1 == connect(proxy_fd, proxy_addr, servlen)) {
31310 -               if (errno == EINPROGRESS || errno == EALREADY) {
31311 +#ifdef _WIN32
31312 +       errno = WSAGetLastError();
31313 +#endif
31314 +       switch(errno) {
31315 +#ifdef _WIN32
31316 +       case WSAEWOULDBLOCK:
31317 +#endif
31318 +       case EINPROGRESS:
31319 +       case EALREADY:
31320                         if (p->conf.debug) {
31321 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
31322 +                               log_error_write(srv, __FILE__, __LINE__, "sd",
31323                                                 "connect delayed:", proxy_fd);
31324                         }
31325 -                       
31326 +
31327                         return 1;
31328 -               } else {
31329 -                       
31330 -                       log_error_write(srv, __FILE__, __LINE__, "sdsd", 
31331 +               default:
31332 +
31333 +                       log_error_write(srv, __FILE__, __LINE__, "sdsd",
31334                                         "connect failed:", proxy_fd, strerror(errno), errno);
31335 -                       
31336 +
31337                         return -1;
31338                 }
31339         }
31340 +       fprintf(stderr, "%s.%d: connected fd = %d\r\n", __FILE__, __LINE__, proxy_fd);
31341         if (p->conf.debug) {
31342 -               log_error_write(srv, __FILE__, __LINE__, "sd", 
31343 +               log_error_write(srv, __FILE__, __LINE__, "sd",
31344                                 "connect succeeded: ", proxy_fd);
31345         }
31346  
31347 @@ -396,51 +436,52 @@
31348  }
31349  
31350  void proxy_set_header(connection *con, const char *key, const char *value) {
31351 -    data_string *ds_dst;
31352 +       data_string *ds_dst;
31353 +
31354 +       if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
31355 +               ds_dst = data_string_init();
31356 +       }
31357  
31358 -    if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
31359 -          ds_dst = data_string_init();
31360 -    }
31361 -
31362 -    buffer_copy_string(ds_dst->key, key);
31363 -    buffer_copy_string(ds_dst->value, value);
31364 -    array_insert_unique(con->request.headers, (data_unset *)ds_dst);
31365 +       buffer_copy_string(ds_dst->key, key);
31366 +       buffer_copy_string(ds_dst->value, value);
31367 +       array_insert_unique(con->request.headers, (data_unset *)ds_dst);
31368  }
31369  
31370  void proxy_append_header(connection *con, const char *key, const char *value) {
31371 -    data_string *ds_dst;
31372 +       data_string *ds_dst;
31373 +
31374 +       if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
31375 +               ds_dst = data_string_init();
31376 +       }
31377  
31378 -    if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
31379 -          ds_dst = data_string_init();
31380 -    }
31381 -
31382 -    buffer_copy_string(ds_dst->key, key);
31383 -    buffer_append_string(ds_dst->value, value);
31384 -    array_insert_unique(con->request.headers, (data_unset *)ds_dst);
31385 +       buffer_copy_string(ds_dst->key, key);
31386 +       buffer_append_string(ds_dst->value, value);
31387 +       array_insert_unique(con->request.headers, (data_unset *)ds_dst);
31388  }
31389  
31390  
31391  static int proxy_create_env(server *srv, handler_ctx *hctx) {
31392         size_t i;
31393 -       
31394 +
31395         connection *con   = hctx->remote_conn;
31396 +       plugin_data *p    = hctx->plugin_data;
31397         buffer *b;
31398 -       
31399 +
31400         /* build header */
31401  
31402         b = chunkqueue_get_append_buffer(hctx->wb);
31403 -       
31404 +
31405         /* request line */
31406         buffer_copy_string(b, get_http_method_name(con->request.http_method));
31407         BUFFER_APPEND_STRING_CONST(b, " ");
31408 -       
31409 +
31410         buffer_append_string_buffer(b, con->request.uri);
31411         BUFFER_APPEND_STRING_CONST(b, " HTTP/1.0\r\n");
31412  
31413         proxy_append_header(con, "X-Forwarded-For", (char *)inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
31414 -       /* http_host is NOT is just a pointer to a buffer 
31415 +       /* http_host is NOT is just a pointer to a buffer
31416          * which is NULL if it is not set */
31417 -       if (con->request.http_host && 
31418 +       if (con->request.http_host &&
31419             !buffer_is_empty(con->request.http_host)) {
31420                 proxy_set_header(con, "X-Host", con->request.http_host->ptr);
31421         }
31422 @@ -449,26 +490,27 @@
31423         /* request header */
31424         for (i = 0; i < con->request.headers->used; i++) {
31425                 data_string *ds;
31426 -               
31427 +
31428                 ds = (data_string *)con->request.headers->data[i];
31429 -               
31430 -               if (ds->value->used && ds->key->used) {
31431 -                       if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue;
31432 -                       
31433 -                       buffer_append_string_buffer(b, ds->key);
31434 -                       BUFFER_APPEND_STRING_CONST(b, ": ");
31435 -                       buffer_append_string_buffer(b, ds->value);
31436 -                       BUFFER_APPEND_STRING_CONST(b, "\r\n");
31437 -               }
31438 +
31439 +               if (buffer_is_empty(ds->value) || buffer_is_empty(ds->key)) continue;
31440 +
31441 +               if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue;
31442 +               if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Keep-Alive"))) continue;
31443 +
31444 +               buffer_append_string_buffer(b, ds->key);
31445 +               BUFFER_APPEND_STRING_CONST(b, ": ");
31446 +               buffer_append_string_buffer(b, ds->value);
31447 +               BUFFER_APPEND_STRING_CONST(b, "\r\n");
31448         }
31449 -       
31450 +
31451         BUFFER_APPEND_STRING_CONST(b, "\r\n");
31452 -       
31453 +
31454         hctx->wb->bytes_in += b->used - 1;
31455         /* body */
31456 -       
31457 +
31458         if (con->request.content_length) {
31459 -               chunkqueue *req_cq = con->request_content_queue;
31460 +               chunkqueue *req_cq = con->recv;
31461                 chunk *req_c;
31462                 off_t offset;
31463  
31464 @@ -479,7 +521,7 @@
31465  
31466                         /* we announce toWrite octects
31467                          * now take all the request_content chunk that we need to fill this request
31468 -                        * */   
31469 +                        * */
31470  
31471                         switch (req_c->type) {
31472                         case FILE_CHUNK:
31473 @@ -507,223 +549,145 @@
31474  
31475                                 req_c->offset += weHave;
31476                                 req_cq->bytes_out += weHave;
31477 -                               
31478 +
31479                                 hctx->wb->bytes_in += weHave;
31480  
31481                                 break;
31482                         default:
31483                                 break;
31484                         }
31485 -                       
31486 +
31487                         offset += weHave;
31488                 }
31489  
31490         }
31491 -       
31492 +
31493         return 0;
31494  }
31495  
31496  static int proxy_set_state(server *srv, handler_ctx *hctx, proxy_connection_state_t state) {
31497         hctx->state = state;
31498         hctx->state_timestamp = srv->cur_ts;
31499 -       
31500 -       return 0;
31501 -}
31502  
31503 -
31504 -static int proxy_response_parse(server *srv, connection *con, plugin_data *p, buffer *in) {
31505 -       char *s, *ns;
31506 -       int http_response_status = -1;
31507 -       
31508 -       UNUSED(srv);
31509 -
31510 -       /* \r\n -> \0\0 */
31511 -       
31512 -       buffer_copy_string_buffer(p->parse_response, in);
31513 -       
31514 -       for (s = p->parse_response->ptr; NULL != (ns = strstr(s, "\r\n")); s = ns + 2) {
31515 -               char *key, *value;
31516 -               int key_len;
31517 -               data_string *ds;
31518 -               int copy_header;
31519 -               
31520 -               ns[0] = '\0';
31521 -               ns[1] = '\0';
31522 -
31523 -               if (-1 == http_response_status) {
31524 -                       /* The first line of a Response message is the Status-Line */
31525 -
31526 -                       for (key=s; *key && *key != ' '; key++);
31527 -
31528 -                       if (*key) {
31529 -                               http_response_status = (int) strtol(key, NULL, 10);
31530 -                               if (http_response_status <= 0) http_response_status = 502;
31531 -                       } else {
31532 -                               http_response_status = 502;
31533 -                       }
31534 -
31535 -                       con->http_status = http_response_status;
31536 -                       con->parsed_response |= HTTP_STATUS;
31537 -                       continue;
31538 -               }
31539 -               
31540 -               if (NULL == (value = strchr(s, ':'))) {
31541 -                       /* now we expect: "<key>: <value>\n" */
31542 -
31543 -                       continue;
31544 -               }
31545 -
31546 -               key = s;
31547 -               key_len = value - key;
31548 -               
31549 -               value++;
31550 -               /* strip WS */
31551 -               while (*value == ' ' || *value == '\t') value++;
31552 -               
31553 -               copy_header = 1;
31554 -               
31555 -               switch(key_len) {
31556 -               case 4:
31557 -                       if (0 == strncasecmp(key, "Date", key_len)) {
31558 -                               con->parsed_response |= HTTP_DATE;
31559 -                       }
31560 -                       break;
31561 -               case 8:
31562 -                       if (0 == strncasecmp(key, "Location", key_len)) {
31563 -                               con->parsed_response |= HTTP_LOCATION;
31564 -                       }
31565 -                       break;
31566 -               case 10:
31567 -                       if (0 == strncasecmp(key, "Connection", key_len)) {
31568 -                               copy_header = 0;
31569 -                       }
31570 -                       break;
31571 -               case 14:
31572 -                       if (0 == strncasecmp(key, "Content-Length", key_len)) {
31573 -                               con->response.content_length = strtol(value, NULL, 10);
31574 -                               con->parsed_response |= HTTP_CONTENT_LENGTH;
31575 -                       }
31576 -                       break;
31577 -               default:
31578 -                       break;
31579 -               }
31580 -
31581 -               if (copy_header) {
31582 -                       if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
31583 -                               ds = data_response_init();
31584 -                       }
31585 -                       buffer_copy_string_len(ds->key, key, key_len);
31586 -                       buffer_copy_string(ds->value, value);
31587 -                       
31588 -                       array_insert_unique(con->response.headers, (data_unset *)ds);
31589 -               }
31590 -       }
31591 -       
31592         return 0;
31593  }
31594  
31595  
31596  static int proxy_demux_response(server *srv, handler_ctx *hctx) {
31597 -       int fin = 0;
31598 -       int b;
31599 -       ssize_t r;
31600 -       
31601         plugin_data *p    = hctx->plugin_data;
31602         connection *con   = hctx->remote_conn;
31603 -       int proxy_fd       = hctx->fd;
31604 -       
31605 -       /* check how much we have to read */
31606 -       if (ioctl(hctx->fd, FIONREAD, &b)) {
31607 -               log_error_write(srv, __FILE__, __LINE__, "sd", 
31608 -                               "ioctl failed: ",
31609 -                               proxy_fd);
31610 +       chunkqueue *next_queue = NULL;
31611 +       chunk *c = NULL;
31612 +
31613 +       switch(srv->network_backend_read(srv, con, hctx->sock, hctx->rb)) {
31614 +       case NETWORK_STATUS_SUCCESS:
31615 +               /* we got content */
31616 +               break;
31617 +       case NETWORK_STATUS_WAIT_FOR_EVENT:
31618 +               return 0;
31619 +       case NETWORK_STATUS_CONNECTION_CLOSE:
31620 +               /* we are done, get out of here */
31621 +               con->send->is_closed = 1;
31622 +
31623 +               /* close the chunk-queue with a empty chunk */
31624 +
31625 +               return 1;
31626 +       default:
31627 +               /* oops */
31628                 return -1;
31629         }
31630  
31631 +       /* looks like we got some content
31632 +       *
31633 +       * split off the header from the incoming stream
31634 +       */
31635  
31636 -       if (p->conf.debug) {
31637 -               log_error_write(srv, __FILE__, __LINE__, "sd",
31638 -                              "proxy - have to read:", b);
31639 -       }
31640 +       if (hctx->state == PROXY_STATE_RESPONSE_HEADER) {
31641 +               size_t i;
31642 +               int have_content_length = 0;
31643  
31644 -       if (b > 0) {
31645 -               if (hctx->response->used == 0) {
31646 -                       /* avoid too small buffer */
31647 -                       buffer_prepare_append(hctx->response, b + 1);
31648 -                       hctx->response->used = 1;
31649 -               } else {
31650 -                       buffer_prepare_append(hctx->response, hctx->response->used + b);
31651 -               }
31652 -               
31653 -               if (-1 == (r = read(hctx->fd, hctx->response->ptr + hctx->response->used - 1, b))) {
31654 -                       log_error_write(srv, __FILE__, __LINE__, "sds", 
31655 -                                       "unexpected end-of-file (perhaps the proxy process died):",
31656 -                                       proxy_fd, strerror(errno));
31657 -                       return -1;
31658 -               }
31659 -               
31660 -               /* this should be catched by the b > 0 above */
31661 -               assert(r);
31662 -               
31663 -               hctx->response->used += r;
31664 -               hctx->response->ptr[hctx->response->used - 1] = '\0';
31665 -
31666 -#if 0
31667 -               log_error_write(srv, __FILE__, __LINE__, "sdsbs", 
31668 -                               "demux: Response buffer len", hctx->response->used, ":", hctx->response, ":");
31669 -#endif
31670 +               http_response_reset(p->resp);
31671  
31672 -               if (0 == con->got_response) {
31673 -                       con->got_response = 1;
31674 -                       buffer_prepare_copy(hctx->response_header, 128);
31675 -               }
31676 -                               
31677 -               if (0 == con->file_started) {
31678 -                       char *c;
31679 -                               
31680 -                       /* search for the \r\n\r\n in the string */
31681 -                       if (NULL != (c = buffer_search_string_len(hctx->response, "\r\n\r\n", 4))) {
31682 -                               size_t hlen = c - hctx->response->ptr + 4;
31683 -                               size_t blen = hctx->response->used - hlen - 1;
31684 -                               /* found */
31685 -                               
31686 -                               buffer_append_string_len(hctx->response_header, hctx->response->ptr, c - hctx->response->ptr + 4);
31687 -#if 0
31688 -                               log_error_write(srv, __FILE__, __LINE__, "sb", "Header:", hctx->response_header);
31689 -#endif
31690 -                               /* parse the response header */
31691 -                               proxy_response_parse(srv, con, p, hctx->response_header);
31692 -                                       
31693 -                               /* enable chunked-transfer-encoding */
31694 -                               if (con->request.http_version == HTTP_VERSION_1_1 &&
31695 -                                   !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
31696 -                                       con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
31697 +               /* the response header is not fully received yet,
31698 +               *
31699 +               * extract the http-response header from the rb-cq
31700 +               */
31701 +               switch (http_response_parse_cq(hctx->rb, p->resp)) {
31702 +               case PARSE_ERROR:
31703 +                       /* parsing failed */
31704 +
31705 +                       con->http_status = 502; /* Bad Gateway */
31706 +                       return 1;
31707 +               case PARSE_NEED_MORE:
31708 +                       return 0;
31709 +               case PARSE_SUCCESS:
31710 +                       con->http_status = p->resp->status;
31711 +
31712 +                       chunkqueue_remove_finished_chunks(hctx->rb);
31713 +
31714 +                       /* copy the http-headers */
31715 +                       for (i = 0; i < p->resp->headers->used; i++) {
31716 +                               const char *ign[] = { "Status", "Connection", NULL };
31717 +                               size_t j;
31718 +                               data_string *ds;
31719 +
31720 +                               data_string *header = (data_string *)p->resp->headers->data[i];
31721 +
31722 +                               /* some headers are ignored by default */
31723 +                               for (j = 0; ign[j]; j++) {
31724 +                                       if (0 == strcasecmp(ign[j], header->key->ptr)) break;
31725 +                               }
31726 +                               if (ign[j]) continue;
31727 +
31728 +                               if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
31729 +                                       /* CGI/1.1 rev 03 - 7.2.1.2 */
31730 +                                       if (con->http_status == 0) con->http_status = 302;
31731 +                               } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
31732 +                                       have_content_length = 1;
31733                                 }
31734 -                                       
31735 -                               con->file_started = 1;
31736 -                               if (blen) {
31737 -                                       http_chunk_append_mem(srv, con, c + 4, blen + 1);
31738 -                                       joblist_append(srv, con);
31739 +                               
31740 +                               if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
31741 +                                       ds = data_response_init();
31742                                 }
31743 -                               hctx->response->used = 0;
31744 +                               buffer_copy_string_buffer(ds->key, header->key);
31745 +                               buffer_copy_string_buffer(ds->value, header->value);
31746 +
31747 +                               array_insert_unique(con->response.headers, (data_unset *)ds);
31748                         }
31749 -               } else {
31750 -                       http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used);
31751 -                       joblist_append(srv, con);
31752 -                       hctx->response->used = 0;
31753 +
31754 +                       con->file_started = 1;
31755 +
31756 +                       hctx->state = PROXY_STATE_RESPONSE_CONTENT;
31757 +                       break;
31758                 }
31759 -               
31760 -       } else {
31761 -               /* reading from upstream done */
31762 -               con->file_finished = 1;
31763 -               
31764 -               http_chunk_append_mem(srv, con, NULL, 0);
31765 -               joblist_append(srv, con);
31766 -               
31767 -               fin = 1;
31768         }
31769 -       
31770 -       return fin;
31771 +
31772 +       /* FIXME: pass the response-header to the other plugins to
31773 +       * setup the filter-queue
31774 +       *
31775 +       * - use next-queue instead of con->write_queue
31776 +       */
31777 +
31778 +       next_queue = con->send;
31779 +
31780 +       assert(hctx->state == PROXY_STATE_RESPONSE_CONTENT);
31781 +
31782 +       /* FIXME: if we have a content-length or chunked-encoding
31783 +       * handle it.
31784 +       *
31785 +       * for now we wait for EOF on the socket */
31786 +
31787 +       /* copy the content to the next cq */
31788 +       for (c = hctx->rb->first; c; c = c->next) {
31789 +               chunkqueue_append_mem(con->send, c->mem->ptr + c->offset, c->mem->used - c->offset);
31790 +
31791 +               c->offset = c->mem->used - 1;
31792 +       }
31793 +
31794 +       chunkqueue_remove_finished_chunks(hctx->rb);
31795 +       joblist_append(srv, con);
31796 +
31797 +       return 0;
31798  }
31799  
31800  
31801 @@ -731,32 +695,32 @@
31802         data_proxy *host= hctx->host;
31803         plugin_data *p    = hctx->plugin_data;
31804         connection *con   = hctx->remote_conn;
31805 -       
31806 +
31807         int ret;
31808 -       
31809 -       if (!host || 
31810 -           (!host->host->used || !host->port)) return -1;
31811 -       
31812 +
31813 +       if (!host ||
31814 +               (!host->host->used || !host->port)) return -1;
31815 +
31816         switch(hctx->state) {
31817         case PROXY_STATE_INIT:
31818 -               if (-1 == (hctx->fd = socket(AF_INET, SOCK_STREAM, 0))) {
31819 +               if (-1 == (hctx->sock->fd = socket(AF_INET, SOCK_STREAM, 0))) {
31820                         log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed: ", strerror(errno));
31821                         return HANDLER_ERROR;
31822                 }
31823 -               hctx->fde_ndx = -1;
31824 -               
31825 +               hctx->sock->fde_ndx = -1;
31826 +
31827                 srv->cur_fds++;
31828 -               
31829 -               fdevent_register(srv->ev, hctx->fd, proxy_handle_fdevent, hctx);
31830 -               
31831 -               if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
31832 +
31833 +               fdevent_register(srv->ev, hctx->sock, proxy_handle_fdevent, hctx);
31834 +
31835 +               if (-1 == fdevent_fcntl_set(srv->ev, hctx->sock)) {
31836                         log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
31837 -                       
31838 +
31839                         return HANDLER_ERROR;
31840                 }
31841 -               
31842 +
31843                 /* fall through */
31844 -               
31845 +
31846         case PROXY_STATE_CONNECT:
31847                 /* try to finish the connect() */
31848                 if (hctx->state == PROXY_STATE_INIT) {
31849 @@ -764,16 +728,16 @@
31850                         switch (proxy_establish_connection(srv, hctx)) {
31851                         case 1:
31852                                 proxy_set_state(srv, hctx, PROXY_STATE_CONNECT);
31853 -                               
31854 +
31855                                 /* connection is in progress, wait for an event and call getsockopt() below */
31856 -                               
31857 -                               fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
31858 -                               
31859 +
31860 +                               fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
31861 +
31862                                 return HANDLER_WAIT_FOR_EVENT;
31863                         case -1:
31864                                 /* if ECONNREFUSED choose another connection -> FIXME */
31865 -                               hctx->fde_ndx = -1;
31866 -                               
31867 +                               hctx->sock->fde_ndx = -1;
31868 +
31869                                 return HANDLER_ERROR;
31870                         default:
31871                                 /* everything is ok, go on */
31872 @@ -782,152 +746,152 @@
31873                 } else {
31874                         int socket_error;
31875                         socklen_t socket_error_len = sizeof(socket_error);
31876 -               
31877 -                       /* we don't need it anymore */  
31878 -                       fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
31879 +
31880 +                       /* we don't need it anymore */
31881 +                       fdevent_event_del(srv->ev, hctx->sock);
31882  
31883                         /* try to finish the connect() */
31884 -                       if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
31885 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
31886 +                       if (0 != getsockopt(hctx->sock->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
31887 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
31888                                                 "getsockopt failed:", strerror(errno));
31889 -                               
31890 +
31891                                 return HANDLER_ERROR;
31892                         }
31893                         if (socket_error != 0) {
31894                                 log_error_write(srv, __FILE__, __LINE__, "ss",
31895 -                                               "establishing connection failed:", strerror(socket_error), 
31896 +                                               "establishing connection failed:", strerror(socket_error),
31897                                                 "port:", hctx->host->port);
31898 -                               
31899 +
31900                                 return HANDLER_ERROR;
31901                         }
31902                         if (p->conf.debug) {
31903 -                               log_error_write(srv, __FILE__, __LINE__,  "s", "proxy - connect - delayed success"); 
31904 +                               log_error_write(srv, __FILE__, __LINE__,  "s", "proxy - connect - delayed success");
31905                         }
31906                 }
31907 -               
31908 +
31909                 proxy_set_state(srv, hctx, PROXY_STATE_PREPARE_WRITE);
31910                 /* fall through */
31911         case PROXY_STATE_PREPARE_WRITE:
31912                 proxy_create_env(srv, hctx);
31913 -               
31914 +
31915                 proxy_set_state(srv, hctx, PROXY_STATE_WRITE);
31916 -               
31917 +
31918                 /* fall through */
31919         case PROXY_STATE_WRITE:;
31920 -               ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb); 
31921 +               ret = srv->network_backend_write(srv, con, hctx->sock, hctx->wb);
31922  
31923                 chunkqueue_remove_finished_chunks(hctx->wb);
31924  
31925 -               if (-1 == ret) {
31926 -                       if (errno != EAGAIN &&
31927 -                           errno != EINTR) {
31928 -                               log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed:", strerror(errno), errno);
31929 -                               
31930 -                               return HANDLER_ERROR;
31931 -                       } else {
31932 -                               fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
31933 +               switch(ret) {
31934 +               case NETWORK_STATUS_FATAL_ERROR:
31935 +                       log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed:", strerror(errno), errno);
31936  
31937 -                               return HANDLER_WAIT_FOR_EVENT;
31938 -                       }
31939 +                       return HANDLER_ERROR;
31940 +               case NETWORK_STATUS_WAIT_FOR_EVENT:
31941 +
31942 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
31943 +
31944 +                       return HANDLER_WAIT_FOR_EVENT;
31945                 }
31946  
31947                 if (hctx->wb->bytes_out == hctx->wb->bytes_in) {
31948 -                       proxy_set_state(srv, hctx, PROXY_STATE_READ);
31949 +                       proxy_set_state(srv, hctx, PROXY_STATE_RESPONSE_HEADER);
31950  
31951 -                       fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
31952 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
31953 +                       fdevent_event_del(srv->ev, hctx->sock);
31954 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
31955                 } else {
31956 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
31957 -                               
31958 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
31959 +
31960                         return HANDLER_WAIT_FOR_EVENT;
31961                 }
31962 -               
31963 +
31964                 return HANDLER_WAIT_FOR_EVENT;
31965 -       case PROXY_STATE_READ:
31966 +       case PROXY_STATE_RESPONSE_CONTENT:
31967 +       case PROXY_STATE_RESPONSE_HEADER:
31968                 /* waiting for a response */
31969 +
31970                 return HANDLER_WAIT_FOR_EVENT;
31971         default:
31972                 log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
31973                 return HANDLER_ERROR;
31974         }
31975 -       
31976 +
31977         return HANDLER_GO_ON;
31978  }
31979  
31980 -#define PATCH(x) \
31981 -       p->conf.x = s->x;
31982  static int mod_proxy_patch_connection(server *srv, connection *con, plugin_data *p) {
31983         size_t i, j;
31984         plugin_config *s = p->config_storage[0];
31985 -       
31986 -       PATCH(extensions);
31987 -       PATCH(debug);
31988 -       PATCH(balance);
31989 -       
31990 +
31991 +       PATCH_OPTION(extensions);
31992 +       PATCH_OPTION(debug);
31993 +       PATCH_OPTION(balance);
31994 +       PATCH_OPTION(last_used_backends);
31995 +
31996         /* skip the first, the global context */
31997         for (i = 1; i < srv->config_context->used; i++) {
31998                 data_config *dc = (data_config *)srv->config_context->data[i];
31999                 s = p->config_storage[i];
32000 -               
32001 +
32002                 /* condition didn't match */
32003                 if (!config_check_cond(srv, con, dc)) continue;
32004 -               
32005 +
32006                 /* merge config */
32007                 for (j = 0; j < dc->value->used; j++) {
32008                         data_unset *du = dc->value->data[j];
32009 -                       
32010 +
32011                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.server"))) {
32012 -                               PATCH(extensions);
32013 +                               PATCH_OPTION(extensions);
32014                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.debug"))) {
32015 -                               PATCH(debug);
32016 +                               PATCH_OPTION(debug);
32017                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.balance"))) {
32018 -                               PATCH(balance);
32019 +                               PATCH_OPTION(balance);
32020 +                               PATCH_OPTION(last_used_backends);
32021                         }
32022                 }
32023         }
32024 -       
32025 +
32026         return 0;
32027  }
32028 -#undef PATCH
32029  
32030  SUBREQUEST_FUNC(mod_proxy_handle_subrequest) {
32031         plugin_data *p = p_d;
32032 -       
32033 +
32034         handler_ctx *hctx = con->plugin_ctx[p->id];
32035         data_proxy *host;
32036 -       
32037 +
32038         if (NULL == hctx) return HANDLER_GO_ON;
32039  
32040         mod_proxy_patch_connection(srv, con, p);
32041 -       
32042 +
32043         host = hctx->host;
32044 -       
32045 +
32046         /* not my job */
32047         if (con->mode != p->id) return HANDLER_GO_ON;
32048 -       
32049 +
32050         /* ok, create the request */
32051         switch(proxy_write_request(srv, hctx)) {
32052         case HANDLER_ERROR:
32053 -               log_error_write(srv, __FILE__, __LINE__,  "sbdd", "proxy-server disabled:", 
32054 +               log_error_write(srv, __FILE__, __LINE__,  "sbdd", "proxy-server disabled:",
32055                                 host->host,
32056                                 host->port,
32057 -                               hctx->fd);
32058 -               
32059 +                               hctx->sock->fd);
32060 +
32061                 /* disable this server */
32062                 host->is_disabled = 1;
32063                 host->disable_ts = srv->cur_ts;
32064 -               
32065 +
32066                 proxy_connection_close(srv, hctx);
32067 -       
32068 -               /* reset the enviroment and restart the sub-request */  
32069 +
32070 +               /* reset the enviroment and restart the sub-request */
32071                 buffer_reset(con->physical.path);
32072                 con->mode = DIRECT;
32073  
32074                 joblist_append(srv, con);
32075  
32076 -               /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop 
32077 -                * and hope that the childs will be restarted 
32078 -                * 
32079 +               /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop
32080 +                * and hope that the childs will be restarted
32081 +                *
32082                  */
32083  
32084                 return HANDLER_WAIT_FOR_FD;
32085 @@ -938,7 +902,7 @@
32086         default:
32087                 break;
32088         }
32089 -       
32090 +
32091         if (con->file_started == 1) {
32092                 return HANDLER_FINISHED;
32093         } else {
32094 @@ -951,13 +915,14 @@
32095         handler_ctx *hctx = ctx;
32096         connection  *con  = hctx->remote_conn;
32097         plugin_data *p    = hctx->plugin_data;
32098 -       
32099 -       
32100 +
32101 +
32102         if ((revents & FDEVENT_IN) &&
32103 -           hctx->state == PROXY_STATE_READ) {
32104 +           (hctx->state == PROXY_STATE_RESPONSE_HEADER ||
32105 +            hctx->state == PROXY_STATE_RESPONSE_CONTENT)) {
32106  
32107                 if (p->conf.debug) {
32108 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
32109 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
32110                                         "proxy: fdevent-in", hctx->state);
32111                 }
32112  
32113 @@ -965,86 +930,87 @@
32114                 case 0:
32115                         break;
32116                 case 1:
32117 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
32118 +                                       "proxy: request done", hctx->sock->fd);
32119                         hctx->host->usage--;
32120 -                       
32121 +
32122                         /* we are done */
32123                         proxy_connection_close(srv, hctx);
32124 -                       
32125 +
32126                         joblist_append(srv, con);
32127                         return HANDLER_FINISHED;
32128                 case -1:
32129                         if (con->file_started == 0) {
32130                                 /* nothing has been send out yet, send a 500 */
32131 -                               connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
32132                                 con->http_status = 500;
32133                                 con->mode = DIRECT;
32134                         } else {
32135                                 /* response might have been already started, kill the connection */
32136                                 connection_set_state(srv, con, CON_STATE_ERROR);
32137                         }
32138 -                       
32139 +
32140                         joblist_append(srv, con);
32141                         return HANDLER_FINISHED;
32142                 }
32143         }
32144 -       
32145 +
32146         if (revents & FDEVENT_OUT) {
32147                 if (p->conf.debug) {
32148 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
32149 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
32150                                         "proxy: fdevent-out", hctx->state);
32151                 }
32152  
32153                 if (hctx->state == PROXY_STATE_CONNECT ||
32154                     hctx->state == PROXY_STATE_WRITE) {
32155                         /* we are allowed to send something out
32156 -                        * 
32157 +                        *
32158                          * 1. in a unfinished connect() call
32159                          * 2. in a unfinished write() call (long POST request)
32160                          */
32161                         return mod_proxy_handle_subrequest(srv, con, p);
32162                 } else {
32163 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
32164 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
32165                                         "proxy: out", hctx->state);
32166                 }
32167         }
32168 -       
32169 +
32170         /* perhaps this issue is already handled */
32171         if (revents & FDEVENT_HUP) {
32172                 if (p->conf.debug) {
32173 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
32174 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
32175                                         "proxy: fdevent-hup", hctx->state);
32176                 }
32177 -               
32178 +
32179                 if (hctx->state == PROXY_STATE_CONNECT) {
32180                         /* connect() -> EINPROGRESS -> HUP */
32181 -                       
32182 +
32183                         /**
32184 -                        * what is proxy is doing if it can't reach the next hop ? 
32185 -                        * 
32186 +                        * what is proxy is doing if it can't reach the next hop ?
32187 +                        *
32188                          */
32189 -                       
32190 +
32191                         proxy_connection_close(srv, hctx);
32192                         joblist_append(srv, con);
32193 -                       
32194 +
32195                         con->http_status = 503;
32196                         con->mode = DIRECT;
32197 -                       
32198 +
32199                         return HANDLER_FINISHED;
32200                 }
32201  
32202 -               con->file_finished = 1;
32203 +               con->send->is_closed = 1;
32204  
32205                 proxy_connection_close(srv, hctx);
32206                 joblist_append(srv, con);
32207         } else if (revents & FDEVENT_ERR) {
32208                 /* kill all connections to the proxy process */
32209 -               
32210 +
32211                 log_error_write(srv, __FILE__, __LINE__, "sd", "proxy-FDEVENT_ERR, but no HUP", revents);
32212  
32213                 joblist_append(srv, con);
32214                 proxy_connection_close(srv, hctx);
32215         }
32216 -       
32217 +
32218         return HANDLER_FINISHED;
32219  }
32220  
32221 @@ -1058,44 +1024,48 @@
32222         buffer *fn;
32223         data_array *extension = NULL;
32224         size_t path_info_offset;
32225 -       
32226 +       data_integer *last_used_backend;
32227 +       data_proxy *host = NULL;
32228 +       handler_ctx *hctx = NULL;
32229 +
32230 +       array *backends = NULL;
32231 +
32232         /* Possibly, we processed already this request */
32233         if (con->file_started == 1) return HANDLER_GO_ON;
32234 -       
32235 +
32236         mod_proxy_patch_connection(srv, con, p);
32237 -       
32238 +
32239         fn = con->uri.path;
32240  
32241         if (fn->used == 0) {
32242                 return HANDLER_ERROR;
32243         }
32244 -       
32245 +
32246         s_len = fn->used - 1;
32247 -       
32248 -       
32249 +
32250         path_info_offset = 0;
32251  
32252 -       if (p->conf.debug) {    
32253 +       if (p->conf.debug) {
32254                 log_error_write(srv, __FILE__, __LINE__,  "s", "proxy - start");
32255         }
32256  
32257         /* check if extension matches */
32258         for (k = 0; k < p->conf.extensions->used; k++) {
32259                 size_t ct_len;
32260 -               
32261 +
32262                 extension = (data_array *)p->conf.extensions->data[k];
32263 -               
32264 +
32265                 if (extension->key->used == 0) continue;
32266 -               
32267 +
32268                 ct_len = extension->key->used - 1;
32269 -               
32270 +
32271                 if (s_len < ct_len) continue;
32272 -               
32273 +
32274                 /* check extension in the form "/proxy_pattern" */
32275                 if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) {
32276                         if (s_len > ct_len + 1) {
32277                                 char *pi_offset;
32278 -                               
32279 +
32280                                 if (0 != (pi_offset = strchr(fn->ptr + ct_len + 1, '/'))) {
32281                                         path_info_offset = pi_offset - fn->ptr;
32282                                 }
32283 @@ -1106,12 +1076,14 @@
32284                         break;
32285                 }
32286         }
32287 -       
32288 +
32289         if (k == p->conf.extensions->used) {
32290                 return HANDLER_GO_ON;
32291         }
32292  
32293 -       if (p->conf.debug) {    
32294 +       backends = extension->value;
32295 +
32296 +       if (p->conf.debug) {
32297                 log_error_write(srv, __FILE__, __LINE__,  "s", "proxy - ext found");
32298         }
32299  
32300 @@ -1120,34 +1092,34 @@
32301                 /* hash balancing */
32302  
32303                 if (p->conf.debug) {
32304 -                       log_error_write(srv, __FILE__, __LINE__,  "sd", 
32305 -                                       "proxy - used hash balancing, hosts:", extension->value->used);
32306 +                       log_error_write(srv, __FILE__, __LINE__,  "sd",
32307 +                                       "proxy - used hash balancing, hosts:", backends->used);
32308                 }
32309  
32310 -               for (k = 0, ndx = -1, last_max = ULONG_MAX; k < extension->value->used; k++) {
32311 -                       data_proxy *host = (data_proxy *)extension->value->data[k];
32312 +               for (k = 0, ndx = -1, last_max = ULONG_MAX; k < backends->used; k++) {
32313                         unsigned long cur_max;
32314  
32315 -                       if (host->is_disabled) continue;
32316 -                       
32317 +                       data_proxy *cur = (data_proxy *)backends->data[k];
32318 +
32319 +                       if (cur->is_disabled) continue;
32320 +
32321                         cur_max = generate_crc32c(CONST_BUF_LEN(con->uri.path)) +
32322 -                               generate_crc32c(CONST_BUF_LEN(host->host)) + /* we can cache this */
32323 +                               generate_crc32c(CONST_BUF_LEN(cur->host)) + /* we can cache this */
32324                                 generate_crc32c(CONST_BUF_LEN(con->uri.authority));
32325 -                       
32326 +
32327                         if (p->conf.debug) {
32328 -                               log_error_write(srv, __FILE__, __LINE__,  "sbbbd", 
32329 +                               log_error_write(srv, __FILE__, __LINE__,  "sbbbd",
32330                                                 "proxy - election:",
32331                                                 con->uri.path,
32332 -                                               host->host,
32333 +                                               cur->host,
32334                                                 con->uri.authority,
32335                                                 cur_max);
32336                         }
32337  
32338 -                       if ((last_max == ULONG_MAX) || /* first round */
32339 -                           (cur_max > last_max)) {
32340 +                       if (host == NULL || (cur_max > last_max)) {
32341                                 last_max = cur_max;
32342  
32343 -                               ndx = k;
32344 +                               host = cur;
32345                         }
32346                 }
32347  
32348 @@ -1155,19 +1127,20 @@
32349         case PROXY_BALANCE_FAIR:
32350                 /* fair balancing */
32351                 if (p->conf.debug) {
32352 -                       log_error_write(srv, __FILE__, __LINE__,  "s", 
32353 +                       log_error_write(srv, __FILE__, __LINE__,  "s",
32354                                         "proxy - used fair balancing");
32355                 }
32356  
32357 -               for (k = 0, ndx = -1, max_usage = INT_MAX; k < extension->value->used; k++) {
32358 -                       data_proxy *host = (data_proxy *)extension->value->data[k];
32359 -               
32360 -                       if (host->is_disabled) continue;
32361 -
32362 -                       if (host->usage < max_usage) {
32363 -                               max_usage = host->usage;
32364 -                       
32365 -                               ndx = k;
32366 +               /* try to find the host with the lowest load */
32367 +               for (k = 0, max_usage = 0; k < backends->used; k++) {
32368 +                       data_proxy *cur = (data_proxy *)backends->data[k];
32369 +
32370 +                       if (cur->is_disabled) continue;
32371 +
32372 +                       if (NULL == host || cur->usage < max_usage) {
32373 +                               max_usage = cur->usage;
32374 +
32375 +                               host = cur;
32376                         }
32377                 }
32378  
32379 @@ -1175,89 +1148,100 @@
32380         case PROXY_BALANCE_RR:
32381                 /* round robin */
32382                 if (p->conf.debug) {
32383 -                       log_error_write(srv, __FILE__, __LINE__,  "s", 
32384 +                       log_error_write(srv, __FILE__, __LINE__,  "s",
32385                                         "proxy - used round-robin balancing");
32386                 }
32387  
32388                 /* just to be sure */
32389 -               assert(extension->value->used < INT_MAX);
32390 -               
32391 -               for (k = 0, ndx = -1, max_usage = INT_MAX; k < extension->value->used; k++) {
32392 -                       data_proxy *host = (data_proxy *)extension->value->data[k];
32393 -               
32394 -                       if (host->is_disabled) continue;
32395 -
32396 -                       /* first usable ndx */
32397 -                       if (max_usage == INT_MAX) {
32398 -                               max_usage = k;
32399 -                       }
32400 +               assert(backends->used < INT_MAX);
32401  
32402 -                       /* get next ndx */
32403 -                       if ((int)k > host->last_used_ndx) {
32404 -                               ndx = k;
32405 -                               host->last_used_ndx = k;
32406 +               /* send each request to another host:
32407 +                *
32408 +                * e.g.:
32409 +                *
32410 +                * if we have three hosts it is
32411 +                *
32412 +                * 1 .. 2 .. 3 .. 1 .. 2 .. 3
32413 +                *
32414 +                **/
32415  
32416 -                               break;
32417 -                       }
32418 +               /* walk through the list */
32419 +               last_used_backend = (data_integer *)array_get_element(p->conf.last_used_backends, extension->key->ptr);
32420 +
32421 +               if (NULL == last_used_backend) {
32422 +                       last_used_backend = data_integer_init();
32423 +
32424 +                       buffer_copy_string_buffer(last_used_backend->key, extension->key);
32425 +                       last_used_backend->value = 0;
32426 +
32427 +                       array_insert_unique(p->conf.last_used_backends, (data_unset *)last_used_backend);
32428 +               }
32429 +
32430 +               /* scan all but the last host to see if they are up
32431 +                * take the first running host */
32432 +               for (k = last_used_backend->value + 1; (int)(k % backends->used) != last_used_backend->value; k++) {
32433 +                       data_proxy *cur = (data_proxy *)backends->data[k % backends->used];
32434 +
32435 +                       if (cur->is_disabled) continue;
32436 +
32437 +                       host = cur;
32438 +
32439 +                       last_used_backend->value = k;
32440 +
32441 +                       break;
32442                 }
32443 -               
32444 -               /* didn't found a higher id, wrap to the start */
32445 -               if (ndx != -1 && max_usage != INT_MAX) {
32446 -                       ndx = max_usage;
32447 +
32448 +               if (NULL == host) {
32449 +                       /* we found nothing better, fallback to the last used backend
32450 +                        * and check if it is still up */
32451 +                       host = (data_proxy *)backends->data[last_used_backend->value];
32452 +
32453 +                       if (host->is_disabled) host = NULL;
32454                 }
32455  
32456                 break;
32457         default:
32458                 break;
32459         }
32460 -       
32461 -       /* found a server */
32462 -       if (ndx != -1) {
32463 -               data_proxy *host = (data_proxy *)extension->value->data[ndx];
32464 -               
32465 -               /* 
32466 -                * if check-local is disabled, use the uri.path handler 
32467 -                * 
32468 -                */
32469 -               
32470 -               /* init handler-context */
32471 -               handler_ctx *hctx;
32472 -               hctx = handler_ctx_init();
32473 -                               
32474 -               hctx->path_info_offset = path_info_offset;
32475 -               hctx->remote_conn      = con;
32476 -               hctx->plugin_data      = p;
32477 -               hctx->host             = host;
32478 -                               
32479 -               con->plugin_ctx[p->id] = hctx;
32480 -               
32481 -               host->usage++;
32482 -               
32483 -               con->mode = p->id;
32484 -               
32485 -               if (p->conf.debug) {
32486 -                       log_error_write(srv, __FILE__, __LINE__,  "sbd", 
32487 -                                       "proxy - found a host",
32488 -                                       host->host, host->port);
32489 -               }
32490  
32491 -               return HANDLER_GO_ON;
32492 -       } else {
32493 -               /* no handler found */
32494 +       /* we havn't found a host */
32495 +       if (NULL == host) {
32496                 con->http_status = 500;
32497 -               
32498 -               log_error_write(srv, __FILE__, __LINE__,  "sb", 
32499 -                               "no proxy-handler found for:", 
32500 +
32501 +               log_error_write(srv, __FILE__, __LINE__,  "sb",
32502 +                               "no proxy-handler found for:",
32503                                 fn);
32504 -               
32505 +
32506                 return HANDLER_FINISHED;
32507         }
32508 +
32509 +       /* init handler-context */
32510 +       hctx = handler_ctx_init();
32511 +
32512 +       hctx->path_info_offset = path_info_offset;
32513 +       hctx->remote_conn      = con;
32514 +       hctx->plugin_data      = p;
32515 +       hctx->host             = host;
32516 +
32517 +       con->plugin_ctx[p->id] = hctx;
32518 +
32519 +       host->usage++;
32520 +
32521 +       /* we handle this request */
32522 +       con->mode = p->id;
32523 +
32524 +       if (p->conf.debug) {
32525 +               log_error_write(srv, __FILE__, __LINE__,  "sbd",
32526 +                               "proxy - found a host",
32527 +                               host->host, host->port);
32528 +       }
32529 +
32530         return HANDLER_GO_ON;
32531  }
32532  
32533  static handler_t mod_proxy_connection_close_callback(server *srv, connection *con, void *p_d) {
32534         plugin_data *p = p_d;
32535 -       
32536 +
32537         proxy_connection_close(srv, con->plugin_ctx[p->id]);
32538  
32539         return HANDLER_GO_ON;
32540 @@ -1276,11 +1260,11 @@
32541                 size_t i, n, k;
32542                 for (i = 0; i < srv->config_context->used; i++) {
32543                         plugin_config *s = p->config_storage[i];
32544 -                       
32545 -                       if (!s) continue; 
32546 +
32547 +                       if (!s) continue;
32548  
32549                         /* get the extensions for all configs */
32550 -                       
32551 +
32552                         for (k = 0; k < s->extensions->used; k++) {
32553                                 data_array *extension = (data_array *)s->extensions->data[k];
32554  
32555 @@ -1290,8 +1274,8 @@
32556  
32557                                         if (!host->is_disabled ||
32558                                             srv->cur_ts - host->disable_ts < 5) continue;
32559 -                       
32560 -                                       log_error_write(srv, __FILE__, __LINE__,  "sbd", 
32561 +
32562 +                                       log_error_write(srv, __FILE__, __LINE__,  "sbd",
32563                                                         "proxy - re-enabled:",
32564                                                         host->host, host->port);
32565  
32566 @@ -1315,10 +1299,10 @@
32567         p->connection_reset        = mod_proxy_connection_close_callback; /* end of req-resp cycle */
32568         p->handle_connection_close = mod_proxy_connection_close_callback; /* end of client connection */
32569         p->handle_uri_clean        = mod_proxy_check_extension;
32570 -       p->handle_subrequest       = mod_proxy_handle_subrequest;
32571 +       p->handle_start_backend    = mod_proxy_handle_subrequest;
32572         p->handle_trigger          = mod_proxy_trigger;
32573 -       
32574 +
32575         p->data         = NULL;
32576 -       
32577 +
32578         return 0;
32579  }
32580 --- ../lighttpd-1.4.11/src/mod_proxy_backend_fastcgi.c  1970-01-01 03:00:00.000000000 +0300
32581 +++ lighttpd-1.5.0/src/mod_proxy_backend_fastcgi.c      2006-09-07 00:57:05.000000000 +0300
32582 @@ -0,0 +1,656 @@
32583 +#include <stdlib.h>
32584 +#include <string.h>
32585 +#include <assert.h>
32586 +
32587 +#include "inet_ntop_cache.h"
32588 +#include "mod_proxy_core.h"
32589 +#include "buffer.h"
32590 +#include "log.h"
32591 +#include "fastcgi.h"
32592 +
32593 +int proxy_fastcgi_get_env_fastcgi(server *srv, connection *con, plugin_data *p, proxy_session *sess) {
32594 +       buffer *b;
32595 +
32596 +       char buf[32];
32597 +       const char *s;
32598 +       server_socket *srv_sock = con->srv_socket;
32599 +#ifdef HAVE_IPV6
32600 +       char b2[INET6_ADDRSTRLEN + 1];
32601 +#endif
32602 +
32603 +       sock_addr our_addr;
32604 +       socklen_t our_addr_len;
32605 +
32606 +       proxy_set_header(sess->env_headers, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION));
32607 +
32608 +       if (con->server_name->used) {
32609 +               proxy_set_header(sess->env_headers, CONST_STR_LEN("SERVER_NAME"), CONST_BUF_LEN(con->server_name));
32610 +       } else {
32611 +#ifdef HAVE_IPV6
32612 +               s = inet_ntop(srv_sock->addr.plain.sa_family,
32613 +                             srv_sock->addr.plain.sa_family == AF_INET6 ?
32614 +                             (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
32615 +                             (const void *) &(srv_sock->addr.ipv4.sin_addr),
32616 +                             b2, sizeof(b2)-1);
32617 +#else
32618 +               s = inet_ntoa(srv_sock->addr.ipv4.sin_addr);
32619 +#endif
32620 +               proxy_set_header(sess->env_headers, CONST_STR_LEN("SERVER_NAME"), s, strlen(s));
32621 +       }
32622 +
32623 +       proxy_set_header(sess->env_headers, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
32624 +
32625 +       ltostr(buf,
32626 +#ifdef HAVE_IPV6
32627 +              ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
32628 +#else
32629 +              ntohs(srv_sock->addr.ipv4.sin_port)
32630 +#endif
32631 +              );
32632 +
32633 +       proxy_set_header(sess->env_headers, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
32634 +
32635 +       /* get the server-side of the connection to the client */
32636 +       our_addr_len = sizeof(our_addr);
32637 +
32638 +       if (-1 == getsockname(con->sock->fd, &(our_addr.plain), &our_addr_len)) {
32639 +               s = inet_ntop_cache_get_ip(srv, &(srv_sock->addr));
32640 +       } else {
32641 +               s = inet_ntop_cache_get_ip(srv, &(our_addr));
32642 +       }
32643 +       proxy_set_header(sess->env_headers, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
32644 +
32645 +       ltostr(buf,
32646 +#ifdef HAVE_IPV6
32647 +              ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
32648 +#else
32649 +              ntohs(con->dst_addr.ipv4.sin_port)
32650 +#endif
32651 +              );
32652 +
32653 +       proxy_set_header(sess->env_headers, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
32654 +
32655 +       s = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
32656 +       proxy_set_header(sess->env_headers, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
32657 +
32658 +       if (!buffer_is_empty(con->authed_user)) {
32659 +               proxy_set_header(sess->env_headers, CONST_STR_LEN("REMOTE_USER"),
32660 +                            CONST_BUF_LEN(con->authed_user));
32661 +       }
32662 +
32663 +       if (con->request.content_length > 0) {
32664 +               /* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */
32665 +
32666 +               /* request.content_length < SSIZE_MAX, see request.c */
32667 +               ltostr(buf, con->request.content_length);
32668 +               proxy_set_header(sess->env_headers, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
32669 +       }
32670 +
32671 +       
32672 +       /*
32673 +        * SCRIPT_NAME, PATH_INFO and PATH_TRANSLATED according to
32674 +        * http://cgi-spec.golux.com/draft-coar-cgi-v11-03-clean.html
32675 +        * (6.1.14, 6.1.6, 6.1.7)
32676 +        * For AUTHORIZER mode these headers should be omitted.
32677 +        */
32678 +
32679 +       proxy_set_header(sess->env_headers, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
32680 +
32681 +       if (!buffer_is_empty(con->request.pathinfo)) {
32682 +               proxy_set_header(sess->env_headers, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
32683 +
32684 +               /* PATH_TRANSLATED is only defined if PATH_INFO is set */
32685 +
32686 +               buffer_copy_string_buffer(p->tmp_buf, con->physical.doc_root);
32687 +               buffer_append_string_buffer(p->tmp_buf, con->request.pathinfo);
32688 +               proxy_set_header(sess->env_headers, CONST_STR_LEN("PATH_TRANSLATED"), CONST_BUF_LEN(p->tmp_buf));
32689 +       } else {
32690 +               proxy_set_header(sess->env_headers, CONST_STR_LEN("PATH_INFO"), CONST_STR_LEN(""));
32691 +       }
32692 +
32693 +       /*
32694 +        * SCRIPT_FILENAME and DOCUMENT_ROOT for php. The PHP manual
32695 +        * http://www.php.net/manual/en/reserved.variables.php
32696 +        * treatment of PATH_TRANSLATED is different from the one of CGI specs.
32697 +        * TODO: this code should be checked against cgi.fix_pathinfo php
32698 +        * parameter.
32699 +        */
32700 +
32701 +       if (1) {
32702 +               proxy_set_header(sess->env_headers, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path));
32703 +               proxy_set_header(sess->env_headers, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root));
32704 +       }
32705 +
32706 +       proxy_set_header(sess->env_headers, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
32707 +
32708 +       if (!buffer_is_equal(con->request.uri, con->request.orig_uri)) {
32709 +               proxy_set_header(sess->env_headers, CONST_STR_LEN("REDIRECT_URI"), CONST_BUF_LEN(con->request.uri));
32710 +       }
32711 +       if (!buffer_is_empty(con->uri.query)) {
32712 +               proxy_set_header(sess->env_headers, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query));
32713 +       } else {
32714 +               proxy_set_header(sess->env_headers, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
32715 +       }
32716 +
32717 +       s = get_http_method_name(con->request.http_method);
32718 +       proxy_set_header(sess->env_headers, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
32719 +       proxy_set_header(sess->env_headers, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")); /* if php is compiled with --force-redirect */
32720 +       s = get_http_version_name(con->request.http_version);
32721 +       proxy_set_header(sess->env_headers, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
32722 +
32723 +#ifdef USE_OPENSSL
32724 +       if (srv_sock->is_ssl) {
32725 +               proxy_set_header(sess->env_headers, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on"));
32726 +       }
32727 +#endif
32728 +
32729 +       return 0;
32730 +}
32731 +
32732 +/**
32733 + * transform the HTTP-Request headers into CGI notation
32734 + */
32735 +int proxy_fastcgi_get_env_request(server *srv, connection *con, plugin_data *p, proxy_session *sess) {
32736 +       size_t i;
32737 +       /* the request header got already copied into the sess->request_headers for us
32738 +        * no extra filter is needed
32739 +        *
32740 +        * prepend a HTTP_ and uppercase the keys
32741 +        */
32742 +       for (i = 0; i < sess->request_headers->used; i++) {
32743 +               data_string *ds;
32744 +               size_t j;
32745 +
32746 +               ds = (data_string *)sess->request_headers->data[i];
32747 +
32748 +               buffer_reset(p->tmp_buf);
32749 +
32750 +               if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
32751 +                       BUFFER_COPY_STRING_CONST(p->tmp_buf, "HTTP_");
32752 +                       p->tmp_buf->used--;
32753 +               }
32754 +
32755 +               buffer_prepare_append(p->tmp_buf, ds->key->used + 2);
32756 +               for (j = 0; j < ds->key->used - 1; j++) {
32757 +                       char c = '_';
32758 +                       if (light_isalpha(ds->key->ptr[j])) {
32759 +                               /* upper-case */
32760 +                               c = ds->key->ptr[j] & ~32;
32761 +                       } else if (light_isdigit(ds->key->ptr[j])) {
32762 +                               /* copy */
32763 +                               c = ds->key->ptr[j];
32764 +                       }
32765 +                       p->tmp_buf->ptr[p->tmp_buf->used++] = c;
32766 +               }
32767 +               p->tmp_buf->ptr[p->tmp_buf->used++] = '\0';
32768 +
32769 +               proxy_set_header(sess->env_headers, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value));
32770 +       }
32771 +
32772 +       return 0;
32773 +}
32774 +
32775 +
32776 +/**
32777 + * add a key-value pair to the fastcgi-buffer
32778 + */
32779 +
32780 +static int fcgi_env_add(buffer *env, const char *key, size_t key_len, const char *val, size_t val_len) {
32781 +       size_t len;
32782 +
32783 +       if (!key || !val) return -1;
32784 +
32785 +       len = key_len + val_len;
32786 +
32787 +       len += key_len > 127 ? 4 : 1;
32788 +       len += val_len > 127 ? 4 : 1;
32789 +
32790 +       buffer_prepare_append(env, len);
32791 +
32792 +       if (key_len > 127) {
32793 +               env->ptr[env->used++] = ((key_len >> 24) & 0xff) | 0x80;
32794 +               env->ptr[env->used++] = (key_len >> 16) & 0xff;
32795 +               env->ptr[env->used++] = (key_len >> 8) & 0xff;
32796 +               env->ptr[env->used++] = (key_len >> 0) & 0xff;
32797 +       } else {
32798 +               env->ptr[env->used++] = (key_len >> 0) & 0xff;
32799 +       }
32800 +
32801 +       if (val_len > 127) {
32802 +               env->ptr[env->used++] = ((val_len >> 24) & 0xff) | 0x80;
32803 +               env->ptr[env->used++] = (val_len >> 16) & 0xff;
32804 +               env->ptr[env->used++] = (val_len >> 8) & 0xff;
32805 +               env->ptr[env->used++] = (val_len >> 0) & 0xff;
32806 +       } else {
32807 +               env->ptr[env->used++] = (val_len >> 0) & 0xff;
32808 +       }
32809 +
32810 +       memcpy(env->ptr + env->used, key, key_len);
32811 +       env->used += key_len;
32812 +       memcpy(env->ptr + env->used, val, val_len);
32813 +       env->used += val_len;
32814 +
32815 +       return 0;
32816 +}
32817 +
32818 +/**
32819 + * init the FCGI_header 
32820 + */
32821 +static int fcgi_header(FCGI_Header * header, unsigned char type, size_t request_id, int contentLength, unsigned char paddingLength) {
32822 +       header->version = FCGI_VERSION_1;
32823 +       header->type = type;
32824 +       header->requestIdB0 = request_id & 0xff;
32825 +       header->requestIdB1 = (request_id >> 8) & 0xff;
32826 +       header->contentLengthB0 = contentLength & 0xff;
32827 +       header->contentLengthB1 = (contentLength >> 8) & 0xff;
32828 +       header->paddingLength = paddingLength;
32829 +       header->reserved = 0;
32830 +
32831 +       return 0;
32832 +}
32833 +
32834 +
32835 +int proxy_fastcgi_get_request_chunk(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *out) {
32836 +       buffer *b, *packet;
32837 +       size_t i;
32838 +       FCGI_BeginRequestRecord beginRecord;
32839 +       FCGI_Header header;
32840 +       int request_id = 1;
32841 +
32842 +       b = chunkqueue_get_append_buffer(out);
32843 +       /* send FCGI_BEGIN_REQUEST */
32844 +
32845 +       fcgi_header(&(beginRecord.header), FCGI_BEGIN_REQUEST, FCGI_NULL_REQUEST_ID, sizeof(beginRecord.body), 0);
32846 +       beginRecord.body.roleB0 = FCGI_RESPONDER;
32847 +       beginRecord.body.roleB1 = 0;
32848 +       beginRecord.body.flags = 0;
32849 +       memset(beginRecord.body.reserved, 0, sizeof(beginRecord.body.reserved));
32850 +
32851 +       buffer_copy_string_len(b, (const char *)&beginRecord, sizeof(beginRecord));
32852 +       out->bytes_in += sizeof(beginRecord);
32853 +
32854 +       /* send FCGI_PARAMS */
32855 +       b = chunkqueue_get_append_buffer(out);
32856 +       buffer_prepare_copy(b, 1024);
32857 +
32858 +       /* fill the sess->env_headers */
32859 +       array_reset(sess->env_headers);
32860 +       proxy_fastcgi_get_env_request(srv, con, p, sess);
32861 +       proxy_fastcgi_get_env_fastcgi(srv, con, p, sess);
32862 +
32863 +       packet = buffer_init();
32864 +
32865 +       for (i = 0; i < sess->env_headers->used; i++) {
32866 +               data_string *ds;
32867 +
32868 +               ds = (data_string *)sess->env_headers->data[i];
32869 +               fcgi_env_add(packet, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
32870 +       }
32871 +
32872 +       fcgi_header(&(header), FCGI_PARAMS, FCGI_NULL_REQUEST_ID, packet->used, 0);
32873 +       buffer_append_memory(b, (const char *)&header, sizeof(header));
32874 +       buffer_append_memory(b, (const char *)packet->ptr, packet->used);
32875 +       out->bytes_in += sizeof(header);
32876 +       out->bytes_in += packet->used - 1;
32877 +
32878 +       buffer_free(packet);
32879 +
32880 +       fcgi_header(&(header), FCGI_PARAMS, FCGI_NULL_REQUEST_ID, 0, 0);
32881 +       buffer_append_memory(b, (const char *)&header, sizeof(header));
32882 +       out->bytes_in += sizeof(header);
32883 +
32884 +       return 0;
32885 +}
32886 +
32887 +
32888 +typedef struct {
32889 +       buffer  *b;
32890 +       size_t   len;
32891 +       int      type;
32892 +       int      padding;
32893 +       size_t   request_id;
32894 +} fastcgi_response_packet;
32895 +
32896 +int proxy_fastcgi_stream_decoder(server *srv, proxy_session *sess, chunkqueue *raw, chunkqueue *decoded) {
32897 +       chunk * c;
32898 +       size_t offset = 0;
32899 +       size_t toread = 0;
32900 +       FCGI_Header *header;
32901 +       fastcgi_response_packet packet;
32902 +       buffer *b;
32903 +
32904 +       if (!raw->first) return 0;
32905 +
32906 +       packet.b = buffer_init();
32907 +       packet.len = 0;
32908 +       packet.type = 0;
32909 +       packet.padding = 0;
32910 +       packet.request_id = 0;
32911 +
32912 +       /* get at least the FastCGI header */
32913 +       for (c = raw->first; c; c = c->next) {
32914 +               if (packet.b->used == 0) {
32915 +                       buffer_copy_string_len(packet.b, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
32916 +               } else {
32917 +                       buffer_append_string_len(packet.b, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
32918 +               }
32919 +
32920 +               if (packet.b->used >= sizeof(*header) + 1) break;
32921 +       }
32922 +
32923 +       if ((packet.b->used == 0) ||
32924 +           (packet.b->used - 1 < sizeof(FCGI_Header))) {
32925 +               /* no header */
32926 +               buffer_free(packet.b);
32927 +
32928 +               ERROR("%s", "FastCGI: header too small");
32929 +               return -1;
32930 +       }
32931 +
32932 +       /* we have at least a header, now check how much me have to fetch */
32933 +       header = (FCGI_Header *)(packet.b->ptr);
32934 +
32935 +       packet.len = (header->contentLengthB0 | (header->contentLengthB1 << 8)) + header->paddingLength;
32936 +       packet.request_id = (header->requestIdB0 | (header->requestIdB1 << 8));
32937 +       packet.type = header->type;
32938 +       packet.padding = header->paddingLength;
32939 +
32940 +       /* the first bytes in packet->b are the header */
32941 +       offset = sizeof(*header);
32942 +
32943 +       buffer_copy_string(packet.b, "");
32944 +
32945 +       if (packet.len) {
32946 +               /* copy the content */
32947 +               for (; c && (packet.b->used < packet.len + 1); c = c->next) {
32948 +                       size_t weWant = packet.len - (packet.b->used - 1);
32949 +                       size_t weHave = c->mem->used - c->offset - offset - 1;
32950 +
32951 +                       if (weHave > weWant) weHave = weWant;
32952 +
32953 +                       buffer_append_string_len(packet.b, c->mem->ptr + c->offset + offset, weHave);
32954 +
32955 +                       /* we only skipped the first 8 bytes as they are the fcgi header */
32956 +                       offset = 0;
32957 +               }
32958 +
32959 +               if (packet.b->used < packet.len + 1) {
32960 +                       /* we didn't got the full packet */
32961 +
32962 +                       buffer_free(packet.b);
32963 +
32964 +                       TRACE("%s", "need more");
32965 +
32966 +                       return 0;
32967 +               }
32968 +
32969 +               packet.b->used -= packet.padding;
32970 +               packet.b->ptr[packet.b->used - 1] = '\0';
32971 +       }
32972 +
32973 +       /* tag the chunks as read */
32974 +       toread = packet.len + sizeof(FCGI_Header);
32975 +       for (c = raw->first; c && toread; c = c->next) {
32976 +               if (c->mem->used - c->offset - 1 <= toread) {
32977 +                       /* we read this whole buffer, move it to unused */
32978 +                       toread -= c->mem->used - c->offset - 1;
32979 +                       c->offset = c->mem->used - 1; /* everthing has been written */
32980 +               } else {
32981 +                       c->offset += toread;
32982 +                       toread = 0;
32983 +               }
32984 +       }
32985 +
32986 +       chunkqueue_remove_finished_chunks(raw);
32987 +
32988 +       /* we are still here ? */
32989 +
32990 +       switch (packet.type) {
32991 +       case FCGI_STDOUT:
32992 +               b = chunkqueue_get_append_buffer(decoded);
32993 +               buffer_copy_string_buffer(b, packet.b);
32994 +               buffer_free(packet.b);
32995 +               return 0;
32996 +       case FCGI_STDERR:
32997 +               if (!buffer_is_empty(packet.b)) {
32998 +                       TRACE("(fastcgi-stderr) %s", BUF_STR(packet.b));
32999 +               }
33000 +               buffer_free(packet.b);
33001 +               return 0;
33002 +       case FCGI_END_REQUEST:
33003 +               buffer_free(packet.b);
33004 +               return 1;
33005 +       default:
33006 +               buffer_free(packet.b);
33007 +
33008 +               TRACE("unknown packet.type: %d", packet.type);
33009 +               return -1;
33010 +       }
33011 +}
33012 +
33013 +/**
33014 + * transform the content-stream into a valid HTTP-content-stream
33015 + *
33016 + * as we don't apply chunked-encoding here, pass it on AS IS
33017 + */
33018 +int proxy_fastcgi_stream_encoder(server *srv, proxy_session *sess, chunkqueue *in, chunkqueue *out) {
33019 +       chunk *c;
33020 +       buffer *b;
33021 +       FCGI_Header header;
33022 +
33023 +       /* there is nothing that we have to send out anymore */
33024 +       for (c = in->first; in->bytes_out < in->bytes_in; ) {
33025 +               off_t weWant = in->bytes_in - in->bytes_out > FCGI_MAX_LENGTH ? FCGI_MAX_LENGTH : in->bytes_in - in->bytes_out;
33026 +               off_t weHave = 0;
33027 +
33028 +               /* we announce toWrite octects
33029 +                * now take all the request_content chunk that we need to fill this request
33030 +                */
33031 +               b = chunkqueue_get_append_buffer(out);
33032 +               fcgi_header(&(header), FCGI_STDIN, FCGI_NULL_REQUEST_ID, weWant, 0);
33033 +               buffer_copy_memory(b, (const char *)&header, sizeof(header) + 1);
33034 +               out->bytes_in += sizeof(header);
33035 +
33036 +               switch (c->type) {
33037 +               case FILE_CHUNK:
33038 +                       weHave = c->file.length - c->offset;
33039 +
33040 +                       if (weHave > weWant) weHave = weWant;
33041 +
33042 +                       chunkqueue_append_file(out, c->file.name, c->offset, weHave);
33043 +
33044 +                       c->offset += weHave;
33045 +                       in->bytes_out += weHave;
33046 +
33047 +                       out->bytes_in += weHave;
33048 +
33049 +                       /* steal the tempfile
33050 +                        *
33051 +                        * This is tricky:
33052 +                        * - we reference the tempfile from the in-queue several times
33053 +                        *   if the chunk is larger than FCGI_MAX_LENGTH
33054 +                        * - we can't simply cleanup the in-queue as soon as possible
33055 +                        *   as it would remove the tempfiles
33056 +                        * - the idea is to 'steal' the tempfiles and attach the is_temp flag to the last
33057 +                        *   referencing chunk of the fastcgi-write-queue
33058 +                        *
33059 +                        */
33060 +
33061 +                       if (c->offset == c->file.length) {
33062 +                               chunk *out_c;
33063 +
33064 +                               out_c = out->last;
33065 +
33066 +                               /* the last of the out-queue should be a FILE_CHUNK (we just created it)
33067 +                                * and the incoming side should have given use a temp-file-chunk */
33068 +                               assert(out_c->type == FILE_CHUNK);
33069 +                               assert(c->file.is_temp == 1);
33070 +
33071 +                               out_c->file.is_temp = 1;
33072 +                               c->file.is_temp = 0;
33073 +
33074 +                               c = c->next;
33075 +                       }
33076 +
33077 +                       break;
33078 +               case MEM_CHUNK:
33079 +                       /* append to the buffer */
33080 +                       weHave = c->mem->used - 1 - c->offset;
33081 +
33082 +                       if (weHave > weWant) weHave = weWant;
33083 +
33084 +                       b = chunkqueue_get_append_buffer(out);
33085 +                       buffer_append_memory(b, c->mem->ptr + c->offset, weHave);
33086 +                       b->used++; /* add virtual \0 */
33087 +
33088 +                       c->offset += weHave;
33089 +                       in->bytes_out += weHave;
33090 +
33091 +                       out->bytes_in += weHave;
33092 +
33093 +                       if (c->offset == c->mem->used - 1) {
33094 +                               c = c->next;
33095 +                       }
33096 +
33097 +                       break;
33098 +               default:
33099 +                       break;
33100 +               }
33101 +       }
33102 +
33103 +       if (in->bytes_in == in->bytes_out && in->is_closed && !out->is_closed) {
33104 +               /* send the closing packet */
33105 +               b = chunkqueue_get_append_buffer(out);
33106 +               /* terminate STDIN */
33107 +               fcgi_header(&(header), FCGI_STDIN, FCGI_NULL_REQUEST_ID, 0, 0);
33108 +               buffer_copy_memory(b, (const char *)&header, sizeof(header) + 1);
33109 +
33110 +               out->bytes_in += sizeof(header);
33111 +               out->is_closed = 1;
33112 +       }
33113 +
33114 +       return 0;
33115 +
33116 +}
33117 +
33118 +/**
33119 + * parse the response header
33120 + *
33121 + * NOTE: this can be used by all backends as they all send a HTTP-Response a clean block
33122 + * - fastcgi needs some decoding for the protocol
33123 + */
33124 +parse_status_t proxy_fastcgi_parse_response_header(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *cq) {
33125 +       int have_content_length = 0;
33126 +       size_t i;
33127 +       off_t old_len;
33128 +
33129 +       http_response_reset(p->resp);
33130 +
33131 +       /* decode the whole packet stream */
33132 +       do {
33133 +               old_len = chunkqueue_length(sess->recv);
33134 +               /* decode the packet */
33135 +               switch (proxy_fastcgi_stream_decoder(srv, sess, cq, sess->recv)) {
33136 +               case 0:
33137 +                       /* STDERR + STDOUT */
33138 +                       break;
33139 +               case 1:
33140 +                       /* the FIN packet was catched, why ever */
33141 +                       return PARSE_ERROR;
33142 +               case -1:
33143 +                       return PARSE_ERROR;
33144 +               }
33145 +       } while (chunkqueue_length(sess->recv) == old_len);
33146 +       
33147 +       switch (http_response_parse_cq(sess->recv, p->resp)) {
33148 +       case PARSE_ERROR:
33149 +               /* parsing failed */
33150 +
33151 +               return PARSE_ERROR;
33152 +       case PARSE_NEED_MORE:
33153 +               return PARSE_NEED_MORE;
33154 +       case PARSE_SUCCESS:
33155 +               con->http_status = p->resp->status;
33156 +
33157 +               chunkqueue_remove_finished_chunks(cq);
33158 +
33159 +               sess->content_length = -1;
33160 +
33161 +               /* copy the http-headers */
33162 +               for (i = 0; i < p->resp->headers->used; i++) {
33163 +                       const char *ign[] = { "Status", "Connection", NULL };
33164 +                       size_t j, k;
33165 +                       data_string *ds;
33166 +
33167 +                       data_string *header = (data_string *)p->resp->headers->data[i];
33168 +
33169 +                       /* some headers are ignored by default */
33170 +                       for (j = 0; ign[j]; j++) {
33171 +                               if (0 == strcasecmp(ign[j], header->key->ptr)) break;
33172 +                       }
33173 +                       if (ign[j]) continue;
33174 +
33175 +                       if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
33176 +                               /* CGI/1.1 rev 03 - 7.2.1.2 */
33177 +                               if (con->http_status == 0) con->http_status = 302;
33178 +                       } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
33179 +                               have_content_length = 1;
33180 +
33181 +                               sess->content_length = strtol(header->value->ptr, NULL, 10);
33182 +
33183 +                               if (sess->content_length < 0) {
33184 +                                       return PARSE_ERROR;
33185 +                               }
33186 +                       } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Transfer-Encoding"))) {
33187 +                               if (strstr(header->value->ptr, "chunked")) {
33188 +                                       sess->is_chunked = 1;
33189 +                               }
33190 +                               /* ignore the header */
33191 +                               continue;
33192 +                       }
33193 +                       
33194 +                       if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
33195 +                               ds = data_response_init();
33196 +                       }
33197 +
33198 +
33199 +                       buffer_copy_string_buffer(ds->key, header->key);
33200 +
33201 +                       for (k = 0; k < p->conf.response_rewrites->used; k++) {
33202 +                               proxy_rewrite *rw = p->conf.response_rewrites->ptr[k];
33203 +
33204 +                               if (buffer_is_equal(rw->header, header->key)) {
33205 +                                       int ret;
33206 +       
33207 +                                       if ((ret = pcre_replace(rw->regex, rw->replace, header->value, p->replace_buf)) < 0) {
33208 +                                               switch (ret) {
33209 +                                               case PCRE_ERROR_NOMATCH:
33210 +                                                       /* hmm, ok. no problem */
33211 +                                                       buffer_append_string_buffer(ds->value, header->value);
33212 +                                                       break;
33213 +                                               default:
33214 +                                                       TRACE("oops, pcre_replace failed with: %d", ret);
33215 +                                                       break;
33216 +                                               }
33217 +                                       } else {
33218 +                                               buffer_append_string_buffer(ds->value, p->replace_buf);
33219 +                                       }
33220 +
33221 +                                       break;
33222 +                               }
33223 +                       }
33224 +
33225 +                       if (k == p->conf.response_rewrites->used) {
33226 +                               buffer_copy_string_buffer(ds->value, header->value);
33227 +                       }
33228 +
33229 +                       array_insert_unique(con->response.headers, (data_unset *)ds);
33230 +               }
33231 +
33232 +               break;
33233 +       }
33234 +
33235 +       return PARSE_SUCCESS; /* we have a full header */
33236 +}
33237 +
33238 +
33239 --- ../lighttpd-1.4.11/src/mod_proxy_backend_fastcgi.h  1970-01-01 03:00:00.000000000 +0300
33240 +++ lighttpd-1.5.0/src/mod_proxy_backend_fastcgi.h      2006-09-07 00:57:05.000000000 +0300
33241 @@ -0,0 +1,13 @@
33242 +#ifndef _MOD_PROXY_BACKEND_FASTCGI_H_
33243 +#define _MOD_PROXY_BACKEND_FASTCGI_H_
33244 +
33245 +#include "mod_proxy_core.h"
33246 +#include "base.h"
33247 +
33248 +int proxy_fastcgi_stream_decoder(server *srv, proxy_session *sess, chunkqueue *in, chunkqueue *out);
33249 +int proxy_fastcgi_stream_encoder(server *srv, proxy_session *sess, chunkqueue *in, chunkqueue *out);
33250 +
33251 +parse_status_t proxy_fastcgi_parse_response_header(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *cq);
33252 +int proxy_fastcgi_get_request_chunk(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *cq);
33253 +
33254 +#endif
33255 --- ../lighttpd-1.4.11/src/mod_proxy_backend_http.c     1970-01-01 03:00:00.000000000 +0300
33256 +++ lighttpd-1.5.0/src/mod_proxy_backend_http.c 2006-09-07 00:57:05.000000000 +0300
33257 @@ -0,0 +1,436 @@
33258 +#include <stdlib.h>
33259 +#include <string.h>
33260 +
33261 +#include "mod_proxy_core.h"
33262 +#include "configfile.h"
33263 +#include "buffer.h"
33264 +#include "log.h"
33265 +#include "sys-strings.h"
33266 +
33267 +void chunkqueue_skip(chunkqueue *cq, off_t skip) {
33268 +       chunk *c;
33269 +
33270 +       for (c = cq->first; c && skip; c = c->next) {
33271 +               if (skip > c->mem->used - c->offset - 1) {
33272 +                       skip -= c->mem->used - c->offset - 1;
33273 +               } else {
33274 +                       c->offset += skip;
33275 +                       skip = 0;
33276 +               }
33277 +       }
33278 +
33279 +       return;
33280 +}
33281 +
33282 +int proxy_http_stream_decoder(server *srv, proxy_session *sess, chunkqueue *raw, chunkqueue *decoded) {
33283 +       chunk *c;
33284 +
33285 +       if (raw->first == NULL) return 0;
33286 +
33287 +       if (sess->is_chunked) {
33288 +               do {
33289 +                       /* the start should always be a chunk-length */
33290 +                       off_t chunk_len = 0;
33291 +                       char *err = NULL;
33292 +                       int chunklen_strlen = 0;
33293 +                       char ch;
33294 +                       off_t we_have = 0, we_need = 0;
33295 +
33296 +                       c = raw->first;
33297 +
33298 +                       if (c->mem->used == 0) return 0;
33299 +
33300 +                       chunk_len = strtol(BUF_STR(c->mem) + c->offset, &err, 16);
33301 +                       if (!(*err == ' ' || *err == '\r' || *err == ';')) {
33302 +                               if (*err == '\0') {
33303 +                                       /* we just need more data */
33304 +                                       return 0;
33305 +                               }
33306 +                               return -1;
33307 +                       }
33308 +
33309 +                       if (chunk_len < 0) {
33310 +                               ERROR("chunk_len is negative: %Ld", chunk_len);
33311 +                               return -1;
33312 +                       }
33313 +
33314 +                       chunklen_strlen = err - (BUF_STR(c->mem) + c->offset);
33315 +                       chunklen_strlen++; /* skip the err-char */ 
33316 +                       
33317 +                       do {
33318 +                               ch = BUF_STR(c->mem)[c->offset + chunklen_strlen];
33319 +       
33320 +                               switch (ch) {
33321 +                               case '\n':
33322 +                               case '\0':
33323 +                                       /* bingo, chunk-header is finished */
33324 +                                       break;
33325 +                               default:
33326 +                                       break;
33327 +                               }
33328 +                               chunklen_strlen++;
33329 +                       } while (ch != '\n' && c != '\0');
33330 +
33331 +                       if (ch != '\n') {
33332 +                               ERROR("%s", "missing the CRLF");
33333 +                               return 0;
33334 +                       }
33335 +
33336 +                       we_need = chunk_len + chunklen_strlen + 2;
33337 +                       /* do we have the full chunk ? */
33338 +                       for (c = raw->first; c; c = c->next) {
33339 +                               we_have += c->mem->used - 1 - c->offset;
33340 +
33341 +                               /* we have enough, jump out */
33342 +                               if (we_have > we_need) break;
33343 +                       }
33344 +
33345 +                       /* get more data */
33346 +                       if (we_have < we_need) {
33347 +                               return 0;
33348 +                       }
33349 +
33350 +                       /* skip the chunk-header */
33351 +                       chunkqueue_skip(raw, chunklen_strlen);
33352 +
33353 +                       /* final chunk */
33354 +                       if (chunk_len == 0) {
33355 +                               chunkqueue_skip(raw, 2);
33356 +
33357 +                               return 1;
33358 +                       }
33359 +
33360 +                       /* we have enough, copy the data */     
33361 +                       for (c = raw->first; c && chunk_len; c = c->next) {
33362 +                               off_t we_want = 0;
33363 +                               buffer *b = chunkqueue_get_append_buffer(decoded);
33364 +
33365 +                               we_want = chunk_len > (c->mem->used - c->offset - 1) ? c->mem->used - c->offset - 1: chunk_len;
33366 +
33367 +                               buffer_copy_string_len(b, c->mem->ptr + c->offset, we_want);
33368 +
33369 +                               c->offset += we_want;
33370 +                               chunk_len -= we_want;
33371 +                       }
33372 +
33373 +                       /* skip the \r\n */
33374 +                       chunkqueue_skip(raw, 2);
33375 +
33376 +                       /* we are done, give the connection to someone else */
33377 +                       chunkqueue_remove_finished_chunks(raw);
33378 +               } while (1);
33379 +       } else {
33380 +               /* no chunked encoding, ok, perhaps a content-length ? */
33381 +
33382 +               chunkqueue_remove_finished_chunks(raw);
33383 +               for (c = raw->first; c; c = c->next) {
33384 +                       buffer *b;
33385 +
33386 +                       if (c->mem->used == 0) continue;
33387 +                      
33388 +                       b = chunkqueue_get_append_buffer(decoded);
33389 +
33390 +                       sess->bytes_read += c->mem->used - c->offset - 1;
33391 +
33392 +                       buffer_copy_string_len(b, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
33393 +
33394 +                       c->offset = c->mem->used - 1;
33395 +
33396 +                       if (sess->bytes_read == sess->content_length) {
33397 +                               break;
33398 +                       }
33399 +
33400 +               }
33401 +               if (sess->bytes_read == sess->content_length) {
33402 +                       return 1; /* finished */
33403 +               }
33404 +       }
33405 +
33406 +       return 0;
33407 +}
33408 +
33409 +/**
33410 + * transform the content-stream into a valid HTTP-content-stream
33411 + *
33412 + * as we don't apply chunked-encoding here, pass it on AS IS
33413 + */
33414 +int proxy_http_stream_encoder(server *srv, proxy_session *sess, chunkqueue *in, chunkqueue *out) {
33415 +       chunk *c;
33416 +
33417 +       /* there is nothing that we have to send out anymore */
33418 +       if (in->bytes_in == in->bytes_out && 
33419 +           in->is_closed) return 0;
33420 +
33421 +       for (c = in->first; in->bytes_out < in->bytes_in; c = c->next) {
33422 +               buffer *b;
33423 +               off_t weWant = in->bytes_in - in->bytes_out;
33424 +               off_t weHave = 0;
33425 +
33426 +               /* we announce toWrite octects
33427 +                * now take all the request_content chunk that we need to fill this request
33428 +                */
33429 +
33430 +               switch (c->type) {
33431 +               case FILE_CHUNK:
33432 +                       weHave = c->file.length - c->offset;
33433 +
33434 +                       if (weHave > weWant) weHave = weWant;
33435 +
33436 +                       chunkqueue_append_file(out, c->file.name, c->offset, weHave);
33437 +
33438 +                       c->offset += weHave;
33439 +                       in->bytes_out += weHave;
33440 +
33441 +                       out->bytes_in += weHave;
33442 +
33443 +                       break;
33444 +               case MEM_CHUNK:
33445 +                       /* append to the buffer */
33446 +                       weHave = c->mem->used - 1 - c->offset;
33447 +
33448 +                       if (weHave > weWant) weHave = weWant;
33449 +
33450 +                       b = chunkqueue_get_append_buffer(out);
33451 +                       buffer_append_memory(b, c->mem->ptr + c->offset, weHave);
33452 +                       b->used++; /* add virtual \0 */
33453 +
33454 +                       c->offset += weHave;
33455 +                       in->bytes_out += weHave;
33456 +
33457 +                       out->bytes_in += weHave;
33458 +
33459 +                       break;
33460 +               default:
33461 +                       break;
33462 +               }
33463 +       }
33464 +
33465 +       return 0;
33466 +
33467 +}
33468 +/**
33469 + * generate a HTTP/1.1 proxy request from the set of request-headers
33470 + *
33471 + * TODO: this is HTTP-proxy specific and will be moved moved into a separate backed
33472 + *
33473 + */
33474 +int proxy_http_get_request_chunk(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *cq) {
33475 +       buffer *b;
33476 +       size_t i;
33477 +       
33478 +       b = chunkqueue_get_append_buffer(cq);
33479 +
33480 +       /* request line */
33481 +       buffer_copy_string(b, get_http_method_name(con->request.http_method));
33482 +       BUFFER_APPEND_STRING_CONST(b, " ");
33483 +
33484 +       /* check if we want to rewrite the uri */
33485 +
33486 +       for (i = 0; i < p->conf.request_rewrites->used; i++) {
33487 +               proxy_rewrite *rw = p->conf.request_rewrites->ptr[i];
33488 +
33489 +               if (buffer_is_equal_string(rw->header, CONST_STR_LEN("_uri"))) {
33490 +                       int ret;
33491 +
33492 +                       if ((ret = pcre_replace(rw->regex, rw->replace, con->request.uri, p->replace_buf)) < 0) {
33493 +                               switch (ret) {
33494 +                               case PCRE_ERROR_NOMATCH:
33495 +                                       /* hmm, ok. no problem */
33496 +                                       buffer_append_string_buffer(b, con->request.uri);
33497 +                                       break;
33498 +                               default:
33499 +                                       TRACE("oops, pcre_replace failed with: %d", ret);
33500 +                                       break;
33501 +                               }
33502 +                       } else {
33503 +                               buffer_append_string_buffer(b, p->replace_buf);
33504 +                       }
33505 +
33506 +                       break;
33507 +               }
33508 +       }
33509 +
33510 +       if (i == p->conf.request_rewrites->used) {
33511 +               /* not found */
33512 +               buffer_append_string_buffer(b, con->request.uri);
33513 +       }
33514 +
33515 +       if (con->request.http_version == HTTP_VERSION_1_1) {
33516 +               BUFFER_APPEND_STRING_CONST(b, " HTTP/1.1\r\n");
33517 +       } else {
33518 +               BUFFER_APPEND_STRING_CONST(b, " HTTP/1.0\r\n");
33519 +       }
33520 +
33521 +       for (i = 0; i < sess->request_headers->used; i++) {
33522 +               data_string *ds;
33523 +
33524 +               ds = (data_string *)sess->request_headers->data[i];
33525 +
33526 +               buffer_append_string_buffer(b, ds->key);
33527 +               BUFFER_APPEND_STRING_CONST(b, ": ");
33528 +               buffer_append_string_buffer(b, ds->value);
33529 +               BUFFER_APPEND_STRING_CONST(b, "\r\n");
33530 +       }
33531 +
33532 +       BUFFER_APPEND_STRING_CONST(b, "\r\n");
33533 +       
33534 +       return 0;
33535 +}
33536 +
33537 +/**
33538 + * parse the response header
33539 + *
33540 + * NOTE: this can be used by all backends as they all send a HTTP-Response a clean block
33541 + * - fastcgi needs some decoding for the protocol
33542 + */
33543 +parse_status_t proxy_http_parse_response_header(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *cq) {
33544 +       int have_content_length = 0;
33545 +       size_t i;
33546 +
33547 +       http_response_reset(p->resp);
33548 +       
33549 +       switch (http_response_parse_cq(cq, p->resp)) {
33550 +       case PARSE_ERROR:
33551 +               /* parsing failed */
33552 +
33553 +               return PARSE_ERROR;
33554 +       case PARSE_NEED_MORE:
33555 +               return PARSE_NEED_MORE;
33556 +       case PARSE_SUCCESS:
33557 +               con->http_status = p->resp->status;
33558 +
33559 +               chunkqueue_remove_finished_chunks(cq);
33560 +
33561 +               sess->content_length = -1;
33562 +
33563 +               /* copy the http-headers */
33564 +               for (i = 0; i < p->resp->headers->used; i++) {
33565 +                       const char *ign[] = { "Status", NULL };
33566 +                       size_t j, k;
33567 +                       data_string *ds;
33568 +
33569 +                       data_string *header = (data_string *)p->resp->headers->data[i];
33570 +
33571 +                       /* some headers are ignored by default */
33572 +                       for (j = 0; ign[j]; j++) {
33573 +                               if (0 == strcasecmp(ign[j], header->key->ptr)) break;
33574 +                       }
33575 +                       if (ign[j]) continue;
33576 +
33577 +                       if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
33578 +                               /* CGI/1.1 rev 03 - 7.2.1.2 */
33579 +                               if (con->http_status == 0) con->http_status = 302;
33580 +                       } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
33581 +                               have_content_length = 1;
33582 +
33583 +                               sess->content_length = strtol(header->value->ptr, NULL, 10);
33584 +
33585 +                               if (sess->content_length < 0) {
33586 +                                       return PARSE_ERROR;
33587 +                               }
33588 +                       } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("X-Sendfile")) ||
33589 +                                  0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("X-LIGHTTPD-Sendfile"))) {
33590 +                               if (p->conf.allow_x_sendfile) {
33591 +                                       sess->send_response_content = 0;
33592 +                                       sess->do_internal_redirect = 1;
33593 +                                       
33594 +                                       /* don't try to rewrite this request through mod_proxy_core again */
33595 +                                       sess->internal_redirect_count = MAX_INTERNAL_REDIRECTS; 
33596 +
33597 +                                       buffer_copy_string_buffer(con->physical.path, header->value);
33598 +
33599 +                                       /* as we want to support ETag and friends we set the physical path for the file
33600 +                                        * and hope mod_staticfile catches up */
33601 +                               }
33602 +
33603 +                               continue;
33604 +                       } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("X-Rewrite-URI"))) { 
33605 +                               if (p->conf.allow_x_rewrite) {
33606 +                                       sess->send_response_content = 0;
33607 +                                       sess->do_internal_redirect = 1;
33608 +
33609 +                                       buffer_copy_string_buffer(con->request.uri, header->value);
33610 +                                       buffer_reset(con->physical.path);
33611 +
33612 +                                       config_cond_cache_reset(srv, con);
33613 +                               }
33614 +
33615 +                               continue;
33616 +                       } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("X-Rewrite-Host"))) { 
33617 +                               if (p->conf.allow_x_rewrite) {
33618 +                                       sess->send_response_content = 0;
33619 +                                       sess->do_internal_redirect = 1;
33620 +
33621 +                                       buffer_copy_string_buffer(con->request.http_host, header->value);
33622 +                                       buffer_reset(con->physical.path);
33623 +
33624 +                                       config_cond_cache_reset(srv, con);
33625 +                               }
33626 +
33627 +                               continue;
33628 +                       } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Transfer-Encoding"))) {
33629 +                               if (strstr(header->value->ptr, "chunked")) {
33630 +                                       sess->is_chunked = 1;
33631 +                               }
33632 +                               /* ignore the header */
33633 +                               continue;
33634 +                       } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Connection"))) {
33635 +                               if (strstr(header->value->ptr, "close")) {
33636 +                                       sess->is_closing = 1;
33637 +                               }
33638 +                               /* ignore the header */
33639 +                               continue;
33640 +
33641 +                       }
33642 +                       
33643 +                       if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
33644 +                               ds = data_response_init();
33645 +                       }
33646 +
33647 +
33648 +                       buffer_copy_string_buffer(ds->key, header->key);
33649 +
33650 +                       for (k = 0; k < p->conf.response_rewrites->used; k++) {
33651 +                               proxy_rewrite *rw = p->conf.response_rewrites->ptr[k];
33652 +
33653 +                               if (buffer_is_equal(rw->header, header->key)) {
33654 +                                       int ret;
33655 +       
33656 +                                       if ((ret = pcre_replace(rw->regex, rw->replace, header->value, p->replace_buf)) < 0) {
33657 +                                               switch (ret) {
33658 +                                               case PCRE_ERROR_NOMATCH:
33659 +                                                       /* hmm, ok. no problem */
33660 +                                                       buffer_append_string_buffer(ds->value, header->value);
33661 +                                                       break;
33662 +                                               default:
33663 +                                                       TRACE("oops, pcre_replace failed with: %d", ret);
33664 +                                                       break;
33665 +                                               }
33666 +                                       } else {
33667 +                                               buffer_append_string_buffer(ds->value, p->replace_buf);
33668 +                                       }
33669 +
33670 +                                       break;
33671 +                               }
33672 +                       }
33673 +
33674 +                       if (k == p->conf.response_rewrites->used) {
33675 +                               buffer_copy_string_buffer(ds->value, header->value);
33676 +                       }
33677 +
33678 +                       array_insert_unique(con->response.headers, (data_unset *)ds);
33679 +               }
33680 +
33681 +               /* does the client allow us to send chunked encoding ? */
33682 +               if (con->request.http_version == HTTP_VERSION_1_1 &&
33683 +                   !have_content_length) {
33684 +                       con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
33685 +               }
33686 +
33687 +               break;
33688 +       }
33689 +
33690 +       return PARSE_SUCCESS; /* we have a full header */
33691 +}
33692 +
33693 +
33694 --- ../lighttpd-1.4.11/src/mod_proxy_backend_http.h     1970-01-01 03:00:00.000000000 +0300
33695 +++ lighttpd-1.5.0/src/mod_proxy_backend_http.h 2006-09-07 00:57:05.000000000 +0300
33696 @@ -0,0 +1,13 @@
33697 +#ifndef _MOD_PROXY_BACKEND_HTTP_H_
33698 +#define _MOD_PROXY_BACKEND_HTTP_H_
33699 +
33700 +#include "mod_proxy_core.h"
33701 +#include "base.h"
33702 +
33703 +int proxy_http_stream_decoder(server *srv, proxy_session *sess, chunkqueue *in, chunkqueue *out);
33704 +int proxy_http_stream_encoder(server *srv, proxy_session *sess, chunkqueue *in, chunkqueue *out);
33705 +
33706 +parse_status_t proxy_http_parse_response_header(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *cq);
33707 +int proxy_http_get_request_chunk(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *cq);
33708 +
33709 +#endif
33710 --- ../lighttpd-1.4.11/src/mod_proxy_core.c     1970-01-01 03:00:00.000000000 +0300
33711 +++ lighttpd-1.5.0/src/mod_proxy_core.c 2006-09-07 00:57:05.000000000 +0300
33712 @@ -0,0 +1,1471 @@
33713 +#include <string.h>
33714 +#include <stdlib.h>
33715 +#include <fcntl.h>
33716 +#include <errno.h>
33717 +#include <ctype.h>
33718 +#include <assert.h>
33719 +
33720 +#include "buffer.h"
33721 +#include "array.h"
33722 +#include "log.h"
33723 +
33724 +#include "base.h"
33725 +#include "plugin.h"
33726 +#include "joblist.h"
33727 +#include "sys-files.h"
33728 +#include "inet_ntop_cache.h"
33729 +#include "crc32.h"
33730 +#include "configfile.h"
33731 +
33732 +#include "mod_proxy_core.h"
33733 +#include "mod_proxy_backend_http.h"
33734 +#include "mod_proxy_backend_fastcgi.h"
33735 +
33736 +#define CONFIG_PROXY_CORE_BALANCER "proxy-core.balancer"
33737 +#define CONFIG_PROXY_CORE_PROTOCOL "proxy-core.protocol"
33738 +#define CONFIG_PROXY_CORE_DEBUG "proxy-core.debug"
33739 +#define CONFIG_PROXY_CORE_BACKENDS "proxy-core.backends"
33740 +#define CONFIG_PROXY_CORE_REWRITE_REQUEST "proxy-core.rewrite-request"
33741 +#define CONFIG_PROXY_CORE_REWRITE_RESPONSE "proxy-core.rewrite-response"
33742 +#define CONFIG_PROXY_CORE_ALLOW_X_SENDFILE "proxy-core.allow-x-sendfile"
33743 +#define CONFIG_PROXY_CORE_ALLOW_X_REWRITE "proxy-core.allow-x-rewrite"
33744 +#define CONFIG_PROXY_CORE_MAX_POOL_SIZE "proxy-core.max-pool-size"
33745 +
33746 +int array_insert_int(array *a, const char *key, int val) {
33747 +       data_integer *di;
33748 +
33749 +       if (NULL == (di = (data_integer *)array_get_unused_element(a, TYPE_INTEGER))) {
33750 +               di = data_integer_init();
33751 +       }
33752 +
33753 +       buffer_copy_string(di->key, key);
33754 +       di->value = val;
33755 +       array_insert_unique(a, (data_unset *)di);
33756 +
33757 +       return 0;
33758 +}
33759 +
33760 +INIT_FUNC(mod_proxy_core_init) {
33761 +       plugin_data *p;
33762 +
33763 +       p = calloc(1, sizeof(*p));
33764 +
33765 +       /* create some backends as long as we don't have the config-parser */
33766 +
33767 +       p->possible_balancers = array_init();
33768 +       array_insert_int(p->possible_balancers, "fair", PROXY_BALANCE_FAIR);
33769 +       array_insert_int(p->possible_balancers, "hash", PROXY_BALANCE_HASH);
33770 +       array_insert_int(p->possible_balancers, "round-robin", PROXY_BALANCE_RR);
33771 +
33772 +       p->possible_protocols = array_init();
33773 +       array_insert_int(p->possible_protocols, "http", PROXY_PROTOCOL_HTTP);
33774 +       array_insert_int(p->possible_protocols, "fastcgi", PROXY_PROTOCOL_FASTCGI);
33775 +       array_insert_int(p->possible_protocols, "scgi", PROXY_PROTOCOL_SCGI);
33776 +       array_insert_int(p->possible_protocols, "https", PROXY_PROTOCOL_HTTPS);
33777 +
33778 +       p->balance_buf = buffer_init();
33779 +       p->protocol_buf = buffer_init();
33780 +       p->replace_buf = buffer_init();
33781 +       p->backends_arr = array_init();
33782 +
33783 +       p->tmp_buf = buffer_init();
33784 +
33785 +       p->resp = http_response_init();
33786 +
33787 +       return p;
33788 +}
33789 +
33790 +FREE_FUNC(mod_proxy_core_free) {
33791 +       plugin_data *p = p_d;
33792 +
33793 +       if (!p) return HANDLER_GO_ON;
33794 +
33795 +       if (p->config_storage) {
33796 +               size_t i;
33797 +               for (i = 0; i < srv->config_context->used; i++) {
33798 +                       plugin_config *s = p->config_storage[i];
33799 +
33800 +                       if (!s) continue;
33801 +
33802 +                       proxy_backends_free(s->backends);
33803 +                       proxy_backlog_free(s->backlog);
33804 +
33805 +                       proxy_rewrites_free(s->request_rewrites);
33806 +                       proxy_rewrites_free(s->response_rewrites);
33807 +
33808 +                       free(s);
33809 +               }
33810 +               free(p->config_storage);
33811 +       }
33812 +
33813 +       array_free(p->possible_protocols);
33814 +       array_free(p->possible_balancers);
33815 +       array_free(p->backends_arr);
33816 +
33817 +       buffer_free(p->balance_buf);
33818 +       buffer_free(p->protocol_buf);
33819 +       buffer_free(p->replace_buf);
33820 +       buffer_free(p->tmp_buf);
33821 +       
33822 +       http_response_free(p->resp);
33823 +
33824 +       free(p);
33825 +
33826 +       return HANDLER_GO_ON;
33827 +}
33828 +
33829 +static handler_t mod_proxy_core_config_parse_rewrites(proxy_rewrites *dest, array *src, const char *config_key) {
33830 +       data_unset *du;
33831 +       size_t j;
33832 +
33833 +       if (NULL != (du = array_get_element(src, config_key))) {
33834 +               data_array *keys = (data_array *)du;
33835 +
33836 +               if (keys->type != TYPE_ARRAY) {
33837 +                       ERROR("%s = <...>", 
33838 +                               config_key);
33839 +
33840 +                       return HANDLER_ERROR;
33841 +               }
33842 +
33843 +               /*
33844 +                * proxy-core.rewrite-request = (
33845 +                *   "_uri" => ( ... ) 
33846 +                * )
33847 +                */
33848 +
33849 +               for (j = 0; j < keys->value->used; j++) {
33850 +                       size_t k;
33851 +                       data_array *headers = (data_array *)keys->value->data[j];
33852 +
33853 +                       /* keys->key should be "_uri" and the value a array of rewrite */
33854 +                       if (headers->type != TYPE_ARRAY) {
33855 +                               ERROR("%s = ( %s => <...> ) has to a array", 
33856 +                                       config_key,
33857 +                                       BUF_STR(headers->key));
33858 +
33859 +                               return HANDLER_ERROR;
33860 +                       }
33861 +
33862 +                       if (headers->value->used > 1) {
33863 +                               ERROR("%s = ( %s => <...> ) has to a array with only one element", 
33864 +                                       config_key,
33865 +                                       BUF_STR(headers->key));
33866 +
33867 +                               return HANDLER_ERROR;
33868 +
33869 +                       }
33870 +
33871 +                       for (k = 0; k < headers->value->used; k++) {
33872 +                               data_string *rewrites = (data_string *)headers->value->data[k];
33873 +                               proxy_rewrite *rw;
33874 +
33875 +                               /* keys->key should be "_uri" and the value a array of rewrite */
33876 +                               if (rewrites->type != TYPE_STRING) {
33877 +                                       ERROR("%s = ( \"%s\" => ( \"%s\" => <value> ) ) has to a string", 
33878 +                                               config_key,
33879 +                                               BUF_STR(headers->key),
33880 +                                               BUF_STR(rewrites->key));
33881 +
33882 +                                       return HANDLER_ERROR;
33883 +                               }
33884 +                       
33885 +                               rw = proxy_rewrite_init();
33886 +
33887 +                               if (0 != proxy_rewrite_set_regex(rw, rewrites->key)) {
33888 +                                       return HANDLER_ERROR;
33889 +                               }
33890 +                               buffer_copy_string_buffer(rw->replace, rewrites->value);
33891 +                               buffer_copy_string_buffer(rw->match, rewrites->key);
33892 +                               buffer_copy_string_buffer(rw->header, headers->key);
33893 +
33894 +                               proxy_rewrites_add(dest, rw);
33895 +                       }
33896 +               }
33897 +       }
33898 +
33899 +       return HANDLER_GO_ON;
33900 +}
33901 +
33902 +
33903 +SETDEFAULTS_FUNC(mod_proxy_core_set_defaults) {
33904 +       plugin_data *p = p_d;
33905 +       size_t i, j;
33906 +
33907 +       config_values_t cv[] = {
33908 +               { CONFIG_PROXY_CORE_BACKENDS,       NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
33909 +               { CONFIG_PROXY_CORE_DEBUG,          NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
33910 +               { CONFIG_PROXY_CORE_BALANCER,       NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },      /* 2 */
33911 +               { CONFIG_PROXY_CORE_PROTOCOL,       NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },      /* 3 */
33912 +               { CONFIG_PROXY_CORE_REWRITE_REQUEST, NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION },      /* 4 */
33913 +               { CONFIG_PROXY_CORE_REWRITE_RESPONSE, NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION },     /* 5 */
33914 +               { CONFIG_PROXY_CORE_ALLOW_X_SENDFILE, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },   /* 6 */
33915 +               { CONFIG_PROXY_CORE_ALLOW_X_REWRITE, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },    /* 7 */
33916 +               { CONFIG_PROXY_CORE_MAX_POOL_SIZE, NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 8 */
33917 +               { NULL,                        NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
33918 +       };
33919 +
33920 +       p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
33921 +
33922 +       for (i = 0; i < srv->config_context->used; i++) {
33923 +               plugin_config *s;
33924 +               array *ca;
33925 +               proxy_backend *backend;
33926 +
33927 +               array_reset(p->backends_arr);
33928 +               buffer_reset(p->balance_buf);
33929 +               buffer_reset(p->protocol_buf);
33930 +
33931 +               s = calloc(1, sizeof(plugin_config));
33932 +               s->debug     = 0;
33933 +               s->balancer  = PROXY_BALANCE_UNSET;
33934 +               s->protocol  = PROXY_PROTOCOL_UNSET;
33935 +               s->backends  = proxy_backends_init();
33936 +               s->backlog   = proxy_backlog_init();
33937 +               s->response_rewrites   = proxy_rewrites_init();
33938 +               s->request_rewrites   = proxy_rewrites_init();
33939 +
33940 +               cv[0].destination = p->backends_arr;
33941 +               cv[1].destination = &(s->debug);
33942 +               cv[2].destination = p->balance_buf;         /* parse into a constant */
33943 +               cv[3].destination = p->protocol_buf;        /* parse into a constant */
33944 +               cv[6].destination = &(s->allow_x_sendfile);
33945 +               cv[7].destination = &(s->allow_x_rewrite);
33946 +               cv[8].destination = &(s->max_pool_size);
33947 +
33948 +               buffer_reset(p->balance_buf);
33949 +
33950 +               p->config_storage[i] = s;
33951 +               ca = ((data_config *)srv->config_context->data[i])->value;
33952 +
33953 +               if (0 != config_insert_values_global(srv, ca, cv)) {
33954 +                       return HANDLER_ERROR;
33955 +               }
33956 +
33957 +               if (!buffer_is_empty(p->balance_buf)) {
33958 +                       data_integer *di;
33959 +                       
33960 +                       if (NULL == (di = (data_integer *)array_get_element(p->possible_balancers, BUF_STR(p->balance_buf)))) {
33961 +                               ERROR("proxy.balance has to be on of 'fair', 'round-robin', 'hash', got %s", BUF_STR(p->balance_buf));
33962 +
33963 +                               return HANDLER_ERROR;
33964 +                       }
33965 +
33966 +                       s->balancer = di->value;
33967 +               }
33968 +
33969 +               if (!buffer_is_empty(p->protocol_buf)) {
33970 +                       data_integer *di;
33971 +                       
33972 +                       if (NULL == (di = (data_integer *)array_get_element(p->possible_protocols, BUF_STR(p->protocol_buf)))) {
33973 +                               ERROR("proxy.balance has to be on of 'fair', 'round-robin', 'hash', got %s", BUF_STR(p->protocol_buf));
33974 +
33975 +                               return HANDLER_ERROR;
33976 +                       }
33977 +
33978 +                       s->protocol = di->value;
33979 +               }
33980 +
33981 +               if (p->backends_arr->used) {
33982 +                       backend = proxy_backend_init();
33983 +
33984 +                       /* check if the backends have a valid host-name */
33985 +                       for (j = 0; j < p->backends_arr->used; j++) {
33986 +                               data_string *ds = (data_string *)p->backends_arr->data[j];
33987 +
33988 +                               /* the values should be ips or hostnames */
33989 +                               if (0 != proxy_address_pool_add_string(backend->address_pool, ds->value)) {
33990 +                                       return HANDLER_ERROR;
33991 +                               }
33992 +                       }
33993 +
33994 +                       if (s->max_pool_size) {
33995 +                               backend->pool->max_size = s->max_pool_size;
33996 +                       }
33997 +
33998 +                       proxy_backends_add(s->backends, backend);
33999 +               }
34000 +
34001 +               if (HANDLER_GO_ON != mod_proxy_core_config_parse_rewrites(s->request_rewrites, ca, CONFIG_PROXY_CORE_REWRITE_REQUEST)) {
34002 +                       return HANDLER_ERROR;
34003 +               }
34004 +               
34005 +               if (HANDLER_GO_ON != mod_proxy_core_config_parse_rewrites(s->response_rewrites, ca, CONFIG_PROXY_CORE_REWRITE_RESPONSE)) {
34006 +                       return HANDLER_ERROR;
34007 +               }
34008 +       }
34009 +
34010 +       return HANDLER_GO_ON;
34011 +}
34012 +
34013 +
34014 +proxy_session *proxy_session_init(void) {
34015 +       proxy_session *sess;
34016 +
34017 +       sess = calloc(1, sizeof(*sess));
34018 +
34019 +       sess->state = PROXY_STATE_UNSET;
34020 +       sess->request_headers = array_init();
34021 +       sess->env_headers = array_init();
34022 +
34023 +       sess->recv = chunkqueue_init();
34024 +       sess->recv_raw = chunkqueue_init();
34025 +       sess->send_raw = chunkqueue_init();
34026 +       sess->send = chunkqueue_init();
34027 +
34028 +       sess->is_chunked = 0;
34029 +       sess->send_response_content = 1;
34030 +
34031 +       return sess;
34032 +}
34033 +
34034 +void proxy_session_free(proxy_session *sess) {
34035 +       if (!sess) return;
34036 +
34037 +       array_free(sess->request_headers);
34038 +       array_free(sess->env_headers);
34039 +
34040 +       chunkqueue_free(sess->recv);
34041 +       chunkqueue_free(sess->recv_raw);
34042 +       chunkqueue_free(sess->send_raw);
34043 +       chunkqueue_free(sess->send);
34044 +
34045 +       free(sess);
34046 +}
34047 +
34048 +/**
34049 + * decode the content for the protocol
34050 + *
34051 + * http might have chunk-encoding 
34052 + * fastcgi has the fastcgi wrapper code
34053 + *
34054 + * @param in chunkqueue for the encoded, protocol specific data
34055 + * @param out chunkqueue for the plain content
34056 + */
34057 +
34058 +int proxy_stream_decoder(server *srv, proxy_session *sess, chunkqueue *in, chunkqueue *out) {
34059 +       switch (sess->proxy_backend->protocol) {
34060 +       case PROXY_PROTOCOL_HTTP:
34061 +               return proxy_http_stream_decoder(srv, sess, in, out);
34062 +       case PROXY_PROTOCOL_FASTCGI:
34063 +               return proxy_fastcgi_stream_decoder(srv, sess, in, out);
34064 +       default:
34065 +               ERROR("protocol %d is not supported yet", sess->proxy_backend->protocol);
34066 +               return -1;
34067 +       }
34068 +}
34069 +/**
34070 + * encode the content for the protocol
34071 + *
34072 + * @param in chunkqueue with the content to (no encoding)
34073 + * @param out chunkqueue for the encoded, protocol specific data
34074 + */
34075 +int proxy_stream_encoder(server *srv, proxy_session *sess, chunkqueue *in, chunkqueue *out) {
34076 +       switch (sess->proxy_backend->protocol) {
34077 +       case PROXY_PROTOCOL_HTTP:
34078 +               return proxy_http_stream_encoder(srv, sess, in, out);
34079 +       case PROXY_PROTOCOL_FASTCGI:
34080 +               return proxy_fastcgi_stream_encoder(srv, sess, in, out);
34081 +       default:
34082 +               ERROR("protocol %d is not supported yet", sess->proxy_backend->protocol);
34083 +               return -1;
34084 +       }
34085 +}
34086 +
34087 +int proxy_get_request_chunk(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *cq) {
34088 +       switch (sess->proxy_backend->protocol) {
34089 +       case PROXY_PROTOCOL_HTTP:
34090 +               return proxy_http_get_request_chunk(srv, con, p, sess, cq);
34091 +       case PROXY_PROTOCOL_FASTCGI:
34092 +               return proxy_fastcgi_get_request_chunk(srv, con, p, sess, cq);
34093 +       default:
34094 +               ERROR("protocol %d is not supported yet", sess->proxy_backend->protocol);
34095 +               return -1;
34096 +       }
34097 +}
34098 +
34099 +
34100 +parse_status_t proxy_parse_response_header(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *cq) {
34101 +       switch (sess->proxy_backend->protocol) {
34102 +       case PROXY_PROTOCOL_HTTP:
34103 +               return proxy_http_parse_response_header(srv, con, p, sess, cq);
34104 +       case PROXY_PROTOCOL_FASTCGI:
34105 +               return proxy_fastcgi_parse_response_header(srv, con, p, sess, cq);
34106 +       default:
34107 +               ERROR("protocol %d is not supported yet", sess->proxy_backend->protocol);
34108 +               return PARSE_ERROR;
34109 +       }
34110 +}
34111 +
34112 +
34113 +handler_t proxy_connection_connect(proxy_connection *con) {
34114 +       int fd;
34115 +
34116 +       if (-1 == (fd = socket(con->address->addr.plain.sa_family, SOCK_STREAM, 0))) {
34117 +       }
34118 +
34119 +       fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR);
34120 +
34121 +       con->sock->fd = fd;
34122 +       con->sock->fde_ndx = -1;
34123 +       con->sock->type = IOSOCKET_TYPE_SOCKET;
34124 +
34125 +       if (-1 == connect(fd, &(con->address->addr.plain), sizeof(con->address->addr))) {
34126 +               switch(errno) {
34127 +               case EINPROGRESS:
34128 +               case EALREADY:
34129 +               case EINTR:
34130 +                       return HANDLER_WAIT_FOR_EVENT;
34131 +               default:
34132 +                       close(fd);
34133 +                       con->sock->fd = -1;
34134 +
34135 +                       return HANDLER_ERROR;
34136 +               }
34137 +       }
34138 +
34139 +       return HANDLER_GO_ON;
34140 +}
34141 +
34142 +/**
34143 + * event-handler for idling connections
34144 + *
34145 + * unused (idling) keep-alive connections are not bound to a session
34146 + * and need their own event-handler 
34147 + *
34148 + * if the connection closes (we get a FDEVENT_IN), close our side too and 
34149 + * let the trigger-func handle the cleanup
34150 + *
34151 + * @see proxy_trigger
34152 + */
34153 +
34154 +
34155 +static handler_t proxy_handle_fdevent_idle(void *s, void *ctx, int revents) {
34156 +       server      *srv  = (server *)s;
34157 +       proxy_connection *proxy_con = ctx;
34158 +
34159 +       if (revents & FDEVENT_IN) {
34160 +               switch (proxy_con->state) {
34161 +               case PROXY_CONNECTION_STATE_IDLE:
34162 +                       proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
34163 +
34164 +                       /* close + unregister have to be in the same call,
34165 +                        * otherwise we get a events for a re-opened fd */
34166 +
34167 +                       fdevent_event_del(srv->ev, proxy_con->sock);
34168 +
34169 +                       break;
34170 +               case PROXY_CONNECTION_STATE_CLOSED:
34171 +                       /* poll() is state-driven, we will get events as long as it isn't disabled
34172 +                        * the close() above should disable the events too */
34173 +                       ERROR("%s", "hurry up buddy, I got another event for a closed idle-connection");
34174 +                       break;
34175 +               default:
34176 +                       ERROR("invalid connection state: %d, should be idle", proxy_con->state);
34177 +                       break;
34178 +               }
34179 +       }
34180 +
34181 +       return HANDLER_GO_ON;
34182 +}
34183 +
34184 +
34185 +/* don't call any proxy functions directly */
34186 +static handler_t proxy_handle_fdevent(void *s, void *ctx, int revents) {
34187 +       server      *srv  = (server *)s;
34188 +       proxy_session *sess = ctx;
34189 +       connection  *con  = sess->remote_con;
34190 +
34191 +       if (revents & FDEVENT_OUT) {
34192 +               switch (sess->state) {
34193 +               case PROXY_STATE_CONNECTING: /* delayed connect */
34194 +               case PROXY_STATE_WRITE_REQUEST_HEADER:
34195 +               case PROXY_STATE_WRITE_REQUEST_BODY:
34196 +                       /* we are still connection */
34197 +
34198 +                       joblist_append(srv, con);
34199 +                       break;
34200 +               default:
34201 +                       ERROR("oops, unexpected state for fdevent-out %d", sess->state);
34202 +                       break;
34203 +               }
34204 +       } else if (revents & FDEVENT_IN) {
34205 +               chunk *c;
34206 +
34207 +               switch (sess->state) {
34208 +               case PROXY_STATE_READ_RESPONSE_HEADER:
34209 +                       /* call our header parser */
34210 +                       joblist_append(srv, con);
34211 +                       break;
34212 +               case PROXY_STATE_READ_RESPONSE_BODY:
34213 +                       /* we should be in the WRITE state now, 
34214 +                        * just read in the content and forward it to the outgoing connection
34215 +                        * */
34216 +
34217 +                       chunkqueue_remove_finished_chunks(sess->recv_raw);
34218 +                       switch (srv->network_backend_read(srv, con, sess->proxy_con->sock, sess->recv_raw)) {
34219 +                       case NETWORK_STATUS_CONNECTION_CLOSE:
34220 +                               fdevent_event_del(srv->ev,sess->proxy_con->sock);
34221 +
34222 +                               /* the connection is gone
34223 +                                * make the connect */
34224 +                               con->send->is_closed = 1;
34225 +                               sess->proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
34226 +
34227 +                       case NETWORK_STATUS_SUCCESS:
34228 +                               /* read even more, do we have all the content */
34229 +
34230 +                               /* how much do we want to read ? */
34231 +                               
34232 +                               /* call stream-decoder (HTTP-chunked, FastCGI, ... ) */
34233 +
34234 +                               switch (proxy_stream_decoder(srv, sess, sess->recv_raw, sess->recv)) {
34235 +                               case 0:
34236 +                                       /* need more */
34237 +                                       break;
34238 +                               case -1:
34239 +                                       /* error */
34240 +                                       break;
34241 +                               case 1:
34242 +                                       /* we are done */
34243 +                                       con->send->is_closed = 1;
34244 +
34245 +                                       break;
34246 +                               }
34247 +                               chunkqueue_remove_finished_chunks(sess->recv_raw);
34248 +
34249 +
34250 +                               /* copy the content to the next cq */
34251 +                               for (c = sess->recv->first; c; c = c->next) {
34252 +                                       if (c->mem->used == 0) continue;
34253 +
34254 +                                       if (sess->send_response_content) {
34255 +                                               /* X-Sendfile ignores the content-body */
34256 +                                               chunkqueue_append_mem(con->send, c->mem->ptr + c->offset, c->mem->used - c->offset);
34257 +                                       }
34258 +       
34259 +                                       c->offset = c->mem->used - 1;
34260 +
34261 +                               }
34262 +                               chunkqueue_remove_finished_chunks(sess->recv);
34263 +                               
34264 +                               break;
34265 +                       default:
34266 +                               ERROR("%s", "oops, we failed to read");
34267 +                               break;
34268 +                       }
34269 +
34270 +                       /* we wrote something into the the send-buffers, 
34271 +                        * call the connection-handler to push it to the client */
34272 +                       joblist_append(srv, con);
34273 +                       break;
34274 +               default:
34275 +                       ERROR("oops, unexpected state for fdevent-in %d", sess->state);
34276 +                       break;
34277 +               }
34278 +       }
34279 +
34280 +       if (revents & FDEVENT_HUP) {
34281 +               /* someone closed our connection */
34282 +               switch (sess->state) {
34283 +               case PROXY_STATE_CONNECTING:
34284 +                       /* let the getsockopt() catch this */
34285 +                       joblist_append(srv, con);
34286 +                       break;
34287 +               case PROXY_STATE_READ_RESPONSE_BODY:
34288 +                       /* the keep-alive race-condition */
34289 +                       break;
34290 +               default:
34291 +                       ERROR("oops, unexpected state for fdevent-hup %d", sess->state);
34292 +                       break;
34293 +               }
34294 +       }
34295 +
34296 +       return HANDLER_GO_ON;
34297 +}
34298 +void proxy_set_header(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len) {
34299 +       data_string *ds_dst;
34300 +
34301 +       if (NULL != (ds_dst = (data_string *)array_get_element(hdrs, key))) {
34302 +               buffer_copy_string_len(ds_dst->value, value, val_len);
34303 +               return;
34304 +       }
34305 +
34306 +       if (NULL == (ds_dst = (data_string *)array_get_unused_element(hdrs, TYPE_STRING))) {
34307 +               ds_dst = data_string_init();
34308 +       }
34309 +
34310 +       buffer_copy_string_len(ds_dst->key, key, key_len);
34311 +       buffer_copy_string_len(ds_dst->value, value, val_len);
34312 +       array_insert_unique(hdrs, (data_unset *)ds_dst);
34313 +}
34314 +
34315 +void proxy_append_header(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len) {
34316 +       data_string *ds_dst;
34317 +
34318 +       if (NULL == (ds_dst = (data_string *)array_get_unused_element(hdrs, TYPE_STRING))) {
34319 +               ds_dst = data_string_init();
34320 +       }
34321 +
34322 +       buffer_copy_string_len(ds_dst->key, key, key_len);
34323 +       buffer_copy_string_len(ds_dst->value, value, val_len);
34324 +       array_insert_unique(hdrs, (data_unset *)ds_dst);
34325 +}
34326 +
34327 +
34328 +/**
34329 + * build the request-header array and call the backend specific request formater
34330 + * to fill the chunkqueue
34331 + */
34332 +int proxy_get_request_header(server *srv, connection *con, plugin_data *p, proxy_session *sess) {
34333 +       /* request line */
34334 +       const char *remote_ip;
34335 +       size_t i;
34336 +
34337 +       remote_ip = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
34338 +       proxy_append_header(sess->request_headers, CONST_STR_LEN("X-Forwarded-For"), remote_ip, strlen(remote_ip));
34339 +
34340 +       /* http_host is NOT is just a pointer to a buffer
34341 +        * which is NULL if it is not set */
34342 +       if (con->request.http_host &&
34343 +           !buffer_is_empty(con->request.http_host)) {
34344 +               proxy_set_header(sess->request_headers, CONST_STR_LEN("X-Host"), CONST_BUF_LEN(con->request.http_host));
34345 +       }
34346 +       if (con->conf.is_ssl) {
34347 +               proxy_set_header(sess->request_headers, CONST_STR_LEN("X-Forwarded-Proto"), CONST_STR_LEN("https"));
34348 +       } else {
34349 +               proxy_set_header(sess->request_headers, CONST_STR_LEN("X-Forwarded-Proto"), CONST_STR_LEN("http"));
34350 +       }
34351 +
34352 +       /* request header */
34353 +       for (i = 0; i < con->request.headers->used; i++) {
34354 +               data_string *ds;
34355 +               size_t k;
34356 +
34357 +               ds = (data_string *)con->request.headers->data[i];
34358 +
34359 +               if (buffer_is_empty(ds->value) || buffer_is_empty(ds->key)) continue;
34360 +
34361 +               if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue;
34362 +               if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Keep-Alive"))) continue;
34363 +
34364 +               for (k = 0; k < p->conf.request_rewrites->used; k++) {
34365 +                       proxy_rewrite *rw = p->conf.request_rewrites->ptr[k];
34366 +
34367 +                       if (buffer_is_equal(rw->header, ds->key)) {
34368 +                               int ret;
34369 +
34370 +                               if ((ret = pcre_replace(rw->regex, rw->replace, ds->value, p->replace_buf)) < 0) {
34371 +                                       switch (ret) {
34372 +                                       case PCRE_ERROR_NOMATCH:
34373 +                                               /* hmm, ok. no problem */
34374 +                                               proxy_set_header(sess->request_headers, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
34375 +                                               break;
34376 +                                       default:
34377 +                                               TRACE("oops, pcre_replace failed with: %d", ret);
34378 +                                               break;
34379 +                                       }
34380 +                               } else {
34381 +                                       proxy_set_header(sess->request_headers, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(p->replace_buf));
34382 +                               }
34383 +
34384 +                               break;
34385 +                       }
34386 +               }
34387 +
34388 +               if (k == p->conf.request_rewrites->used) {
34389 +                       proxy_set_header(sess->request_headers, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
34390 +               }
34391 +       }
34392 +
34393 +       proxy_get_request_chunk(srv, con, p, sess, sess->send_raw);
34394 +
34395 +       return 0;
34396 +}
34397 +
34398 +
34399 +/* we are event-driven
34400 + * 
34401 + * the first entry is connect() call, if the doesn't need a event 
34402 + *
34403 + * a bit boring
34404 + * - connect (+ delayed connect)
34405 + * - write header + content
34406 + * - read header + content
34407 + *
34408 + * as soon as have read the response header we switch con->file_started and return HANDLER_GO_ON to
34409 + * tell the core we are ready to stream out the content.
34410 + *  */
34411 +handler_t proxy_state_engine(server *srv, connection *con, plugin_data *p, proxy_session *sess) {
34412 +       /* do we have a connection ? */
34413 +
34414 +       if (sess->state == PROXY_STATE_UNSET) {
34415 +               /* we are not started yet */
34416 +               sess->connect_start_ts = srv->cur_ts;
34417 +               switch(proxy_connection_connect(sess->proxy_con)) {
34418 +               case HANDLER_WAIT_FOR_EVENT:
34419 +                       /* waiting on the connect call */
34420 +
34421 +                       fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent, sess);
34422 +                       fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_OUT);
34423 +
34424 +                       sess->state = PROXY_STATE_CONNECTING;
34425 +                       sess->proxy_con->state = PROXY_CONNECTION_STATE_CONNECTING;
34426 +                       
34427 +                       return HANDLER_WAIT_FOR_EVENT;
34428 +               case HANDLER_GO_ON:
34429 +                       /* we are connected */
34430 +                       sess->state = PROXY_STATE_CONNECTED;
34431 +                       sess->proxy_con->state = PROXY_CONNECTION_STATE_CONNECTED;
34432 +                       fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent, sess);
34433 +
34434 +                       break;
34435 +               case HANDLER_ERROR:
34436 +               default:
34437 +                       /* not good, something failed */
34438 +                       return HANDLER_ERROR;
34439 +               
34440 +               }
34441 +       } else if (sess->state == PROXY_STATE_CONNECTING) {
34442 +               int socket_error;
34443 +               socklen_t socket_error_len = sizeof(socket_error);
34444 +
34445 +               fdevent_event_del(srv->ev, sess->proxy_con->sock);
34446 +
34447 +               if (0 != getsockopt(sess->proxy_con->sock->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
34448 +                       ERROR("getsockopt failed:", strerror(errno));
34449 +
34450 +                       return HANDLER_ERROR;
34451 +               }
34452 +               if (socket_error != 0) {
34453 +                       switch (socket_error) {
34454 +                       case ECONNREFUSED:
34455 +                               /* there is no-one on the other side */
34456 +                               sess->proxy_con->address->disabled_until = srv->cur_ts + 2;
34457 +
34458 +                               TRACE("address %s refused us, disabling for 2 sec", sess->proxy_con->address->name->ptr);
34459 +                               break;
34460 +                       case EHOSTUNREACH:
34461 +                               /* there is no-one on the other side */
34462 +                               sess->proxy_con->address->disabled_until = srv->cur_ts + 60;
34463 +
34464 +                               TRACE("host %s is unreachable, disabling for 60 sec", sess->proxy_con->address->name->ptr);
34465 +                               break;
34466 +                       default:
34467 +                               sess->proxy_con->address->disabled_until = srv->cur_ts + 60;
34468 +
34469 +                               TRACE("connected finally failed: %s (%d)", strerror(socket_error), socket_error);
34470 +
34471 +                               TRACE("connect to address %s failed and I don't know why, disabling for 10 sec", sess->proxy_con->address->name->ptr);
34472 +
34473 +                               break;
34474 +                       }
34475 +
34476 +                       sess->proxy_con->address->state = PROXY_ADDRESS_STATE_DISABLED;
34477 +
34478 +                       sess->proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
34479 +                       return HANDLER_COMEBACK;
34480 +               }
34481 +
34482 +               sess->state = PROXY_STATE_CONNECTED;
34483 +               sess->proxy_con->state = PROXY_CONNECTION_STATE_CONNECTED;
34484 +       }
34485 +
34486 +       if (sess->state == PROXY_STATE_CONNECTED) {
34487 +               /* build the header */
34488 +               proxy_get_request_header(srv, con, p, sess);
34489 +
34490 +               sess->state = PROXY_STATE_WRITE_REQUEST_HEADER;
34491 +       }
34492 +
34493 +       switch (sess->state) {
34494 +       case PROXY_STATE_WRITE_REQUEST_HEADER:
34495 +               /* create the request-packet */ 
34496 +               fdevent_event_del(srv->ev, sess->proxy_con->sock);
34497 +
34498 +               switch (srv->network_backend_write(srv, con, sess->proxy_con->sock, sess->send_raw)) {
34499 +               case NETWORK_STATUS_SUCCESS:
34500 +                       sess->state = PROXY_STATE_WRITE_REQUEST_BODY;
34501 +                       break;
34502 +               case NETWORK_STATUS_WAIT_FOR_EVENT:
34503 +                       fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_OUT);
34504 +
34505 +                       return HANDLER_WAIT_FOR_EVENT;
34506 +               case NETWORK_STATUS_CONNECTION_CLOSE:
34507 +                       sess->proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
34508 +
34509 +                       /* this connection is closed, restart the request with a new connection */
34510 +
34511 +                       return HANDLER_COMEBACK;
34512 +               default:
34513 +                       return HANDLER_ERROR;
34514 +               }
34515 +
34516 +               chunkqueue_remove_finished_chunks(sess->send_raw);
34517 +               
34518 +               /* fall through */
34519 +       case PROXY_STATE_WRITE_REQUEST_BODY:
34520 +               /* do we have a content-body to send up to the backend ? */
34521 +
34522 +               fdevent_event_del(srv->ev, sess->proxy_con->sock);
34523 +
34524 +               proxy_stream_encoder(srv, sess, con->recv, sess->send_raw);
34525 +
34526 +               chunkqueue_remove_finished_chunks(con->recv);
34527 +
34528 +               switch (srv->network_backend_write(srv, con, sess->proxy_con->sock, sess->send_raw)) {
34529 +               case NETWORK_STATUS_SUCCESS:
34530 +                       if (con->recv->is_closed && /* no further input */
34531 +                           con->recv->bytes_in == con->recv->bytes_out &&  /* everything is encoded */
34532 +                           sess->send_raw->bytes_in == sess->send_raw->bytes_out) { /* everything is sent */
34533 +                               sess->state = PROXY_STATE_READ_RESPONSE_HEADER;
34534 +                       }
34535 +                       break;
34536 +               case NETWORK_STATUS_WAIT_FOR_EVENT:
34537 +                       fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_OUT);
34538 +
34539 +                       chunkqueue_remove_finished_chunks(sess->send_raw);
34540 +
34541 +                       return HANDLER_WAIT_FOR_EVENT;
34542 +               case NETWORK_STATUS_CONNECTION_CLOSE:
34543 +                       /* the connection got close while sending the request content up 
34544 +                        * to the backend, for now handle this as error */
34545 +
34546 +                       TRACE("%s", "(con-close)");
34547 +                       return HANDLER_ERROR;
34548 +               default:
34549 +                       TRACE("%s", "(error)");
34550 +                       return HANDLER_ERROR;
34551 +               }
34552 +               chunkqueue_remove_finished_chunks(sess->send_raw);
34553 +
34554 +               /* fall through */
34555 +       case PROXY_STATE_READ_RESPONSE_HEADER:
34556 +               fdevent_event_del(srv->ev, sess->proxy_con->sock);
34557 +
34558 +               chunkqueue_remove_finished_chunks(sess->recv_raw);
34559 +
34560 +               switch (srv->network_backend_read(srv, con, sess->proxy_con->sock, sess->recv_raw)) {
34561 +               case NETWORK_STATUS_SUCCESS:
34562 +                       /* we read everything from the socket, do we have a full header ? */
34563 +
34564 +                       switch (proxy_parse_response_header(srv, con, p, sess, sess->recv_raw)) {
34565 +                       case PARSE_ERROR:
34566 +                               con->http_status = 502; /* bad gateway */
34567 +
34568 +                               return HANDLER_FINISHED;
34569 +                       case PARSE_NEED_MORE:
34570 +                               /* we need more */
34571 +                               fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
34572 +
34573 +                               return HANDLER_WAIT_FOR_EVENT;
34574 +                       case PARSE_SUCCESS:
34575 +                               break;
34576 +                       default:
34577 +                               return HANDLER_ERROR;
34578 +                       }
34579 +
34580 +                       if (sess->do_internal_redirect) {
34581 +                               /* now it becomes tricky
34582 +                                * 
34583 +                                * mod_staticfile should handle this file for us
34584 +                                * con->mode = DIRECT is taking us out of the loop */
34585 +
34586 +                               return HANDLER_COMEBACK;
34587 +                       }
34588 +
34589 +                       con->file_started = 1;
34590 +                       /* if Status: ... is not set, 200 is our default status-code */
34591 +                       if (con->http_status == 0) con->http_status = 200;
34592 +
34593 +                       sess->state = PROXY_STATE_READ_RESPONSE_BODY;
34594 +
34595 +                       /**
34596 +                        * set the event to pass the content through to the server
34597 +                        *
34598 +                        * this triggers the event-handler
34599 +                        * @see proxy_handle_fdevent
34600 +                        */
34601 +                       fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
34602 +
34603 +                       return HANDLER_GO_ON; /* tell http_response_prepare that we are done with the header */
34604 +               case NETWORK_STATUS_WAIT_FOR_EVENT:
34605 +                       fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
34606 +                       return HANDLER_WAIT_FOR_EVENT;
34607 +               case NETWORK_STATUS_CONNECTION_CLOSE:
34608 +                       if (chunkqueue_length(sess->recv_raw) == 0) {
34609 +                               /* the connection went away before we got something back */
34610 +                               sess->proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
34611 +
34612 +                               /**
34613 +                                * we might run into a 'race-condition' 
34614 +                                *
34615 +                                * 1. proxy-con is keep-alive, idling and just being closed (FDEVENT_IN) [fd=27]
34616 +                                * 2. new connection comes in, we use the idling connection [fd=14]
34617 +                                * 3. we write(), successful [to fd=27]
34618 +                                * 3. we read() ... and finally receive the close-event for the connection
34619 +                                */
34620 +
34621 +                               ERROR("%s", "++ oops, connection closed while waiting to read a response, restarting");
34622 +
34623 +                               return HANDLER_COMEBACK;
34624 +                       }
34625 +
34626 +                       ERROR("%s", "conn-close after header-read");
34627 +                               
34628 +                       break;
34629 +               default:
34630 +                       ERROR("++ %s", "oops, something went wrong while reading");
34631 +                       return HANDLER_ERROR;
34632 +               }
34633 +       case PROXY_STATE_READ_RESPONSE_BODY:
34634 +               /* if we do everything right, we won't get call for this state-anymore */
34635 +
34636 +               ERROR("%s", "PROXY_STATE_READ_RESPONSE_BODY");
34637 +               
34638 +               break;
34639 +       }
34640 +
34641 +       return HANDLER_GO_ON;
34642 +}
34643 +
34644 +proxy_backend *proxy_get_backend(server *srv, connection *con, plugin_data *p) {
34645 +       size_t i;
34646 +
34647 +       for (i = 0; i < p->conf.backends->used; i++) {
34648 +               proxy_backend *backend = p->conf.backends->ptr[i];
34649 +
34650 +               return backend;
34651 +       }
34652 +
34653 +       return NULL;
34654 +}
34655 +
34656 +/**
34657 + * choose a available address from the address-pool
34658 + *
34659 + * the backend has different balancers 
34660 + */
34661 +proxy_address *proxy_backend_balance(server *srv, connection *con, proxy_backend *backend) {
34662 +       size_t i;
34663 +       proxy_address_pool *address_pool = backend->address_pool;
34664 +       unsigned long last_max; /* for the HASH balancer */
34665 +       proxy_address *address = NULL, *cur_address = NULL;
34666 +       int active_addresses = 0, rand_ndx;
34667 +
34668 +       switch(backend->balancer) {
34669 +       case PROXY_BALANCE_HASH:
34670 +               /* hash balancing */
34671 +
34672 +               for (i = 0, last_max = ULONG_MAX; i < address_pool->used; i++) {
34673 +                       unsigned long cur_max;
34674 +
34675 +                       cur_address = address_pool->ptr[i];
34676 +
34677 +                       if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
34678 +
34679 +                       cur_max = generate_crc32c(CONST_BUF_LEN(con->uri.path)) +
34680 +                               generate_crc32c(CONST_BUF_LEN(cur_address->name)) + /* we can cache this */
34681 +                               generate_crc32c(CONST_BUF_LEN(con->uri.authority));
34682 +#if 0
34683 +                       TRACE("hash-election: %s - %s - %s: %ld", 
34684 +                                       con->uri.path->ptr,
34685 +                                       cur_address->name->ptr,
34686 +                                       con->uri.authority->ptr,
34687 +                                       cur_max);
34688 +#endif
34689 +                       if (address == NULL || (cur_max > last_max)) {
34690 +                               last_max = cur_max;
34691 +
34692 +                               address = cur_address;
34693 +                       }
34694 +               }
34695 +
34696 +               break;
34697 +       case PROXY_BALANCE_FAIR:
34698 +               /* fair balancing */
34699 +
34700 +               for (i = 0; i < address_pool->used; i++) {
34701 +                       cur_address = address_pool->ptr[i];
34702 +
34703 +                       if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
34704 +
34705 +                       /* the address is up, use it */
34706 +
34707 +                       address = cur_address;
34708 +
34709 +                       break;
34710 +               }
34711 +
34712 +               break;
34713 +       case PROXY_BALANCE_RR:
34714 +               /* round robin */
34715 +
34716 +               /**
34717 +                * instead of real RoundRobin we just do a RandomSelect
34718 +                *
34719 +                * it is state-less and has the same distribution
34720 +                */
34721 +
34722 +               active_addresses = 0;
34723 +               
34724 +               for (i = 0; i < address_pool->used; i++) {
34725 +                       cur_address = address_pool->ptr[i];
34726 +
34727 +                       if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
34728 +
34729 +                       active_addresses++;
34730 +               }
34731 +
34732 +               rand_ndx = (int) (1.0 * active_addresses * rand()/(RAND_MAX));
34733 +       
34734 +               active_addresses = 0;
34735 +               for (i = 0; i < address_pool->used; i++) {
34736 +                       cur_address = address_pool->ptr[i];
34737 +
34738 +                       if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
34739 +
34740 +                       address = cur_address;
34741 +
34742 +                       if (rand_ndx == active_addresses++) break;
34743 +               }
34744 +
34745 +               break;
34746 +       default:
34747 +               break;
34748 +       }
34749 +
34750 +       return address;
34751 +}
34752 +
34753 +static int mod_proxy_core_patch_connection(server *srv, connection *con, plugin_data *p) {
34754 +       size_t i, j;
34755 +       plugin_config *s = p->config_storage[0];
34756 +
34757 +       /* global defaults */
34758 +       PATCH_OPTION(balancer);
34759 +       PATCH_OPTION(debug);
34760 +       PATCH_OPTION(backends);
34761 +       PATCH_OPTION(backlog);
34762 +       PATCH_OPTION(protocol);
34763 +       PATCH_OPTION(request_rewrites);
34764 +       PATCH_OPTION(response_rewrites);
34765 +       PATCH_OPTION(allow_x_sendfile);
34766 +       PATCH_OPTION(allow_x_rewrite);
34767 +
34768 +       /* skip the first, the global context */
34769 +       for (i = 1; i < srv->config_context->used; i++) {
34770 +               data_config *dc = (data_config *)srv->config_context->data[i];
34771 +               s = p->config_storage[i];
34772 +
34773 +               /* condition didn't match */
34774 +               if (!config_check_cond(srv, con, dc)) continue;
34775 +
34776 +               /* merge config */
34777 +               for (j = 0; j < dc->value->used; j++) {
34778 +                       data_unset *du = dc->value->data[j];
34779 +
34780 +                       if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_BACKENDS))) {
34781 +                               PATCH_OPTION(backends);
34782 +                               PATCH_OPTION(backlog);
34783 +                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_DEBUG))) {
34784 +                               PATCH_OPTION(debug);
34785 +                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_BALANCER))) {
34786 +                               PATCH_OPTION(balancer);
34787 +                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_PROTOCOL))) {
34788 +                               PATCH_OPTION(protocol);
34789 +                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_REWRITE_REQUEST))) {
34790 +                               PATCH_OPTION(request_rewrites);
34791 +                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_REWRITE_RESPONSE))) {
34792 +                               PATCH_OPTION(response_rewrites);
34793 +                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_ALLOW_X_SENDFILE))) {
34794 +                               PATCH_OPTION(allow_x_sendfile);
34795 +                       } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_ALLOW_X_REWRITE))) {
34796 +                               PATCH_OPTION(allow_x_rewrite);
34797 +                       }
34798 +               }
34799 +       }
34800 +
34801 +       return 0;
34802 +}
34803 +
34804 +SUBREQUEST_FUNC(mod_proxy_core_check_extension) {
34805 +       plugin_data *p = p_d;
34806 +       proxy_session *sess = con->plugin_ctx[p->id]; /* if this is the second round, sess is already prepared */
34807 +
34808 +       /* check if we have a matching conditional for this request */
34809 +
34810 +       if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
34811 +
34812 +       mod_proxy_core_patch_connection(srv, con, p);
34813 +
34814 +       if (p->conf.backends->used == 0) return HANDLER_GO_ON;
34815 +
34816 +       if (!sess) {
34817 +               /* a session lives for a single request */
34818 +               sess = proxy_session_init();
34819 +
34820 +               con->plugin_ctx[p->id] = sess;
34821 +               con->mode = p->id;
34822 +
34823 +               sess->remote_con = con;
34824 +       }
34825 +
34826 +       return HANDLER_GO_ON;
34827 +}
34828 +
34829 +CONNECTION_FUNC(mod_proxy_core_start_backend) {
34830 +       plugin_data *p = p_d;
34831 +       proxy_session *sess = con->plugin_ctx[p->id];
34832 +
34833 +       if (p->id != con->mode) return HANDLER_GO_ON;
34834 +
34835 +       /* 
34836 +        * 0. build session
34837 +        * 1. get a proxy connection
34838 +        * 2. create the http-request header
34839 +        * 3. stream the content to the backend 
34840 +        * 4. wait for http-response header 
34841 +        * 5. decode the response + parse the response
34842 +        * 6. stream the response-content to the client 
34843 +        * 7. kill session
34844 +        * */
34845 +
34846 +
34847 +       assert(sess);
34848 +
34849 +       if (sess->do_internal_redirect) {
34850 +              if (sess->internal_redirect_count > MAX_INTERNAL_REDIRECTS) {
34851 +                       /* we already handled this request and sent it to the static file handling */
34852 +
34853 +                       return HANDLER_GO_ON;
34854 +               }
34855 +       }
34856 +
34857 +       switch (sess->state) {
34858 +       case PROXY_STATE_CONNECTING:
34859 +               /* this connections is waited 10 seconds to connect to the backend
34860 +                * and didn't got a successful connection yet, sending timeout */
34861 +               if (srv->cur_ts - sess->connect_start_ts > 10) {
34862 +                       con->http_status = 504; /* gateway timeout */
34863 +                       con->send->is_closed = 1;
34864 +
34865 +                       if (sess->proxy_con) {
34866 +                               /* if we are waiting for a proxy-connection right now, close it */
34867 +                               proxy_connection_pool_remove_connection(sess->proxy_backend->pool, sess->proxy_con);
34868 +       
34869 +                               fdevent_event_del(srv->ev, sess->proxy_con->sock);
34870 +                               fdevent_unregister(srv->ev, sess->proxy_con->sock);
34871 +
34872 +                               proxy_connection_free(sess->proxy_con);
34873 +                       
34874 +                               sess->proxy_con = NULL;
34875 +                       }
34876 +
34877 +                       TRACE("%s", "connect to backend timed out");
34878 +                       
34879 +                       return HANDLER_FINISHED;
34880 +               }
34881 +       default:
34882 +               /* handle-request-timeout,  */
34883 +#if 0
34884 +               if (srv->cur_ts - con->request_start > 60) {
34885 +                       TRACE("request runs longer than 60sec: current state: %d", sess->state);
34886 +               }
34887 +#endif
34888 +               break;
34889 +       }
34890 +
34891 +       /* if the WRITE fails from the start, restart the connection */
34892 +       while (1) {
34893 +               if (sess->proxy_con == NULL) {
34894 +                       proxy_address *address = NULL;
34895 +                       if (NULL == (sess->proxy_backend = proxy_get_backend(srv, con, p))) {
34896 +                               /* no connection pool for this location */
34897 +                               SEGFAULT();
34898 +                       }
34899 +
34900 +                       sess->proxy_backend->balancer = p->conf.balancer;
34901 +                       sess->proxy_backend->protocol = p->conf.protocol;
34902 +
34903 +                       /**
34904 +                        * ask the balancer for the next address and
34905 +                        * check the connection pool if we have a connection open
34906 +                        * for that address
34907 +                        */
34908 +                       if (NULL == (address = proxy_backend_balance(srv, con, sess->proxy_backend))) {
34909 +                               /* we don't have any backends to connect to */
34910 +                               proxy_request *req;
34911 +
34912 +                               /* connection pool is full, queue the request for now */
34913 +                               req = proxy_request_init();
34914 +                               req->added_ts = srv->cur_ts;
34915 +                               req->con = con;
34916 +                               
34917 +                               TRACE("backlog: all backends are down, putting %s (%d) into the backlog", BUF_STR(con->uri.path), con->sock->fd);
34918 +                               proxy_backlog_push(p->conf.backlog, req);
34919 +
34920 +                               /* no, not really a event, 
34921 +                                * we just want to block the outer loop from stepping forward
34922 +                                *
34923 +                                * the trigger will bring this connection back into the game
34924 +                                * */
34925 +                               return HANDLER_WAIT_FOR_EVENT;
34926 +                       }
34927 +
34928 +                       if (PROXY_CONNECTIONPOOL_FULL == proxy_connection_pool_get_connection(
34929 +                                               sess->proxy_backend->pool, 
34930 +                                               address,
34931 +                                               &(sess->proxy_con))) {
34932 +                               proxy_request *req;
34933 +
34934 +                               /* connection pool is full, queue the request for now */
34935 +                               req = proxy_request_init();
34936 +                               req->added_ts = srv->cur_ts;
34937 +                               req->con = con;
34938 +                       
34939 +#if 0  
34940 +                               TRACE("backlog: the con-pool is full, putting %s (%d) into the backlog", BUF_STR(con->uri.path), con->sock->fd);
34941 +#endif
34942 +                               proxy_backlog_push(p->conf.backlog, req);
34943 +
34944 +                               /* no, not really a event, 
34945 +                                * we just want to block the outer loop from stepping forward
34946 +                                *
34947 +                                * the trigger will bring this connection back into the game
34948 +                                * */
34949 +                               return HANDLER_WAIT_FOR_EVENT;
34950 +                       }
34951 +
34952 +                       /* a fresh connection, we need address for it */
34953 +                       if (sess->proxy_con->state == PROXY_CONNECTION_STATE_CONNECTING) {
34954 +                               sess->state = PROXY_STATE_UNSET;
34955 +                               sess->bytes_read = 0;
34956 +                       } else {
34957 +                               /* we are already connected */
34958 +                               sess->state = PROXY_STATE_CONNECTED;
34959 +                               
34960 +                               /* the connection was idling and using the fdevent_idle-handler 
34961 +                                * switch it back to the normal proxy-event-handler */
34962 +                               fdevent_event_del(srv->ev, sess->proxy_con->sock);
34963 +                               fdevent_unregister(srv->ev, sess->proxy_con->sock);
34964 +
34965 +                               fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent, sess);
34966 +                               fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
34967 +                       }
34968 +               }
34969 +
34970 +               switch (proxy_state_engine(srv, con, p, sess)) {
34971 +               case HANDLER_WAIT_FOR_EVENT:
34972 +                       return HANDLER_WAIT_FOR_EVENT;
34973 +               case HANDLER_COMEBACK:
34974 +                       proxy_connection_pool_remove_connection(sess->proxy_backend->pool, sess->proxy_con);
34975 +       
34976 +                       fdevent_event_del(srv->ev, sess->proxy_con->sock);
34977 +                       fdevent_unregister(srv->ev, sess->proxy_con->sock);
34978 +
34979 +                       proxy_connection_free(sess->proxy_con);
34980 +
34981 +                       sess->proxy_con = NULL;
34982 +
34983 +                       if (sess->do_internal_redirect) {
34984 +                               con->mode = DIRECT;
34985 +                               con->http_status = 0;
34986 +
34987 +                               return HANDLER_COMEBACK;
34988 +                       }
34989 +                       /* restart the connection to the backend */
34990 +                       TRACE("%s", "write failed, restarting request");
34991 +                       break;
34992 +               case HANDLER_GO_ON:
34993 +                       return HANDLER_GO_ON;
34994 +               default:
34995 +                       TRACE("state: %d (error)", sess->state);
34996 +                       return HANDLER_ERROR;
34997 +               }
34998 +       }
34999 +
35000 +       TRACE("state: %d", sess->state);
35001 +       /* should not be reached */
35002 +       return HANDLER_ERROR;
35003 +}
35004 +
35005 +CONNECTION_FUNC(mod_proxy_send_request_content) {
35006 +       plugin_data *p = p_d;
35007 +       proxy_session *sess = con->plugin_ctx[p->id]; 
35008 +
35009 +       if (p->id != con->mode) return HANDLER_GO_ON;
35010 +
35011 +       /* read all the content before we start our backend */
35012 +       if (!con->recv->is_closed) {
35013 +               return HANDLER_GO_ON;
35014 +       }
35015 +
35016 +       /* copy the chunks to our queue and call the state-engine to send it out */
35017 +       return mod_proxy_core_start_backend(srv, con, p_d);
35018 +}
35019 +/**
35020 + * end of the connection to the client
35021 + */
35022 +REQUESTDONE_FUNC(mod_proxy_connection_close_callback) {
35023 +       plugin_data *p = p_d;
35024 +       
35025 +       if (con->mode != p->id) return HANDLER_GO_ON;
35026 +
35027 +       return HANDLER_GO_ON;
35028 +}
35029 +
35030 +/**
35031 + * end of a request
35032 + */
35033 +CONNECTION_FUNC(mod_proxy_connection_reset) {
35034 +       plugin_data *p = p_d;
35035 +       proxy_session *sess = con->plugin_ctx[p->id]; 
35036 +       proxy_request *req;
35037 +
35038 +       if (!sess) return HANDLER_GO_ON;
35039 +
35040 +       if (sess->proxy_con) {
35041 +               switch (sess->proxy_con->state) {
35042 +               case PROXY_CONNECTION_STATE_CONNECTED:
35043 +                       if (!sess->is_closing) {
35044 +                               sess->proxy_con->state = PROXY_CONNECTION_STATE_IDLE;
35045 +
35046 +                               /* don't ignore events as the FD is idle
35047 +                                * we might get a HUP as the remote connection might close */
35048 +                               fdevent_event_del(srv->ev, sess->proxy_con->sock);
35049 +                               fdevent_unregister(srv->ev, sess->proxy_con->sock);
35050 +
35051 +                               fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent_idle, sess->proxy_con);
35052 +                               fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
35053 +
35054 +                               break;
35055 +                       }
35056 +
35057 +                       /* fall-through for non-keep-alive */
35058 +
35059 +               case PROXY_CONNECTION_STATE_CLOSED:
35060 +                       proxy_connection_pool_remove_connection(sess->proxy_backend->pool, sess->proxy_con);
35061 +       
35062 +                       fdevent_event_del(srv->ev, sess->proxy_con->sock);
35063 +                       fdevent_unregister(srv->ev, sess->proxy_con->sock);
35064 +
35065 +                       proxy_connection_free(sess->proxy_con);
35066 +                       break;
35067 +               case PROXY_CONNECTION_STATE_IDLE:
35068 +                       TRACE("%s", "... connection is already back in the pool");
35069 +                       break;
35070 +               default:
35071 +                       ERROR("connection is in a unexpected state at close-time: %d", sess->proxy_con->state);
35072 +                       break;
35073 +               }
35074 +       } else {
35075 +               /* if we have the connection in the backlog, remove it */
35076 +               proxy_backlog_remove_connection(p->conf.backlog, con);
35077 +       }
35078 +       
35079 +
35080 +       proxy_session_free(sess);
35081 +
35082 +       con->plugin_ctx[p->id] = NULL;
35083 +
35084 +       /* wake up a connection from the backlog */
35085 +       if ((req = proxy_backlog_shift(p->conf.backlog))) {
35086 +               connection *next_con = req->con;
35087 +
35088 +               joblist_append(srv, next_con);
35089 +
35090 +               proxy_request_free(req);
35091 +       }
35092 +
35093 +       
35094 +       return HANDLER_GO_ON;
35095 +}
35096 +
35097 +
35098 +
35099 +/**
35100 + * cleanup dead connections once a second
35101 + *
35102 + * the idling event-handler can't cleanup connections itself and has to wait until the 
35103 + * trigger cleans up
35104 + */
35105 +handler_t mod_proxy_trigger_context(server *srv, plugin_config *p) {
35106 +       size_t i, j;
35107 +       proxy_request *req;
35108 +
35109 +       for (i = 0; i < p->backends->used; i++) {
35110 +               proxy_backend *backend = p->backends->ptr[i];
35111 +               proxy_connection_pool *pool = backend->pool;
35112 +               proxy_address_pool *address_pool = backend->address_pool;
35113 +
35114 +               for (j = 0; j < pool->used; ) {
35115 +                       proxy_connection *proxy_con = pool->ptr[j];
35116 +
35117 +                       /* remove-con is removing the current con and moves the good connections to the left
35118 +                        * no need to increment i */
35119 +                       if (proxy_con->state == PROXY_CONNECTION_STATE_CLOSED) {
35120 +                               proxy_connection_pool_remove_connection(backend->pool, proxy_con);
35121 +       
35122 +                               fdevent_event_del(srv->ev, proxy_con->sock);
35123 +                               fdevent_unregister(srv->ev, proxy_con->sock);
35124 +
35125 +                               proxy_connection_free(proxy_con);
35126 +                       } else {
35127 +                               j++;
35128 +                       }
35129 +               }
35130 +
35131 +               /* active the disabled addresses again */
35132 +               for (j = 0; j < address_pool->used; j++) {
35133 +                       proxy_address *address = address_pool->ptr[j];
35134 +
35135 +                       if (address->state != PROXY_ADDRESS_STATE_DISABLED) continue;
35136 +
35137 +                       if (srv->cur_ts > address->disabled_until) {
35138 +                               address->disabled_until = 0;
35139 +                               address->state = PROXY_ADDRESS_STATE_ACTIVE;
35140 +                       }
35141 +               }
35142 +       }
35143 +
35144 +       /* wake up the connections from the backlog */
35145 +       while ((req = proxy_backlog_shift(p->backlog))) {
35146 +               connection *con = req->con;
35147 +
35148 +               joblist_append(srv, con);
35149 +
35150 +               proxy_request_free(req);
35151 +       }
35152 +       
35153 +       return HANDLER_GO_ON;
35154 +}
35155 +
35156 +TRIGGER_FUNC(mod_proxy_trigger) {
35157 +       plugin_data *p = p_d;
35158 +       size_t i;
35159 +       
35160 +       for (i = 0; i < srv->config_context->used; i++) {
35161 +               mod_proxy_trigger_context(srv, p->config_storage[i]);
35162 +       }
35163 +
35164 +       return HANDLER_GO_ON;
35165 +}
35166 +
35167 +int mod_proxy_core_plugin_init(plugin *p) {
35168 +       p->version      = LIGHTTPD_VERSION_ID;
35169 +       p->name         = buffer_init_string("mod_proxy_core");
35170 +
35171 +       p->init         = mod_proxy_core_init;
35172 +       p->cleanup      = mod_proxy_core_free;
35173 +       p->set_defaults = mod_proxy_core_set_defaults;
35174 +       p->handle_physical         = mod_proxy_core_check_extension;
35175 +       p->handle_send_request_content = mod_proxy_send_request_content;
35176 +       p->connection_reset        = mod_proxy_connection_reset;
35177 +       p->handle_connection_close = mod_proxy_connection_close_callback;
35178 +       p->handle_trigger          = mod_proxy_trigger;
35179 +
35180 +       p->data         = NULL;
35181 +
35182 +       return 0;
35183 +}
35184 --- ../lighttpd-1.4.11/src/mod_proxy_core.h     1970-01-01 03:00:00.000000000 +0300
35185 +++ lighttpd-1.5.0/src/mod_proxy_core.h 2006-09-07 00:57:05.000000000 +0300
35186 @@ -0,0 +1,104 @@
35187 +#ifndef _MOD_PROXY_CORE_H_
35188 +#define _MOD_PROXY_CORE_H_
35189 +
35190 +#include "buffer.h"
35191 +#include "plugin.h"
35192 +#include "http_resp.h"
35193 +#include "array.h"
35194 +
35195 +#include "mod_proxy_core_pool.h"       
35196 +#include "mod_proxy_core_backend.h"
35197 +#include "mod_proxy_core_backlog.h"
35198 +#include "mod_proxy_core_rewrites.h"
35199 +
35200 +#define MAX_INTERNAL_REDIRECTS 8
35201 +
35202 +typedef struct {
35203 +       proxy_backends *backends;
35204 +
35205 +       proxy_backlog *backlog;
35206 +
35207 +       proxy_rewrites *request_rewrites;
35208 +       proxy_rewrites *response_rewrites;
35209 +
35210 +       unsigned short allow_x_sendfile;
35211 +       unsigned short allow_x_rewrite;
35212 +       unsigned short debug;
35213 +       unsigned short max_pool_size;
35214 +
35215 +       proxy_balance_t balancer;
35216 +       proxy_protocol_t protocol;
35217 +} plugin_config;
35218 +
35219 +typedef struct {
35220 +       PLUGIN_DATA;
35221 +
35222 +       http_resp *resp;
35223 +
35224 +       array *possible_balancers;
35225 +       array *possible_protocols;
35226 +
35227 +       /* for parsing only */
35228 +       array *backends_arr;
35229 +       buffer *protocol_buf;
35230 +       buffer *balance_buf;
35231 +
35232 +       buffer *replace_buf;
35233 +
35234 +       buffer *tmp_buf;     /** a temporary buffer, used by mod_proxy_backend_fastcgi */
35235 +
35236 +       plugin_config **config_storage;
35237 +
35238 +       plugin_config conf;
35239 +} plugin_data;
35240 +
35241 +
35242 +typedef enum {
35243 +       PROXY_STATE_UNSET,
35244 +       PROXY_STATE_CONNECTING,
35245 +       PROXY_STATE_CONNECTED,
35246 +       PROXY_STATE_WRITE_REQUEST_HEADER,
35247 +       PROXY_STATE_WRITE_REQUEST_BODY,
35248 +       PROXY_STATE_READ_RESPONSE_HEADER,
35249 +       PROXY_STATE_READ_RESPONSE_BODY
35250 +} proxy_state_t;
35251 +
35252 +typedef struct {
35253 +       proxy_connection *proxy_con;
35254 +       proxy_backend *proxy_backend;
35255 +
35256 +       connection *remote_con;
35257 +
35258 +       array *request_headers;    /** the con->request.headers without the hop-to-hop headers */
35259 +       array *env_headers;        /** transformed request-headers for the backend */
35260 +
35261 +       int is_chunked;            /** is the incoming content chunked (for HTTP) */
35262 +       int is_closing;            /** our connection will close when we are done */
35263 +       int send_response_content; /** 0 if we have to ignore the content-body */
35264 +       int do_internal_redirect;  /** 1 if we do a internal redirect to the ->mode = DIRECT */
35265 +       int internal_redirect_count;  /** protection against infinite loops */
35266 +       
35267 +       /**
35268 +        * chunkqueues
35269 +        * - the encoded_rb is the raw network stuff
35270 +        * - the rb is filtered through the stream decoder
35271 +        *
35272 +        * - wb is the normal bytes stream
35273 +        * - encoded_wb is encoded for the network by the stream encoder
35274 +        */
35275 +       chunkqueue *recv;
35276 +       chunkqueue *recv_raw;
35277 +       chunkqueue *send_raw;
35278 +       chunkqueue *send;
35279 +       
35280 +       off_t bytes_read;
35281 +       off_t content_length;
35282 +
35283 +       proxy_state_t state;
35284 +
35285 +       time_t connect_start_ts;
35286 +} proxy_session;
35287 +
35288 +void proxy_set_header(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len);
35289 +
35290 +#endif
35291 --- ../lighttpd-1.4.11/src/mod_proxy_core_address.c     1970-01-01 03:00:00.000000000 +0300
35292 +++ lighttpd-1.5.0/src/mod_proxy_core_address.c 2006-07-20 00:57:20.000000000 +0300
35293 @@ -0,0 +1,186 @@
35294 +#include <stdlib.h>
35295 +#include <string.h>
35296 +
35297 +#include "log.h"
35298 +#include "sys-socket.h"
35299 +#include "mod_proxy_core_address.h"
35300 +
35301 +proxy_address *proxy_address_init(void) {
35302 +       proxy_address *address;
35303 +
35304 +       address = calloc(1, sizeof(*address));
35305 +
35306 +       address->name = buffer_init();
35307 +
35308 +       return address;
35309 +}
35310 +
35311 +void proxy_address_free(proxy_address *address) {
35312 +       if (!address) return;
35313 +
35314 +       buffer_free(address->name);
35315 +
35316 +       free(address);
35317 +}
35318 +
35319 +
35320 +proxy_address_pool *proxy_address_pool_init(void) {
35321 +       proxy_address_pool *address_pool;
35322 +
35323 +       address_pool = calloc(1, sizeof(*address_pool));
35324 +
35325 +       return address_pool;
35326 +}
35327 +
35328 +void proxy_address_pool_free(proxy_address_pool *address_pool) {
35329 +       if (!address_pool) return;
35330 +
35331 +       FOREACH(address_pool, element, proxy_address_free(element));
35332 +
35333 +       if (address_pool->ptr) free(address_pool->ptr);
35334 +
35335 +       free(address_pool);
35336 +}
35337 +
35338 +void proxy_address_pool_add(proxy_address_pool *address_pool, proxy_address *address) {
35339 +       size_t i;
35340 +
35341 +       /* check if this address is already known */
35342 +
35343 +       for (i = 0; i < address_pool->used; i++) {
35344 +               proxy_address *pool_address = address_pool->ptr[i];
35345 +
35346 +               if (buffer_is_equal(address->name, pool_address->name)) {
35347 +                       TRACE("%s is already in the address-pool", BUF_STR(address->name));
35348 +
35349 +                       proxy_address_free(address);
35350 +
35351 +                       return;
35352 +               }       
35353 +       }
35354 +
35355 +       TRACE("adding %s to the address-pool", BUF_STR(address->name));
35356 +
35357 +       ARRAY_STATIC_PREPARE_APPEND(address_pool);
35358 +
35359 +       address_pool->ptr[address_pool->used++] = address;
35360 +}
35361 +
35362 +int  proxy_address_pool_add_string(proxy_address_pool *address_pool, buffer *name) {
35363 +       struct addrinfo *res = NULL, pref, *cur;
35364 +       int ret;
35365 +       buffer *hostname = NULL, *port = NULL;
35366 +       char *colon;
35367 +
35368 +       pref.ai_flags = 0;
35369 +       pref.ai_family = PF_UNSPEC;
35370 +       pref.ai_socktype = SOCK_STREAM;
35371 +       pref.ai_protocol = 0;
35372 +       pref.ai_addrlen = 0;
35373 +       pref.ai_addr = NULL;
35374 +       pref.ai_canonname = NULL;
35375 +       pref.ai_next = NULL;
35376 +
35377 +       /* check the address style
35378 +        *
35379 +        * unix:/tmp/socket
35380 +        * www.example.org
35381 +        * www.example.org:80
35382 +        * 127.0.0.1
35383 +        * 127.0.0.1:80
35384 +        * [::1]:80
35385 +        * [::1]
35386 +        */
35387 +
35388 +       if (buffer_is_empty(name)) return -1;
35389 +
35390 +       if (0 == strncmp(BUF_STR(name), "unix:", 5)) {
35391 +               /* a unix domain socket */
35392 +               ERROR("unix: scheme is not supported for %s", BUF_STR(name));
35393 +               return -1;
35394 +       } else if (name->ptr[0] == '[') {
35395 +               if (name->ptr[name->used - 1] == ']') {
35396 +                       /* no port-number attached */
35397 +               
35398 +                       hostname = buffer_init();
35399 +                       buffer_copy_string_len(hostname, BUF_STR(name) + 1, name->used - 3);
35400 +                       port = buffer_init_string("80");
35401 +               } else if (NULL != (colon = strrchr(BUF_STR(name), ':'))) {
35402 +                       /* with port number */
35403 +
35404 +                       hostname = buffer_init();
35405 +                       buffer_copy_string_len(hostname, BUF_STR(name) + 1, colon - BUF_STR(name) - 2);
35406 +                       port = buffer_init();
35407 +                       buffer_copy_string(port, colon + 1);
35408 +
35409 +               } else {
35410 +                       ERROR("this is neither [<ipv6-address>] nor [<ipv6-address>]:<port>: %s", BUF_STR(name));
35411 +
35412 +                       return -1;
35413 +               }
35414 +       } else if (name->ptr[name->used - 1] != ']' &&
35415 +                  NULL != (colon = strrchr(BUF_STR(name), ':'))) {
35416 +
35417 +               hostname = buffer_init();
35418 +               buffer_copy_string_len(hostname, BUF_STR(name), colon - BUF_STR(name));
35419 +               port = buffer_init();
35420 +               buffer_copy_string(port, colon + 1);
35421 +       } else {
35422 +               /* no colon, just a IPv4 address or a domain name */
35423 +
35424 +               hostname = buffer_init_string(BUF_STR(name));
35425 +               port = buffer_init_string("80");
35426 +       }
35427 +
35428 +       TRACE("resolving %s on port %s", BUF_STR(hostname), BUF_STR(port));
35429 +       
35430 +       if (0 != (ret = getaddrinfo(BUF_STR(hostname), BUF_STR(port), &pref, &res))) {
35431 +               ERROR("getaddrinfo failed: %s", gai_strerror(ret));
35432 +
35433 +               buffer_free(hostname);
35434 +               buffer_free(port);
35435 +
35436 +               return -1;
35437 +       }
35438 +
35439 +       buffer_free(hostname);
35440 +       buffer_free(port);
35441 +
35442 +       for (cur = res; cur; cur = cur->ai_next) {
35443 +               proxy_address *a = proxy_address_init();
35444 +
35445 +               memcpy(&(a->addr), cur->ai_addr, cur->ai_addrlen);
35446 +
35447 +               a->state = PROXY_ADDRESS_STATE_ACTIVE;
35448 +               buffer_prepare_copy(a->name, 128);
35449 +
35450 +               switch (cur->ai_family) {
35451 +               case AF_INET6:
35452 +                       a->name->ptr[0] = '[';
35453 +                       inet_ntop(cur->ai_family, &(a->addr.ipv6.sin6_addr), a->name->ptr + 1, a->name->size - 2);
35454 +                       a->name->used = strlen(a->name->ptr) + 1;
35455 +                       buffer_append_string(a->name, "]:");
35456 +                       buffer_append_long(a->name, ntohs(a->addr.ipv6.sin6_port));
35457 +                       break;
35458 +               case AF_INET:
35459 +                       inet_ntop(cur->ai_family, &(a->addr.ipv4.sin_addr), a->name->ptr, a->name->size - 1);
35460 +                       a->name->used = strlen(a->name->ptr) + 1;
35461 +
35462 +                       buffer_append_string(a->name, ":");
35463 +                       buffer_append_long(a->name, ntohs(a->addr.ipv4.sin_port));
35464 +                       break;
35465 +               default:
35466 +                       ERROR("unknown address-family: %d", cur->ai_family);
35467 +                       return -1;
35468 +               }
35469 +
35470 +
35471 +               proxy_address_pool_add(address_pool, a);
35472 +       }
35473 +
35474 +       freeaddrinfo(res);
35475 +
35476 +       return 0;
35477 +}
35478 +
35479 +
35480 --- ../lighttpd-1.4.11/src/mod_proxy_core_address.h     1970-01-01 03:00:00.000000000 +0300
35481 +++ lighttpd-1.5.0/src/mod_proxy_core_address.h 2006-07-18 13:03:40.000000000 +0300
35482 @@ -0,0 +1,33 @@
35483 +#ifndef _MOD_PROXY_CORE_ADDRESS_H_
35484 +#define _MOD_PROXY_CORE_ADDRESS_H_
35485 +
35486 +#include <time.h>
35487 +#include "buffer.h"
35488 +#include "sys-socket.h"
35489 +#include "array-static.h"
35490 +
35491 +typedef enum {
35492 +       PROXY_ADDRESS_STATE_UNSET,
35493 +       PROXY_ADDRESS_STATE_ACTIVE,
35494 +       PROXY_ADDRESS_STATE_DISABLED,
35495 +} proxy_address_state_t;
35496 +
35497 +typedef struct {
35498 +       sock_addr addr;
35499 +
35500 +       buffer *name; /* a inet_ntoa() prepresentation of the address */
35501 +
35502 +       time_t last_used;
35503 +       time_t disabled_until;
35504 +
35505 +       proxy_address_state_t state;
35506 +} proxy_address;
35507 +
35508 +ARRAY_STATIC_DEF(proxy_address_pool, proxy_address, );
35509 +
35510 +proxy_address_pool *proxy_address_pool_init(void); 
35511 +void proxy_address_pool_free(proxy_address_pool *address_pool); 
35512 +void proxy_address_pool_add(proxy_address_pool *address_pool, proxy_address *address);
35513 +int proxy_address_pool_add_string(proxy_address_pool *address_pool, buffer *address);
35514 +
35515 +#endif
35516 --- ../lighttpd-1.4.11/src/mod_proxy_core_backend.c     1970-01-01 03:00:00.000000000 +0300
35517 +++ lighttpd-1.5.0/src/mod_proxy_core_backend.c 2006-07-20 00:57:19.000000000 +0300
35518 @@ -0,0 +1,47 @@
35519 +#include <stdlib.h>
35520 +
35521 +#include "mod_proxy_core_backend.h"
35522 +#include "mod_proxy_core_pool.h"
35523 +#include "mod_proxy_core_address.h"
35524 +
35525 +proxy_backend *proxy_backend_init(void) {
35526 +       proxy_backend *backend;
35527 +
35528 +       backend = calloc(1, sizeof(*backend));
35529 +       backend->pool = proxy_connection_pool_init();
35530 +       backend->address_pool = proxy_address_pool_init();
35531 +       backend->balancer = PROXY_BALANCE_RR;
35532 +
35533 +       return backend;
35534 +}
35535 +
35536 +void proxy_backend_free(proxy_backend *backend) {
35537 +       if (!backend) return;
35538 +
35539 +       proxy_address_pool_free(backend->address_pool);
35540 +       proxy_connection_pool_free(backend->pool);
35541 +       
35542 +       free(backend);
35543 +}
35544 +
35545 +proxy_backends *proxy_backends_init(void) {
35546 +       proxy_backends *backends;
35547 +
35548 +       backends = calloc(1, sizeof(*backends));
35549 +
35550 +       return backends;
35551 +}
35552 +
35553 +void proxy_backends_free(proxy_backends *backends) {
35554 +       FOREACH(backends, element, proxy_backend_free(element))
35555 +
35556 +       if (backends->ptr) free(backends->ptr);
35557 +
35558 +       free(backends);
35559 +}
35560 +
35561 +void proxy_backends_add(proxy_backends *backends, proxy_backend *backend) {
35562 +       ARRAY_STATIC_PREPARE_APPEND(backends);
35563 +
35564 +       backends->ptr[backends->used++] = backend;
35565 +}
35566 --- ../lighttpd-1.4.11/src/mod_proxy_core_backend.h     1970-01-01 03:00:00.000000000 +0300
35567 +++ lighttpd-1.5.0/src/mod_proxy_core_backend.h 2006-09-07 00:57:05.000000000 +0300
35568 @@ -0,0 +1,63 @@
35569 +#ifndef _MOD_PROXY_CORE_BACKEND_H_
35570 +#define _MOD_PROXY_CORE_BACKEND_H_
35571 +
35572 +#include "array-static.h"
35573 +#include "buffer.h"
35574 +#include "mod_proxy_core_address.h"
35575 +#include "mod_proxy_core_pool.h"
35576 +#include "sys-socket.h"
35577 +
35578 +/**
35579 + * a single DNS name might explode to several IP addresses 
35580 + * 
35581 + * url: 
35582 + * - http://foo.bar/suburl/
35583 + * - https://foo.bar/suburl/
35584 + * - unix:/tmp/socket
35585 + * - tcp://foobar:1025/
35586 + *
35587 + * backend:
35588 + * - scgi
35589 + * - http
35590 + * - fastcgi
35591 + *
35592 + * request-url-rewrite
35593 + * response-url-rewrite
35594 + */ 
35595 +typedef enum {
35596 +       PROXY_BALANCE_UNSET,
35597 +       PROXY_BALANCE_FAIR,
35598 +       PROXY_BALANCE_HASH,
35599 +       PROXY_BALANCE_RR
35600 +} proxy_balance_t;
35601 +
35602 +typedef enum {
35603 +       PROXY_PROTOCOL_UNSET,
35604 +       PROXY_PROTOCOL_HTTP,
35605 +       PROXY_PROTOCOL_HTTPS,
35606 +       PROXY_PROTOCOL_FASTCGI,
35607 +       PROXY_PROTOCOL_SCGI
35608 +} proxy_protocol_t;
35609 +
35610 +typedef struct {
35611 +       buffer *url;
35612 +
35613 +       proxy_connection_pool *pool;  /* pool of active connections */
35614 +       int use_keepalive;
35615 +
35616 +       proxy_address_pool *address_pool; /* possible destination-addresses, disabling is done here */
35617 +       proxy_balance_t balancer; /* how to choose a address from the address-pool */
35618 +       proxy_protocol_t protocol; /* how to choose a address from the address-pool */
35619 +} proxy_backend;
35620 +
35621 +ARRAY_STATIC_DEF(proxy_backends, proxy_backend, );
35622 +
35623 +proxy_backend *proxy_backend_init(void);
35624 +void proxy_backend_free(proxy_backend *backend);
35625 +
35626 +proxy_backends *proxy_backends_init(void);
35627 +void proxy_backends_free(proxy_backends *backends);
35628 +void proxy_backends_add(proxy_backends *backends, proxy_backend *backend);
35629 +
35630 +#endif
35631 +
35632 --- ../lighttpd-1.4.11/src/mod_proxy_core_backlog.c     1970-01-01 03:00:00.000000000 +0300
35633 +++ lighttpd-1.5.0/src/mod_proxy_core_backlog.c 2006-07-18 13:03:40.000000000 +0300
35634 @@ -0,0 +1,109 @@
35635 +#include <stdlib.h>
35636 +
35637 +#include "mod_proxy_core_backlog.h"
35638 +#include "array-static.h"
35639 +
35640 +proxy_backlog *proxy_backlog_init(void) {
35641 +       STRUCT_INIT(proxy_backlog, backlog);
35642 +
35643 +       return backlog;
35644 +}
35645 +
35646 +void proxy_backlog_free(proxy_backlog *backlog) {
35647 +       if (!backlog) return;
35648 +
35649 +       free(backlog);
35650 +}
35651 +
35652 +int proxy_backlog_push(proxy_backlog *backlog, proxy_request *req) {
35653 +       /* first entry */
35654 +       if (NULL == backlog->first) {
35655 +               backlog->first = backlog->last = req;
35656 +       } else {
35657 +               backlog->last->next = req;
35658 +               backlog->last = req;
35659 +       }
35660 +       backlog->length++;
35661 +
35662 +       return 0;
35663 +}
35664 +
35665 +/**
35666 + * remove the first element from the backlog
35667 + */
35668 +proxy_request *proxy_backlog_shift(proxy_backlog *backlog) {
35669 +       proxy_request *req = NULL;
35670 +
35671 +       if (!backlog->first) return req;
35672 +
35673 +       backlog->length--;
35674 +
35675 +       req = backlog->first;
35676 +
35677 +       backlog->first = req->next;
35678 +
35679 +       /* the backlog is empty */
35680 +       if (backlog->first == NULL) backlog->last = NULL;
35681 +
35682 +       return req;
35683 +}
35684 +
35685 +int proxy_backlog_remove_connection(proxy_backlog *backlog, void *con) {
35686 +       proxy_request *req = NULL;
35687 +
35688 +       if (!backlog->first) return -1;
35689 +       if (!con) return -1;
35690 +
35691 +       /* the first element is what we look for */
35692 +       if (backlog->first->con == con) {
35693 +               req = backlog->first;
35694 +               
35695 +               backlog->first = req->next;
35696 +               if (backlog->first == NULL) backlog->last = NULL;
35697 +
35698 +               backlog->length--;
35699 +               
35700 +               proxy_request_free(req);
35701 +
35702 +               return 0;
35703 +       }
35704 +
35705 +
35706 +       for (req = backlog->first; req && req->next; req = req->next) {
35707 +               proxy_request *cur;
35708 +
35709 +               if (req->next->con != con) continue;
35710 +
35711 +               backlog->length--;
35712 +               /* the next node is our searched connection */
35713 +
35714 +               cur = req->next;
35715 +               req->next = cur->next;
35716 +
35717 +               /* the next node is the last one, make the current the new last */
35718 +               if (cur == backlog->last) {
35719 +                       backlog->last = req;
35720 +               }
35721 +               cur->next = NULL;
35722 +
35723 +               proxy_request_free(req);
35724 +
35725 +               return 0;
35726 +       }
35727 +
35728 +       return -1;
35729 +}
35730 +
35731 +proxy_request *proxy_request_init(void) {
35732 +       STRUCT_INIT(proxy_request, request);
35733 +
35734 +       return request;
35735 +}
35736 +
35737 +void proxy_request_free(proxy_request *request) {
35738 +       if (!request) return;
35739 +
35740 +       free(request);
35741 +}
35742 +
35743 +
35744 --- ../lighttpd-1.4.11/src/mod_proxy_core_backlog.h     1970-01-01 03:00:00.000000000 +0300
35745 +++ lighttpd-1.5.0/src/mod_proxy_core_backlog.h 2006-07-18 13:03:40.000000000 +0300
35746 @@ -0,0 +1,56 @@
35747 +#ifndef _MOD_PROXY_CORE_BACKLOG_H_
35748 +#define _MOD_PROXY_CORE_BACKLOG_H_
35749 +
35750 +#include <sys/types.h>
35751 +#include <sys/time.h>
35752 +
35753 +typedef struct _proxy_request {
35754 +       void *con; /* a pointer to the client-connection, (type: connection) */
35755 +
35756 +       time_t added_ts; /* when was the entry added (for timeout handling) */
35757 +
35758 +       struct _proxy_request *next;
35759 +} proxy_request;
35760 +
35761 +/**
35762 + * a we can't get a connection from the pool, queue the request in the
35763 + * request queue (FIFO)
35764 + *
35765 + * - the queue is infinite
35766 + * - entries are removed after a timeout (status 504)
35767 + */
35768 +typedef struct {
35769 +       proxy_request *first; /* pull() does q->first = q->first->next */
35770 +       proxy_request *last; /* push() does q->last = r */
35771 +
35772 +       size_t length;
35773 +} proxy_backlog;
35774 +
35775 +proxy_backlog *proxy_backlog_init(void);
35776 +void proxy_backlog_free(proxy_backlog *backlog);
35777 +
35778 +/**
35779 + * append a request to the end
35780 + * 
35781 + * @return 0 in success, -1 if full
35782 + */ 
35783 +int proxy_backlog_push(proxy_backlog *backlog, proxy_request *req);
35784 +
35785 +/**
35786 + * remove the first request from the backlog
35787 + *
35788 + * @return NULL if backlog is empty, the request otherwise
35789 + */
35790 +proxy_request *proxy_backlog_shift(proxy_backlog *backlog);
35791 +/**
35792 + * remove the request with the connection 'con' from the backlog
35793 + *
35794 + * @return -1 if not found, 0 otherwise
35795 + */
35796 +int proxy_backlog_remove_connection(proxy_backlog *backlog, void *con);
35797 +
35798 +proxy_request *proxy_request_init(void);
35799 +void proxy_request_free(proxy_request *req);
35800 +
35801 +#endif
35802 +
35803 --- ../lighttpd-1.4.11/src/mod_proxy_core_pool.c        1970-01-01 03:00:00.000000000 +0300
35804 +++ lighttpd-1.5.0/src/mod_proxy_core_pool.c    2006-07-18 13:03:40.000000000 +0300
35805 @@ -0,0 +1,127 @@
35806 +
35807 +#include <stdlib.h>
35808 +
35809 +#include "array-static.h"
35810 +#include "sys-files.h"
35811 +#include "log.h"
35812 +#include "mod_proxy_core_pool.h"
35813 +
35814 +proxy_connection * proxy_connection_init(void) {
35815 +       proxy_connection *con;
35816 +
35817 +       con = calloc(1, sizeof(*con));
35818 +
35819 +       con->sock = iosocket_init();
35820 +
35821 +       return con;
35822 +}
35823 +
35824 +void proxy_connection_free(proxy_connection *con) {
35825 +       if (!con) return;
35826 +
35827 +       iosocket_free(con->sock);
35828 +
35829 +       free(con);
35830 +}
35831 +
35832 +proxy_connection_pool *proxy_connection_pool_init(void) {
35833 +       proxy_connection_pool *pool;
35834 +
35835 +       pool = calloc(1, sizeof(*pool));
35836 +
35837 +               /* default: max parallel connections to the backend
35838 +        * 
35839 +        * this should match max-procs if we manage the procs ourself
35840 +                */
35841 +
35842 +       pool->max_size = 8;
35843 +
35844 +       return pool;
35845 +}
35846 +
35847 +void proxy_connection_pool_free(proxy_connection_pool *pool) {
35848 +       size_t i;
35849 +
35850 +       if (!pool) return;
35851 +
35852 +       for (i = 0; i < pool->used; i++) {
35853 +               proxy_connection_free(pool->ptr[i]);
35854 +       }
35855 +
35856 +       if (pool->size) free(pool->ptr);
35857 +
35858 +       free(pool);
35859 +}
35860 +
35861 +void proxy_connection_pool_add_connection(proxy_connection_pool *pool, proxy_connection *c) {
35862 +       ARRAY_STATIC_PREPARE_APPEND(pool);
35863 +
35864 +       pool->ptr[pool->used++] = c;
35865 +}
35866 +/**
35867 + * remove the connection from the pool
35868 + *
35869 + * usually called on conn-shutdown
35870 + */
35871 +int proxy_connection_pool_remove_connection(proxy_connection_pool *pool, proxy_connection *c) {
35872 +       size_t i;
35873 +
35874 +       if (pool->used == 0) return -1; /* empty */
35875 +
35876 +       for (i = 0; i < pool->used; i++) {
35877 +               if (pool->ptr[i] == c) {
35878 +                       break;
35879 +               }
35880 +       }
35881 +
35882 +       if (i == pool->used) return -1; /* not found */
35883 +
35884 +       /**
35885 +        * move all elements one to the left
35886 +        *
35887 +        * if the last element is going to be removed, skip the loop
35888 +        */
35889 +       for (; i < pool->used - 1; i++) {
35890 +               pool->ptr[i] = pool->ptr[i + 1];
35891 +       }
35892 +
35893 +       pool->used--;
35894 +
35895 +       return 0;
35896 +}
35897 +
35898 +proxy_connection_pool_t proxy_connection_pool_get_connection(proxy_connection_pool *pool, proxy_address *address, proxy_connection **rcon) {
35899 +       proxy_connection *proxy_con = NULL;
35900 +       size_t i;
35901 +
35902 +       /* search for a idling proxy connection with the given address */
35903 +       for (i = 0; i < pool->used; i++) {
35904 +               proxy_con = pool->ptr[i];
35905 +
35906 +               if (proxy_con->address == address &&
35907 +                   proxy_con->state == PROXY_CONNECTION_STATE_IDLE) {
35908 +                       break;
35909 +               }
35910 +       }
35911 +
35912 +       if (i == pool->used) {
35913 +               /* no idling connection found */
35914 +
35915 +               if (pool->used == pool->max_size) return PROXY_CONNECTIONPOOL_FULL;
35916 +               
35917 +               proxy_con = proxy_connection_init();
35918 +
35919 +               proxy_con->state = PROXY_CONNECTION_STATE_CONNECTING;
35920 +               proxy_con->address = address;
35921 +
35922 +               proxy_connection_pool_add_connection(pool, proxy_con);
35923 +       } else {
35924 +               proxy_con->state = PROXY_CONNECTION_STATE_CONNECTED;
35925 +       }
35926 +
35927 +       *rcon = proxy_con;
35928 +
35929 +       return PROXY_CONNECTIONPOOL_GOT_CONNECTION;
35930 +}
35931 +
35932 +
35933 --- ../lighttpd-1.4.11/src/mod_proxy_core_pool.h        1970-01-01 03:00:00.000000000 +0300
35934 +++ lighttpd-1.5.0/src/mod_proxy_core_pool.h    2006-07-18 13:03:40.000000000 +0300
35935 @@ -0,0 +1,52 @@
35936 +#ifndef _MOD_PROXY_CORE_POOL_H_
35937 +#define _MOD_PROXY_CORE_POOL_H_
35938 +
35939 +#include <sys/time.h>
35940 +
35941 +#include "iosocket.h"
35942 +#include "array-static.h"
35943 +#include "mod_proxy_core_address.h"
35944 +
35945 +typedef enum {
35946 +       PROXY_CONNECTION_STATE_UNSET,
35947 +       PROXY_CONNECTION_STATE_CONNECTING,
35948 +       PROXY_CONNECTION_STATE_CONNECTED,
35949 +       PROXY_CONNECTION_STATE_IDLE,
35950 +       PROXY_CONNECTION_STATE_CLOSED,
35951 +} proxy_connection_state_t;
35952 +
35953 +/**
35954 + * a connection to a proxy backend
35955 + * 
35956 + * the connection is independent of the incoming request to allow keep-alive
35957 + */
35958 +typedef struct { 
35959 +       iosocket *sock;
35960 +
35961 +       time_t last_read; /* timeout handling for keep-alive connections */
35962 +       time_t last_write;
35963 +
35964 +       proxy_address *address; /* the struct sock_addr for the sock */
35965 +
35966 +       proxy_connection_state_t state;
35967 +} proxy_connection;
35968 +
35969 +ARRAY_STATIC_DEF(proxy_connection_pool, proxy_connection, size_t max_size;);
35970 +
35971 +typedef enum {
35972 +       PROXY_CONNECTIONPOOL_UNSET,
35973 +       PROXY_CONNECTIONPOOL_FULL,
35974 +       PROXY_CONNECTIONPOOL_GOT_CONNECTION,
35975 +} proxy_connection_pool_t;
35976 +
35977 +proxy_connection_pool *proxy_connection_pool_init(void); 
35978 +void proxy_connection_pool_free(proxy_connection_pool *pool); 
35979 +
35980 +proxy_connection_pool_t proxy_connection_pool_get_connection(proxy_connection_pool *pool, proxy_address *address, proxy_connection **rcon);
35981 +int proxy_connection_pool_remove_connection(proxy_connection_pool *pool, proxy_connection *c);
35982 +
35983 +proxy_connection * proxy_connection_init(void);
35984 +void proxy_connection_free(proxy_connection *pool);
35985 +
35986 +#endif
35987 +
35988 --- ../lighttpd-1.4.11/src/mod_proxy_core_rewrites.c    1970-01-01 03:00:00.000000000 +0300
35989 +++ lighttpd-1.5.0/src/mod_proxy_core_rewrites.c        2006-09-07 00:57:05.000000000 +0300
35990 @@ -0,0 +1,122 @@
35991 +#include <stdlib.h>
35992 +#include <string.h>
35993 +#include <ctype.h>
35994 +
35995 +#include "mod_proxy_core_rewrites.h"
35996 +#include "log.h"
35997 +
35998 +proxy_rewrite *proxy_rewrite_init(void) {
35999 +       STRUCT_INIT(proxy_rewrite, rewrite);
36000 +
36001 +       rewrite->header = buffer_init();
36002 +       rewrite->match = buffer_init();
36003 +       rewrite->replace = buffer_init();
36004 +
36005 +       return rewrite;
36006 +
36007 +}
36008 +void proxy_rewrite_free(proxy_rewrite *rewrite) {
36009 +       if (!rewrite) return;
36010 +
36011 +       if (rewrite->regex) pcre_free(rewrite->regex);
36012 +
36013 +       buffer_free(rewrite->header);
36014 +       buffer_free(rewrite->match);
36015 +       buffer_free(rewrite->replace);
36016 +
36017 +       free(rewrite);
36018 +}
36019 +
36020 +int proxy_rewrite_set_regex(proxy_rewrite *rewrite, buffer *regex) {
36021 +       const char *errptr;
36022 +       int erroff;
36023 +
36024 +       if (NULL == (rewrite->regex = pcre_compile(BUF_STR(regex),
36025 +                 0, &errptr, &erroff, NULL))) {
36026 +               
36027 +               TRACE("regex compilation for %s failed at %s", BUF_STR(regex), errptr);
36028 +
36029 +               return -1;
36030 +       }
36031 +
36032 +       return 0;
36033 +}
36034 +
36035 +
36036 +proxy_rewrites *proxy_rewrites_init(void) {
36037 +       STRUCT_INIT(proxy_rewrites, rewrites);
36038 +
36039 +       return rewrites;
36040 +}
36041 +
36042 +void proxy_rewrites_add(proxy_rewrites *rewrites, proxy_rewrite *rewrite) {
36043 +       ARRAY_STATIC_PREPARE_APPEND(rewrites);
36044 +
36045 +       rewrites->ptr[rewrites->used++] = rewrite;
36046 +}
36047 +
36048 +void proxy_rewrites_free(proxy_rewrites *rewrites) {
36049 +       if (!rewrites) return;
36050 +
36051 +       FOREACH(rewrites, rewrite, proxy_rewrite_free(rewrite))
36052 +
36053 +       if (rewrites->ptr) free(rewrites->ptr);
36054 +
36055 +       free(rewrites);
36056 +}
36057 +
36058 +int pcre_replace(pcre *match, buffer *replace, buffer *match_buf, buffer *result) {
36059 +       const char *pattern = replace->ptr;
36060 +       size_t pattern_len = replace->used - 1;
36061 +
36062 +# define N 10
36063 +       int ovec[N * 3];
36064 +       int n;
36065 +
36066 +       if ((n = pcre_exec(match, NULL, match_buf->ptr, match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
36067 +               if (n != PCRE_ERROR_NOMATCH) {
36068 +                       return n;
36069 +               }
36070 +       } else {
36071 +               const char **list;
36072 +               size_t start, end;
36073 +               size_t k;
36074 +
36075 +               /* it matched */
36076 +               pcre_get_substring_list(match_buf->ptr, ovec, n, &list);
36077 +
36078 +               /* search for $[0-9] */
36079 +
36080 +               buffer_reset(result);
36081 +
36082 +               start = 0; end = pattern_len;
36083 +               for (k = 0; k < pattern_len; k++) {
36084 +                       if ((pattern[k] == '$') &&
36085 +                           isdigit((unsigned char)pattern[k + 1])) {
36086 +                               /* got one */
36087 +
36088 +                               size_t num = pattern[k + 1] - '0';
36089 +
36090 +                               end = k;
36091 +
36092 +                               buffer_append_string_len(result, pattern + start, end - start);
36093 +
36094 +                               /* n is always > 0 */
36095 +                               if (num < (size_t)n) {
36096 +                                       buffer_append_string(result, list[num]);
36097 +                               }
36098 +
36099 +                               k++;
36100 +                               start = k + 1;
36101 +                       }
36102 +               }
36103 +
36104 +               buffer_append_string_len(result, pattern + start, pattern_len - start);
36105 +
36106 +               pcre_free(list);
36107 +       }
36108 +
36109 +       return n;
36110 +}
36111 +
36112 +
36113 --- ../lighttpd-1.4.11/src/mod_proxy_core_rewrites.h    1970-01-01 03:00:00.000000000 +0300
36114 +++ lighttpd-1.5.0/src/mod_proxy_core_rewrites.h        2006-09-07 00:57:05.000000000 +0300
36115 @@ -0,0 +1,30 @@
36116 +#ifndef _MOD_PROXY_CORE_REWRITES_H_
36117 +#define _MOD_PROXY_CORE_REWRITES_H_
36118 +
36119 +#include <pcre.h>
36120 +#include "array-static.h"
36121 +#include "buffer.h"
36122 +
36123 +typedef struct {
36124 +       buffer *header;
36125 +
36126 +       pcre *regex; /* regex compiled from the <match> */
36127 +
36128 +       buffer *match;
36129 +       buffer *replace;
36130 +} proxy_rewrite;
36131 +
36132 +ARRAY_STATIC_DEF(proxy_rewrites, proxy_rewrite,);
36133 +
36134 +proxy_rewrite *proxy_rewrite_init(void);
36135 +void proxy_rewrite_free(proxy_rewrite *rewrite);
36136 +int proxy_rewrite_set_regex(proxy_rewrite *rewrite, buffer *regex);
36137 +
36138 +proxy_rewrites *proxy_rewrites_init(void);
36139 +void proxy_rewrites_add(proxy_rewrites *rewrites, proxy_rewrite *rewrite);
36140 +void proxy_rewrites_free(proxy_rewrites *rewrites);
36141 +
36142 +int pcre_replace(pcre *match, buffer *replace, buffer *match_buf, buffer *result);
36143 +
36144 +#endif
36145 +
36146 --- ../lighttpd-1.4.11/src/mod_redirect.c       2006-02-08 15:38:06.000000000 +0200
36147 +++ lighttpd-1.5.0/src/mod_redirect.c   2006-09-07 00:57:05.000000000 +0300
36148 @@ -22,35 +22,35 @@
36149         PLUGIN_DATA;
36150         buffer *match_buf;
36151         buffer *location;
36152 -       
36153 +
36154         plugin_config **config_storage;
36155 -       
36156 -       plugin_config conf; 
36157 +
36158 +       plugin_config conf;
36159  } plugin_data;
36160  
36161  INIT_FUNC(mod_redirect_init) {
36162         plugin_data *p;
36163 -       
36164 +
36165         p = calloc(1, sizeof(*p));
36166 -       
36167 +
36168         p->match_buf = buffer_init();
36169         p->location = buffer_init();
36170 -       
36171 +
36172         return p;
36173  }
36174  
36175  FREE_FUNC(mod_redirect_free) {
36176         plugin_data *p = p_d;
36177 -       
36178 +
36179         if (!p) return HANDLER_GO_ON;
36180  
36181         if (p->config_storage) {
36182                 size_t i;
36183                 for (i = 0; i < srv->config_context->used; i++) {
36184                         plugin_config *s = p->config_storage[i];
36185 -                       
36186 +
36187                         pcre_keyvalue_buffer_free(s->redirect);
36188 -                       
36189 +
36190                         free(s);
36191                 }
36192                 free(p->config_storage);
36193 @@ -59,9 +59,9 @@
36194  
36195         buffer_free(p->match_buf);
36196         buffer_free(p->location);
36197 -       
36198 +
36199         free(p);
36200 -       
36201 +
36202         return HANDLER_GO_ON;
36203  }
36204  
36205 @@ -69,195 +69,137 @@
36206         plugin_data *p = p_d;
36207         data_unset *du;
36208         size_t i = 0;
36209 -       
36210 -       config_values_t cv[] = { 
36211 +
36212 +       config_values_t cv[] = {
36213                 { "url.redirect",               NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
36214                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
36215         };
36216 -       
36217 +
36218         if (!p) return HANDLER_ERROR;
36219 -       
36220 +
36221         /* 0 */
36222         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
36223 -       
36224 +
36225         for (i = 0; i < srv->config_context->used; i++) {
36226                 plugin_config *s;
36227                 size_t j;
36228                 array *ca;
36229                 data_array *da = (data_array *)du;
36230 -               
36231 +
36232                 s = calloc(1, sizeof(plugin_config));
36233                 s->redirect   = pcre_keyvalue_buffer_init();
36234 -               
36235 +
36236                 cv[0].destination = s->redirect;
36237 -               
36238 +
36239                 p->config_storage[i] = s;
36240                 ca = ((data_config *)srv->config_context->data[i])->value;
36241 -       
36242 +
36243                 if (0 != config_insert_values_global(srv, ca, cv)) {
36244                         return HANDLER_ERROR;
36245                 }
36246 -               
36247 +
36248                 if (NULL == (du = array_get_element(ca, "url.redirect"))) {
36249                         /* no url.redirect defined */
36250                         continue;
36251                 }
36252 -               
36253 +
36254                 if (du->type != TYPE_ARRAY) {
36255 -                       log_error_write(srv, __FILE__, __LINE__, "sss", 
36256 +                       log_error_write(srv, __FILE__, __LINE__, "sss",
36257                                         "unexpected type for key: ", "url.redirect", "array of strings");
36258 -                       
36259 +
36260                         return HANDLER_ERROR;
36261                 }
36262 -               
36263 +
36264                 da = (data_array *)du;
36265 -                               
36266 +
36267                 for (j = 0; j < da->value->used; j++) {
36268                         if (da->value->data[j]->type != TYPE_STRING) {
36269 -                               log_error_write(srv, __FILE__, __LINE__, "sssbs", 
36270 -                                               "unexpected type for key: ", 
36271 -                                               "url.redirect", 
36272 +                               log_error_write(srv, __FILE__, __LINE__, "sssbs",
36273 +                                               "unexpected type for key: ",
36274 +                                               "url.redirect",
36275                                                 "[", da->value->data[j]->key, "](string)");
36276 -                               
36277 +
36278                                 return HANDLER_ERROR;
36279                         }
36280 -                               
36281 -                       if (0 != pcre_keyvalue_buffer_append(s->redirect, 
36282 +
36283 +                       if (0 != pcre_keyvalue_buffer_append(s->redirect,
36284                                                              ((data_string *)(da->value->data[j]))->key->ptr,
36285                                                              ((data_string *)(da->value->data[j]))->value->ptr)) {
36286 -                                       
36287 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
36288 +
36289 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
36290                                                 "pcre-compile failed for", da->value->data[j]->key);
36291                         }
36292                 }
36293         }
36294 -       
36295 +
36296         return HANDLER_GO_ON;
36297  }
36298  #ifdef HAVE_PCRE_H
36299  static int mod_redirect_patch_connection(server *srv, connection *con, plugin_data *p) {
36300         size_t i, j;
36301         plugin_config *s = p->config_storage[0];
36302 -       
36303 +
36304         p->conf.redirect = s->redirect;
36305 -       
36306 +
36307         /* skip the first, the global context */
36308         for (i = 1; i < srv->config_context->used; i++) {
36309                 data_config *dc = (data_config *)srv->config_context->data[i];
36310                 s = p->config_storage[i];
36311 -               
36312 +
36313                 /* condition didn't match */
36314                 if (!config_check_cond(srv, con, dc)) continue;
36315 -               
36316 +
36317                 /* merge config */
36318                 for (j = 0; j < dc->value->used; j++) {
36319                         data_unset *du = dc->value->data[j];
36320 -                       
36321 +
36322                         if (0 == strcmp(du->key->ptr, "url.redirect")) {
36323                                 p->conf.redirect = s->redirect;
36324                                 p->conf.context = dc;
36325                         }
36326                 }
36327         }
36328 -       
36329 +
36330         return 0;
36331  }
36332  #endif
36333  static handler_t mod_redirect_uri_handler(server *srv, connection *con, void *p_data) {
36334  #ifdef HAVE_PCRE_H
36335         plugin_data *p = p_data;
36336 -       size_t i;
36337 +       int i;
36338  
36339 -       /* 
36340 +       /*
36341          * REWRITE URL
36342 -        * 
36343 +        *
36344          * e.g. redirect /base/ to /index.php?section=base
36345 -        * 
36346 +        *
36347          */
36348 -       
36349 +
36350         mod_redirect_patch_connection(srv, con, p);
36351 -       
36352 +
36353         buffer_copy_string_buffer(p->match_buf, con->request.uri);
36354 -       
36355 -       for (i = 0; i < p->conf.redirect->used; i++) {
36356 -               pcre *match;
36357 -               pcre_extra *extra;
36358 -               const char *pattern;
36359 -               size_t pattern_len;
36360 -               int n;
36361 -               pcre_keyvalue *kv = p->conf.redirect->kv[i];
36362 -# define N 10
36363 -               int ovec[N * 3];
36364 -               
36365 -               match       = kv->key;
36366 -               extra       = kv->key_extra;
36367 -               pattern     = kv->value->ptr;
36368 -               pattern_len = kv->value->used - 1;
36369 -               
36370 -               if ((n = pcre_exec(match, extra, p->match_buf->ptr, p->match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
36371 -                       if (n != PCRE_ERROR_NOMATCH) {
36372 -                               log_error_write(srv, __FILE__, __LINE__, "sd",
36373 -                                               "execution error while matching: ", n);
36374 -                               return HANDLER_ERROR;
36375 -                       }
36376 -               } else {
36377 -                       const char **list;
36378 -                       size_t start, end;
36379 -                       size_t k;
36380 -                       
36381 -                       /* it matched */
36382 -                       pcre_get_substring_list(p->match_buf->ptr, ovec, n, &list);
36383 -                       
36384 -                       /* search for $[0-9] */
36385 -                       
36386 -                       buffer_reset(p->location);
36387 -                       
36388 -                       start = 0; end = pattern_len;
36389 -                       for (k = 0; k < pattern_len; k++) {
36390 -                               if ((pattern[k] == '$' || pattern[k] == '%') &&
36391 -                                   isdigit((unsigned char)pattern[k + 1])) {
36392 -                                       /* got one */
36393 -                                       
36394 -                                       size_t num = pattern[k + 1] - '0';
36395 -                                       
36396 -                                       end = k;
36397 -                                       
36398 -                                       buffer_append_string_len(p->location, pattern + start, end - start);
36399 -                                       
36400 -                                       if (pattern[k] == '$') {
36401 -                                               /* n is always > 0 */
36402 -                                               if (num < (size_t)n) {
36403 -                                                       buffer_append_string(p->location, list[num]);
36404 -                                               }
36405 -                                       } else {
36406 -                                               config_append_cond_match_buffer(con, p->conf.context, p->location, num);
36407 -                                       }
36408 -                                       
36409 -                                       k++;
36410 -                                       start = k + 1;
36411 -                               } 
36412 -                       }
36413 -                       
36414 -                       buffer_append_string_len(p->location, pattern + start, pattern_len - start);
36415 -                       
36416 -                       pcre_free(list);
36417 -                       
36418 -                       response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->location));
36419 -                       
36420 -                       con->http_status = 301;
36421 -                       con->file_finished = 1;
36422 -                       
36423 -                       return HANDLER_FINISHED;
36424 -               }
36425 +       i = config_exec_pcre_keyvalue_buffer(con, p->conf.redirect, p->conf.context, p->match_buf, p->location);
36426 +
36427 +       if (i >= 0) {
36428 +               response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->location));
36429 +
36430 +               con->http_status = 301;
36431 +               con->send->is_closed = 1;
36432 +
36433 +               return HANDLER_FINISHED;
36434 +       }
36435 +       else if (i != PCRE_ERROR_NOMATCH) {
36436 +               log_error_write(srv, __FILE__, __LINE__, "s",
36437 +                               "execution error while matching", i);
36438         }
36439  #undef N
36440 -               
36441 +
36442  #else
36443         UNUSED(srv);
36444         UNUSED(con);
36445         UNUSED(p_data);
36446  #endif
36447 -       
36448 +
36449         return HANDLER_GO_ON;
36450  }
36451  
36452 @@ -265,13 +207,13 @@
36453  int mod_redirect_plugin_init(plugin *p) {
36454         p->version     = LIGHTTPD_VERSION_ID;
36455         p->name        = buffer_init_string("redirect");
36456 -       
36457 +
36458         p->init        = mod_redirect_init;
36459         p->handle_uri_clean  = mod_redirect_uri_handler;
36460         p->set_defaults  = mod_redirect_set_defaults;
36461         p->cleanup     = mod_redirect_free;
36462 -       
36463 +
36464         p->data        = NULL;
36465 -       
36466 +
36467         return 0;
36468  }
36469 --- ../lighttpd-1.4.11/src/mod_rewrite.c        2005-09-29 20:59:10.000000000 +0300
36470 +++ lighttpd-1.5.0/src/mod_rewrite.c    2006-07-16 00:26:03.000000000 +0300
36471 @@ -13,24 +13,8 @@
36472  #endif
36473  
36474  typedef struct {
36475 -#ifdef HAVE_PCRE_H
36476 -       pcre *key;
36477 -#endif
36478 -       
36479 -       buffer *value;
36480 -       
36481 -       int once;
36482 -} rewrite_rule;
36483 -
36484 -typedef struct {
36485 -       rewrite_rule **ptr;
36486 -       
36487 -       size_t used;
36488 -       size_t size;
36489 -} rewrite_rule_buffer;
36490 -
36491 -typedef struct {
36492 -       rewrite_rule_buffer *rewrite;
36493 +       pcre_keyvalue_buffer *rewrite;
36494 +       buffer *once;
36495         data_config *context; /* to which apply me */
36496  } plugin_config;
36497  
36498 @@ -42,20 +26,20 @@
36499  typedef struct {
36500         PLUGIN_DATA;
36501         buffer *match_buf;
36502 -       
36503 +
36504         plugin_config **config_storage;
36505 -       
36506 -       plugin_config conf; 
36507 +
36508 +       plugin_config conf;
36509  } plugin_data;
36510  
36511  static handler_ctx * handler_ctx_init() {
36512         handler_ctx * hctx;
36513 -       
36514 +
36515         hctx = calloc(1, sizeof(*hctx));
36516 -       
36517 +
36518         hctx->state = REWRITE_STATE_UNSET;
36519         hctx->loops = 0;
36520 -       
36521 +
36522         return hctx;
36523  }
36524  
36525 @@ -63,207 +47,136 @@
36526         free(hctx);
36527  }
36528  
36529 -rewrite_rule_buffer *rewrite_rule_buffer_init(void) {
36530 -       rewrite_rule_buffer *kvb;
36531 -       
36532 -       kvb = calloc(1, sizeof(*kvb));
36533 -       
36534 -       return kvb;
36535 -}
36536 -
36537 -int rewrite_rule_buffer_append(rewrite_rule_buffer *kvb, buffer *key, buffer *value, int once) {
36538 -#ifdef HAVE_PCRE_H
36539 -       size_t i;
36540 -       const char *errptr;
36541 -       int erroff;
36542 -       
36543 -       if (!key) return -1;
36544 -
36545 -       if (kvb->size == 0) {
36546 -               kvb->size = 4;
36547 -               kvb->used = 0;
36548 -               
36549 -               kvb->ptr = malloc(kvb->size * sizeof(*kvb->ptr));
36550 -               
36551 -               for(i = 0; i < kvb->size; i++) {
36552 -                       kvb->ptr[i] = calloc(1, sizeof(**kvb->ptr));
36553 -               }
36554 -       } else if (kvb->used == kvb->size) {
36555 -               kvb->size += 4;
36556 -               
36557 -               kvb->ptr = realloc(kvb->ptr, kvb->size * sizeof(*kvb->ptr));
36558 -               
36559 -               for(i = kvb->used; i < kvb->size; i++) {
36560 -                       kvb->ptr[i] = calloc(1, sizeof(**kvb->ptr));
36561 -               }
36562 -       }
36563 -       
36564 -       if (NULL == (kvb->ptr[kvb->used]->key = pcre_compile(key->ptr,
36565 -                                                           0, &errptr, &erroff, NULL))) {
36566 -               
36567 -               return -1;
36568 -       }
36569 -       
36570 -       kvb->ptr[kvb->used]->value = buffer_init();
36571 -       buffer_copy_string_buffer(kvb->ptr[kvb->used]->value, value);
36572 -       kvb->ptr[kvb->used]->once = once;
36573 -       
36574 -       kvb->used++;
36575 -       
36576 -       return 0;
36577 -#else
36578 -       UNUSED(kvb);
36579 -       UNUSED(value);
36580 -       UNUSED(once);
36581 -       UNUSED(key);
36582 -
36583 -       return -1;
36584 -#endif
36585 -}
36586 -
36587 -void rewrite_rule_buffer_free(rewrite_rule_buffer *kvb) {
36588 -#ifdef HAVE_PCRE_H
36589 -       size_t i;
36590 -
36591 -       for (i = 0; i < kvb->size; i++) {
36592 -               if (kvb->ptr[i]->key) pcre_free(kvb->ptr[i]->key);
36593 -               if (kvb->ptr[i]->value) buffer_free(kvb->ptr[i]->value);
36594 -               free(kvb->ptr[i]);
36595 -       }
36596 -       
36597 -       if (kvb->ptr) free(kvb->ptr);
36598 -#endif
36599 -       
36600 -       free(kvb);
36601 -}
36602 -
36603  
36604  INIT_FUNC(mod_rewrite_init) {
36605         plugin_data *p;
36606 -       
36607 +
36608         p = calloc(1, sizeof(*p));
36609 -       
36610 +
36611         p->match_buf = buffer_init();
36612 -       
36613 +
36614         return p;
36615  }
36616  
36617  FREE_FUNC(mod_rewrite_free) {
36618         plugin_data *p = p_d;
36619 -       
36620 +
36621         UNUSED(srv);
36622  
36623         if (!p) return HANDLER_GO_ON;
36624 -       
36625 +
36626         buffer_free(p->match_buf);
36627         if (p->config_storage) {
36628                 size_t i;
36629                 for (i = 0; i < srv->config_context->used; i++) {
36630                         plugin_config *s = p->config_storage[i];
36631 -                       rewrite_rule_buffer_free(s->rewrite);
36632 -                       
36633 +                       pcre_keyvalue_buffer_free(s->rewrite);
36634 +                       buffer_free(s->once);
36635 +
36636                         free(s);
36637                 }
36638                 free(p->config_storage);
36639         }
36640 -       
36641 +
36642         free(p);
36643 -       
36644 +
36645         return HANDLER_GO_ON;
36646  }
36647  
36648  static int parse_config_entry(server *srv, plugin_config *s, array *ca, const char *option, int once) {
36649         data_unset *du;
36650 -       
36651 +
36652         if (NULL != (du = array_get_element(ca, option))) {
36653                 data_array *da = (data_array *)du;
36654                 size_t j;
36655 -               
36656 +
36657                 if (du->type != TYPE_ARRAY) {
36658 -                       log_error_write(srv, __FILE__, __LINE__, "sss", 
36659 +                       log_error_write(srv, __FILE__, __LINE__, "sss",
36660                                         "unexpected type for key: ", option, "array of strings");
36661 -                       
36662 +
36663                         return HANDLER_ERROR;
36664                 }
36665 -               
36666 +
36667                 da = (data_array *)du;
36668 -               
36669 +
36670                 for (j = 0; j < da->value->used; j++) {
36671                         if (da->value->data[j]->type != TYPE_STRING) {
36672 -                               log_error_write(srv, __FILE__, __LINE__, "sssbs", 
36673 -                                               "unexpected type for key: ", 
36674 -                                               option, 
36675 +                               log_error_write(srv, __FILE__, __LINE__, "sssbs",
36676 +                                               "unexpected type for key: ",
36677 +                                               option,
36678                                                 "[", da->value->data[j]->key, "](string)");
36679 -                               
36680 +
36681                                 return HANDLER_ERROR;
36682                         }
36683 -                       
36684 -                       if (0 != rewrite_rule_buffer_append(s->rewrite, 
36685 -                                                           ((data_string *)(da->value->data[j]))->key,
36686 -                                                           ((data_string *)(da->value->data[j]))->value,
36687 -                                                           once)) {
36688 +
36689 +                       if (0 != pcre_keyvalue_buffer_append(s->rewrite,
36690 +                                                           ((data_string *)(da->value->data[j]))->key->ptr,
36691 +                                                           ((data_string *)(da->value->data[j]))->value->ptr)) {
36692  #ifdef HAVE_PCRE_H
36693 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
36694 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
36695                                                 "pcre-compile failed for", da->value->data[j]->key);
36696  #else
36697 -                               log_error_write(srv, __FILE__, __LINE__, "s", 
36698 +                               log_error_write(srv, __FILE__, __LINE__, "s",
36699                                                 "pcre support is missing, please install libpcre and the headers");
36700  #endif
36701                         }
36702 +
36703 +                       if (once) {
36704 +                               buffer_append_string_len(s->once, CONST_STR_LEN("1"));
36705 +                       } else {
36706 +                               buffer_append_string_len(s->once, CONST_STR_LEN("0"));
36707 +                       }
36708                 }
36709         }
36710 -       
36711 +
36712         return 0;
36713  }
36714  
36715  SETDEFAULTS_FUNC(mod_rewrite_set_defaults) {
36716         plugin_data *p = p_d;
36717         size_t i = 0;
36718 -       
36719 -       config_values_t cv[] = { 
36720 +
36721 +       config_values_t cv[] = {
36722                 { "url.rewrite-repeat",        NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
36723                 { "url.rewrite-once",          NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
36724 -               
36725 -               /* old names, still supported 
36726 -                * 
36727 +
36728 +               /* old names, still supported
36729 +                *
36730                  * url.rewrite remapped to url.rewrite-once
36731                  * url.rewrite-final    is url.rewrite-once
36732 -                * 
36733 +                *
36734                  */
36735                 { "url.rewrite",               NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
36736                 { "url.rewrite-final",         NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
36737                 { NULL,                        NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
36738         };
36739 -       
36740 +
36741         if (!p) return HANDLER_ERROR;
36742 -       
36743 +
36744         /* 0 */
36745         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
36746 -       
36747 +
36748         for (i = 0; i < srv->config_context->used; i++) {
36749                 plugin_config *s;
36750                 array *ca;
36751 -               
36752 +
36753                 s = calloc(1, sizeof(plugin_config));
36754 -               s->rewrite   = rewrite_rule_buffer_init();
36755 -               
36756 -               cv[0].destination = s->rewrite;
36757 -               cv[1].destination = s->rewrite;
36758 -               cv[2].destination = s->rewrite;
36759 -               
36760 +               s->rewrite   = pcre_keyvalue_buffer_init();
36761 +               s->once      = buffer_init();
36762 +
36763                 p->config_storage[i] = s;
36764                 ca = ((data_config *)srv->config_context->data[i])->value;
36765 -       
36766 +
36767                 if (0 != config_insert_values_global(srv, ca, cv)) {
36768                         return HANDLER_ERROR;
36769                 }
36770 -               
36771 +
36772                 parse_config_entry(srv, s, ca, "url.rewrite-once",   1);
36773                 parse_config_entry(srv, s, ca, "url.rewrite-final",  1);
36774                 parse_config_entry(srv, s, ca, "url.rewrite",        1);
36775                 parse_config_entry(srv, s, ca, "url.rewrite-repeat", 0);
36776         }
36777 -       
36778 +
36779         return HANDLER_GO_ON;
36780  }
36781  #ifdef HAVE_PCRE_H
36782 @@ -271,157 +184,107 @@
36783         size_t i, j;
36784         plugin_config *s = p->config_storage[0];
36785         p->conf.rewrite = s->rewrite;
36786 -       
36787 +       p->conf.once    = s->once;
36788 +
36789         /* skip the first, the global context */
36790         for (i = 1; i < srv->config_context->used; i++) {
36791                 data_config *dc = (data_config *)srv->config_context->data[i];
36792                 s = p->config_storage[i];
36793 -               
36794 +
36795                 if (COMP_HTTP_URL == dc->comp) continue;
36796 -               
36797 +
36798                 /* condition didn't match */
36799                 if (!config_check_cond(srv, con, dc)) continue;
36800 -               
36801 +
36802                 /* merge config */
36803                 for (j = 0; j < dc->value->used; j++) {
36804                         data_unset *du = dc->value->data[j];
36805 -                       
36806 +
36807                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite"))) {
36808                                 p->conf.rewrite = s->rewrite;
36809 +                               p->conf.once    = s->once;
36810                                 p->conf.context = dc;
36811                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-once"))) {
36812                                 p->conf.rewrite = s->rewrite;
36813 +                               p->conf.once    = s->once;
36814                                 p->conf.context = dc;
36815                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-repeat"))) {
36816                                 p->conf.rewrite = s->rewrite;
36817 +                               p->conf.once    = s->once;
36818                                 p->conf.context = dc;
36819                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-final"))) {
36820                                 p->conf.rewrite = s->rewrite;
36821 +                               p->conf.once    = s->once;
36822                                 p->conf.context = dc;
36823                         }
36824                 }
36825         }
36826 -       
36827 +
36828         return 0;
36829  }
36830  #endif
36831  URIHANDLER_FUNC(mod_rewrite_con_reset) {
36832         plugin_data *p = p_d;
36833 -       
36834 +
36835         UNUSED(srv);
36836 -       
36837 +
36838         if (con->plugin_ctx[p->id]) {
36839                 handler_ctx_free(con->plugin_ctx[p->id]);
36840                 con->plugin_ctx[p->id] = NULL;
36841         }
36842 -       
36843 +
36844         return HANDLER_GO_ON;
36845  }
36846  
36847  URIHANDLER_FUNC(mod_rewrite_uri_handler) {
36848  #ifdef HAVE_PCRE_H
36849         plugin_data *p = p_d;
36850 -       size_t i;
36851 +       int i;
36852         handler_ctx *hctx;
36853  
36854 -       /* 
36855 +       /*
36856          * REWRITE URL
36857 -        * 
36858 +        *
36859          * e.g. rewrite /base/ to /index.php?section=base
36860 -        * 
36861 +        *
36862          */
36863 -       
36864 +
36865         if (con->plugin_ctx[p->id]) {
36866                 hctx = con->plugin_ctx[p->id];
36867 -               
36868 +
36869                 if (hctx->loops++ > 100) {
36870 -                       log_error_write(srv, __FILE__, __LINE__,  "s",  
36871 +                       log_error_write(srv, __FILE__, __LINE__,  "s",
36872                                         "ENDLESS LOOP IN rewrite-rule DETECTED ... aborting request, perhaps you want to use url.rewrite-once instead of url.rewrite-repeat");
36873 -                       
36874 +
36875                         return HANDLER_ERROR;
36876                 }
36877 -               
36878 +
36879                 if (hctx->state == REWRITE_STATE_FINISHED) return HANDLER_GO_ON;
36880         }
36881 -       
36882 +
36883         mod_rewrite_patch_connection(srv, con, p);
36884  
36885         if (!p->conf.rewrite) return HANDLER_GO_ON;
36886 -       
36887 +
36888         buffer_copy_string_buffer(p->match_buf, con->request.uri);
36889 -       
36890 -       for (i = 0; i < p->conf.rewrite->used; i++) {
36891 -               pcre *match;
36892 -               const char *pattern;
36893 -               size_t pattern_len;
36894 -               int n;
36895 -               rewrite_rule *rule = p->conf.rewrite->ptr[i];
36896 -# define N 10
36897 -               int ovec[N * 3];
36898 -               
36899 -               match       = rule->key;
36900 -               pattern     = rule->value->ptr;
36901 -               pattern_len = rule->value->used - 1;
36902 -               
36903 -               if ((n = pcre_exec(match, NULL, p->match_buf->ptr, p->match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
36904 -                       if (n != PCRE_ERROR_NOMATCH) {
36905 -                               log_error_write(srv, __FILE__, __LINE__, "sd",
36906 -                                               "execution error while matching: ", n);
36907 -                               return HANDLER_ERROR;
36908 -                       }
36909 -               } else {
36910 -                       const char **list;
36911 -                       size_t start, end;
36912 -                       size_t k;
36913 -                       
36914 -                       /* it matched */
36915 -                       pcre_get_substring_list(p->match_buf->ptr, ovec, n, &list);
36916 -                       
36917 -                       /* search for $[0-9] */
36918 -                       
36919 -                       buffer_reset(con->request.uri);
36920 -                       
36921 -                       start = 0; end = pattern_len;
36922 -                       for (k = 0; k < pattern_len; k++) {
36923 -                               if ((pattern[k] == '$' || pattern[k] == '%') &&
36924 -                                   isdigit((unsigned char)pattern[k + 1])) {
36925 -                                       /* got one */
36926 -                                       
36927 -                                       size_t num = pattern[k + 1] - '0';
36928 -                                       
36929 -                                       end = k;
36930 -                                       
36931 -                                       buffer_append_string_len(con->request.uri, pattern + start, end - start);
36932 -                                       
36933 -                                       if (pattern[k] == '$') {
36934 -                                               /* n is always > 0 */
36935 -                                               if (num < (size_t)n) {
36936 -                                                       buffer_append_string(con->request.uri, list[num]);
36937 -                                               }
36938 -                                       } else {
36939 -                                               config_append_cond_match_buffer(con, p->conf.context, con->request.uri, num);
36940 -                                       }
36941 -                                       
36942 -                                       k++;
36943 -                                       start = k + 1;
36944 -                               } 
36945 -                       }
36946 -                       
36947 -                       buffer_append_string_len(con->request.uri, pattern + start, pattern_len - start);
36948 -                       
36949 -                       pcre_free(list);
36950 -                       
36951 -                       hctx = handler_ctx_init();
36952 -                               
36953 -                       con->plugin_ctx[p->id] = hctx;
36954 -                       
36955 -                       if (rule->once) hctx->state = REWRITE_STATE_FINISHED;
36956 -                       
36957 -                       return HANDLER_COMEBACK;
36958 -               }
36959 +       i = config_exec_pcre_keyvalue_buffer(con, p->conf.rewrite, p->conf.context, p->match_buf, con->request.uri);
36960 +
36961 +       if (i >= 0) {
36962 +               hctx = handler_ctx_init();
36963 +
36964 +               con->plugin_ctx[p->id] = hctx;
36965 +
36966 +               if (p->conf.once->ptr[i] == '1')
36967 +                       hctx->state = REWRITE_STATE_FINISHED;
36968 +
36969 +               return HANDLER_COMEBACK;
36970 +       }
36971 +       else if (i != PCRE_ERROR_NOMATCH) {
36972 +               log_error_write(srv, __FILE__, __LINE__, "s",
36973 +                               "execution error while matching", i);
36974         }
36975  #undef N
36976 -               
36977 +
36978  #else
36979         UNUSED(srv);
36980         UNUSED(con);
36981 @@ -434,17 +297,17 @@
36982  int mod_rewrite_plugin_init(plugin *p) {
36983         p->version     = LIGHTTPD_VERSION_ID;
36984         p->name        = buffer_init_string("rewrite");
36985 -       
36986 +
36987         p->init        = mod_rewrite_init;
36988         /* it has to stay _raw as we are matching on uri + querystring
36989          */
36990 -       
36991 +
36992         p->handle_uri_raw = mod_rewrite_uri_handler;
36993         p->set_defaults = mod_rewrite_set_defaults;
36994         p->cleanup     = mod_rewrite_free;
36995         p->connection_reset = mod_rewrite_con_reset;
36996 -       
36997 +
36998         p->data        = NULL;
36999 -       
37000 +
37001         return 0;
37002  }
37003 --- ../lighttpd-1.4.11/src/mod_rrdtool.c        2005-08-22 01:52:24.000000000 +0300
37004 +++ lighttpd-1.5.0/src/mod_rrdtool.c    2006-09-07 00:57:05.000000000 +0300
37005 @@ -5,7 +5,6 @@
37006  #include <stdlib.h>
37007  #include <stdio.h>
37008  #include <string.h>
37009 -#include <unistd.h>
37010  #include <errno.h>
37011  #include <time.h>
37012  
37013 @@ -20,10 +19,14 @@
37014  /* no need for waitpid if we don't have fork */
37015  #include <sys/wait.h>
37016  #endif
37017 +
37018 +#include "sys-files.h"
37019 +#include "sys-process.h"
37020 +
37021  typedef struct {
37022         buffer *path_rrdtool_bin;
37023         buffer *path_rrd;
37024 -       
37025 +
37026         double requests, *requests_ptr;
37027         double bytes_written, *bytes_written_ptr;
37028         double bytes_read, *bytes_read_ptr;
37029 @@ -31,84 +34,84 @@
37030  
37031  typedef struct {
37032         PLUGIN_DATA;
37033 -       
37034 +
37035         buffer *cmd;
37036         buffer *resp;
37037 -       
37038 +
37039         int read_fd, write_fd;
37040         pid_t rrdtool_pid;
37041 -       
37042 +
37043         int rrdtool_running;
37044 -       
37045 +
37046         plugin_config **config_storage;
37047         plugin_config conf;
37048  } plugin_data;
37049  
37050  INIT_FUNC(mod_rrd_init) {
37051         plugin_data *p;
37052 -       
37053 +
37054         p = calloc(1, sizeof(*p));
37055 -       
37056 +
37057         p->resp = buffer_init();
37058         p->cmd = buffer_init();
37059 -       
37060 +
37061         return p;
37062  }
37063  
37064  FREE_FUNC(mod_rrd_free) {
37065         plugin_data *p = p_d;
37066         size_t i;
37067 -       
37068 +
37069         if (!p) return HANDLER_GO_ON;
37070 -       
37071 +
37072         if (p->config_storage) {
37073                 for (i = 0; i < srv->config_context->used; i++) {
37074                         plugin_config *s = p->config_storage[i];
37075 -                       
37076 +
37077                         buffer_free(s->path_rrdtool_bin);
37078                         buffer_free(s->path_rrd);
37079 -                       
37080 +
37081                         free(s);
37082                 }
37083         }
37084         buffer_free(p->cmd);
37085         buffer_free(p->resp);
37086 -       
37087 +
37088         free(p->config_storage);
37089 -       
37090 +
37091         if (p->rrdtool_pid) {
37092                 int status;
37093                 close(p->read_fd);
37094                 close(p->write_fd);
37095 -#ifdef HAVE_FORK       
37096 +#ifdef HAVE_FORK
37097                 /* collect status */
37098                 waitpid(p->rrdtool_pid, &status, 0);
37099  #endif
37100         }
37101 -       
37102 +
37103         free(p);
37104 -       
37105 +
37106         return HANDLER_GO_ON;
37107  }
37108  
37109  int mod_rrd_create_pipe(server *srv, plugin_data *p) {
37110         pid_t pid;
37111 -       
37112 +
37113         int to_rrdtool_fds[2];
37114         int from_rrdtool_fds[2];
37115 -#ifdef HAVE_FORK       
37116 +#ifdef HAVE_FORK
37117         if (pipe(to_rrdtool_fds)) {
37118 -               log_error_write(srv, __FILE__, __LINE__, "ss", 
37119 +               log_error_write(srv, __FILE__, __LINE__, "ss",
37120                                 "pipe failed: ", strerror(errno));
37121                 return -1;
37122         }
37123 -       
37124 +
37125         if (pipe(from_rrdtool_fds)) {
37126 -               log_error_write(srv, __FILE__, __LINE__, "ss", 
37127 +               log_error_write(srv, __FILE__, __LINE__, "ss",
37128                                 "pipe failed: ", strerror(errno));
37129                 return -1;
37130         }
37131 -       
37132 +
37133         /* fork, execve */
37134         switch (pid = fork()) {
37135         case 0: {
37136 @@ -117,33 +120,28 @@
37137                 int argc;
37138                 int i = 0;
37139                 char *dash = "-";
37140 -               
37141 +
37142                 /* move stdout to from_rrdtool_fd[1] */
37143                 close(STDOUT_FILENO);
37144                 dup2(from_rrdtool_fds[1], STDOUT_FILENO);
37145                 close(from_rrdtool_fds[1]);
37146                 /* not needed */
37147                 close(from_rrdtool_fds[0]);
37148 -               
37149 +
37150                 /* move the stdin to to_rrdtool_fd[0] */
37151                 close(STDIN_FILENO);
37152                 dup2(to_rrdtool_fds[0], STDIN_FILENO);
37153                 close(to_rrdtool_fds[0]);
37154                 /* not needed */
37155                 close(to_rrdtool_fds[1]);
37156 -               
37157 +
37158                 close(STDERR_FILENO);
37159 -               
37160 -               if (srv->errorlog_mode == ERRORLOG_FILE) {
37161 -                       dup2(srv->errorlog_fd, STDERR_FILENO);
37162 -                       close(srv->errorlog_fd);
37163 -               }
37164 -               
37165 +
37166                 /* set up args */
37167                 argc = 3;
37168                 args = malloc(sizeof(*args) * argc);
37169                 i = 0;
37170 -               
37171 +
37172                 args[i++] = p->conf.path_rrdtool_bin->ptr;
37173                 args[i++] = dash;
37174                 args[i++] = NULL;
37175 @@ -152,12 +150,12 @@
37176                 for (i = 3; i < 256; i++) {
37177                         close(i);
37178                 }
37179 -               
37180 +
37181                 /* exec the cgi */
37182                 execv(args[0], args);
37183 -               
37184 +
37185                 log_error_write(srv, __FILE__, __LINE__, "sss", "spawing rrdtool failed: ", strerror(errno), args[0]);
37186 -               
37187 +
37188                 /* */
37189                 SEGFAULT();
37190                 break;
37191 @@ -168,19 +166,19 @@
37192                 break;
37193         default: {
37194                 /* father */
37195 -               
37196 +
37197                 close(from_rrdtool_fds[1]);
37198                 close(to_rrdtool_fds[0]);
37199 -               
37200 +
37201                 /* register PID and wait for them asyncronously */
37202                 p->write_fd = to_rrdtool_fds[1];
37203                 p->read_fd = from_rrdtool_fds[0];
37204                 p->rrdtool_pid = pid;
37205 -               
37206 +
37207                 break;
37208         }
37209         }
37210 -       
37211 +
37212         return 0;
37213  #else
37214         return -1;
37215 @@ -189,19 +187,19 @@
37216  
37217  static int mod_rrdtool_create_rrd(server *srv, plugin_data *p, plugin_config *s) {
37218         struct stat st;
37219 -       
37220 +
37221         /* check if DB already exists */
37222         if (0 == stat(s->path_rrd->ptr, &st)) {
37223                 /* check if it is plain file */
37224                 if (!S_ISREG(st.st_mode)) {
37225 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
37226 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
37227                                         "not a regular file:", s->path_rrd);
37228                         return HANDLER_ERROR;
37229                 }
37230         } else {
37231                 int r ;
37232                 /* create a new one */
37233 -               
37234 +
37235                 BUFFER_COPY_STRING_CONST(p->cmd, "create ");
37236                 buffer_append_string_buffer(p->cmd, s->path_rrd);
37237                 buffer_append_string(p->cmd, " --step 60 ");
37238 @@ -220,158 +218,155 @@
37239                 buffer_append_string(p->cmd, "RRA:MIN:0.5:6:700 ");
37240                 buffer_append_string(p->cmd, "RRA:MIN:0.5:24:775 ");
37241                 buffer_append_string(p->cmd, "RRA:MIN:0.5:288:797\n");
37242 -               
37243 +
37244                 if (-1 == (r = write(p->write_fd, p->cmd->ptr, p->cmd->used - 1))) {
37245 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
37246 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
37247                                 "rrdtool-write: failed", strerror(errno));
37248 -                       
37249 +
37250                         return HANDLER_ERROR;
37251                 }
37252 -               
37253 +
37254                 buffer_prepare_copy(p->resp, 4096);
37255                 if (-1 == (r = read(p->read_fd, p->resp->ptr, p->resp->size))) {
37256 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
37257 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
37258                                 "rrdtool-read: failed", strerror(errno));
37259 -                       
37260 +
37261                         return HANDLER_ERROR;
37262                 }
37263 -               
37264 +
37265                 p->resp->used = r;
37266 -               
37267 +
37268                 if (p->resp->ptr[0] != 'O' ||
37269                     p->resp->ptr[1] != 'K') {
37270 -                       log_error_write(srv, __FILE__, __LINE__, "sbb", 
37271 +                       log_error_write(srv, __FILE__, __LINE__, "sbb",
37272                                 "rrdtool-response:", p->cmd, p->resp);
37273 -                       
37274 +
37275                         return HANDLER_ERROR;
37276                 }
37277         }
37278 -       
37279 +
37280         return HANDLER_GO_ON;
37281  }
37282  
37283 -#define PATCH(x) \
37284 -       p->conf.x = s->x;
37285  static int mod_rrd_patch_connection(server *srv, connection *con, plugin_data *p) {
37286         size_t i, j;
37287         plugin_config *s = p->config_storage[0];
37288 -       
37289 -       PATCH(path_rrdtool_bin);
37290 -       PATCH(path_rrd);
37291 -       
37292 +
37293 +       PATCH_OPTION(path_rrdtool_bin);
37294 +       PATCH_OPTION(path_rrd);
37295 +
37296         p->conf.bytes_written_ptr = &(s->bytes_written);
37297         p->conf.bytes_read_ptr = &(s->bytes_read);
37298         p->conf.requests_ptr = &(s->requests);
37299 -       
37300 +
37301         /* skip the first, the global context */
37302         for (i = 1; i < srv->config_context->used; i++) {
37303                 data_config *dc = (data_config *)srv->config_context->data[i];
37304                 s = p->config_storage[i];
37305 -               
37306 +
37307                 /* condition didn't match */
37308                 if (!config_check_cond(srv, con, dc)) continue;
37309 -               
37310 +
37311                 /* merge config */
37312                 for (j = 0; j < dc->value->used; j++) {
37313                         data_unset *du = dc->value->data[j];
37314 -                       
37315 +
37316                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("rrdtool.db-name"))) {
37317 -                               PATCH(path_rrd);
37318 +                               PATCH_OPTION(path_rrd);
37319                                 /* get pointers to double values */
37320 -                               
37321 +
37322                                 p->conf.bytes_written_ptr = &(s->bytes_written);
37323                                 p->conf.bytes_read_ptr = &(s->bytes_read);
37324                                 p->conf.requests_ptr = &(s->requests);
37325                         }
37326                 }
37327         }
37328 -       
37329 +
37330         return 0;
37331  }
37332 -#undef PATCH
37333  
37334  SETDEFAULTS_FUNC(mod_rrd_set_defaults) {
37335         plugin_data *p = p_d;
37336         size_t i;
37337 -       
37338 -       config_values_t cv[] = { 
37339 +
37340 +       config_values_t cv[] = {
37341                 { "rrdtool.binary",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },
37342                 { "rrdtool.db-name",             NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
37343                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
37344         };
37345 -       
37346 +
37347         if (!p) return HANDLER_ERROR;
37348 -       
37349 +
37350         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
37351 -       
37352 +
37353         for (i = 0; i < srv->config_context->used; i++) {
37354                 plugin_config *s;
37355 -               
37356 +
37357                 s = calloc(1, sizeof(plugin_config));
37358                 s->path_rrdtool_bin = buffer_init();
37359                 s->path_rrd = buffer_init();
37360                 s->requests = 0;
37361                 s->bytes_written = 0;
37362                 s->bytes_read = 0;
37363 -               
37364 +
37365                 cv[0].destination = s->path_rrdtool_bin;
37366                 cv[1].destination = s->path_rrd;
37367 -               
37368 +
37369                 p->config_storage[i] = s;
37370 -       
37371 +
37372                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
37373                         return HANDLER_ERROR;
37374                 }
37375 -               
37376 +
37377                 if (i > 0 && !buffer_is_empty(s->path_rrdtool_bin)) {
37378                         /* path_rrdtool_bin is a global option */
37379 -                       
37380 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
37381 +
37382 +                       log_error_write(srv, __FILE__, __LINE__, "s",
37383                                         "rrdtool.binary can only be set as a global option.");
37384 -                       
37385 +
37386                         return HANDLER_ERROR;
37387                 }
37388 -               
37389 +
37390         }
37391 -       
37392 +
37393         p->conf.path_rrdtool_bin = p->config_storage[0]->path_rrdtool_bin;
37394         p->rrdtool_running = 0;
37395 -       
37396 +
37397         /* check for dir */
37398 -       
37399 +
37400         if (buffer_is_empty(p->conf.path_rrdtool_bin)) {
37401 -               log_error_write(srv, __FILE__, __LINE__, "s", 
37402 +               log_error_write(srv, __FILE__, __LINE__, "s",
37403                                 "rrdtool.binary has to be set");
37404                 return HANDLER_ERROR;
37405         }
37406 -       
37407 +
37408         /* open the pipe to rrdtool */
37409         if (mod_rrd_create_pipe(srv, p)) {
37410                 return HANDLER_ERROR;
37411         }
37412 -       
37413 +
37414         p->rrdtool_running = 1;
37415 -               
37416 +
37417         return HANDLER_GO_ON;
37418  }
37419  
37420  TRIGGER_FUNC(mod_rrd_trigger) {
37421         plugin_data *p = p_d;
37422         size_t i;
37423 -       
37424 +
37425         if (!p->rrdtool_running) return HANDLER_GO_ON;
37426         if ((srv->cur_ts % 60) != 0) return HANDLER_GO_ON;
37427 -       
37428 +
37429         for (i = 0; i < srv->config_context->used; i++) {
37430                 plugin_config *s = p->config_storage[i];
37431                 int r;
37432 -               
37433 +
37434                 if (buffer_is_empty(s->path_rrd)) continue;
37435 -       
37436 +
37437                 /* write the data down every minute */
37438 -               
37439 +
37440                 if (HANDLER_GO_ON != mod_rrdtool_create_rrd(srv, p, s)) return HANDLER_ERROR;
37441 -               
37442 +
37443                 BUFFER_COPY_STRING_CONST(p->cmd, "update ");
37444                 buffer_append_string_buffer(p->cmd, s->path_rrd);
37445                 BUFFER_APPEND_STRING_CONST(p->cmd, " N:");
37446 @@ -381,69 +376,69 @@
37447                 BUFFER_APPEND_STRING_CONST(p->cmd, ":");
37448                 buffer_append_long(p->cmd, s->requests);
37449                 BUFFER_APPEND_STRING_CONST(p->cmd, "\n");
37450 -               
37451 +
37452                 if (-1 == (r = write(p->write_fd, p->cmd->ptr, p->cmd->used - 1))) {
37453                         p->rrdtool_running = 0;
37454 -                       
37455 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
37456 +
37457 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
37458                                         "rrdtool-write: failed", strerror(errno));
37459 -                       
37460 +
37461                         return HANDLER_ERROR;
37462                 }
37463 -               
37464 +
37465                 buffer_prepare_copy(p->resp, 4096);
37466                 if (-1 == (r = read(p->read_fd, p->resp->ptr, p->resp->size))) {
37467                         p->rrdtool_running = 0;
37468 -                       
37469 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
37470 +
37471 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
37472                                         "rrdtool-read: failed", strerror(errno));
37473 -                       
37474 +
37475                         return HANDLER_ERROR;
37476                 }
37477 -               
37478 +
37479                 p->resp->used = r;
37480 -               
37481 +
37482                 if (p->resp->ptr[0] != 'O' ||
37483                     p->resp->ptr[1] != 'K') {
37484                         p->rrdtool_running = 0;
37485 -                       
37486 -                       log_error_write(srv, __FILE__, __LINE__, "sbb", 
37487 +
37488 +                       log_error_write(srv, __FILE__, __LINE__, "sbb",
37489                                         "rrdtool-response:", p->cmd, p->resp);
37490 -                       
37491 +
37492                         return HANDLER_ERROR;
37493                 }
37494                 s->requests = 0;
37495                 s->bytes_written = 0;
37496                 s->bytes_read = 0;
37497         }
37498 -       
37499 +
37500         return HANDLER_GO_ON;
37501  }
37502  
37503  REQUESTDONE_FUNC(mod_rrd_account) {
37504         plugin_data *p = p_d;
37505 -       
37506 +
37507         mod_rrd_patch_connection(srv, con, p);
37508 -       
37509 +
37510         *(p->conf.requests_ptr)      += 1;
37511         *(p->conf.bytes_written_ptr) += con->bytes_written;
37512         *(p->conf.bytes_read_ptr)    += con->bytes_read;
37513 -       
37514 +
37515         return HANDLER_GO_ON;
37516  }
37517  
37518  int mod_rrdtool_plugin_init(plugin *p) {
37519         p->version     = LIGHTTPD_VERSION_ID;
37520         p->name        = buffer_init_string("rrd");
37521 -       
37522 +
37523         p->init        = mod_rrd_init;
37524         p->cleanup     = mod_rrd_free;
37525         p->set_defaults= mod_rrd_set_defaults;
37526 -       
37527 +
37528         p->handle_trigger      = mod_rrd_trigger;
37529 -       p->handle_request_done = mod_rrd_account;
37530 -       
37531 +       p->handle_response_done = mod_rrd_account;
37532 +
37533         p->data        = NULL;
37534 -       
37535 +
37536         return 0;
37537  }
37538 --- ../lighttpd-1.4.11/src/mod_scgi.c   2006-03-04 17:15:26.000000000 +0200
37539 +++ lighttpd-1.5.0/src/mod_scgi.c       2006-09-07 00:57:05.000000000 +0300
37540 @@ -1,5 +1,4 @@
37541  #include <sys/types.h>
37542 -#include <unistd.h>
37543  #include <errno.h>
37544  #include <fcntl.h>
37545  #include <string.h>
37546 @@ -13,11 +12,11 @@
37547  #include "keyvalue.h"
37548  #include "log.h"
37549  
37550 -#include "http_chunk.h"
37551  #include "fdevent.h"
37552  #include "connections.h"
37553  #include "response.h"
37554  #include "joblist.h"
37555 +#include "http_resp.h"
37556  
37557  #include "plugin.h"
37558  
37559 @@ -30,7 +29,9 @@
37560  #endif
37561  
37562  #include "sys-socket.h"
37563 -
37564 +#include "sys-files.h"
37565 +#include "sys-strings.h"
37566 +#include "sys-process.h"
37567  
37568  #ifndef UNIX_PATH_MAX
37569  # define UNIX_PATH_MAX 108
37570 @@ -46,30 +47,29 @@
37571  enum {EOL_UNSET, EOL_N, EOL_RN};
37572  
37573  /*
37574 - * 
37575 + *
37576   * TODO:
37577 - * 
37578 + *
37579   * - add timeout for a connect to a non-scgi process
37580   *   (use state_timestamp + state)
37581 - * 
37582 + *
37583   */
37584  
37585  typedef struct scgi_proc {
37586         size_t id; /* id will be between 1 and max_procs */
37587         buffer *socket; /* config.socket + "-" + id */
37588         unsigned port;  /* config.port + pno */
37589 -       
37590 -       pid_t pid;   /* PID of the spawned process (0 if not spawned locally) */
37591  
37592 +       pid_t pid;   /* PID of the spawned process (0 if not spawned locally) */
37593  
37594         size_t load; /* number of requests waiting on this process */
37595  
37596         time_t last_used; /* see idle_timeout */
37597         size_t requests;  /* see max_requests */
37598         struct scgi_proc *prev, *next; /* see first */
37599 -       
37600 +
37601         time_t disable_ts; /* replace by host->something */
37602 -       
37603 +
37604         int is_local;
37605  
37606         enum { PROC_STATE_UNSET,            /* init-phase */
37607 @@ -78,7 +78,7 @@
37608                         PROC_STATE_KILLED,  /* was killed as we don't have the load anymore */
37609                         PROC_STATE_DIED,    /* marked as dead, should be restarted */
37610                         PROC_STATE_DISABLED /* proc disabled as it resulted in an error */
37611 -       } state; 
37612 +       } state;
37613  } scgi_proc;
37614  
37615  typedef struct {
37616 @@ -86,20 +86,20 @@
37617          * sorted by lowest load
37618          *
37619          * whenever a job is done move it up in the list
37620 -        * until it is sorted, move it down as soon as the 
37621 +        * until it is sorted, move it down as soon as the
37622          * job is started
37623          */
37624 -       scgi_proc *first; 
37625 -       scgi_proc *unused_procs; 
37626 +       scgi_proc *first;
37627 +       scgi_proc *unused_procs;
37628  
37629 -       /* 
37630 +       /*
37631          * spawn at least min_procs, at max_procs.
37632          *
37633 -        * as soon as the load of the first entry 
37634 +        * as soon as the load of the first entry
37635          * is max_load_per_proc we spawn a new one
37636 -        * and add it to the first entry and give it 
37637 +        * and add it to the first entry and give it
37638          * the load
37639 -        * 
37640 +        *
37641          */
37642  
37643         unsigned short min_procs;
37644 @@ -111,44 +111,44 @@
37645  
37646         /*
37647          * kick the process from the list if it was not
37648 -        * used for idle_timeout until min_procs is 
37649 +        * used for idle_timeout until min_procs is
37650          * reached. this helps to get the processlist
37651          * small again we had a small peak load.
37652          *
37653          */
37654 -       
37655 +
37656         unsigned short idle_timeout;
37657 -       
37658 +
37659         /*
37660          * time after a disabled remote connection is tried to be re-enabled
37661 -        * 
37662 -        * 
37663 +        *
37664 +        *
37665          */
37666 -       
37667 +
37668         unsigned short disable_time;
37669  
37670         /*
37671          * same scgi processes get a little bit larger
37672 -        * than wanted. max_requests_per_proc kills a 
37673 +        * than wanted. max_requests_per_proc kills a
37674          * process after a number of handled requests.
37675          *
37676          */
37677         size_t max_requests_per_proc;
37678 -       
37679 +
37680  
37681         /* config */
37682  
37683 -       /* 
37684 -        * host:port 
37685 +       /*
37686 +        * host:port
37687          *
37688 -        * if host is one of the local IP adresses the 
37689 +        * if host is one of the local IP adresses the
37690          * whole connection is local
37691          *
37692          * if tcp/ip should be used host AND port have
37693 -        * to be specified 
37694 -        * 
37695 -        */ 
37696 -       buffer *host; 
37697 +        * to be specified
37698 +        *
37699 +        */
37700 +       buffer *host;
37701         unsigned short port;
37702  
37703         /*
37704 @@ -161,7 +161,7 @@
37705          */
37706         buffer *unixsocket;
37707  
37708 -       /* if socket is local we can start the scgi 
37709 +       /* if socket is local we can start the scgi
37710          * process ourself
37711          *
37712          * bin-path is the path to the binary
37713 @@ -169,19 +169,19 @@
37714          * check min_procs and max_procs for the number
37715          * of process to start-up
37716          */
37717 -       buffer *bin_path; 
37718 -       
37719 -       /* bin-path is set bin-environment is taken to 
37720 +       buffer *bin_path;
37721 +
37722 +       /* bin-path is set bin-environment is taken to
37723          * create the environement before starting the
37724          * FastCGI process
37725 -        * 
37726 +        *
37727          */
37728         array *bin_env;
37729 -       
37730 +
37731         array *bin_env_copy;
37732 -       
37733 +
37734         /*
37735 -        * docroot-translation between URL->phys and the 
37736 +        * docroot-translation between URL->phys and the
37737          * remote host
37738          *
37739          * reasons:
37740 @@ -192,7 +192,7 @@
37741         buffer *docroot;
37742  
37743         /*
37744 -        * check_local tell you if the phys file is stat()ed 
37745 +        * check_local tell you if the phys file is stat()ed
37746          * or not. FastCGI doesn't care if the service is
37747          * remote. If the web-server side doesn't contain
37748          * the scgi-files we should not stat() for them
37749 @@ -202,33 +202,33 @@
37750  
37751         /*
37752          * append PATH_INFO to SCRIPT_FILENAME
37753 -        * 
37754 +        *
37755          * php needs this if cgi.fix_pathinfo is provied
37756 -        * 
37757 +        *
37758          */
37759 -       
37760 +
37761         ssize_t load; /* replace by host->load */
37762  
37763         size_t max_id; /* corresponds most of the time to
37764         num_procs.
37765 -       
37766 +
37767         only if a process is killed max_id waits for the process itself
37768         to die and decrements its afterwards */
37769  } scgi_extension_host;
37770  
37771  /*
37772   * one extension can have multiple hosts assigned
37773 - * one host can spawn additional processes on the same 
37774 + * one host can spawn additional processes on the same
37775   *   socket (if we control it)
37776   *
37777   * ext -> host -> procs
37778   *    1:n     1:n
37779   *
37780 - * if the scgi process is remote that whole goes down 
37781 + * if the scgi process is remote that whole goes down
37782   * to
37783   *
37784   * ext -> host -> procs
37785 - *    1:n     1:1 
37786 + *    1:n     1:1
37787   *
37788   * in case of PHP and FCGI_CHILDREN we have again a procs
37789   * but we don't control it directly.
37790 @@ -239,7 +239,7 @@
37791         buffer *key; /* like .php */
37792  
37793         scgi_extension_host **hosts;
37794 -       
37795 +
37796         size_t used;
37797         size_t size;
37798  } scgi_extension;
37799 @@ -253,14 +253,14 @@
37800  
37801  
37802  typedef struct {
37803 -       scgi_exts *exts; 
37804 -       
37805 +       scgi_exts *exts;
37806 +
37807         int debug;
37808  } plugin_config;
37809  
37810  typedef struct {
37811         char **ptr;
37812 -       
37813 +
37814         size_t size;
37815         size_t used;
37816  } char_array;
37817 @@ -268,52 +268,51 @@
37818  /* generic plugin data, shared between all connections */
37819  typedef struct {
37820         PLUGIN_DATA;
37821 -       
37822 +
37823         buffer *scgi_env;
37824 -       
37825 +
37826         buffer *path;
37827 -       buffer *parse_response;
37828 -       
37829 +
37830 +       http_resp *resp;
37831 +
37832         plugin_config **config_storage;
37833 -       
37834 +
37835         plugin_config conf; /* this is only used as long as no handler_ctx is setup */
37836  } plugin_data;
37837  
37838  /* connection specific data */
37839 -typedef enum { FCGI_STATE_INIT, FCGI_STATE_CONNECT, FCGI_STATE_PREPARE_WRITE, 
37840 -               FCGI_STATE_WRITE, FCGI_STATE_READ 
37841 +typedef enum {
37842 +       SCGI_STATE_INIT,
37843 +       SCGI_STATE_CONNECT,
37844 +       SCGI_STATE_PREPARE_WRITE,
37845 +       SCGI_STATE_WRITE,
37846 +       SCGI_STATE_RESPONSE_HEADER,
37847 +       SCGI_STATE_RESPONSE_CONTENT,
37848 +       SCGI_STATE_ERROR
37849  } scgi_connection_state_t;
37850  
37851  typedef struct {
37852 -       buffer  *response; 
37853 -       size_t   response_len;
37854 -       int      response_type;
37855 -       int      response_padding;
37856 -       
37857         scgi_proc *proc;
37858         scgi_extension_host *host;
37859 -       
37860 +
37861         scgi_connection_state_t state;
37862         time_t   state_timestamp;
37863 -       
37864 +
37865         int      reconnects; /* number of reconnect attempts */
37866 -       
37867 -       read_buffer *rb;
37868 +
37869 +       chunkqueue *rb;
37870         chunkqueue *wb;
37871 -       
37872 -       buffer   *response_header;
37873 -       
37874 +
37875         int       delayed;   /* flag to mark that the connect() is delayed */
37876 -       
37877 +
37878         size_t    request_id;
37879 -       int       fd;        /* fd to the scgi process */
37880 -       int       fde_ndx;   /* index into the fd-event buffer */
37881 +       iosocket  *sock;        /* fd to the scgi process */
37882  
37883         pid_t     pid;
37884         int       got_proc;
37885 -       
37886 +
37887         plugin_config conf;
37888 -       
37889 +
37890         connection *remote_conn;  /* dumb pointer */
37891         plugin_data *plugin_data; /* dumb pointer */
37892  } handler_ctx;
37893 @@ -328,42 +327,30 @@
37894  
37895  static handler_ctx * handler_ctx_init() {
37896         handler_ctx * hctx;
37897 -       
37898 +
37899         hctx = calloc(1, sizeof(*hctx));
37900         assert(hctx);
37901 -       
37902 -       hctx->fde_ndx = -1;
37903 -       
37904 -       hctx->response = buffer_init();
37905 -       hctx->response_header = buffer_init();
37906 -       
37907 +
37908 +       hctx->sock = iosocket_init();;
37909 +
37910         hctx->request_id = 0;
37911 -       hctx->state = FCGI_STATE_INIT;
37912 +       hctx->state = SCGI_STATE_INIT;
37913         hctx->proc = NULL;
37914 -       
37915 -       hctx->response_len = 0;
37916 -       hctx->response_type = 0;
37917 -       hctx->response_padding = 0;
37918 -       hctx->fd = -1;
37919 -       
37920 +
37921         hctx->reconnects = 0;
37922  
37923         hctx->wb = chunkqueue_init();
37924 -       
37925 +       hctx->rb = chunkqueue_init();
37926 +
37927         return hctx;
37928  }
37929  
37930  static void handler_ctx_free(handler_ctx *hctx) {
37931 -       buffer_free(hctx->response);
37932 -       buffer_free(hctx->response_header);
37933 -
37934         chunkqueue_free(hctx->wb);
37935 -       
37936 -       if (hctx->rb) {
37937 -               if (hctx->rb->ptr) free(hctx->rb->ptr);
37938 -               free(hctx->rb);
37939 -       }
37940 -       
37941 +       chunkqueue_free(hctx->rb);
37942 +
37943 +       iosocket_free(hctx->sock);
37944 +
37945         free(hctx);
37946  }
37947  
37948 @@ -372,20 +359,20 @@
37949  
37950         f = calloc(1, sizeof(*f));
37951         f->socket = buffer_init();
37952 -       
37953 +
37954         f->prev = NULL;
37955         f->next = NULL;
37956 -       
37957 +
37958         return f;
37959  }
37960  
37961  void scgi_process_free(scgi_proc *f) {
37962         if (!f) return;
37963 -       
37964 +
37965         scgi_process_free(f->next);
37966 -       
37967 +
37968         buffer_free(f->socket);
37969 -       
37970 +
37971         free(f);
37972  }
37973  
37974 @@ -400,62 +387,62 @@
37975         f->bin_path = buffer_init();
37976         f->bin_env = array_init();
37977         f->bin_env_copy = array_init();
37978 -       
37979 +
37980         return f;
37981  }
37982  
37983  void scgi_host_free(scgi_extension_host *h) {
37984         if (!h) return;
37985 -       
37986 +
37987         buffer_free(h->host);
37988         buffer_free(h->unixsocket);
37989         buffer_free(h->docroot);
37990         buffer_free(h->bin_path);
37991         array_free(h->bin_env);
37992         array_free(h->bin_env_copy);
37993 -       
37994 +
37995         scgi_process_free(h->first);
37996         scgi_process_free(h->unused_procs);
37997 -       
37998 +
37999         free(h);
38000 -       
38001 +
38002  }
38003  
38004  scgi_exts *scgi_extensions_init() {
38005         scgi_exts *f;
38006  
38007         f = calloc(1, sizeof(*f));
38008 -       
38009 +
38010         return f;
38011  }
38012  
38013  void scgi_extensions_free(scgi_exts *f) {
38014         size_t i;
38015 -       
38016 +
38017         if (!f) return;
38018 -       
38019 +
38020         for (i = 0; i < f->used; i++) {
38021                 scgi_extension *fe;
38022                 size_t j;
38023 -               
38024 +
38025                 fe = f->exts[i];
38026 -               
38027 +
38028                 for (j = 0; j < fe->used; j++) {
38029                         scgi_extension_host *h;
38030 -                       
38031 +
38032                         h = fe->hosts[j];
38033 -                       
38034 +
38035                         scgi_host_free(h);
38036                 }
38037 -               
38038 +
38039                 buffer_free(fe->key);
38040                 free(fe->hosts);
38041 -               
38042 +
38043                 free(fe);
38044         }
38045 -       
38046 +
38047         free(f->exts);
38048 -       
38049 +
38050         free(f);
38051  }
38052  
38053 @@ -504,99 +491,103 @@
38054                 assert(fe->hosts);
38055         }
38056  
38057 -       fe->hosts[fe->used++] = fh; 
38058 +       fe->hosts[fe->used++] = fh;
38059  
38060         return 0;
38061 -       
38062 +
38063  }
38064  
38065  INIT_FUNC(mod_scgi_init) {
38066         plugin_data *p;
38067 -       
38068 +
38069         p = calloc(1, sizeof(*p));
38070 -       
38071 +
38072         p->scgi_env = buffer_init();
38073 -       
38074 +
38075         p->path = buffer_init();
38076 -       p->parse_response = buffer_init();
38077 -       
38078 +       p->resp = http_response_init();
38079 +
38080         return p;
38081  }
38082  
38083  
38084  FREE_FUNC(mod_scgi_free) {
38085         plugin_data *p = p_d;
38086 -       
38087 +
38088         UNUSED(srv);
38089  
38090         buffer_free(p->scgi_env);
38091         buffer_free(p->path);
38092 -       buffer_free(p->parse_response);
38093 -       
38094 +       http_response_free(p->resp);
38095 +
38096         if (p->config_storage) {
38097                 size_t i, j, n;
38098                 for (i = 0; i < srv->config_context->used; i++) {
38099                         plugin_config *s = p->config_storage[i];
38100                         scgi_exts *exts;
38101 -                       
38102 +
38103                         if (!s) continue;
38104 -                       
38105 +
38106                         exts = s->exts;
38107  
38108                         for (j = 0; j < exts->used; j++) {
38109                                 scgi_extension *ex;
38110 -                               
38111 +
38112                                 ex = exts->exts[j];
38113 -                               
38114 +
38115                                 for (n = 0; n < ex->used; n++) {
38116                                         scgi_proc *proc;
38117                                         scgi_extension_host *host;
38118 -                                       
38119 +
38120                                         host = ex->hosts[n];
38121 -                                       
38122 +
38123                                         for (proc = host->first; proc; proc = proc->next) {
38124 +#ifndef _WIN32
38125                                                 if (proc->pid != 0) kill(proc->pid, SIGTERM);
38126 -                                               
38127 -                                               if (proc->is_local && 
38128 +#endif
38129 +
38130 +                                               if (proc->is_local &&
38131                                                     !buffer_is_empty(proc->socket)) {
38132                                                         unlink(proc->socket->ptr);
38133                                                 }
38134                                         }
38135 -                                       
38136 +
38137                                         for (proc = host->unused_procs; proc; proc = proc->next) {
38138 +#ifndef _WIN32
38139                                                 if (proc->pid != 0) kill(proc->pid, SIGTERM);
38140 -                                               
38141 -                                               if (proc->is_local && 
38142 +#endif
38143 +
38144 +                                               if (proc->is_local &&
38145                                                     !buffer_is_empty(proc->socket)) {
38146                                                         unlink(proc->socket->ptr);
38147                                                 }
38148                                         }
38149                                 }
38150                         }
38151 -                       
38152 +
38153                         scgi_extensions_free(s->exts);
38154 -                       
38155 +
38156                         free(s);
38157                 }
38158                 free(p->config_storage);
38159         }
38160 -       
38161 +
38162         free(p);
38163 -       
38164 +
38165         return HANDLER_GO_ON;
38166  }
38167  
38168  static int env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) {
38169         char *dst;
38170 -       
38171 +
38172         if (!key || !val) return -1;
38173 -       
38174 +
38175         dst = malloc(key_len + val_len + 3);
38176         memcpy(dst, key, key_len);
38177         dst[key_len] = '=';
38178         /* add the \0 from the value */
38179         memcpy(dst + key_len + 1, val, val_len + 1);
38180 -       
38181 +
38182         if (env->size == 0) {
38183                 env->size = 16;
38184                 env->ptr = malloc(env->size * sizeof(*env->ptr));
38185 @@ -604,13 +595,13 @@
38186                 env->size += 16;
38187                 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
38188         }
38189 -       
38190 +
38191         env->ptr[env->used++] = dst;
38192 -       
38193 +
38194         return 0;
38195  }
38196  
38197 -static int scgi_spawn_connection(server *srv, 
38198 +static int scgi_spawn_connection(server *srv,
38199                                  plugin_data *p,
38200                                  scgi_extension_host *host,
38201                                  scgi_proc *proc) {
38202 @@ -622,31 +613,27 @@
38203  #endif
38204         struct sockaddr_in scgi_addr_in;
38205         struct sockaddr *scgi_addr;
38206 -       
38207 +
38208         socklen_t servlen;
38209 -       
38210 +
38211  #ifndef HAVE_FORK
38212         return -1;
38213  #endif
38214 -       
38215 +
38216         if (p->conf.debug) {
38217                 log_error_write(srv, __FILE__, __LINE__, "sdb",
38218                                 "new proc, socket:", proc->port, proc->socket);
38219         }
38220 -               
38221 +
38222         if (!buffer_is_empty(proc->socket)) {
38223                 memset(&scgi_addr, 0, sizeof(scgi_addr));
38224 -               
38225 +
38226  #ifdef HAVE_SYS_UN_H
38227                 scgi_addr_un.sun_family = AF_UNIX;
38228                 strcpy(scgi_addr_un.sun_path, proc->socket->ptr);
38229 -               
38230 -#ifdef SUN_LEN
38231 +
38232                 servlen = SUN_LEN(&scgi_addr_un);
38233 -#else
38234 -               /* stevens says: */
38235 -               servlen = proc->socket->used + sizeof(scgi_addr_un.sun_family);
38236 -#endif
38237 +
38238                 socket_type = AF_UNIX;
38239                 scgi_addr = (struct sockaddr *) &scgi_addr_un;
38240  #else
38241 @@ -656,115 +643,115 @@
38242  #endif
38243         } else {
38244                 scgi_addr_in.sin_family = AF_INET;
38245 -               
38246 +
38247                 if (buffer_is_empty(host->host)) {
38248                         scgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
38249                 } else {
38250                         struct hostent *he;
38251 -                       
38252 +
38253                         /* set a usefull default */
38254                         scgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
38255 -                       
38256 -                       
38257 +
38258 +
38259                         if (NULL == (he = gethostbyname(host->host->ptr))) {
38260 -                               log_error_write(srv, __FILE__, __LINE__, 
38261 -                                               "sdb", "gethostbyname failed: ", 
38262 +                               log_error_write(srv, __FILE__, __LINE__,
38263 +                                               "sdb", "gethostbyname failed: ",
38264                                                 h_errno, host->host);
38265                                 return -1;
38266                         }
38267 -                       
38268 +
38269                         if (he->h_addrtype != AF_INET) {
38270                                 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype);
38271                                 return -1;
38272                         }
38273 -                       
38274 +
38275                         if (he->h_length != sizeof(struct in_addr)) {
38276                                 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length);
38277                                 return -1;
38278                         }
38279 -                       
38280 +
38281                         memcpy(&(scgi_addr_in.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
38282 -                       
38283 +
38284                 }
38285                 scgi_addr_in.sin_port = htons(proc->port);
38286                 servlen = sizeof(scgi_addr_in);
38287 -               
38288 +
38289                 socket_type = AF_INET;
38290                 scgi_addr = (struct sockaddr *) &scgi_addr_in;
38291         }
38292 -       
38293 +
38294         if (-1 == (scgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
38295 -               log_error_write(srv, __FILE__, __LINE__, "ss", 
38296 +               log_error_write(srv, __FILE__, __LINE__, "ss",
38297                                 "failed:", strerror(errno));
38298                 return -1;
38299         }
38300 -       
38301 +
38302         if (-1 == connect(scgi_fd, scgi_addr, servlen)) {
38303                 /* server is not up, spawn in  */
38304                 pid_t child;
38305                 int val;
38306 -               
38307 +
38308                 if (!buffer_is_empty(proc->socket)) {
38309                         unlink(proc->socket->ptr);
38310                 }
38311 -               
38312 +
38313                 close(scgi_fd);
38314 -               
38315 +
38316                 /* reopen socket */
38317                 if (-1 == (scgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
38318 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
38319 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
38320                                 "socket failed:", strerror(errno));
38321                         return -1;
38322                 }
38323 -               
38324 +
38325                 val = 1;
38326                 if (setsockopt(scgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
38327 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
38328 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
38329                                         "socketsockopt failed:", strerror(errno));
38330                         return -1;
38331                 }
38332 -               
38333 +
38334                 /* create socket */
38335                 if (-1 == bind(scgi_fd, scgi_addr, servlen)) {
38336 -                       log_error_write(srv, __FILE__, __LINE__, "sbds", 
38337 -                               "bind failed for:", 
38338 -                               proc->socket, 
38339 -                               proc->port, 
38340 +                       log_error_write(srv, __FILE__, __LINE__, "sbds",
38341 +                               "bind failed for:",
38342 +                               proc->socket,
38343 +                               proc->port,
38344                                 strerror(errno));
38345                         return -1;
38346                 }
38347 -               
38348 +
38349                 if (-1 == listen(scgi_fd, 1024)) {
38350 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
38351 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
38352                                 "listen failed:", strerror(errno));
38353                         return -1;
38354                 }
38355 -               
38356 -#ifdef HAVE_FORK       
38357 +
38358 +#ifdef HAVE_FORK
38359                 switch ((child = fork())) {
38360                 case 0: {
38361                         buffer *b;
38362                         size_t i = 0;
38363                         int fd = 0;
38364                         char_array env;
38365 -                       
38366 -                       
38367 +
38368 +
38369                         /* create environment */
38370                         env.ptr = NULL;
38371                         env.size = 0;
38372                         env.used = 0;
38373 -                       
38374 +
38375                         /* we don't need the client socket */
38376                         for (fd = 3; fd < 256; fd++) {
38377                                 if (fd != 2 && fd != scgi_fd) close(fd);
38378                         }
38379 -                       
38380 +
38381                         /* build clean environment */
38382                         if (host->bin_env_copy->used) {
38383                                 for (i = 0; i < host->bin_env_copy->used; i++) {
38384                                         data_string *ds = (data_string *)host->bin_env_copy->data[i];
38385                                         char *ge;
38386 -                                       
38387 +
38388                                         if (NULL != (ge = getenv(ds->value->ptr))) {
38389                                                 env_add(&env, CONST_BUF_LEN(ds->value), ge, strlen(ge));
38390                                         }
38391 @@ -772,44 +759,44 @@
38392                         } else {
38393                                 for (i = 0; environ[i]; i++) {
38394                                         char *eq;
38395 -                                       
38396 +
38397                                         if (NULL != (eq = strchr(environ[i], '='))) {
38398                                                 env_add(&env, environ[i], eq - environ[i], eq+1, strlen(eq+1));
38399                                         }
38400                                 }
38401                         }
38402 -                       
38403 +
38404                         /* create environment */
38405                         for (i = 0; i < host->bin_env->used; i++) {
38406                                 data_string *ds = (data_string *)host->bin_env->data[i];
38407 -                               
38408 +
38409                                 env_add(&env, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
38410                         }
38411 -                       
38412 +
38413                         for (i = 0; i < env.used; i++) {
38414                                 /* search for PHP_FCGI_CHILDREN */
38415                                 if (0 == strncmp(env.ptr[i], "PHP_FCGI_CHILDREN=", sizeof("PHP_FCGI_CHILDREN=") - 1)) break;
38416                         }
38417 -                       
38418 +
38419                         /* not found, add a default */
38420                         if (i == env.used) {
38421                                 env_add(&env, CONST_STR_LEN("PHP_FCGI_CHILDREN"), CONST_STR_LEN("1"));
38422                         }
38423 -                       
38424 +
38425                         env.ptr[env.used] = NULL;
38426 -                       
38427 +
38428                         b = buffer_init();
38429                         buffer_copy_string(b, "exec ");
38430                         buffer_append_string_buffer(b, host->bin_path);
38431 -                       
38432 +
38433                         /* exec the cgi */
38434                         execle("/bin/sh", "sh", "-c", b->ptr, NULL, env.ptr);
38435 -                       
38436 -                       log_error_write(srv, __FILE__, __LINE__, "sbs", 
38437 +
38438 +                       log_error_write(srv, __FILE__, __LINE__, "sbs",
38439                                         "execl failed for:", host->bin_path, strerror(errno));
38440 -                       
38441 +
38442                         exit(errno);
38443 -                       
38444 +
38445                         break;
38446                 }
38447                 case -1:
38448 @@ -817,32 +804,32 @@
38449                         break;
38450                 default:
38451                         /* father */
38452 -                       
38453 +
38454                         /* wait */
38455                         select(0, NULL, NULL, NULL, &tv);
38456 -                       
38457 +
38458                         switch (waitpid(child, &status, WNOHANG)) {
38459                         case 0:
38460                                 /* child still running after timeout, good */
38461                                 break;
38462                         case -1:
38463                                 /* no PID found ? should never happen */
38464 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
38465 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
38466                                                 "pid not found:", strerror(errno));
38467                                 return -1;
38468                         default:
38469                                 /* the child should not terminate at all */
38470                                 if (WIFEXITED(status)) {
38471 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
38472 -                                                       "child exited (is this a SCGI binary ?):", 
38473 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
38474 +                                                       "child exited (is this a SCGI binary ?):",
38475                                                         WEXITSTATUS(status));
38476                                 } else if (WIFSIGNALED(status)) {
38477 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
38478 -                                                       "child signaled:", 
38479 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
38480 +                                                       "child signaled:",
38481                                                         WTERMSIG(status));
38482                                 } else {
38483 -                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
38484 -                                                       "child died somehow:", 
38485 +                                       log_error_write(srv, __FILE__, __LINE__, "sd",
38486 +                                                       "child died somehow:",
38487                                                         status);
38488                                 }
38489                                 return -1;
38490 @@ -852,26 +839,26 @@
38491                         proc->pid = child;
38492                         proc->last_used = srv->cur_ts;
38493                         proc->is_local = 1;
38494 -                                               
38495 +
38496                         break;
38497                 }
38498  #endif
38499         } else {
38500                 proc->is_local = 0;
38501                 proc->pid = 0;
38502 -               
38503 +
38504                 if (p->conf.debug) {
38505                         log_error_write(srv, __FILE__, __LINE__, "sb",
38506                                         "(debug) socket is already used, won't spawn:",
38507                                         proc->socket);
38508                 }
38509         }
38510 -       
38511 +
38512         proc->state = PROC_STATE_RUNNING;
38513         host->active_procs++;
38514 -       
38515 +
38516         close(scgi_fd);
38517 -       
38518 +
38519         return 0;
38520  }
38521  
38522 @@ -880,89 +867,89 @@
38523         plugin_data *p = p_d;
38524         data_unset *du;
38525         size_t i = 0;
38526 -       
38527 -       config_values_t cv[] = { 
38528 +
38529 +       config_values_t cv[] = {
38530                 { "scgi.server",              NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
38531                 { "scgi.debug",               NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
38532                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
38533         };
38534 -       
38535 +
38536         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
38537 -       
38538 +
38539         for (i = 0; i < srv->config_context->used; i++) {
38540                 plugin_config *s;
38541                 array *ca;
38542 -               
38543 +
38544                 s = malloc(sizeof(plugin_config));
38545                 s->exts          = scgi_extensions_init();
38546                 s->debug         = 0;
38547 -               
38548 +
38549                 cv[0].destination = s->exts;
38550                 cv[1].destination = &(s->debug);
38551 -               
38552 +
38553                 p->config_storage[i] = s;
38554                 ca = ((data_config *)srv->config_context->data[i])->value;
38555 -       
38556 +
38557                 if (0 != config_insert_values_global(srv, ca, cv)) {
38558                         return HANDLER_ERROR;
38559                 }
38560 -               
38561 -               /* 
38562 +
38563 +               /*
38564                  * <key> = ( ... )
38565                  */
38566 -               
38567 +
38568                 if (NULL != (du = array_get_element(ca, "scgi.server"))) {
38569                         size_t j;
38570                         data_array *da = (data_array *)du;
38571 -                       
38572 +
38573                         if (du->type != TYPE_ARRAY) {
38574 -                               log_error_write(srv, __FILE__, __LINE__, "sss", 
38575 +                               log_error_write(srv, __FILE__, __LINE__, "sss",
38576                                                 "unexpected type for key: ", "scgi.server", "array of strings");
38577 -                               
38578 +
38579                                 return HANDLER_ERROR;
38580                         }
38581 -                       
38582 -                       
38583 -                       /* 
38584 -                        * scgi.server = ( "<ext>" => ( ... ), 
38585 +
38586 +
38587 +                       /*
38588 +                        * scgi.server = ( "<ext>" => ( ... ),
38589                          *                    "<ext>" => ( ... ) )
38590                          */
38591 -                       
38592 +
38593                         for (j = 0; j < da->value->used; j++) {
38594                                 size_t n;
38595                                 data_array *da_ext = (data_array *)da->value->data[j];
38596 -                               
38597 +
38598                                 if (da->value->data[j]->type != TYPE_ARRAY) {
38599 -                                       log_error_write(srv, __FILE__, __LINE__, "sssbs", 
38600 -                                                       "unexpected type for key: ", "scgi.server", 
38601 +                                       log_error_write(srv, __FILE__, __LINE__, "sssbs",
38602 +                                                       "unexpected type for key: ", "scgi.server",
38603                                                         "[", da->value->data[j]->key, "](string)");
38604 -                                       
38605 +
38606                                         return HANDLER_ERROR;
38607                                 }
38608 -                               
38609 -                               /* 
38610 -                                * da_ext->key == name of the extension 
38611 +
38612 +                               /*
38613 +                                * da_ext->key == name of the extension
38614                                  */
38615 -                               
38616 -                               /* 
38617 -                                * scgi.server = ( "<ext>" => 
38618 -                                *                     ( "<host>" => ( ... ), 
38619 +
38620 +                               /*
38621 +                                * scgi.server = ( "<ext>" =>
38622 +                                *                     ( "<host>" => ( ... ),
38623                                  *                       "<host>" => ( ... )
38624 -                                *                     ), 
38625 +                                *                     ),
38626                                  *                    "<ext>" => ... )
38627                                  */
38628 -                                       
38629 +
38630                                 for (n = 0; n < da_ext->value->used; n++) {
38631                                         data_array *da_host = (data_array *)da_ext->value->data[n];
38632 -                                       
38633 +
38634                                         scgi_extension_host *df;
38635 -                                       
38636 -                                       config_values_t fcv[] = { 
38637 +
38638 +                                       config_values_t fcv[] = {
38639                                                 { "host",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
38640                                                 { "docroot",           NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
38641                                                 { "socket",            NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
38642                                                 { "bin-path",          NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 3 */
38643 -                                               
38644 +
38645                                                 { "check-local",       NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },      /* 4 */
38646                                                 { "port",              NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 5 */
38647                                                 { "min-procs-not-working",         NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 7 this is broken for now */
38648 @@ -970,37 +957,37 @@
38649                                                 { "max-load-per-proc", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 8 */
38650                                                 { "idle-timeout",      NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 9 */
38651                                                 { "disable-time",      NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 10 */
38652 -                                               
38653 +
38654                                                 { "bin-environment",   NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },        /* 11 */
38655                                                 { "bin-copy-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },     /* 12 */
38656 -                                               
38657 -                                               
38658 +
38659 +
38660                                                 { NULL,                NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
38661                                         };
38662 -                                       
38663 +
38664                                         if (da_host->type != TYPE_ARRAY) {
38665 -                                               log_error_write(srv, __FILE__, __LINE__, "ssSBS", 
38666 -                                                               "unexpected type for key:", 
38667 -                                                               "scgi.server", 
38668 +                                               log_error_write(srv, __FILE__, __LINE__, "ssSBS",
38669 +                                                               "unexpected type for key:",
38670 +                                                               "scgi.server",
38671                                                                 "[", da_host->key, "](string)");
38672 -                                               
38673 +
38674                                                 return HANDLER_ERROR;
38675                                         }
38676 -                                       
38677 +
38678                                         df = scgi_host_init();
38679 -                                       
38680 +
38681                                         df->check_local  = 1;
38682                                         df->min_procs    = 4;
38683                                         df->max_procs    = 4;
38684                                         df->max_load_per_proc = 1;
38685                                         df->idle_timeout = 60;
38686                                         df->disable_time = 60;
38687 -                                       
38688 +
38689                                         fcv[0].destination = df->host;
38690                                         fcv[1].destination = df->docroot;
38691                                         fcv[2].destination = df->unixsocket;
38692                                         fcv[3].destination = df->bin_path;
38693 -                                       
38694 +
38695                                         fcv[4].destination = &(df->check_local);
38696                                         fcv[5].destination = &(df->port);
38697                                         fcv[6].destination = &(df->min_procs);
38698 @@ -1008,47 +995,47 @@
38699                                         fcv[8].destination = &(df->max_load_per_proc);
38700                                         fcv[9].destination = &(df->idle_timeout);
38701                                         fcv[10].destination = &(df->disable_time);
38702 -                                       
38703 +
38704                                         fcv[11].destination = df->bin_env;
38705                                         fcv[12].destination = df->bin_env_copy;
38706 -                                       
38707 -                                       
38708 +
38709 +
38710                                         if (0 != config_insert_values_internal(srv, da_host->value, fcv)) {
38711                                                 return HANDLER_ERROR;
38712                                         }
38713 -                                                       
38714 -                                       if ((!buffer_is_empty(df->host) || df->port) && 
38715 +
38716 +                                       if ((!buffer_is_empty(df->host) || df->port) &&
38717                                             !buffer_is_empty(df->unixsocket)) {
38718 -                                               log_error_write(srv, __FILE__, __LINE__, "s", 
38719 +                                               log_error_write(srv, __FILE__, __LINE__, "s",
38720                                                                 "either host+port or socket");
38721 -                                               
38722 +
38723                                                 return HANDLER_ERROR;
38724                                         }
38725 -                                       
38726 +
38727                                         if (!buffer_is_empty(df->unixsocket)) {
38728                                                 /* unix domain socket */
38729 -                                               
38730 +
38731                                                 if (df->unixsocket->used > UNIX_PATH_MAX - 2) {
38732 -                                                       log_error_write(srv, __FILE__, __LINE__, "s", 
38733 +                                                       log_error_write(srv, __FILE__, __LINE__, "s",
38734                                                                         "path of the unixdomain socket is too large");
38735                                                         return HANDLER_ERROR;
38736                                                 }
38737                                         } else {
38738                                                 /* tcp/ip */
38739 -                                               
38740 -                                               if (buffer_is_empty(df->host) && 
38741 +
38742 +                                               if (buffer_is_empty(df->host) &&
38743                                                     buffer_is_empty(df->bin_path)) {
38744 -                                                       log_error_write(srv, __FILE__, __LINE__, "sbbbs", 
38745 -                                                                       "missing key (string):", 
38746 +                                                       log_error_write(srv, __FILE__, __LINE__, "sbbbs",
38747 +                                                                       "missing key (string):",
38748                                                                         da->key,
38749                                                                         da_ext->key,
38750                                                                         da_host->key,
38751                                                                         "host");
38752 -                                                       
38753 +
38754                                                         return HANDLER_ERROR;
38755                                                 } else if (df->port == 0) {
38756 -                                                       log_error_write(srv, __FILE__, __LINE__, "sbbbs", 
38757 -                                                                       "missing key (short):", 
38758 +                                                       log_error_write(srv, __FILE__, __LINE__, "sbbbs",
38759 +                                                                       "missing key (short):",
38760                                                                         da->key,
38761                                                                         da_ext->key,
38762                                                                         da_host->key,
38763 @@ -1056,14 +1043,14 @@
38764                                                         return HANDLER_ERROR;
38765                                                 }
38766                                         }
38767 -                                               
38768 -                                       if (!buffer_is_empty(df->bin_path)) { 
38769 +
38770 +                                       if (!buffer_is_empty(df->bin_path)) {
38771                                                 /* a local socket + self spawning */
38772                                                 size_t pno;
38773 -                                               
38774 +
38775                                                 if (df->min_procs > df->max_procs) df->max_procs = df->min_procs;
38776                                                 if (df->max_load_per_proc < 1) df->max_load_per_proc = 0;
38777 -                                               
38778 +
38779                                                 if (s->debug) {
38780                                                         log_error_write(srv, __FILE__, __LINE__, "ssbsdsbsdsd",
38781                                                                         "--- scgi spawning local",
38782 @@ -1073,7 +1060,7 @@
38783                                                                         "\n\tmin-procs:", df->min_procs,
38784                                                                         "\n\tmax-procs:", df->max_procs);
38785                                                 }
38786 -                                               
38787 +
38788                                                 for (pno = 0; pno < df->min_procs; pno++) {
38789                                                         scgi_proc *proc;
38790  
38791 @@ -1088,7 +1075,7 @@
38792                                                                 buffer_append_string(proc->socket, "-");
38793                                                                 buffer_append_long(proc->socket, pno);
38794                                                         }
38795 -                                                       
38796 +
38797                                                         if (s->debug) {
38798                                                                 log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
38799                                                                                 "--- scgi spawning",
38800 @@ -1096,53 +1083,53 @@
38801                                                                                 "\n\tsocket", df->unixsocket,
38802                                                                                 "\n\tcurrent:", pno, "/", df->min_procs);
38803                                                         }
38804 -                                                       
38805 +
38806                                                         if (scgi_spawn_connection(srv, p, df, proc)) {
38807                                                                 log_error_write(srv, __FILE__, __LINE__, "s",
38808                                                                                 "[ERROR]: spawning fcgi failed.");
38809                                                                 return HANDLER_ERROR;
38810                                                         }
38811 -                                                       
38812 +
38813                                                         proc->next = df->first;
38814                                                         if (df->first)  df->first->prev = proc;
38815 -                                                       
38816 +
38817                                                         df->first = proc;
38818                                                 }
38819                                         } else {
38820                                                 scgi_proc *fp;
38821 -                                               
38822 +
38823                                                 fp = scgi_process_init();
38824                                                 fp->id = df->num_procs++;
38825                                                 df->max_id++;
38826                                                 df->active_procs++;
38827                                                 fp->state = PROC_STATE_RUNNING;
38828 -                                               
38829 +
38830                                                 if (buffer_is_empty(df->unixsocket)) {
38831                                                         fp->port = df->port;
38832                                                 } else {
38833                                                         buffer_copy_string_buffer(fp->socket, df->unixsocket);
38834                                                 }
38835 -                                               
38836 +
38837                                                 df->first = fp;
38838 -                                               
38839 +
38840                                                 df->min_procs = 1;
38841                                                 df->max_procs = 1;
38842                                         }
38843 -                                       
38844 +
38845                                         /* if extension already exists, take it */
38846                                         scgi_extension_insert(s->exts, da_ext->key, df);
38847                                 }
38848                         }
38849                 }
38850         }
38851 -       
38852 +
38853         return HANDLER_GO_ON;
38854  }
38855  
38856  static int scgi_set_state(server *srv, handler_ctx *hctx, scgi_connection_state_t state) {
38857         hctx->state = state;
38858         hctx->state_timestamp = srv->cur_ts;
38859 -       
38860 +
38861         return 0;
38862  }
38863  
38864 @@ -1150,35 +1137,35 @@
38865  void scgi_connection_cleanup(server *srv, handler_ctx *hctx) {
38866         plugin_data *p;
38867         connection  *con;
38868 -       
38869 +
38870         if (NULL == hctx) return;
38871 -       
38872 +
38873         p    = hctx->plugin_data;
38874         con  = hctx->remote_conn;
38875 -       
38876 +
38877         if (con->mode != p->id) {
38878 -               WP();
38879                 return;
38880         }
38881 -       
38882 -       if (hctx->fd != -1) {
38883 -               fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
38884 -               fdevent_unregister(srv->ev, hctx->fd);
38885 -               close(hctx->fd);
38886 +
38887 +       if (hctx->sock->fd != -1) {
38888 +               fdevent_event_del(srv->ev, hctx->sock);
38889 +               fdevent_unregister(srv->ev, hctx->sock);
38890 +               closesocket(hctx->sock->fd);
38891 +               hctx->sock->fd = -1;
38892                 srv->cur_fds--;
38893         }
38894 -       
38895 +
38896         if (hctx->host && hctx->proc) {
38897                 hctx->host->load--;
38898 -               
38899 +
38900                 if (hctx->got_proc) {
38901                         /* after the connect the process gets a load */
38902                         hctx->proc->load--;
38903 -                       
38904 +
38905                         if (p->conf.debug) {
38906                                 log_error_write(srv, __FILE__, __LINE__, "sddb",
38907 -                                               "release proc:", 
38908 -                                               hctx->fd,
38909 +                                               "release proc:",
38910 +                                               hctx->sock->fd,
38911                                                 hctx->proc->pid, hctx->proc->socket);
38912                         }
38913                 }
38914 @@ -1186,87 +1173,87 @@
38915                 scgi_proclist_sort_down(srv, hctx->host, hctx->proc);
38916         }
38917  
38918 -       
38919 +
38920         handler_ctx_free(hctx);
38921 -       con->plugin_ctx[p->id] = NULL;  
38922 +       con->plugin_ctx[p->id] = NULL;
38923  }
38924  
38925  static int scgi_reconnect(server *srv, handler_ctx *hctx) {
38926         plugin_data *p    = hctx->plugin_data;
38927 -       
38928 -       /* child died 
38929 -        * 
38930 -        * 1. 
38931 -        * 
38932 +
38933 +       /* child died
38934 +        *
38935 +        * 1.
38936 +        *
38937          * connect was ok, connection was accepted
38938          * but the php accept loop checks after the accept if it should die or not.
38939 -        * 
38940 -        * if yes we can only detect it at a write() 
38941 -        * 
38942 +        *
38943 +        * if yes we can only detect it at a write()
38944 +        *
38945          * next step is resetting this attemp and setup a connection again
38946 -        * 
38947 +        *
38948          * if we have more then 5 reconnects for the same request, die
38949 -        * 
38950 -        * 2. 
38951 -        * 
38952 +        *
38953 +        * 2.
38954 +        *
38955          * we have a connection but the child died by some other reason
38956 -        * 
38957 +        *
38958          */
38959 -       
38960 -       fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
38961 -       fdevent_unregister(srv->ev, hctx->fd);
38962 -       close(hctx->fd);
38963 +
38964 +       fdevent_event_del(srv->ev, hctx->sock);
38965 +       fdevent_unregister(srv->ev, hctx->sock);
38966 +       closesocket(hctx->sock->fd);
38967         srv->cur_fds--;
38968 -       
38969 -       scgi_set_state(srv, hctx, FCGI_STATE_INIT);
38970 -       
38971 +
38972 +       scgi_set_state(srv, hctx, SCGI_STATE_INIT);
38973 +
38974         hctx->request_id = 0;
38975         hctx->reconnects++;
38976 -       
38977 +
38978         if (p->conf.debug) {
38979                 log_error_write(srv, __FILE__, __LINE__, "sddb",
38980 -                               "release proc:", 
38981 -                               hctx->fd,
38982 +                               "release proc:",
38983 +                               hctx->sock->fd,
38984                                 hctx->proc->pid, hctx->proc->socket);
38985         }
38986 -       
38987 +
38988         hctx->proc->load--;
38989         scgi_proclist_sort_down(srv, hctx->host, hctx->proc);
38990 -       
38991 +
38992         return 0;
38993  }
38994  
38995  
38996  static handler_t scgi_connection_reset(server *srv, connection *con, void *p_d) {
38997         plugin_data *p = p_d;
38998 -       
38999 +
39000         scgi_connection_cleanup(srv, con->plugin_ctx[p->id]);
39001 -       
39002 +
39003         return HANDLER_GO_ON;
39004  }
39005  
39006  
39007  static int scgi_env_add(buffer *env, const char *key, size_t key_len, const char *val, size_t val_len) {
39008         size_t len;
39009 -       
39010 +
39011         if (!key || !val) return -1;
39012 -       
39013 +
39014         len = key_len + val_len + 2;
39015 -       
39016 +
39017         buffer_prepare_append(env, len);
39018  
39019 -       /* include the NUL */   
39020 +       /* include the NUL */
39021         memcpy(env->ptr + env->used, key, key_len + 1);
39022         env->used += key_len + 1;
39023         memcpy(env->ptr + env->used, val, val_len + 1);
39024         env->used += val_len + 1;
39025 -       
39026 +
39027         return 0;
39028  }
39029  
39030  
39031  /**
39032 - * 
39033 + *
39034   * returns
39035   *   -1 error
39036   *    0 connected
39037 @@ -1280,24 +1267,21 @@
39038         struct sockaddr_un scgi_addr_un;
39039  #endif
39040         socklen_t servlen;
39041 -       
39042 +
39043         scgi_extension_host *host = hctx->host;
39044         scgi_proc *proc   = hctx->proc;
39045 -       int scgi_fd       = hctx->fd;
39046 -       
39047 +       int scgi_fd       = hctx->sock->fd;
39048 +
39049         memset(&scgi_addr, 0, sizeof(scgi_addr));
39050 -       
39051 +
39052         if (!buffer_is_empty(proc->socket)) {
39053  #ifdef HAVE_SYS_UN_H
39054                 /* use the unix domain socket */
39055                 scgi_addr_un.sun_family = AF_UNIX;
39056                 strcpy(scgi_addr_un.sun_path, proc->socket->ptr);
39057 -#ifdef SUN_LEN
39058 +               
39059                 servlen = SUN_LEN(&scgi_addr_un);
39060 -#else
39061 -               /* stevens says: */
39062 -               servlen = proc->socket->used + sizeof(scgi_addr_un.sun_family);
39063 -#endif
39064 +
39065                 scgi_addr = (struct sockaddr *) &scgi_addr_un;
39066  #else
39067                 return -1;
39068 @@ -1305,105 +1289,105 @@
39069         } else {
39070                 scgi_addr_in.sin_family = AF_INET;
39071                 if (0 == inet_aton(host->host->ptr, &(scgi_addr_in.sin_addr))) {
39072 -                       log_error_write(srv, __FILE__, __LINE__, "sbs", 
39073 -                                       "converting IP-adress failed for", host->host, 
39074 +                       log_error_write(srv, __FILE__, __LINE__, "sbs",
39075 +                                       "converting IP-adress failed for", host->host,
39076                                         "\nBe sure to specify an IP address here");
39077 -                       
39078 +
39079                         return -1;
39080                 }
39081                 scgi_addr_in.sin_port = htons(proc->port);
39082                 servlen = sizeof(scgi_addr_in);
39083 -               
39084 +
39085                 scgi_addr = (struct sockaddr *) &scgi_addr_in;
39086         }
39087 -       
39088 +
39089         if (-1 == connect(scgi_fd, scgi_addr, servlen)) {
39090 -               if (errno == EINPROGRESS || 
39091 +               if (errno == EINPROGRESS ||
39092                     errno == EALREADY ||
39093                     errno == EINTR) {
39094                         if (hctx->conf.debug) {
39095 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
39096 +                               log_error_write(srv, __FILE__, __LINE__, "sd",
39097                                                 "connect delayed, will continue later:", scgi_fd);
39098                         }
39099 -                       
39100 +
39101                         return 1;
39102                 } else {
39103 -                       log_error_write(srv, __FILE__, __LINE__, "sdsddb", 
39104 -                                       "connect failed:", scgi_fd, 
39105 +                       log_error_write(srv, __FILE__, __LINE__, "sdsddb",
39106 +                                       "connect failed:", scgi_fd,
39107                                         strerror(errno), errno,
39108                                         proc->port, proc->socket);
39109  
39110                         if (errno == EAGAIN) {
39111                                 /* this is Linux only */
39112 -                               
39113 -                               log_error_write(srv, __FILE__, __LINE__, "s", 
39114 +
39115 +                               log_error_write(srv, __FILE__, __LINE__, "s",
39116                                                 "If this happend on Linux: You have been run out of local ports. "
39117                                                 "Check the manual, section Performance how to handle this.");
39118 -                       } 
39119 -                       
39120 +                       }
39121 +
39122                         return -1;
39123                 }
39124         }
39125         if (hctx->conf.debug > 1) {
39126 -               log_error_write(srv, __FILE__, __LINE__, "sd", 
39127 +               log_error_write(srv, __FILE__, __LINE__, "sd",
39128                                 "connect succeeded: ", scgi_fd);
39129         }
39130  
39131  
39132 -       
39133 +
39134         return 0;
39135  }
39136  
39137  static int scgi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
39138         size_t i;
39139 -       
39140 +
39141         for (i = 0; i < con->request.headers->used; i++) {
39142                 data_string *ds;
39143 -               
39144 +
39145                 ds = (data_string *)con->request.headers->data[i];
39146 -               
39147 +
39148                 if (ds->value->used && ds->key->used) {
39149                         size_t j;
39150                         buffer_reset(srv->tmp_buf);
39151 -                       
39152 +
39153                         if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
39154                                 BUFFER_COPY_STRING_CONST(srv->tmp_buf, "HTTP_");
39155                                 srv->tmp_buf->used--;
39156                         }
39157 -                       
39158 +
39159                         buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
39160                         for (j = 0; j < ds->key->used - 1; j++) {
39161 -                               srv->tmp_buf->ptr[srv->tmp_buf->used++] = 
39162 -                                       light_isalpha(ds->key->ptr[j]) ? 
39163 +                               srv->tmp_buf->ptr[srv->tmp_buf->used++] =
39164 +                                       light_isalpha(ds->key->ptr[j]) ?
39165                                         ds->key->ptr[j] & ~32 : '_';
39166                         }
39167                         srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
39168 -                       
39169 +
39170                         scgi_env_add(p->scgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
39171                 }
39172         }
39173 -       
39174 +
39175         for (i = 0; i < con->environment->used; i++) {
39176                 data_string *ds;
39177 -               
39178 +
39179                 ds = (data_string *)con->environment->data[i];
39180 -               
39181 +
39182                 if (ds->value->used && ds->key->used) {
39183                         size_t j;
39184                         buffer_reset(srv->tmp_buf);
39185 -                       
39186 +
39187                         buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
39188                         for (j = 0; j < ds->key->used - 1; j++) {
39189 -                               srv->tmp_buf->ptr[srv->tmp_buf->used++] = 
39190 -                                       isalpha((unsigned char)ds->key->ptr[j]) ? 
39191 +                               srv->tmp_buf->ptr[srv->tmp_buf->used++] =
39192 +                                       isalpha((unsigned char)ds->key->ptr[j]) ?
39193                                         toupper((unsigned char)ds->key->ptr[j]) : '_';
39194                         }
39195                         srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
39196 -                       
39197 +
39198                         scgi_env_add(p->scgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
39199                 }
39200         }
39201 -       
39202 +
39203         return 0;
39204  }
39205  
39206 @@ -1415,20 +1399,20 @@
39207         char b2[INET6_ADDRSTRLEN + 1];
39208  #endif
39209         buffer *b;
39210 -       
39211 +
39212         plugin_data *p    = hctx->plugin_data;
39213         scgi_extension_host *host= hctx->host;
39214  
39215         connection *con   = hctx->remote_conn;
39216         server_socket *srv_sock = con->srv_socket;
39217 -       
39218 +
39219         sock_addr our_addr;
39220         socklen_t our_addr_len;
39221 -       
39222 +
39223         buffer_prepare_copy(p->scgi_env, 1024);
39224  
39225         /* CGI-SPEC 6.1.2, FastCGI spec 6.3 and SCGI spec */
39226 -               
39227 +
39228         /* request.content_length < SSIZE_MAX, see request.c */
39229         ltostr(buf, con->request.content_length);
39230         scgi_env_add(p->scgi_env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
39231 @@ -1436,13 +1420,13 @@
39232  
39233  
39234         scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION));
39235 -       
39236 +
39237         if (con->server_name->used) {
39238                 scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_NAME"), CONST_BUF_LEN(con->server_name));
39239         } else {
39240  #ifdef HAVE_IPV6
39241 -               s = inet_ntop(srv_sock->addr.plain.sa_family, 
39242 -                             srv_sock->addr.plain.sa_family == AF_INET6 ? 
39243 +               s = inet_ntop(srv_sock->addr.plain.sa_family,
39244 +                             srv_sock->addr.plain.sa_family == AF_INET6 ?
39245                               (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
39246                               (const void *) &(srv_sock->addr.ipv4.sin_addr),
39247                               b2, sizeof(b2)-1);
39248 @@ -1451,47 +1435,47 @@
39249  #endif
39250                 scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_NAME"), s, strlen(s));
39251         }
39252 -       
39253 +
39254         scgi_env_add(p->scgi_env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
39255 -       
39256 -       ltostr(buf, 
39257 +
39258 +       ltostr(buf,
39259  #ifdef HAVE_IPV6
39260                ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
39261  #else
39262                ntohs(srv_sock->addr.ipv4.sin_port)
39263  #endif
39264                );
39265 -       
39266 +
39267         scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
39268 -       
39269 +
39270         /* get the server-side of the connection to the client */
39271         our_addr_len = sizeof(our_addr);
39272 -       
39273 -       if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) {
39274 +
39275 +       if (-1 == getsockname(con->sock->fd, &(our_addr.plain), &our_addr_len)) {
39276                 s = inet_ntop_cache_get_ip(srv, &(srv_sock->addr));
39277         } else {
39278                 s = inet_ntop_cache_get_ip(srv, &(our_addr));
39279         }
39280         scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
39281 -       
39282 -       ltostr(buf, 
39283 +
39284 +       ltostr(buf,
39285  #ifdef HAVE_IPV6
39286                ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
39287  #else
39288                ntohs(con->dst_addr.ipv4.sin_port)
39289  #endif
39290                );
39291 -       
39292 +
39293         scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
39294 -       
39295 +
39296         s = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
39297         scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
39298 -       
39299 +
39300         if (!buffer_is_empty(con->authed_user)) {
39301                 scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_USER"),
39302                              CONST_BUF_LEN(con->authed_user));
39303         }
39304 -       
39305 +
39306  
39307         /*
39308          * SCRIPT_NAME, PATH_INFO and PATH_TRANSLATED according to
39309 @@ -1500,12 +1484,12 @@
39310          */
39311  
39312         scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
39313 -               
39314 +
39315         if (!buffer_is_empty(con->request.pathinfo)) {
39316                 scgi_env_add(p->scgi_env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
39317 -               
39318 +
39319                 /* PATH_TRANSLATED is only defined if PATH_INFO is set */
39320 -               
39321 +
39322                 if (!buffer_is_empty(host->docroot)) {
39323                         buffer_copy_string_buffer(p->path, host->docroot);
39324                 } else {
39325 @@ -1526,19 +1510,19 @@
39326          */
39327  
39328         if (!buffer_is_empty(host->docroot)) {
39329 -               /* 
39330 -                * rewrite SCRIPT_FILENAME 
39331 -                * 
39332 +               /*
39333 +                * rewrite SCRIPT_FILENAME
39334 +                *
39335                  */
39336 -               
39337 +
39338                 buffer_copy_string_buffer(p->path, host->docroot);
39339                 buffer_append_string_buffer(p->path, con->uri.path);
39340 -               
39341 +
39342                 scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
39343                 scgi_env_add(p->scgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(host->docroot));
39344         } else {
39345                 buffer_copy_string_buffer(p->path, con->physical.path);
39346 -               
39347 +
39348                 scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
39349                 scgi_env_add(p->scgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root));
39350         }
39351 @@ -1551,32 +1535,32 @@
39352         } else {
39353                 scgi_env_add(p->scgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
39354         }
39355 -       
39356 +
39357         s = get_http_method_name(con->request.http_method);
39358         scgi_env_add(p->scgi_env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
39359         scgi_env_add(p->scgi_env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")); /* if php is compiled with --force-redirect */
39360         s = get_http_version_name(con->request.http_version);
39361         scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
39362 -       
39363 +
39364  #ifdef USE_OPENSSL
39365         if (srv_sock->is_ssl) {
39366                 scgi_env_add(p->scgi_env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on"));
39367         }
39368  #endif
39369 -       
39370 +
39371         scgi_env_add_request_headers(srv, con, p);
39372  
39373         b = chunkqueue_get_append_buffer(hctx->wb);
39374 -       
39375 +
39376         buffer_append_long(b, p->scgi_env->used);
39377         buffer_append_string_len(b, CONST_STR_LEN(":"));
39378         buffer_append_string_len(b, (const char *)p->scgi_env->ptr, p->scgi_env->used);
39379         buffer_append_string_len(b, CONST_STR_LEN(","));
39380  
39381         hctx->wb->bytes_in += b->used - 1;
39382 -       
39383 +
39384         if (con->request.content_length) {
39385 -               chunkqueue *req_cq = con->request_content_queue;
39386 +               chunkqueue *req_cq = con->recv;
39387                 chunk *req_c;
39388                 off_t offset;
39389  
39390 @@ -1587,7 +1571,7 @@
39391  
39392                         /* we announce toWrite octects
39393                          * now take all the request_content chunk that we need to fill this request
39394 -                        * */   
39395 +                        * */
39396  
39397                         switch (req_c->type) {
39398                         case FILE_CHUNK:
39399 @@ -1615,293 +1599,170 @@
39400  
39401                                 req_c->offset += weHave;
39402                                 req_cq->bytes_out += weHave;
39403 -                               
39404 +
39405                                 hctx->wb->bytes_in += weHave;
39406  
39407                                 break;
39408                         default:
39409                                 break;
39410                         }
39411 -                       
39412 +
39413                         offset += weHave;
39414                 }
39415         }
39416 -       
39417 +
39418  #if 0
39419         for (i = 0; i < hctx->write_buffer->used; i++) {
39420                 fprintf(stderr, "%02x ", hctx->write_buffer->ptr[i]);
39421                 if ((i+1) % 16 == 0) {
39422                         size_t j;
39423                         for (j = i-15; j <= i; j++) {
39424 -                               fprintf(stderr, "%c", 
39425 +                               fprintf(stderr, "%c",
39426                                         isprint((unsigned char)hctx->write_buffer->ptr[j]) ? hctx->write_buffer->ptr[j] : '.');
39427                         }
39428                         fprintf(stderr, "\n");
39429                 }
39430         }
39431  #endif
39432 -       
39433 -       return 0;
39434 -}
39435  
39436 -static int scgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in, int eol) {
39437 -       char *ns;
39438 -       const char *s;
39439 -       int line = 0;
39440 -       
39441 -       UNUSED(srv);
39442 -       
39443 -       buffer_copy_string_buffer(p->parse_response, in);
39444 -       
39445 -       for (s = p->parse_response->ptr; 
39446 -            NULL != (ns = (eol == EOL_RN ? strstr(s, "\r\n") : strchr(s, '\n'))); 
39447 -            s = ns + (eol == EOL_RN ? 2 : 1), line++) {
39448 -               const char *key, *value;
39449 -               int key_len;
39450 -               data_string *ds;
39451 -               
39452 -               ns[0] = '\0';
39453 -               
39454 -               if (line == 0 && 
39455 -                   0 == strncmp(s, "HTTP/1.", 7)) {
39456 -                       /* non-parsed header ... we parse them anyway */
39457 -                       
39458 -                       if ((s[7] == '1' ||
39459 -                            s[7] == '0') &&
39460 -                           s[8] == ' ') {
39461 -                               int status;
39462 -                               /* after the space should be a status code for us */
39463 -                               
39464 -                               status = strtol(s+9, NULL, 10);
39465 -                               
39466 -                               if (con->http_status >= 100 &&
39467 -                                   con->http_status < 1000) {
39468 -                                       /* we expected 3 digits and didn't got them */
39469 -                                       con->parsed_response |= HTTP_STATUS;
39470 -                                       con->http_status = status;
39471 -                               }
39472 -                       }
39473 -               } else {
39474 -               
39475 -                       key = s;
39476 -                       if (NULL == (value = strchr(s, ':'))) {
39477 -                               /* we expect: "<key>: <value>\r\n" */
39478 -                               continue;
39479 -                       }
39480 -                       
39481 -                       key_len = value - key;
39482 -                       value += 1;
39483 -                       
39484 -                       /* skip LWS */
39485 -                       while (*value == ' ' || *value == '\t') value++;
39486 -                       
39487 -                       if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
39488 -                               ds = data_response_init();
39489 -                       }
39490 -                       buffer_copy_string_len(ds->key, key, key_len);
39491 -                       buffer_copy_string(ds->value, value);
39492 -                       
39493 -                       array_insert_unique(con->response.headers, (data_unset *)ds);
39494 -                       
39495 -                       switch(key_len) {
39496 -                       case 4:
39497 -                               if (0 == strncasecmp(key, "Date", key_len)) {
39498 -                                       con->parsed_response |= HTTP_DATE;
39499 -                               }
39500 -                               break;
39501 -                       case 6:
39502 -                               if (0 == strncasecmp(key, "Status", key_len)) {
39503 -                                       con->http_status = strtol(value, NULL, 10);
39504 -                                       con->parsed_response |= HTTP_STATUS;
39505 -                               }
39506 -                               break;
39507 -                       case 8:
39508 -                               if (0 == strncasecmp(key, "Location", key_len)) {
39509 -                                       con->parsed_response |= HTTP_LOCATION;
39510 -                               }
39511 -                               break;
39512 -                       case 10:
39513 -                               if (0 == strncasecmp(key, "Connection", key_len)) {
39514 -                                       con->response.keep_alive = (0 == strcasecmp(value, "Keep-Alive")) ? 1 : 0;
39515 -                                       con->parsed_response |= HTTP_CONNECTION;
39516 -                               }
39517 -                               break;
39518 -                       case 14:
39519 -                               if (0 == strncasecmp(key, "Content-Length", key_len)) {
39520 -                                       con->response.content_length = strtol(value, NULL, 10);
39521 -                                       con->parsed_response |= HTTP_CONTENT_LENGTH;
39522 -                               }
39523 -                               break;
39524 -                       default:
39525 -                               break;
39526 -                       }
39527 -               }
39528 -       }
39529 -       
39530 -       /* CGI/1.1 rev 03 - 7.2.1.2 */
39531 -       if ((con->parsed_response & HTTP_LOCATION) &&
39532 -           !(con->parsed_response & HTTP_STATUS)) {
39533 -               con->http_status = 302;
39534 -       }
39535 -       
39536         return 0;
39537  }
39538  
39539 -
39540  static int scgi_demux_response(server *srv, handler_ctx *hctx) {
39541         plugin_data *p    = hctx->plugin_data;
39542         connection  *con  = hctx->remote_conn;
39543 -       
39544 -       while(1) {
39545 -               int n;
39546 -               
39547 -               buffer_prepare_copy(hctx->response, 1024);
39548 -               if (-1 == (n = read(hctx->fd, hctx->response->ptr, hctx->response->size - 1))) {
39549 -                       if (errno == EAGAIN || errno == EINTR) {
39550 -                               /* would block, wait for signal */
39551 -                               return 0;
39552 -                       }
39553 -                       /* error */
39554 -                       log_error_write(srv, __FILE__, __LINE__, "sdd", strerror(errno), con->fd, hctx->fd);
39555 -                       return -1;
39556 -               }
39557 -               
39558 -               if (n == 0) {
39559 -                       /* read finished */
39560 -                       
39561 -                       con->file_finished = 1;
39562 -                       
39563 -                       /* send final chunk */
39564 -                       http_chunk_append_mem(srv, con, NULL, 0);
39565 -                       joblist_append(srv, con);
39566 -                       
39567 +       chunk *c;
39568 +
39569 +       switch(srv->network_backend_read(srv, con, hctx->sock, hctx->rb)) {
39570 +       case NETWORK_STATUS_SUCCESS:
39571 +               /* we got content */
39572 +               break;
39573 +       case NETWORK_STATUS_WAIT_FOR_EVENT:
39574 +               /* the ioctl will return WAIT_FOR_EVENT on a read */
39575 +               if (0 == con->file_started) return -1;
39576 +       case NETWORK_STATUS_CONNECTION_CLOSE:
39577 +               /* we are done, get out of here */
39578 +               con->send->is_closed = 1;
39579 +
39580 +               /* close the chunk-queue with a empty chunk */
39581 +
39582 +               return 1;
39583 +       default:
39584 +               /* oops */
39585 +               return -1;
39586 +       }
39587 +
39588 +       /* looks like we got some content
39589 +       *
39590 +       * split off the header from the incoming stream
39591 +       */
39592 +
39593 +       if (hctx->state == SCGI_STATE_RESPONSE_HEADER) {
39594 +               size_t i;
39595 +               int have_content_length = 0;
39596 +
39597 +               http_response_reset(p->resp);
39598 +
39599 +               /* the response header is not fully received yet,
39600 +               *
39601 +               * extract the http-response header from the rb-cq
39602 +               */
39603 +               switch (http_response_parse_cq(hctx->rb, p->resp)) {
39604 +               case PARSE_ERROR:
39605 +                       /* parsing failed */
39606 +
39607 +                       con->http_status = 502; /* Bad Gateway */
39608                         return 1;
39609 -               }
39610 -               
39611 -               hctx->response->ptr[n] = '\0';
39612 -               hctx->response->used = n+1;
39613 -               
39614 -               /* split header from body */
39615 -               
39616 -               if (con->file_started == 0) {
39617 -                       char *c;
39618 -                       int in_header = 0;
39619 -                       int header_end = 0;
39620 -                       int cp, eol = EOL_UNSET;
39621 -                       size_t used = 0;
39622 -                       
39623 -                       buffer_append_string_buffer(hctx->response_header, hctx->response);
39624 -                       
39625 -                       /* nph (non-parsed headers) */
39626 -                       if (0 == strncmp(hctx->response_header->ptr, "HTTP/1.", 7)) in_header = 1;
39627 -                       
39628 -                       /* search for the \r\n\r\n or \n\n in the string */
39629 -                       for (c = hctx->response_header->ptr, cp = 0, used = hctx->response_header->used - 1; used; c++, cp++, used--) {
39630 -                               if (*c == ':') in_header = 1;
39631 -                               else if (*c == '\n') {
39632 -                                       if (in_header == 0) {
39633 -                                               /* got a response without a response header */
39634 -                                               
39635 -                                               c = NULL;
39636 -                                               header_end = 1;
39637 -                                               break;
39638 -                                       }
39639 -                                       
39640 -                                       if (eol == EOL_UNSET) eol = EOL_N;
39641 -                                       
39642 -                                       if (*(c+1) == '\n') {
39643 -                                               header_end = 1;
39644 -                                               break;
39645 -                                       }
39646 -                                       
39647 -                               } else if (used > 1 && *c == '\r' && *(c+1) == '\n') {
39648 -                                       if (in_header == 0) {
39649 -                                               /* got a response without a response header */
39650 -                                               
39651 -                                               c = NULL;
39652 -                                               header_end = 1;
39653 -                                               break;
39654 -                                       }
39655 -                                       
39656 -                                       if (eol == EOL_UNSET) eol = EOL_RN;
39657 -                                       
39658 -                                       if (used > 3 &&
39659 -                                           *(c+2) == '\r' && 
39660 -                                           *(c+3) == '\n') {
39661 -                                               header_end = 1;
39662 -                                               break;
39663 -                                       }
39664 -                                       
39665 -                                       /* skip the \n */
39666 -                                       c++;
39667 -                                       cp++;
39668 -                                       used--;
39669 +               case PARSE_NEED_MORE:
39670 +                       return 0;
39671 +               case PARSE_SUCCESS:
39672 +                       con->http_status = p->resp->status;
39673 +
39674 +                       chunkqueue_remove_finished_chunks(hctx->rb);
39675 +
39676 +                       /* copy the http-headers */
39677 +                       for (i = 0; i < p->resp->headers->used; i++) {
39678 +                               const char *ign[] = { "Status", "Connection", NULL };
39679 +                               size_t j;
39680 +                               data_string *ds;
39681 +
39682 +                               data_string *header = (data_string *)p->resp->headers->data[i];
39683 +
39684 +                               /* some headers are ignored by default */
39685 +                               for (j = 0; ign[j]; j++) {
39686 +                                       if (0 == strcasecmp(ign[j], header->key->ptr)) break;
39687                                 }
39688 -                       }
39689 -                       
39690 -                       if (header_end) {
39691 -                               if (c == NULL) {
39692 -                                       /* no header, but a body */
39693 -                                       
39694 -                                       if (con->request.http_version == HTTP_VERSION_1_1) {
39695 -                                               con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
39696 -                                       }
39697 -                                       
39698 -                                       http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used);
39699 -                                       joblist_append(srv, con);
39700 -                               } else {
39701 -                                       size_t hlen = c - hctx->response_header->ptr + (eol == EOL_RN ? 4 : 2);
39702 -                                       size_t blen = hctx->response_header->used - hlen - 1;
39703 -                               
39704 -                                       /* a small hack: terminate after at the second \r */
39705 -                                       hctx->response_header->used = hlen + 1 - (eol == EOL_RN ? 2 : 1);
39706 -                                       hctx->response_header->ptr[hlen - (eol == EOL_RN ? 2 : 1)] = '\0';
39707 -                               
39708 -                                       /* parse the response header */
39709 -                                       scgi_response_parse(srv, con, p, hctx->response_header, eol);
39710 -                                       
39711 -                                       /* enable chunked-transfer-encoding */
39712 -                                       if (con->request.http_version == HTTP_VERSION_1_1 &&
39713 -                                           !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
39714 -                                               con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
39715 -                                       }
39716 -                                       
39717 -                                       if ((hctx->response->used != hlen) && blen > 0) {
39718 -                                               http_chunk_append_mem(srv, con, c + (eol == EOL_RN ? 4: 2), blen + 1);
39719 -                                               joblist_append(srv, con);
39720 -                                       }
39721 +                               if (ign[j]) continue;
39722 +
39723 +                               if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
39724 +                                       /* CGI/1.1 rev 03 - 7.2.1.2 */
39725 +                                       if (con->http_status == 0) con->http_status = 302;
39726 +                               } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
39727 +                                       have_content_length = 1;
39728                                 }
39729                                 
39730 -                               con->file_started = 1;
39731 +                               if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
39732 +                                       ds = data_response_init();
39733 +                               }
39734 +                               buffer_copy_string_buffer(ds->key, header->key);
39735 +                               buffer_copy_string_buffer(ds->value, header->value);
39736 +
39737 +                               array_insert_unique(con->response.headers, (data_unset *)ds);
39738                         }
39739 -               } else {
39740 -                       http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used);
39741 -                       joblist_append(srv, con);
39742 +
39743 +                       con->file_started = 1;
39744 +
39745 +                       if (con->request.http_version == HTTP_VERSION_1_1 &&
39746 +                           !have_content_length) {
39747 +                               con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
39748 +                       }
39749 +
39750 +                       hctx->state = SCGI_STATE_RESPONSE_CONTENT;
39751 +                       break;
39752                 }
39753 -               
39754 -#if 0          
39755 -               log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), b->ptr);
39756 -#endif
39757         }
39758 -       
39759 +
39760 +       /* FIXME: pass the response-header to the other plugins to
39761 +       * setup the filter-queue
39762 +       *
39763 +       * - use next-queue instead of con->write_queue
39764 +       */
39765 +
39766 +       assert(hctx->state == SCGI_STATE_RESPONSE_CONTENT);
39767 +
39768 +       /* FIXME: if we have a content-length or chunked-encoding
39769 +       * handle it.
39770 +       *
39771 +       * for now we wait for EOF on the socket */
39772 +
39773 +       /* copy the content to the next cq */
39774 +       for (c = hctx->rb->first; c; c = c->next) {
39775 +               chunkqueue_append_mem(con->send, c->mem->ptr + c->offset, c->mem->used - c->offset);
39776 +
39777 +               c->offset = c->mem->used - 1;
39778 +       }
39779 +
39780 +       chunkqueue_remove_finished_chunks(hctx->rb);
39781 +       joblist_append(srv, con);
39782 +
39783         return 0;
39784  }
39785  
39786  
39787  int scgi_proclist_sort_up(server *srv, scgi_extension_host *host, scgi_proc *proc) {
39788         scgi_proc *p;
39789 -       
39790 +
39791         UNUSED(srv);
39792 -       
39793 -       /* we have been the smallest of the current list 
39794 -        * and we want to insert the node sorted as soon 
39795 +
39796 +       /* we have been the smallest of the current list
39797 +        * and we want to insert the node sorted as soon
39798          * possible
39799          *
39800 -        * 1 0 0 0 1 1 1 
39801 -        * |      ^ 
39802 +        * 1 0 0 0 1 1 1
39803 +        * |      ^
39804          * |      |
39805          * +------+
39806 -        * 
39807 +        *
39808          */
39809  
39810         /* nothing to sort, only one element */
39811 @@ -1909,9 +1770,9 @@
39812  
39813         for (p = proc; p->next && p->next->load < proc->load; p = p->next);
39814  
39815 -       /* no need to move something 
39816 +       /* no need to move something
39817          *
39818 -        * 1 2 2 2 3 3 3 
39819 +        * 1 2 2 2 3 3 3
39820          * ^
39821          * |
39822          * +
39823 @@ -1930,16 +1791,16 @@
39824  
39825         if (proc->prev) proc->prev->next = proc->next;
39826         if (proc->next) proc->next->prev = proc->prev;
39827 -       
39828 +
39829         /* proc should be right of p */
39830 -       
39831 +
39832         proc->next = p->next;
39833         proc->prev = p;
39834         if (p->next) p->next->prev = proc;
39835         p->next = proc;
39836  #if 0
39837         for(p = host->first; p; p = p->next) {
39838 -               log_error_write(srv, __FILE__, __LINE__, "dd", 
39839 +               log_error_write(srv, __FILE__, __LINE__, "dd",
39840                                 p->pid, p->load);
39841         }
39842  #else
39843 @@ -1951,21 +1812,21 @@
39844  
39845  int scgi_proclist_sort_down(server *srv, scgi_extension_host *host, scgi_proc *proc) {
39846         scgi_proc *p;
39847 -       
39848 +
39849         UNUSED(srv);
39850 -       
39851 -       /* we have been the smallest of the current list 
39852 -        * and we want to insert the node sorted as soon 
39853 +
39854 +       /* we have been the smallest of the current list
39855 +        * and we want to insert the node sorted as soon
39856          * possible
39857          *
39858 -        *  0 0 0 0 1 0 1 
39859 +        *  0 0 0 0 1 0 1
39860          * ^          |
39861          * |          |
39862          * +----------+
39863          *
39864          *
39865          * the basic is idea is:
39866 -        * - the last active scgi process should be still 
39867 +        * - the last active scgi process should be still
39868          *   in ram and is not swapped out yet
39869          * - processes that are not reused will be killed
39870          *   after some time by the trigger-handler
39871 @@ -1975,7 +1836,7 @@
39872          *   ice-cold processes are propably unused since more
39873          *   than 'unused-timeout', are swaped out and won't be
39874          *   reused in the next seconds anyway.
39875 -        * 
39876 +        *
39877          */
39878  
39879         /* nothing to sort, only one element */
39880 @@ -1984,16 +1845,16 @@
39881         for (p = host->first; p != proc && p->load < proc->load; p = p->next);
39882  
39883  
39884 -       /* no need to move something 
39885 +       /* no need to move something
39886          *
39887 -        * 1 2 2 2 3 3 3 
39888 +        * 1 2 2 2 3 3 3
39889          * ^
39890          * |
39891          * +
39892          *
39893          */
39894         if (p == proc) return 0;
39895 -       
39896 +
39897         /* we have to move left. If we are already the first element
39898          * we are done */
39899         if (host->first == proc) return 0;
39900 @@ -2009,9 +1870,9 @@
39901         p->prev = proc;
39902  
39903         if (proc->prev == NULL) host->first = proc;
39904 -#if 0  
39905 +#if 0
39906         for(p = host->first; p; p = p->next) {
39907 -               log_error_write(srv, __FILE__, __LINE__, "dd", 
39908 +               log_error_write(srv, __FILE__, __LINE__, "dd",
39909                                 p->pid, p->load);
39910         }
39911  #else
39912 @@ -2023,41 +1884,42 @@
39913  
39914  static int scgi_restart_dead_procs(server *srv, plugin_data *p, scgi_extension_host *host) {
39915         scgi_proc *proc;
39916 -       
39917 +
39918         for (proc = host->first; proc; proc = proc->next) {
39919                 if (p->conf.debug) {
39920 -                       log_error_write(srv, __FILE__, __LINE__,  "sbdbdddd", 
39921 -                                       "proc:", 
39922 -                                       host->host, proc->port, 
39923 +                       log_error_write(srv, __FILE__, __LINE__,  "sbdbdddd",
39924 +                                       "proc:",
39925 +                                       host->host, proc->port,
39926                                         proc->socket,
39927                                         proc->state,
39928                                         proc->is_local,
39929                                         proc->load,
39930                                         proc->pid);
39931                 }
39932 -               
39933 +
39934                 if (0 == proc->is_local) {
39935 -                       /* 
39936 -                        * external servers might get disabled 
39937 -                        * 
39938 -                        * enable the server again, perhaps it is back again 
39939 +                       /*
39940 +                        * external servers might get disabled
39941 +                        *
39942 +                        * enable the server again, perhaps it is back again
39943                          */
39944 -                       
39945 +
39946                         if ((proc->state == PROC_STATE_DISABLED) &&
39947                             (srv->cur_ts - proc->disable_ts > host->disable_time)) {
39948                                 proc->state = PROC_STATE_RUNNING;
39949                                 host->active_procs++;
39950 -                               
39951 -                               log_error_write(srv, __FILE__, __LINE__,  "sbdb", 
39952 -                                               "fcgi-server re-enabled:", 
39953 -                                               host->host, host->port, 
39954 +
39955 +                               log_error_write(srv, __FILE__, __LINE__,  "sbdb",
39956 +                                               "fcgi-server re-enabled:",
39957 +                                               host->host, host->port,
39958                                                 host->unixsocket);
39959                         }
39960                 } else {
39961                         /* the child should not terminate at all */
39962                         int status;
39963 -                       
39964 +
39965                         if (proc->state == PROC_STATE_DIED_WAIT_FOR_PID) {
39966 +#ifndef _WIN32
39967                                 switch(waitpid(proc->pid, &status, WNOHANG)) {
39968                                 case 0:
39969                                         /* child is still alive */
39970 @@ -2067,33 +1929,34 @@
39971                                 default:
39972                                         if (WIFEXITED(status)) {
39973  #if 0
39974 -                                               log_error_write(srv, __FILE__, __LINE__, "sdsd", 
39975 +                                               log_error_write(srv, __FILE__, __LINE__, "sdsd",
39976                                                                 "child exited, pid:", proc->pid,
39977                                                                 "status:", WEXITSTATUS(status));
39978  #endif
39979                                         } else if (WIFSIGNALED(status)) {
39980 -                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
39981 -                                                               "child signaled:", 
39982 +                                               log_error_write(srv, __FILE__, __LINE__, "sd",
39983 +                                                               "child signaled:",
39984                                                                 WTERMSIG(status));
39985                                         } else {
39986 -                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
39987 -                                                               "child died somehow:", 
39988 +                                               log_error_write(srv, __FILE__, __LINE__, "sd",
39989 +                                                               "child died somehow:",
39990                                                                 status);
39991                                         }
39992 -                                       
39993 +
39994                                         proc->state = PROC_STATE_DIED;
39995                                         break;
39996                                 }
39997 +#endif
39998                         }
39999 -                       
40000 -                       /* 
40001 +
40002 +                       /*
40003                          * local servers might died, but we restart them
40004 -                        * 
40005 +                        *
40006                          */
40007                         if (proc->state == PROC_STATE_DIED &&
40008                             proc->load == 0) {
40009                                 /* restart the child */
40010 -                               
40011 +
40012                                 if (p->conf.debug) {
40013                                         log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
40014                                                         "--- scgi spawning",
40015 @@ -2101,18 +1964,18 @@
40016                                                         "\n\tsocket", host->unixsocket,
40017                                                         "\n\tcurrent:", 1, "/", host->min_procs);
40018                                 }
40019 -                               
40020 +
40021                                 if (scgi_spawn_connection(srv, p, host, proc)) {
40022                                         log_error_write(srv, __FILE__, __LINE__, "s",
40023                                                         "ERROR: spawning fcgi failed.");
40024                                         return HANDLER_ERROR;
40025                                 }
40026 -                               
40027 +
40028                                 scgi_proclist_sort_down(srv, host, proc);
40029                         }
40030                 }
40031         }
40032 -       
40033 +
40034         return 0;
40035  }
40036  
40037 @@ -2121,13 +1984,13 @@
40038         plugin_data *p    = hctx->plugin_data;
40039         scgi_extension_host *host= hctx->host;
40040         connection *con   = hctx->remote_conn;
40041 -       
40042 +
40043         int ret;
40044  
40045 -       /* sanity check */      
40046 +       /* sanity check */
40047         if (!host ||
40048             ((!host->host->used || !host->port) && !host->unixsocket->used)) {
40049 -               log_error_write(srv, __FILE__, __LINE__, "sxddd", 
40050 +               log_error_write(srv, __FILE__, __LINE__, "sxddd",
40051                                 "write-req: error",
40052                                 host,
40053                                 host->host->used,
40054 @@ -2135,259 +1998,260 @@
40055                                 host->unixsocket->used);
40056                 return HANDLER_ERROR;
40057         }
40058 -       
40059 +
40060  
40061         switch(hctx->state) {
40062 -       case FCGI_STATE_INIT:
40063 +       case SCGI_STATE_INIT:
40064                 ret = host->unixsocket->used ? AF_UNIX : AF_INET;
40065 -               
40066 -               if (-1 == (hctx->fd = socket(ret, SOCK_STREAM, 0))) {
40067 +
40068 +               if (-1 == (hctx->sock->fd = socket(ret, SOCK_STREAM, 0))) {
40069                         if (errno == EMFILE ||
40070                             errno == EINTR) {
40071 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
40072 -                                               "wait for fd at connection:", con->fd);
40073 -                               
40074 +                               log_error_write(srv, __FILE__, __LINE__, "sd",
40075 +                                               "wait for fd at connection:", con->sock->fd);
40076 +
40077                                 return HANDLER_WAIT_FOR_FD;
40078                         }
40079 -                       
40080 -                       log_error_write(srv, __FILE__, __LINE__, "ssdd", 
40081 +
40082 +                       log_error_write(srv, __FILE__, __LINE__, "ssdd",
40083                                         "socket failed:", strerror(errno), srv->cur_fds, srv->max_fds);
40084                         return HANDLER_ERROR;
40085                 }
40086 -               hctx->fde_ndx = -1;
40087 -               
40088 +               hctx->sock->fde_ndx = -1;
40089 +
40090                 srv->cur_fds++;
40091 -               
40092 -               fdevent_register(srv->ev, hctx->fd, scgi_handle_fdevent, hctx);
40093 -               
40094 -               if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
40095 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
40096 +
40097 +               fdevent_register(srv->ev, hctx->sock, scgi_handle_fdevent, hctx);
40098 +
40099 +               if (-1 == fdevent_fcntl_set(srv->ev, hctx->sock)) {
40100 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
40101                                         "fcntl failed: ", strerror(errno));
40102 -                       
40103 +
40104                         return HANDLER_ERROR;
40105                 }
40106 -               
40107 +
40108                 /* fall through */
40109 -       case FCGI_STATE_CONNECT:
40110 -               if (hctx->state == FCGI_STATE_INIT) {
40111 -                       for (hctx->proc = hctx->host->first; 
40112 -                            hctx->proc && hctx->proc->state != PROC_STATE_RUNNING; 
40113 +       case SCGI_STATE_CONNECT:
40114 +               if (hctx->state == SCGI_STATE_INIT) {
40115 +                       for (hctx->proc = hctx->host->first;
40116 +                            hctx->proc && hctx->proc->state != PROC_STATE_RUNNING;
40117                              hctx->proc = hctx->proc->next);
40118 -                       
40119 +
40120                         /* all childs are dead */
40121                         if (hctx->proc == NULL) {
40122 -                               hctx->fde_ndx = -1;
40123 -                               
40124 +                               hctx->sock->fde_ndx = -1;
40125 +
40126                                 return HANDLER_ERROR;
40127                         }
40128 -                       
40129 +
40130                         if (hctx->proc->is_local) {
40131                                 hctx->pid = hctx->proc->pid;
40132                         }
40133 -                       
40134 +
40135                         switch (scgi_establish_connection(srv, hctx)) {
40136                         case 1:
40137 -                               scgi_set_state(srv, hctx, FCGI_STATE_CONNECT);
40138 -                               
40139 +                               scgi_set_state(srv, hctx, SCGI_STATE_CONNECT);
40140 +
40141                                 /* connection is in progress, wait for an event and call getsockopt() below */
40142 -                               
40143 -                               fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
40144 -                               
40145 +
40146 +                               fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
40147 +
40148                                 return HANDLER_WAIT_FOR_EVENT;
40149                         case -1:
40150                                 /* if ECONNREFUSED choose another connection -> FIXME */
40151 -                               hctx->fde_ndx = -1;
40152 -                               
40153 +                               hctx->sock->fde_ndx = -1;
40154 +
40155                                 return HANDLER_ERROR;
40156                         default:
40157                                 /* everything is ok, go on */
40158                                 break;
40159                         }
40160  
40161 -                       
40162 +
40163                 } else {
40164                         int socket_error;
40165                         socklen_t socket_error_len = sizeof(socket_error);
40166 -                       
40167 +
40168                         /* try to finish the connect() */
40169 -                       if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
40170 -                               log_error_write(srv, __FILE__, __LINE__, "ss", 
40171 +                       if (0 != getsockopt(hctx->sock->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
40172 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
40173                                                 "getsockopt failed:", strerror(errno));
40174 -                               
40175 +
40176                                 return HANDLER_ERROR;
40177                         }
40178                         if (socket_error != 0) {
40179                                 if (!hctx->proc->is_local || p->conf.debug) {
40180                                         /* local procs get restarted */
40181 -                                       
40182 +
40183                                         log_error_write(srv, __FILE__, __LINE__, "ss",
40184 -                                                       "establishing connection failed:", strerror(socket_error), 
40185 +                                                       "establishing connection failed:", strerror(socket_error),
40186                                                         "port:", hctx->proc->port);
40187                                 }
40188 -                               
40189 +
40190                                 return HANDLER_ERROR;
40191                         }
40192                 }
40193 -               
40194 +
40195                 /* ok, we have the connection */
40196 -               
40197 +
40198                 hctx->proc->load++;
40199                 hctx->proc->last_used = srv->cur_ts;
40200                 hctx->got_proc = 1;
40201 -               
40202 +
40203                 if (p->conf.debug) {
40204                         log_error_write(srv, __FILE__, __LINE__, "sddbdd",
40205 -                                       "got proc:", 
40206 -                                       hctx->fd,
40207 -                                       hctx->proc->pid, 
40208 -                                       hctx->proc->socket, 
40209 +                                       "got proc:",
40210 +                                       hctx->sock->fd,
40211 +                                       hctx->proc->pid,
40212 +                                       hctx->proc->socket,
40213                                         hctx->proc->port,
40214                                         hctx->proc->load);
40215                 }
40216  
40217                 /* move the proc-list entry down the list */
40218                 scgi_proclist_sort_up(srv, hctx->host, hctx->proc);
40219 -               
40220 -               scgi_set_state(srv, hctx, FCGI_STATE_PREPARE_WRITE);
40221 +
40222 +               scgi_set_state(srv, hctx, SCGI_STATE_PREPARE_WRITE);
40223                 /* fall through */
40224 -       case FCGI_STATE_PREPARE_WRITE:
40225 +       case SCGI_STATE_PREPARE_WRITE:
40226                 scgi_create_env(srv, hctx);
40227 -               
40228 -               scgi_set_state(srv, hctx, FCGI_STATE_WRITE);
40229 -               
40230 +
40231 +               scgi_set_state(srv, hctx, SCGI_STATE_WRITE);
40232 +
40233                 /* fall through */
40234 -       case FCGI_STATE_WRITE:
40235 -               ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb); 
40236 +       case SCGI_STATE_WRITE:
40237 +               ret = srv->network_backend_write(srv, con, hctx->sock, hctx->wb);
40238  
40239                 chunkqueue_remove_finished_chunks(hctx->wb);
40240 -       
40241 +
40242                 if (-1 == ret) {
40243                         if (errno == ENOTCONN) {
40244 -                               /* the connection got dropped after accept() 
40245 -                                * 
40246 -                                * this is most of the time a PHP which dies 
40247 +                               /* the connection got dropped after accept()
40248 +                                *
40249 +                                * this is most of the time a PHP which dies
40250                                  * after PHP_FCGI_MAX_REQUESTS
40251 -                                * 
40252 -                                */ 
40253 +                                *
40254 +                                */
40255                                 if (hctx->wb->bytes_out == 0 &&
40256                                     hctx->reconnects < 5) {
40257 -                                       usleep(10000); /* take away the load of the webserver 
40258 -                                                       * to let the php a chance to restart 
40259 +#ifndef _WIN32
40260 +                                       usleep(10000); /* take away the load of the webserver
40261 +                                                       * to let the php a chance to restart
40262                                                         */
40263 -                                       
40264 +#endif
40265                                         scgi_reconnect(srv, hctx);
40266 -                               
40267 +
40268                                         return HANDLER_WAIT_FOR_FD;
40269                                 }
40270 -                               
40271 +
40272                                 /* not reconnected ... why
40273 -                                * 
40274 +                                *
40275                                  * far@#lighttpd report this for FreeBSD
40276 -                                * 
40277 +                                *
40278                                  */
40279 -                               
40280 -                               log_error_write(srv, __FILE__, __LINE__, "ssdsd", 
40281 +
40282 +                               log_error_write(srv, __FILE__, __LINE__, "ssosd",
40283                                                 "[REPORT ME] connection was dropped after accept(). reconnect() denied:",
40284                                                 "write-offset:", hctx->wb->bytes_out,
40285                                                 "reconnect attempts:", hctx->reconnects);
40286 -                               
40287 +
40288                                 return HANDLER_ERROR;
40289                         }
40290 -                       
40291 +
40292                         if ((errno != EAGAIN) &&
40293                             (errno != EINTR)) {
40294 -                               
40295 -                               log_error_write(srv, __FILE__, __LINE__, "ssd", 
40296 +
40297 +                               log_error_write(srv, __FILE__, __LINE__, "ssd",
40298                                                 "write failed:", strerror(errno), errno);
40299 -                               
40300 +
40301                                 return HANDLER_ERROR;
40302                         } else {
40303 -                               fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
40304 -                               
40305 +                               fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
40306 +
40307                                 return HANDLER_WAIT_FOR_EVENT;
40308                         }
40309                 }
40310 -               
40311 +
40312                 if (hctx->wb->bytes_out == hctx->wb->bytes_in) {
40313                         /* we don't need the out event anymore */
40314 -                       fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
40315 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
40316 -                       scgi_set_state(srv, hctx, FCGI_STATE_READ);
40317 +                       fdevent_event_del(srv->ev, hctx->sock);
40318 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
40319 +                       scgi_set_state(srv, hctx, SCGI_STATE_RESPONSE_HEADER);
40320                 } else {
40321 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
40322 -                       
40323 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
40324 +
40325                         return HANDLER_WAIT_FOR_EVENT;
40326                 }
40327 -               
40328 +
40329                 break;
40330 -       case FCGI_STATE_READ:
40331 +       case SCGI_STATE_RESPONSE_HEADER:
40332                 /* waiting for a response */
40333                 break;
40334         default:
40335                 log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
40336                 return HANDLER_ERROR;
40337         }
40338 -       
40339 +
40340         return HANDLER_WAIT_FOR_EVENT;
40341  }
40342  
40343  SUBREQUEST_FUNC(mod_scgi_handle_subrequest) {
40344         plugin_data *p = p_d;
40345 -       
40346 +
40347         handler_ctx *hctx = con->plugin_ctx[p->id];
40348         scgi_proc *proc;
40349         scgi_extension_host *host;
40350 -       
40351 +
40352         if (NULL == hctx) return HANDLER_GO_ON;
40353 -       
40354 +
40355         /* not my job */
40356         if (con->mode != p->id) return HANDLER_GO_ON;
40357 -       
40358 +
40359         /* ok, create the request */
40360         switch(scgi_write_request(srv, hctx)) {
40361         case HANDLER_ERROR:
40362                 proc = hctx->proc;
40363                 host = hctx->host;
40364 -               
40365 -               if (proc && 
40366 +
40367 +               if (proc &&
40368                     0 == proc->is_local &&
40369                     proc->state != PROC_STATE_DISABLED) {
40370                         /* only disable remote servers as we don't manage them*/
40371 -                       
40372 -                       log_error_write(srv, __FILE__, __LINE__,  "sbdb", "fcgi-server disabled:", 
40373 +
40374 +                       log_error_write(srv, __FILE__, __LINE__,  "sbdb", "fcgi-server disabled:",
40375                                         host->host,
40376                                         proc->port,
40377                                         proc->socket);
40378 -                       
40379 +
40380                         /* disable this server */
40381                         proc->disable_ts = srv->cur_ts;
40382                         proc->state = PROC_STATE_DISABLED;
40383                         host->active_procs--;
40384                 }
40385 -               
40386 -               if (hctx->state == FCGI_STATE_INIT ||
40387 -                   hctx->state == FCGI_STATE_CONNECT) {
40388 -                       /* connect() or getsockopt() failed, 
40389 -                        * restart the request-handling 
40390 +
40391 +               if (hctx->state == SCGI_STATE_INIT ||
40392 +                   hctx->state == SCGI_STATE_CONNECT) {
40393 +                       /* connect() or getsockopt() failed,
40394 +                        * restart the request-handling
40395                          */
40396                         if (proc && proc->is_local) {
40397  
40398                                 if (p->conf.debug) {
40399 -                                       log_error_write(srv, __FILE__, __LINE__,  "sbdb", "connect() to scgi failed, restarting the request-handling:", 
40400 +                                       log_error_write(srv, __FILE__, __LINE__,  "sbdb", "connect() to scgi failed, restarting the request-handling:",
40401                                                         host->host,
40402                                                         proc->port,
40403                                                         proc->socket);
40404                                 }
40405  
40406 -                               /* 
40407 +                               /*
40408                                  * several hctx might reference the same proc
40409 -                                * 
40410 +                                *
40411                                  * Only one of them should mark the proc as dead all the other
40412                                  * ones should just take a new one.
40413 -                                * 
40414 +                                *
40415                                  * If a new proc was started with the old struct this might lead
40416                                  * the mark a perfect proc as dead otherwise
40417 -                                * 
40418 +                                *
40419                                  */
40420                                 if (proc->state == PROC_STATE_RUNNING &&
40421                                     hctx->pid == proc->pid) {
40422 @@ -2395,25 +2259,25 @@
40423                                 }
40424                         }
40425                         scgi_restart_dead_procs(srv, p, host);
40426 -                       
40427 +
40428                         scgi_connection_cleanup(srv, hctx);
40429 -                       
40430 +
40431                         buffer_reset(con->physical.path);
40432                         con->mode = DIRECT;
40433                         joblist_append(srv, con);
40434 -                       
40435 -                       /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop 
40436 -                        * and hope that the childs will be restarted 
40437 -                        * 
40438 +
40439 +                       /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop
40440 +                        * and hope that the childs will be restarted
40441 +                        *
40442                          */
40443                         return HANDLER_WAIT_FOR_FD;
40444                 } else {
40445                         scgi_connection_cleanup(srv, hctx);
40446 -                       
40447 +
40448                         buffer_reset(con->physical.path);
40449                         con->mode = DIRECT;
40450                         con->http_status = 503;
40451 -                       
40452 +
40453                         return HANDLER_FINISHED;
40454                 }
40455         case HANDLER_WAIT_FOR_EVENT:
40456 @@ -2433,23 +2297,23 @@
40457  static handler_t scgi_connection_close(server *srv, handler_ctx *hctx) {
40458         plugin_data *p;
40459         connection  *con;
40460 -       
40461 +
40462         if (NULL == hctx) return HANDLER_GO_ON;
40463 -       
40464 +
40465         p    = hctx->plugin_data;
40466         con  = hctx->remote_conn;
40467 -       
40468 +
40469         if (con->mode != p->id) return HANDLER_GO_ON;
40470 -       
40471 -       log_error_write(srv, __FILE__, __LINE__, "ssdsd", 
40472 -                       "emergency exit: scgi:", 
40473 -                       "connection-fd:", con->fd,
40474 -                       "fcgi-fd:", hctx->fd);
40475 -       
40476 -       
40477 -       
40478 +
40479 +       log_error_write(srv, __FILE__, __LINE__, "ssdsd",
40480 +                       "emergency exit: scgi:",
40481 +                       "connection-fd:", con->sock->fd,
40482 +                       "fcgi-fd:", hctx->sock->fd);
40483 +
40484 +
40485 +
40486         scgi_connection_cleanup(srv, hctx);
40487 -       
40488 +
40489         return HANDLER_FINISHED;
40490  }
40491  
40492 @@ -2459,27 +2323,28 @@
40493         handler_ctx *hctx = ctx;
40494         connection  *con  = hctx->remote_conn;
40495         plugin_data *p    = hctx->plugin_data;
40496 -       
40497 +
40498         scgi_proc *proc   = hctx->proc;
40499         scgi_extension_host *host= hctx->host;
40500  
40501         if ((revents & FDEVENT_IN) &&
40502 -           hctx->state == FCGI_STATE_READ) {
40503 +           (hctx->state == SCGI_STATE_RESPONSE_HEADER ||
40504 +            hctx->state == SCGI_STATE_RESPONSE_CONTENT)) {
40505                 switch (scgi_demux_response(srv, hctx)) {
40506                 case 0:
40507                         break;
40508                 case 1:
40509                         /* we are done */
40510                         scgi_connection_cleanup(srv, hctx);
40511 -                       
40512 +
40513                         joblist_append(srv, con);
40514                         return HANDLER_FINISHED;
40515                 case -1:
40516                         if (proc->pid && proc->state != PROC_STATE_DIED) {
40517                                 int status;
40518 -                               
40519 +
40520                                 /* only fetch the zombie if it is not already done */
40521 -                               
40522 +#ifndef _WIN32
40523                                 switch(waitpid(proc->pid, &status, WNOHANG)) {
40524                                 case 0:
40525                                         /* child is still alive */
40526 @@ -2489,19 +2354,19 @@
40527                                 default:
40528                                         /* the child should not terminate at all */
40529                                         if (WIFEXITED(status)) {
40530 -                                               log_error_write(srv, __FILE__, __LINE__, "sdsd", 
40531 +                                               log_error_write(srv, __FILE__, __LINE__, "sdsd",
40532                                                                 "child exited, pid:", proc->pid,
40533                                                                 "status:", WEXITSTATUS(status));
40534                                         } else if (WIFSIGNALED(status)) {
40535 -                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
40536 -                                                               "child signaled:", 
40537 +                                               log_error_write(srv, __FILE__, __LINE__, "sd",
40538 +                                                               "child signaled:",
40539                                                                 WTERMSIG(status));
40540                                         } else {
40541 -                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
40542 -                                                               "child died somehow:", 
40543 +                                               log_error_write(srv, __FILE__, __LINE__, "sd",
40544 +                                                               "child died somehow:",
40545                                                                 status);
40546                                         }
40547 -                                       
40548 +
40549                                         if (p->conf.debug) {
40550                                                 log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
40551                                                                 "--- scgi spawning",
40552 @@ -2509,117 +2374,118 @@
40553                                                                 "\n\tsocket", host->unixsocket,
40554                                                                 "\n\tcurrent:", 1, "/", host->min_procs);
40555                                         }
40556 -                                       
40557 +
40558                                         if (scgi_spawn_connection(srv, p, host, proc)) {
40559                                                 /* child died */
40560                                                 proc->state = PROC_STATE_DIED;
40561                                         } else {
40562                                                 scgi_proclist_sort_down(srv, host, proc);
40563                                         }
40564 -                                       
40565 +
40566                                         break;
40567                                 }
40568 +#endif
40569                         }
40570  
40571                         if (con->file_started == 0) {
40572                                 /* nothing has been send out yet, try to use another child */
40573 -                               
40574 +
40575                                 if (hctx->wb->bytes_out == 0 &&
40576                                     hctx->reconnects < 5) {
40577                                         scgi_reconnect(srv, hctx);
40578 -                                       
40579 -                                       log_error_write(srv, __FILE__, __LINE__, "sdsdsd", 
40580 +
40581 +                                       log_error_write(srv, __FILE__, __LINE__, "sdsdsd",
40582                                                 "response not sent, request not sent, reconnection.",
40583 -                                               "connection-fd:", con->fd,
40584 -                                               "fcgi-fd:", hctx->fd);
40585 -                                       
40586 +                                               "connection-fd:", con->sock->fd,
40587 +                                               "fcgi-fd:", hctx->sock->fd);
40588 +
40589                                         return HANDLER_WAIT_FOR_FD;
40590                                 }
40591 -                               
40592 -                               log_error_write(srv, __FILE__, __LINE__, "sdsdsd", 
40593 +
40594 +                               log_error_write(srv, __FILE__, __LINE__, "sosdsd",
40595                                                 "response not sent, request sent:", hctx->wb->bytes_out,
40596 -                                               "connection-fd:", con->fd,
40597 -                                               "fcgi-fd:", hctx->fd);
40598 -                               
40599 +                                               "connection-fd:", con->sock->fd,
40600 +                                               "fcgi-fd:", hctx->sock->fd);
40601 +
40602                                 scgi_connection_cleanup(srv, hctx);
40603 -                               
40604 -                               connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
40605 +
40606                                 buffer_reset(con->physical.path);
40607                                 con->http_status = 500;
40608                                 con->mode = DIRECT;
40609                         } else {
40610                                 /* response might have been already started, kill the connection */
40611                                 scgi_connection_cleanup(srv, hctx);
40612 -                               
40613 -                               log_error_write(srv, __FILE__, __LINE__, "ssdsd", 
40614 +
40615 +                               log_error_write(srv, __FILE__, __LINE__, "ssdsd",
40616                                                 "response already sent out, termination connection",
40617 -                                               "connection-fd:", con->fd,
40618 -                                               "fcgi-fd:", hctx->fd);
40619 -                               
40620 +                                               "connection-fd:", con->sock->fd,
40621 +                                               "fcgi-fd:", hctx->sock->fd);
40622 +
40623                                 connection_set_state(srv, con, CON_STATE_ERROR);
40624                         }
40625  
40626                         /* */
40627 -                       
40628 -                       
40629 +
40630 +
40631                         joblist_append(srv, con);
40632                         return HANDLER_FINISHED;
40633                 }
40634         }
40635 -       
40636 +
40637         if (revents & FDEVENT_OUT) {
40638 -               if (hctx->state == FCGI_STATE_CONNECT ||
40639 -                   hctx->state == FCGI_STATE_WRITE) {
40640 +               if (hctx->state == SCGI_STATE_CONNECT ||
40641 +                   hctx->state == SCGI_STATE_WRITE) {
40642                         /* we are allowed to send something out
40643 -                        * 
40644 +                        *
40645                          * 1. in a unfinished connect() call
40646                          * 2. in a unfinished write() call (long POST request)
40647                          */
40648                         return mod_scgi_handle_subrequest(srv, con, p);
40649                 } else {
40650 -                       log_error_write(srv, __FILE__, __LINE__, "sd", 
40651 -                                       "got a FDEVENT_OUT and didn't know why:", 
40652 +                       log_error_write(srv, __FILE__, __LINE__, "sd",
40653 +                                       "got a FDEVENT_OUT and didn't know why:",
40654                                         hctx->state);
40655                 }
40656         }
40657 -       
40658 +
40659         /* perhaps this issue is already handled */
40660         if (revents & FDEVENT_HUP) {
40661 -               if (hctx->state == FCGI_STATE_CONNECT) {
40662 +               if (hctx->state == SCGI_STATE_CONNECT) {
40663                         /* getoptsock will catch this one (right ?)
40664 -                        * 
40665 -                        * if we are in connect we might get a EINPROGRESS 
40666 -                        * in the first call and a FDEVENT_HUP in the 
40667 +                        *
40668 +                        * if we are in connect we might get a EINPROGRESS
40669 +                        * in the first call and a FDEVENT_HUP in the
40670                          * second round
40671 -                        * 
40672 +                        *
40673                          * FIXME: as it is a bit ugly.
40674 -                        * 
40675 +                        *
40676                          */
40677                         return mod_scgi_handle_subrequest(srv, con, p);
40678 -               } else if (hctx->state == FCGI_STATE_READ &&
40679 +               } else if ((hctx->state == SCGI_STATE_RESPONSE_HEADER ||
40680 +                           hctx->state == SCGI_STATE_RESPONSE_CONTENT ) &&
40681                            hctx->proc->port == 0) {
40682                         /* FIXME:
40683 -                        * 
40684 +                        *
40685                          * ioctl says 8192 bytes to read from PHP and we receive directly a HUP for the socket
40686                          * even if the FCGI_FIN packet is not received yet
40687                          */
40688                 } else {
40689 -                       log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd", 
40690 -                                       "error: unexpected close of scgi connection for", 
40691 +                       log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd",
40692 +                                       "error: unexpected close of scgi connection for",
40693                                         con->uri.path,
40694 -                                       "(no scgi process on host: ", 
40695 +                                       "(no scgi process on host: ",
40696                                         host->host,
40697 -                                       ", port: ", 
40698 +                                       ", port: ",
40699                                         host->port,
40700                                         " ?)",
40701                                         hctx->state);
40702 -                       
40703 +
40704                         connection_set_state(srv, con, CON_STATE_ERROR);
40705                         scgi_connection_close(srv, hctx);
40706                         joblist_append(srv, con);
40707                 }
40708         } else if (revents & FDEVENT_ERR) {
40709 -               log_error_write(srv, __FILE__, __LINE__, "s", 
40710 +               log_error_write(srv, __FILE__, __LINE__, "s",
40711                                 "fcgi: got a FDEVENT_ERR. Don't know why.");
40712                 /* kill all connections to the scgi process */
40713  
40714 @@ -2628,42 +2494,39 @@
40715                 scgi_connection_close(srv, hctx);
40716                 joblist_append(srv, con);
40717         }
40718 -       
40719 +
40720         return HANDLER_FINISHED;
40721  }
40722 -#define PATCH(x) \
40723 -       p->conf.x = s->x;
40724 +
40725  static int scgi_patch_connection(server *srv, connection *con, plugin_data *p) {
40726         size_t i, j;
40727         plugin_config *s = p->config_storage[0];
40728 -       
40729 -       PATCH(exts);
40730 -       PATCH(debug);
40731 -       
40732 +
40733 +       PATCH_OPTION(exts);
40734 +       PATCH_OPTION(debug);
40735 +
40736         /* skip the first, the global context */
40737         for (i = 1; i < srv->config_context->used; i++) {
40738                 data_config *dc = (data_config *)srv->config_context->data[i];
40739                 s = p->config_storage[i];
40740 -               
40741 +
40742                 /* condition didn't match */
40743                 if (!config_check_cond(srv, con, dc)) continue;
40744 -               
40745 +
40746                 /* merge config */
40747                 for (j = 0; j < dc->value->used; j++) {
40748                         data_unset *du = dc->value->data[j];
40749 -                       
40750 +
40751                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("scgi.server"))) {
40752 -                               PATCH(exts);
40753 +                               PATCH_OPTION(exts);
40754                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("scgi.debug"))) {
40755 -                               PATCH(debug);
40756 +                               PATCH_OPTION(debug);
40757                         }
40758                 }
40759         }
40760 -       
40761 +
40762         return 0;
40763  }
40764 -#undef PATCH
40765 -
40766  
40767  static handler_t scgi_check_extension(server *srv, connection *con, void *p_d, int uri_path_handler) {
40768         plugin_data *p = p_d;
40769 @@ -2673,30 +2536,30 @@
40770         size_t k;
40771         buffer *fn;
40772         scgi_extension *extension = NULL;
40773 -       
40774 +
40775         /* Possibly, we processed already this request */
40776         if (con->file_started == 1) return HANDLER_GO_ON;
40777 -       
40778 +
40779         fn = uri_path_handler ? con->uri.path : con->physical.path;
40780  
40781         if (buffer_is_empty(fn)) return HANDLER_GO_ON;
40782  
40783         s_len = fn->used - 1;
40784 -       
40785 +
40786         scgi_patch_connection(srv, con, p);
40787  
40788         /* check if extension matches */
40789         for (k = 0; k < p->conf.exts->used; k++) {
40790                 size_t ct_len;
40791 -               
40792 +
40793                 extension = p->conf.exts->exts[k];
40794 -               
40795 +
40796                 if (extension->key->used == 0) continue;
40797 -               
40798 +
40799                 ct_len = extension->key->used - 1;
40800 -               
40801 +
40802                 if (s_len < ct_len) continue;
40803 -               
40804 +
40805                 /* check extension in the form "/scgi_pattern" */
40806                 if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) {
40807                         break;
40808 @@ -2710,17 +2573,17 @@
40809         if (k == p->conf.exts->used) {
40810                 return HANDLER_GO_ON;
40811         }
40812 -       
40813 +
40814         /* get best server */
40815         for (k = 0, ndx = -1; k < extension->used; k++) {
40816                 scgi_extension_host *host = extension->hosts[k];
40817 -               
40818 +
40819                 /* we should have at least one proc that can do somthing */
40820                 if (host->active_procs == 0) continue;
40821  
40822                 if (used == -1 || host->load < used) {
40823                         used = host->load;
40824 -                       
40825 +
40826                         ndx = k;
40827                 }
40828         }
40829 @@ -2728,12 +2591,12 @@
40830         /* found a server */
40831         if (ndx != -1) {
40832                 scgi_extension_host *host = extension->hosts[ndx];
40833 -               
40834 -               /* 
40835 -                * if check-local is disabled, use the uri.path handler 
40836 -                * 
40837 +
40838 +               /*
40839 +                * if check-local is disabled, use the uri.path handler
40840 +                *
40841                  */
40842 -               
40843 +
40844                 /* init handler-context */
40845                 if (uri_path_handler) {
40846                         if (host->check_local == 0) {
40847 @@ -2741,7 +2604,7 @@
40848                                 char *pathinfo;
40849  
40850                                 hctx = handler_ctx_init();
40851 -                               
40852 +
40853                                 hctx->remote_conn      = con;
40854                                 hctx->plugin_data      = p;
40855                                 hctx->host             = host;
40856 @@ -2749,45 +2612,45 @@
40857  
40858                                 hctx->conf.exts        = p->conf.exts;
40859                                 hctx->conf.debug       = p->conf.debug;
40860 -                               
40861 +
40862                                 con->plugin_ctx[p->id] = hctx;
40863 -                               
40864 +
40865                                 host->load++;
40866 -                               
40867 +
40868                                 con->mode = p->id;
40869  
40870                                 if (con->conf.log_request_handling) {
40871                                         log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_scgi");
40872                                 }
40873  
40874 -                               /* the prefix is the SCRIPT_NAME, 
40875 +                               /* the prefix is the SCRIPT_NAME,
40876                                  * everthing from start to the next slash
40877                                  * this is important for check-local = "disable"
40878 -                                * 
40879 +                                *
40880                                  * if prefix = /admin.fcgi
40881 -                                * 
40882 +                                *
40883                                  * /admin.fcgi/foo/bar
40884 -                                * 
40885 +                                *
40886                                  * SCRIPT_NAME = /admin.fcgi
40887                                  * PATH_INFO   = /foo/bar
40888 -                                * 
40889 +                                *
40890                                  * if prefix = /fcgi-bin/
40891 -                                * 
40892 +                                *
40893                                  * /fcgi-bin/foo/bar
40894 -                                * 
40895 +                                *
40896                                  * SCRIPT_NAME = /fcgi-bin/foo
40897                                  * PATH_INFO   = /bar
40898 -                                * 
40899 +                                *
40900                                  */
40901 -                               
40902 +
40903                                 /* the rewrite is only done for /prefix/? matches */
40904                                 if (extension->key->ptr[0] == '/' &&
40905                                     con->uri.path->used > extension->key->used &&
40906                                     NULL != (pathinfo = strchr(con->uri.path->ptr + extension->key->used - 1, '/'))) {
40907 -                                       /* rewrite uri.path and pathinfo */ 
40908 -                                       
40909 +                                       /* rewrite uri.path and pathinfo */
40910 +
40911                                         buffer_copy_string(con->request.pathinfo, pathinfo);
40912 -                                       
40913 +
40914                                         con->uri.path->used -= con->request.pathinfo->used - 1;
40915                                         con->uri.path->ptr[con->uri.path->used - 1] = '\0';
40916                                 }
40917 @@ -2796,21 +2659,21 @@
40918                 } else {
40919                         handler_ctx *hctx;
40920                         hctx = handler_ctx_init();
40921 -                       
40922 +
40923                         hctx->remote_conn      = con;
40924                         hctx->plugin_data      = p;
40925                         hctx->host             = host;
40926                         hctx->proc             = NULL;
40927 -                       
40928 +
40929                         hctx->conf.exts        = p->conf.exts;
40930                         hctx->conf.debug       = p->conf.debug;
40931 -                       
40932 +
40933                         con->plugin_ctx[p->id] = hctx;
40934 -                       
40935 +
40936                         host->load++;
40937 -                       
40938 +
40939                         con->mode = p->id;
40940 -                       
40941 +
40942                         if (con->conf.log_request_handling) {
40943                                 log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_fastcgi");
40944                         }
40945 @@ -2821,11 +2684,11 @@
40946                 /* no handler found */
40947                 buffer_reset(con->physical.path);
40948                 con->http_status = 500;
40949 -               
40950 -               log_error_write(srv, __FILE__, __LINE__,  "sb", 
40951 -                               "no fcgi-handler found for:", 
40952 +
40953 +               log_error_write(srv, __FILE__, __LINE__,  "sb",
40954 +                               "no fcgi-handler found for:",
40955                                 fn);
40956 -               
40957 +
40958                 return HANDLER_FINISHED;
40959         }
40960         return HANDLER_GO_ON;
40961 @@ -2844,21 +2707,22 @@
40962  JOBLIST_FUNC(mod_scgi_handle_joblist) {
40963         plugin_data *p = p_d;
40964         handler_ctx *hctx = con->plugin_ctx[p->id];
40965 -       
40966 +
40967         if (hctx == NULL) return HANDLER_GO_ON;
40968  
40969 -       if (hctx->fd != -1) {
40970 +       if (hctx->sock->fd != -1) {
40971                 switch (hctx->state) {
40972 -               case FCGI_STATE_READ:
40973 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
40974 -                       
40975 +               case SCGI_STATE_RESPONSE_HEADER:
40976 +               case SCGI_STATE_RESPONSE_CONTENT:
40977 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
40978 +
40979                         break;
40980 -               case FCGI_STATE_CONNECT:
40981 -               case FCGI_STATE_WRITE:
40982 -                       fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
40983 -                       
40984 +               case SCGI_STATE_CONNECT:
40985 +               case SCGI_STATE_WRITE:
40986 +                       fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
40987 +
40988                         break;
40989 -               case FCGI_STATE_INIT:
40990 +               case SCGI_STATE_INIT:
40991                         /* at reconnect */
40992                         break;
40993                 default:
40994 @@ -2873,21 +2737,21 @@
40995  
40996  static handler_t scgi_connection_close_callback(server *srv, connection *con, void *p_d) {
40997         plugin_data *p = p_d;
40998 -       
40999 +
41000         return scgi_connection_close(srv, con->plugin_ctx[p->id]);
41001  }
41002  
41003  TRIGGER_FUNC(mod_scgi_handle_trigger) {
41004         plugin_data *p = p_d;
41005         size_t i, j, n;
41006 -       
41007 -       
41008 +
41009 +
41010         /* perhaps we should kill a connect attempt after 10-15 seconds
41011 -        * 
41012 +        *
41013          * currently we wait for the TCP timeout which is on Linux 180 seconds
41014 -        * 
41015 -        * 
41016 -        * 
41017 +        *
41018 +        *
41019 +        *
41020          */
41021  
41022         /* check all childs if they are still up */
41023 @@ -2904,47 +2768,47 @@
41024                         scgi_extension *ex;
41025  
41026                         ex = exts->exts[j];
41027 -                       
41028 +
41029                         for (n = 0; n < ex->used; n++) {
41030 -                               
41031 +
41032                                 scgi_proc *proc;
41033                                 unsigned long sum_load = 0;
41034                                 scgi_extension_host *host;
41035 -                               
41036 +
41037                                 host = ex->hosts[n];
41038 -                               
41039 +
41040                                 scgi_restart_dead_procs(srv, p, host);
41041 -                               
41042 +
41043                                 for (proc = host->first; proc; proc = proc->next) {
41044                                         sum_load += proc->load;
41045                                 }
41046 -                               
41047 +
41048                                 if (host->num_procs &&
41049                                     host->num_procs < host->max_procs &&
41050                                     (sum_load / host->num_procs) > host->max_load_per_proc) {
41051                                         /* overload, spawn new child */
41052                                         scgi_proc *fp = NULL;
41053 -                                       
41054 +
41055                                         if (p->conf.debug) {
41056 -                                               log_error_write(srv, __FILE__, __LINE__, "s", 
41057 +                                               log_error_write(srv, __FILE__, __LINE__, "s",
41058                                                                 "overload detected, spawning a new child");
41059                                         }
41060 -                                       
41061 +
41062                                         for (fp = host->unused_procs; fp && fp->pid != 0; fp = fp->next);
41063 -                                       
41064 +
41065                                         if (fp) {
41066                                                 if (fp == host->unused_procs) host->unused_procs = fp->next;
41067 -                                               
41068 +
41069                                                 if (fp->next) fp->next->prev = NULL;
41070 -                                               
41071 +
41072                                                 host->max_id++;
41073                                         } else {
41074                                                 fp = scgi_process_init();
41075                                                 fp->id = host->max_id++;
41076                                         }
41077 -                                       
41078 +
41079                                         host->num_procs++;
41080 -                                       
41081 +
41082                                         if (buffer_is_empty(host->unixsocket)) {
41083                                                 fp->port = host->port + fp->id;
41084                                         } else {
41085 @@ -2952,13 +2816,13 @@
41086                                                 buffer_append_string(fp->socket, "-");
41087                                                 buffer_append_long(fp->socket, fp->id);
41088                                         }
41089 -                                       
41090 +
41091                                         if (scgi_spawn_connection(srv, p, host, fp)) {
41092                                                 log_error_write(srv, __FILE__, __LINE__, "s",
41093                                                                 "ERROR: spawning fcgi failed.");
41094                                                 return HANDLER_ERROR;
41095                                         }
41096 -                                       
41097 +
41098                                         fp->prev = NULL;
41099                                         fp->next = host->first;
41100                                         if (host->first) {
41101 @@ -2966,56 +2830,57 @@
41102                                         }
41103                                         host->first = fp;
41104                                 }
41105 -                               
41106 +
41107                                 for (proc = host->first; proc; proc = proc->next) {
41108                                         if (proc->load != 0) break;
41109                                         if (host->num_procs <= host->min_procs) break;
41110                                         if (proc->pid == 0) continue;
41111 -                                       
41112 +#ifndef _WIN32
41113                                         if (srv->cur_ts - proc->last_used > host->idle_timeout) {
41114                                                 /* a proc is idling for a long time now,
41115                                                  * terminated it */
41116 -                                               
41117 +
41118                                                 if (p->conf.debug) {
41119 -                                                       log_error_write(srv, __FILE__, __LINE__, "ssbsd", 
41120 -                                                                       "idle-timeout reached, terminating child:", 
41121 -                                                                       "socket:", proc->socket, 
41122 +                                                       log_error_write(srv, __FILE__, __LINE__, "ssbsd",
41123 +                                                                       "idle-timeout reached, terminating child:",
41124 +                                                                       "socket:", proc->socket,
41125                                                                         "pid", proc->pid);
41126                                                 }
41127 -                                               
41128 -                                               
41129 +
41130 +
41131                                                 if (proc->next) proc->next->prev = proc->prev;
41132                                                 if (proc->prev) proc->prev->next = proc->next;
41133 -                                               
41134 +
41135                                                 if (proc->prev == NULL) host->first = proc->next;
41136 -                                               
41137 +
41138                                                 proc->prev = NULL;
41139                                                 proc->next = host->unused_procs;
41140 -                                               
41141 +
41142                                                 if (host->unused_procs) host->unused_procs->prev = proc;
41143                                                 host->unused_procs = proc;
41144 -                                               
41145 +
41146                                                 kill(proc->pid, SIGTERM);
41147 -                                               
41148 +
41149                                                 proc->state = PROC_STATE_KILLED;
41150 -                                               
41151 -                                               log_error_write(srv, __FILE__, __LINE__, "ssbsd", 
41152 -                                                                       "killed:", 
41153 -                                                                       "socket:", proc->socket, 
41154 +
41155 +                                               log_error_write(srv, __FILE__, __LINE__, "ssbsd",
41156 +                                                                       "killed:",
41157 +                                                                       "socket:", proc->socket,
41158                                                                         "pid", proc->pid);
41159 -                                               
41160 +
41161                                                 host->num_procs--;
41162 -                                               
41163 +
41164                                                 /* proc is now in unused, let the next second handle the next process */
41165                                                 break;
41166 -                                       }       
41167 +                                       }
41168 +#endif
41169                                 }
41170 -                               
41171 +
41172                                 for (proc = host->unused_procs; proc; proc = proc->next) {
41173                                         int status;
41174 -                                       
41175 +
41176                                         if (proc->pid == 0) continue;
41177 -                                       
41178 +#ifndef _WIN32
41179                                         switch (waitpid(proc->pid, &status, WNOHANG)) {
41180                                         case 0:
41181                                                 /* child still running after timeout, good */
41182 @@ -3023,10 +2888,10 @@
41183                                         case -1:
41184                                                 if (errno != EINTR) {
41185                                                         /* no PID found ? should never happen */
41186 -                                                       log_error_write(srv, __FILE__, __LINE__, "sddss", 
41187 +                                                       log_error_write(srv, __FILE__, __LINE__, "sddss",
41188                                                                         "pid ", proc->pid, proc->state,
41189                                                                         "not found:", strerror(errno));
41190 -                                                       
41191 +
41192  #if 0
41193                                                         if (errno == ECHILD) {
41194                                                                 /* someone else has cleaned up for us */
41195 @@ -3040,25 +2905,26 @@
41196                                                 /* the child should not terminate at all */
41197                                                 if (WIFEXITED(status)) {
41198                                                         if (proc->state != PROC_STATE_KILLED) {
41199 -                                                               log_error_write(srv, __FILE__, __LINE__, "sdb", 
41200 -                                                                               "child exited:", 
41201 +                                                               log_error_write(srv, __FILE__, __LINE__, "sdb",
41202 +                                                                               "child exited:",
41203                                                                                 WEXITSTATUS(status), proc->socket);
41204                                                         }
41205                                                 } else if (WIFSIGNALED(status)) {
41206                                                         if (WTERMSIG(status) != SIGTERM) {
41207 -                                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
41208 -                                                                               "child signaled:", 
41209 +                                                               log_error_write(srv, __FILE__, __LINE__, "sd",
41210 +                                                                               "child signaled:",
41211                                                                                 WTERMSIG(status));
41212                                                         }
41213                                                 } else {
41214 -                                                       log_error_write(srv, __FILE__, __LINE__, "sd", 
41215 -                                                                       "child died somehow:", 
41216 +                                                       log_error_write(srv, __FILE__, __LINE__, "sd",
41217 +                                                                       "child died somehow:",
41218                                                                         status);
41219                                                 }
41220                                                 proc->pid = 0;
41221                                                 proc->state = PROC_STATE_UNSET;
41222                                                 host->max_id--;
41223                                         }
41224 +#endif
41225                                 }
41226                         }
41227                 }
41228 @@ -3078,12 +2944,14 @@
41229         p->connection_reset        = scgi_connection_reset;
41230         p->handle_connection_close = scgi_connection_close_callback;
41231         p->handle_uri_clean        = scgi_check_extension_1;
41232 -       p->handle_subrequest_start = scgi_check_extension_2;
41233 +       p->handle_start_backend    = scgi_check_extension_2;
41234 +#if 0
41235         p->handle_subrequest       = mod_scgi_handle_subrequest;
41236 +#endif
41237         p->handle_joblist          = mod_scgi_handle_joblist;
41238         p->handle_trigger          = mod_scgi_handle_trigger;
41239 -       
41240 +
41241         p->data         = NULL;
41242 -       
41243 +
41244         return 0;
41245  }
41246 --- ../lighttpd-1.4.11/src/mod_secure_download.c        2005-12-14 14:37:29.000000000 +0200
41247 +++ lighttpd-1.5.0/src/mod_secure_download.c    2006-07-16 00:26:03.000000000 +0300
41248 @@ -25,7 +25,7 @@
41249  #ifdef USE_OPENSSL
41250  #define IN const
41251  #else
41252 -#define IN 
41253 +#define IN
41254  #endif
41255  #define OUT
41256  
41257 @@ -36,28 +36,28 @@
41258         buffer *doc_root;
41259         buffer *secret;
41260         buffer *uri_prefix;
41261 -       
41262 +
41263         unsigned short timeout;
41264  } plugin_config;
41265  
41266  typedef struct {
41267         PLUGIN_DATA;
41268 -       
41269 +
41270         buffer *md5;
41271 -       
41272 +
41273         plugin_config **config_storage;
41274 -       
41275 -       plugin_config conf; 
41276 +
41277 +       plugin_config conf;
41278  } plugin_data;
41279  
41280  /* init the plugin data */
41281  INIT_FUNC(mod_secdownload_init) {
41282         plugin_data *p;
41283 -       
41284 +
41285         p = calloc(1, sizeof(*p));
41286 -       
41287 +
41288         p->md5 = buffer_init();
41289 -       
41290 +
41291         return p;
41292  }
41293  
41294 @@ -65,27 +65,27 @@
41295  FREE_FUNC(mod_secdownload_free) {
41296         plugin_data *p = p_d;
41297         UNUSED(srv);
41298 -       
41299 +
41300         if (!p) return HANDLER_GO_ON;
41301 -       
41302 +
41303         if (p->config_storage) {
41304                 size_t i;
41305                 for (i = 0; i < srv->config_context->used; i++) {
41306                         plugin_config *s = p->config_storage[i];
41307 -                       
41308 +
41309                         buffer_free(s->secret);
41310                         buffer_free(s->doc_root);
41311                         buffer_free(s->uri_prefix);
41312 -                       
41313 +
41314                         free(s);
41315                 }
41316                 free(p->config_storage);
41317         }
41318 -       
41319 +
41320         buffer_free(p->md5);
41321 -       
41322 +
41323         free(p);
41324 -       
41325 +
41326         return HANDLER_GO_ON;
41327  }
41328  
41329 @@ -94,107 +94,103 @@
41330  SETDEFAULTS_FUNC(mod_secdownload_set_defaults) {
41331         plugin_data *p = p_d;
41332         size_t i = 0;
41333 -       
41334 -       config_values_t cv[] = { 
41335 +
41336 +       config_values_t cv[] = {
41337                 { "secdownload.secret",            NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
41338                 { "secdownload.document-root",     NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
41339                 { "secdownload.uri-prefix",        NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
41340                 { "secdownload.timeout",           NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 3 */
41341                 { NULL,                            NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
41342         };
41343 -       
41344 +
41345         if (!p) return HANDLER_ERROR;
41346 -       
41347 +
41348         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
41349 -       
41350 +
41351         for (i = 0; i < srv->config_context->used; i++) {
41352                 plugin_config *s;
41353 -               
41354 +
41355                 s = calloc(1, sizeof(plugin_config));
41356                 s->secret        = buffer_init();
41357                 s->doc_root      = buffer_init();
41358                 s->uri_prefix    = buffer_init();
41359                 s->timeout       = 60;
41360 -               
41361 +
41362                 cv[0].destination = s->secret;
41363                 cv[1].destination = s->doc_root;
41364                 cv[2].destination = s->uri_prefix;
41365                 cv[3].destination = &(s->timeout);
41366 -               
41367 +
41368                 p->config_storage[i] = s;
41369 -       
41370 +
41371                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
41372                         return HANDLER_ERROR;
41373                 }
41374         }
41375 -       
41376 +
41377         return HANDLER_GO_ON;
41378  }
41379  
41380  /**
41381   * checks if the supplied string is a MD5 string
41382 - * 
41383 + *
41384   * @param str a possible MD5 string
41385   * @return if the supplied string is a valid MD5 string 1 is returned otherwise 0
41386   */
41387  
41388  int is_hex_len(const char *str, size_t len) {
41389         size_t i;
41390 -       
41391 +
41392         if (NULL == str) return 0;
41393 -       
41394 +
41395         for (i = 0; i < len && *str; i++, str++) {
41396                 /* illegal characters */
41397                 if (!((*str >= '0' && *str <= '9') ||
41398                       (*str >= 'a' && *str <= 'f') ||
41399 -                     (*str >= 'A' && *str <= 'F')) 
41400 +                     (*str >= 'A' && *str <= 'F'))
41401                     ) {
41402                         return 0;
41403                 }
41404         }
41405 -       
41406 +
41407         return i == len;
41408  }
41409  
41410 -#define PATCH(x) \
41411 -       p->conf.x = s->x;
41412  static int mod_secdownload_patch_connection(server *srv, connection *con, plugin_data *p) {
41413         size_t i, j;
41414         plugin_config *s = p->config_storage[0];
41415 -       
41416 -       PATCH(secret);
41417 -       PATCH(doc_root);
41418 -       PATCH(uri_prefix);
41419 -       PATCH(timeout);
41420 -       
41421 +
41422 +       PATCH_OPTION(secret);
41423 +       PATCH_OPTION(doc_root);
41424 +       PATCH_OPTION(uri_prefix);
41425 +       PATCH_OPTION(timeout);
41426 +
41427         /* skip the first, the global context */
41428         for (i = 1; i < srv->config_context->used; i++) {
41429                 data_config *dc = (data_config *)srv->config_context->data[i];
41430                 s = p->config_storage[i];
41431 -               
41432 +
41433                 /* condition didn't match */
41434                 if (!config_check_cond(srv, con, dc)) continue;
41435 -               
41436 +
41437                 /* merge config */
41438                 for (j = 0; j < dc->value->used; j++) {
41439                         data_unset *du = dc->value->data[j];
41440 -                       
41441 +
41442                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.secret"))) {
41443 -                               PATCH(secret);
41444 +                               PATCH_OPTION(secret);
41445                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.document-root"))) {
41446 -                               PATCH(doc_root);
41447 +                               PATCH_OPTION(doc_root);
41448                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.uri-prefix"))) {
41449 -                               PATCH(uri_prefix);
41450 +                               PATCH_OPTION(uri_prefix);
41451                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.timeout"))) {
41452 -                               PATCH(timeout);
41453 +                               PATCH_OPTION(timeout);
41454                         }
41455                 }
41456         }
41457 -       
41458 +
41459         return 0;
41460  }
41461 -#undef PATCH
41462 -
41463  
41464  URIHANDLER_FUNC(mod_secdownload_uri_handler) {
41465         plugin_data *p = p_d;
41466 @@ -203,88 +199,88 @@
41467         const char *rel_uri, *ts_str, *md5_str;
41468         time_t ts = 0;
41469         size_t i;
41470 -       
41471 +
41472         if (con->uri.path->used == 0) return HANDLER_GO_ON;
41473 -       
41474 +
41475         mod_secdownload_patch_connection(srv, con, p);
41476  
41477         if (buffer_is_empty(p->conf.uri_prefix)) return HANDLER_GO_ON;
41478 -       
41479 +
41480         if (buffer_is_empty(p->conf.secret)) {
41481                 log_error_write(srv, __FILE__, __LINE__, "s",
41482                                 "secdownload.secret has to be set");
41483                 return HANDLER_ERROR;
41484         }
41485 -       
41486 +
41487         if (buffer_is_empty(p->conf.doc_root)) {
41488                 log_error_write(srv, __FILE__, __LINE__, "s",
41489                                 "secdownload.document-root has to be set");
41490                 return HANDLER_ERROR;
41491         }
41492 -       
41493 -       /* 
41494 +
41495 +       /*
41496          *  /<uri-prefix>[a-f0-9]{32}/[a-f0-9]{8}/<rel-path>
41497          */
41498 -       
41499 +
41500         if (0 != strncmp(con->uri.path->ptr, p->conf.uri_prefix->ptr, p->conf.uri_prefix->used - 1)) return HANDLER_GO_ON;
41501 -       
41502 +
41503         md5_str = con->uri.path->ptr + p->conf.uri_prefix->used - 1;
41504 -       
41505 +
41506         if (!is_hex_len(md5_str, 32)) return HANDLER_GO_ON;
41507         if (*(md5_str + 32) != '/') return HANDLER_GO_ON;
41508 -       
41509 +
41510         ts_str = md5_str + 32 + 1;
41511 -       
41512 +
41513         if (!is_hex_len(ts_str, 8)) return HANDLER_GO_ON;
41514         if (*(ts_str + 8) != '/') return HANDLER_GO_ON;
41515 -       
41516 +
41517         for (i = 0; i < 8; i++) {
41518                 ts = (ts << 4) + hex2int(*(ts_str + i));
41519         }
41520 -       
41521 +
41522         /* timed-out */
41523 -       if (srv->cur_ts - ts > p->conf.timeout || 
41524 +       if (srv->cur_ts - ts > p->conf.timeout ||
41525             srv->cur_ts - ts < -p->conf.timeout) {
41526                 con->http_status = 408;
41527 -               
41528 +
41529                 return HANDLER_FINISHED;
41530         }
41531 -       
41532 +
41533         rel_uri = ts_str + 8;
41534 -       
41535 -       /* checking MD5 
41536 -        * 
41537 +
41538 +       /* checking MD5
41539 +        *
41540          * <secret><rel-path><timestamp-hex>
41541          */
41542 -       
41543 +
41544         buffer_copy_string_buffer(p->md5, p->conf.secret);
41545         buffer_append_string(p->md5, rel_uri);
41546         buffer_append_string_len(p->md5, ts_str, 8);
41547 -       
41548 +
41549         MD5_Init(&Md5Ctx);
41550         MD5_Update(&Md5Ctx, (unsigned char *)p->md5->ptr, p->md5->used - 1);
41551         MD5_Final(HA1, &Md5Ctx);
41552 -       
41553 +
41554         buffer_copy_string_hex(p->md5, (char *)HA1, 16);
41555 -       
41556 +
41557         if (0 != strncmp(md5_str, p->md5->ptr, 32)) {
41558                 con->http_status = 403;
41559 -               
41560 -               log_error_write(srv, __FILE__, __LINE__, "sss", 
41561 +
41562 +               log_error_write(srv, __FILE__, __LINE__, "sss",
41563                                 "md5 invalid:",
41564                                 md5_str, p->md5->ptr);
41565 -               
41566 +
41567                 return HANDLER_FINISHED;
41568         }
41569 -       
41570 +
41571         /* starting with the last / we should have relative-path to the docroot
41572          */
41573 -       
41574 +
41575         buffer_copy_string_buffer(con->physical.doc_root, p->conf.doc_root);
41576         buffer_copy_string(con->physical.rel_path, rel_uri);
41577         buffer_copy_string_buffer(con->physical.path, con->physical.doc_root);
41578         buffer_append_string_buffer(con->physical.path, con->physical.rel_path);
41579 -       
41580 +
41581         return HANDLER_GO_ON;
41582  }
41583  
41584 @@ -293,13 +289,13 @@
41585  int mod_secdownload_plugin_init(plugin *p) {
41586         p->version     = LIGHTTPD_VERSION_ID;
41587         p->name        = buffer_init_string("secdownload");
41588 -       
41589 +
41590         p->init        = mod_secdownload_init;
41591         p->handle_physical  = mod_secdownload_uri_handler;
41592         p->set_defaults  = mod_secdownload_set_defaults;
41593         p->cleanup     = mod_secdownload_free;
41594 -       
41595 +
41596         p->data        = NULL;
41597 -       
41598 +
41599         return 0;
41600  }
41601 --- ../lighttpd-1.4.11/src/mod_setenv.c 2006-01-14 20:33:12.000000000 +0200
41602 +++ lighttpd-1.5.0/src/mod_setenv.c     2006-09-07 00:57:05.000000000 +0300
41603 @@ -18,25 +18,25 @@
41604  typedef struct {
41605         array *request_header;
41606         array *response_header;
41607 -       
41608 +
41609         array *environment;
41610  } plugin_config;
41611  
41612  typedef struct {
41613         PLUGIN_DATA;
41614 -       
41615 +
41616         plugin_config **config_storage;
41617 -       
41618 -       plugin_config conf; 
41619 +
41620 +       plugin_config conf;
41621  } plugin_data;
41622  
41623  static handler_ctx * handler_ctx_init() {
41624         handler_ctx * hctx;
41625 -       
41626 +
41627         hctx = calloc(1, sizeof(*hctx));
41628 -       
41629 +
41630         hctx->handled = 0;
41631 -       
41632 +
41633         return hctx;
41634  }
41635  
41636 @@ -48,36 +48,36 @@
41637  /* init the plugin data */
41638  INIT_FUNC(mod_setenv_init) {
41639         plugin_data *p;
41640 -       
41641 +
41642         p = calloc(1, sizeof(*p));
41643 -       
41644 +
41645         return p;
41646  }
41647  
41648  /* detroy the plugin data */
41649  FREE_FUNC(mod_setenv_free) {
41650         plugin_data *p = p_d;
41651 -       
41652 +
41653         UNUSED(srv);
41654  
41655         if (!p) return HANDLER_GO_ON;
41656 -       
41657 +
41658         if (p->config_storage) {
41659                 size_t i;
41660                 for (i = 0; i < srv->config_context->used; i++) {
41661                         plugin_config *s = p->config_storage[i];
41662 -                       
41663 +
41664                         array_free(s->request_header);
41665                         array_free(s->response_header);
41666                         array_free(s->environment);
41667 -                       
41668 +
41669                         free(s);
41670                 }
41671                 free(p->config_storage);
41672         }
41673 -       
41674 +
41675         free(p);
41676 -       
41677 +
41678         return HANDLER_GO_ON;
41679  }
41680  
41681 @@ -86,86 +86,83 @@
41682  SETDEFAULTS_FUNC(mod_setenv_set_defaults) {
41683         plugin_data *p = p_d;
41684         size_t i = 0;
41685 -       
41686 -       config_values_t cv[] = { 
41687 +
41688 +       config_values_t cv[] = {
41689                 { "setenv.add-request-header",  NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
41690                 { "setenv.add-response-header", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
41691                 { "setenv.add-environment",     NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
41692                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
41693         };
41694 -       
41695 +
41696         if (!p) return HANDLER_ERROR;
41697 -       
41698 +
41699         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
41700 -       
41701 +
41702         for (i = 0; i < srv->config_context->used; i++) {
41703                 plugin_config *s;
41704 -               
41705 +
41706                 s = calloc(1, sizeof(plugin_config));
41707                 s->request_header   = array_init();
41708                 s->response_header  = array_init();
41709                 s->environment      = array_init();
41710 -               
41711 +
41712                 cv[0].destination = s->request_header;
41713                 cv[1].destination = s->response_header;
41714                 cv[2].destination = s->environment;
41715 -               
41716 +
41717                 p->config_storage[i] = s;
41718 -       
41719 +
41720                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
41721                         return HANDLER_ERROR;
41722                 }
41723         }
41724 -       
41725 +
41726         return HANDLER_GO_ON;
41727  }
41728  
41729 -#define PATCH(x) \
41730 -       p->conf.x = s->x;
41731  static int mod_setenv_patch_connection(server *srv, connection *con, plugin_data *p) {
41732         size_t i, j;
41733         plugin_config *s = p->config_storage[0];
41734 -       
41735 -       PATCH(request_header);
41736 -       PATCH(response_header);
41737 -       PATCH(environment);
41738 -       
41739 +
41740 +       PATCH_OPTION(request_header);
41741 +       PATCH_OPTION(response_header);
41742 +       PATCH_OPTION(environment);
41743 +
41744         /* skip the first, the global context */
41745         for (i = 1; i < srv->config_context->used; i++) {
41746                 data_config *dc = (data_config *)srv->config_context->data[i];
41747                 s = p->config_storage[i];
41748 -               
41749 +
41750                 /* condition didn't match */
41751                 if (!config_check_cond(srv, con, dc)) continue;
41752 -               
41753 +
41754                 /* merge config */
41755                 for (j = 0; j < dc->value->used; j++) {
41756                         data_unset *du = dc->value->data[j];
41757 -                       
41758 +
41759                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-request-header"))) {
41760 -                               PATCH(request_header);
41761 +                               PATCH_OPTION(request_header);
41762                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-response-header"))) {
41763 -                               PATCH(response_header);
41764 +                               PATCH_OPTION(response_header);
41765                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-environment"))) {
41766 -                               PATCH(environment);
41767 +                               PATCH_OPTION(environment);
41768                         }
41769                 }
41770         }
41771 -       
41772 +
41773         return 0;
41774  }
41775 -#undef PATCH
41776  
41777  URIHANDLER_FUNC(mod_setenv_uri_handler) {
41778         plugin_data *p = p_d;
41779         size_t k;
41780         handler_ctx *hctx;
41781 -       
41782 +
41783         if (con->plugin_ctx[p->id]) {
41784                 hctx = con->plugin_ctx[p->id];
41785         } else {
41786                 hctx = handler_ctx_init();
41787 -                               
41788 +
41789                 con->plugin_ctx[p->id] = hctx;
41790         }
41791  
41792 @@ -180,52 +177,52 @@
41793         for (k = 0; k < p->conf.request_header->used; k++) {
41794                 data_string *ds = (data_string *)p->conf.request_header->data[k];
41795                 data_string *ds_dst;
41796 -               
41797 +
41798                 if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
41799                         ds_dst = data_string_init();
41800                 }
41801 -               
41802 +
41803                 buffer_copy_string_buffer(ds_dst->key, ds->key);
41804                 buffer_copy_string_buffer(ds_dst->value, ds->value);
41805 -               
41806 +
41807                 array_insert_unique(con->request.headers, (data_unset *)ds_dst);
41808         }
41809 -       
41810 +
41811         for (k = 0; k < p->conf.environment->used; k++) {
41812                 data_string *ds = (data_string *)p->conf.environment->data[k];
41813                 data_string *ds_dst;
41814 -               
41815 +
41816                 if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) {
41817                         ds_dst = data_string_init();
41818                 }
41819 -               
41820 +
41821                 buffer_copy_string_buffer(ds_dst->key, ds->key);
41822                 buffer_copy_string_buffer(ds_dst->value, ds->value);
41823 -               
41824 +
41825                 array_insert_unique(con->environment, (data_unset *)ds_dst);
41826         }
41827 -       
41828 +
41829         for (k = 0; k < p->conf.response_header->used; k++) {
41830                 data_string *ds = (data_string *)p->conf.response_header->data[k];
41831 -               
41832 +
41833                 response_header_insert(srv, con, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
41834         }
41835 -       
41836 +
41837         /* not found */
41838         return HANDLER_GO_ON;
41839  }
41840  
41841  REQUESTDONE_FUNC(mod_setenv_reset) {
41842         plugin_data *p = p_d;
41843 -       
41844 +
41845         UNUSED(srv);
41846 -       
41847 +
41848         if (con->plugin_ctx[p->id]) {
41849                 handler_ctx_free(con->plugin_ctx[p->id]);
41850                 con->plugin_ctx[p->id] = NULL;
41851         }
41852  
41853 -       return HANDLER_GO_ON;   
41854 +       return HANDLER_GO_ON;
41855  }
41856  
41857  /* this function is called at dlopen() time and inits the callbacks */
41858 @@ -233,15 +230,15 @@
41859  int mod_setenv_plugin_init(plugin *p) {
41860         p->version     = LIGHTTPD_VERSION_ID;
41861         p->name        = buffer_init_string("setenv");
41862 -       
41863 +
41864         p->init        = mod_setenv_init;
41865         p->handle_uri_clean  = mod_setenv_uri_handler;
41866         p->set_defaults  = mod_setenv_set_defaults;
41867         p->cleanup     = mod_setenv_free;
41868 -       
41869 -       p->handle_request_done  = mod_setenv_reset;
41870 +
41871 +       p->connection_reset  = mod_setenv_reset;
41872  
41873         p->data        = NULL;
41874 -       
41875 +
41876         return 0;
41877  }
41878 --- ../lighttpd-1.4.11/src/mod_simple_vhost.c   2005-11-18 15:16:13.000000000 +0200
41879 +++ lighttpd-1.5.0/src/mod_simple_vhost.c       2006-07-16 00:26:04.000000000 +0300
41880 @@ -10,6 +10,8 @@
41881  
41882  #include "plugin.h"
41883  
41884 +#include "sys-files.h"
41885 +
41886  #ifdef HAVE_CONFIG_H
41887  #include "config.h"
41888  #endif
41889 @@ -18,7 +20,7 @@
41890         buffer *server_root;
41891         buffer *default_host;
41892         buffer *document_root;
41893 -       
41894 +
41895         buffer *docroot_cache_key;
41896         buffer *docroot_cache_value;
41897         buffer *docroot_cache_servername;
41898 @@ -28,138 +30,138 @@
41899  
41900  typedef struct {
41901         PLUGIN_DATA;
41902 -       
41903 +
41904         buffer *doc_root;
41905 -       
41906 +
41907         plugin_config **config_storage;
41908 -       plugin_config conf; 
41909 +       plugin_config conf;
41910  } plugin_data;
41911  
41912  INIT_FUNC(mod_simple_vhost_init) {
41913         plugin_data *p;
41914 -       
41915 +
41916         p = calloc(1, sizeof(*p));
41917 -       
41918 +
41919         p->doc_root = buffer_init();
41920 -       
41921 +
41922         return p;
41923  }
41924  
41925  FREE_FUNC(mod_simple_vhost_free) {
41926         plugin_data *p = p_d;
41927 -       
41928 +
41929         UNUSED(srv);
41930  
41931         if (!p) return HANDLER_GO_ON;
41932 -       
41933 +
41934         if (p->config_storage) {
41935                 size_t i;
41936                 for (i = 0; i < srv->config_context->used; i++) {
41937                         plugin_config *s = p->config_storage[i];
41938 -                       
41939 +
41940                         buffer_free(s->document_root);
41941                         buffer_free(s->default_host);
41942                         buffer_free(s->server_root);
41943 -                       
41944 +
41945                         buffer_free(s->docroot_cache_key);
41946                         buffer_free(s->docroot_cache_value);
41947                         buffer_free(s->docroot_cache_servername);
41948 -                       
41949 +
41950                         free(s);
41951                 }
41952 -       
41953 +
41954                 free(p->config_storage);
41955         }
41956 -       
41957 +
41958         buffer_free(p->doc_root);
41959 -       
41960 +
41961         free(p);
41962 -       
41963 +
41964         return HANDLER_GO_ON;
41965  }
41966  
41967  SETDEFAULTS_FUNC(mod_simple_vhost_set_defaults) {
41968         plugin_data *p = p_d;
41969         size_t i;
41970 -       
41971 -       config_values_t cv[] = { 
41972 +
41973 +       config_values_t cv[] = {
41974                 { "simple-vhost.server-root",       NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
41975                 { "simple-vhost.default-host",      NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
41976                 { "simple-vhost.document-root",     NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
41977                 { "simple-vhost.debug",             NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
41978                 { NULL,                             NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
41979         };
41980 -       
41981 +
41982         if (!p) return HANDLER_ERROR;
41983 -       
41984 +
41985         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
41986 -       
41987 +
41988         for (i = 0; i < srv->config_context->used; i++) {
41989                 plugin_config *s;
41990 -               
41991 +
41992                 s = calloc(1, sizeof(plugin_config));
41993 -               
41994 +
41995                 s->server_root = buffer_init();
41996                 s->default_host = buffer_init();
41997                 s->document_root = buffer_init();
41998 -               
41999 +
42000                 s->docroot_cache_key = buffer_init();
42001                 s->docroot_cache_value = buffer_init();
42002                 s->docroot_cache_servername = buffer_init();
42003  
42004                 s->debug = 0;
42005 -               
42006 +
42007                 cv[0].destination = s->server_root;
42008                 cv[1].destination = s->default_host;
42009                 cv[2].destination = s->document_root;
42010                 cv[3].destination = &(s->debug);
42011 -               
42012 -               
42013 +
42014 +
42015                 p->config_storage[i] = s;
42016 -               
42017 +
42018                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
42019                         return HANDLER_ERROR;
42020                 }
42021         }
42022 -       
42023 +
42024         return HANDLER_GO_ON;
42025  }
42026  
42027  static int build_doc_root(server *srv, connection *con, plugin_data *p, buffer *out, buffer *host) {
42028         stat_cache_entry *sce = NULL;
42029 -       
42030 +
42031         buffer_prepare_copy(out, 128);
42032  
42033         if (p->conf.server_root->used) {
42034                 buffer_copy_string_buffer(out, p->conf.server_root);
42035 -               
42036 +
42037                 if (host->used) {
42038                         /* a hostname has to start with a alpha-numerical character
42039                          * and must not contain a slash "/"
42040                          */
42041                         char *dp;
42042 -                       
42043 -                       BUFFER_APPEND_SLASH(out);
42044 -                       
42045 +
42046 +                       PATHNAME_APPEND_SLASH(out);
42047 +
42048                         if (NULL == (dp = strchr(host->ptr, ':'))) {
42049                                 buffer_append_string_buffer(out, host);
42050                         } else {
42051                                 buffer_append_string_len(out, host->ptr, dp - host->ptr);
42052                         }
42053                 }
42054 -               BUFFER_APPEND_SLASH(out);
42055 -               
42056 +               PATHNAME_APPEND_SLASH(out);
42057 +
42058                 if (p->conf.document_root->used > 2 && p->conf.document_root->ptr[0] == '/') {
42059                         buffer_append_string_len(out, p->conf.document_root->ptr + 1, p->conf.document_root->used - 2);
42060                 } else {
42061                         buffer_append_string_buffer(out, p->conf.document_root);
42062 -                       BUFFER_APPEND_SLASH(out);
42063 +                       PATHNAME_APPEND_SLASH(out);
42064                 }
42065         } else {
42066                 buffer_copy_string_buffer(out, con->conf.document_root);
42067 -               BUFFER_APPEND_SLASH(out);
42068 +               PATHNAME_APPEND_SLASH(out);
42069         }
42070 -       
42071 +
42072         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, out, &sce)) {
42073                 if (p->conf.debug) {
42074                         log_error_write(srv, __FILE__, __LINE__, "sb",
42075 @@ -169,57 +171,53 @@
42076         } else if (!S_ISDIR(sce->st.st_mode)) {
42077                 return -1;
42078         }
42079 -       
42080 +
42081         return 0;
42082  }
42083  
42084 -
42085 -#define PATCH(x) \
42086 -       p->conf.x = s->x;
42087  static int mod_simple_vhost_patch_connection(server *srv, connection *con, plugin_data *p) {
42088         size_t i, j;
42089         plugin_config *s = p->config_storage[0];
42090 -       
42091 -       PATCH(server_root);
42092 -       PATCH(default_host);
42093 -       PATCH(document_root);
42094 -       
42095 -       PATCH(docroot_cache_key);
42096 -       PATCH(docroot_cache_value);
42097 -       PATCH(docroot_cache_servername);
42098  
42099 -       PATCH(debug);
42100 -       
42101 +       PATCH_OPTION(server_root);
42102 +       PATCH_OPTION(default_host);
42103 +       PATCH_OPTION(document_root);
42104 +
42105 +       PATCH_OPTION(docroot_cache_key);
42106 +       PATCH_OPTION(docroot_cache_value);
42107 +       PATCH_OPTION(docroot_cache_servername);
42108 +
42109 +       PATCH_OPTION(debug);
42110 +
42111         /* skip the first, the global context */
42112         for (i = 1; i < srv->config_context->used; i++) {
42113                 data_config *dc = (data_config *)srv->config_context->data[i];
42114                 s = p->config_storage[i];
42115 -               
42116 +
42117                 /* condition didn't match */
42118                 if (!config_check_cond(srv, con, dc)) continue;
42119 -               
42120 +
42121                 /* merge config */
42122                 for (j = 0; j < dc->value->used; j++) {
42123                         data_unset *du = dc->value->data[j];
42124 -                       
42125 +
42126                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.server-root"))) {
42127 -                               PATCH(server_root);
42128 -                               PATCH(docroot_cache_key);
42129 -                               PATCH(docroot_cache_value);
42130 -                               PATCH(docroot_cache_servername);
42131 +                               PATCH_OPTION(server_root);
42132 +                               PATCH_OPTION(docroot_cache_key);
42133 +                               PATCH_OPTION(docroot_cache_value);
42134 +                               PATCH_OPTION(docroot_cache_servername);
42135                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.default-host"))) {
42136 -                               PATCH(default_host);
42137 +                               PATCH_OPTION(default_host);
42138                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.document-root"))) {
42139 -                               PATCH(document_root);
42140 +                               PATCH_OPTION(document_root);
42141                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.debug"))) {
42142 -                               PATCH(debug);
42143 +                               PATCH_OPTION(debug);
42144                         }
42145                 }
42146         }
42147 -       
42148 +
42149         return 0;
42150  }
42151 -#undef PATCH
42152  
42153  static handler_t mod_simple_vhost_docroot(server *srv, connection *con, void *p_data) {
42154         plugin_data *p = p_data;
42155 @@ -227,12 +225,12 @@
42156         /*
42157          * cache the last successfull translation from hostname (authority) to docroot
42158          * - this saves us a stat() call
42159 -        * 
42160 +        *
42161          */
42162 -       
42163 +
42164         mod_simple_vhost_patch_connection(srv, con, p);
42165 -       
42166 -       if (p->conf.docroot_cache_key->used && 
42167 +
42168 +       if (p->conf.docroot_cache_key->used &&
42169             con->uri.authority->used &&
42170             buffer_is_equal(p->conf.docroot_cache_key, con->uri.authority)) {
42171                 /* cache hit */
42172 @@ -243,8 +241,8 @@
42173                 if ((con->uri.authority->used == 0) ||
42174                     build_doc_root(srv, con, p, p->doc_root, con->uri.authority)) {
42175                         /* not found, fallback the default-host */
42176 -                       if (build_doc_root(srv, con, p, 
42177 -                                          p->doc_root, 
42178 +                       if (build_doc_root(srv, con, p,
42179 +                                          p->doc_root,
42180                                            p->conf.default_host)) {
42181                                 return HANDLER_GO_ON;
42182                         } else {
42183 @@ -253,15 +251,15 @@
42184                 } else {
42185                         buffer_copy_string_buffer(con->server_name, con->uri.authority);
42186                 }
42187 -               
42188 +
42189                 /* copy to cache */
42190                 buffer_copy_string_buffer(p->conf.docroot_cache_key,        con->uri.authority);
42191                 buffer_copy_string_buffer(p->conf.docroot_cache_value,      p->doc_root);
42192                 buffer_copy_string_buffer(p->conf.docroot_cache_servername, con->server_name);
42193 -               
42194 +
42195                 buffer_copy_string_buffer(con->physical.doc_root, p->doc_root);
42196         }
42197 -       
42198 +
42199         return HANDLER_GO_ON;
42200  }
42201  
42202 @@ -269,13 +267,13 @@
42203  int mod_simple_vhost_plugin_init(plugin *p) {
42204         p->version     = LIGHTTPD_VERSION_ID;
42205         p->name        = buffer_init_string("simple_vhost");
42206 -       
42207 +
42208         p->init        = mod_simple_vhost_init;
42209         p->set_defaults = mod_simple_vhost_set_defaults;
42210         p->handle_docroot  = mod_simple_vhost_docroot;
42211         p->cleanup     = mod_simple_vhost_free;
42212 -       
42213 +
42214         p->data        = NULL;
42215 -       
42216 +
42217         return 0;
42218  }
42219 --- ../lighttpd-1.4.11/src/mod_skeleton.c       2005-10-02 18:30:51.000000000 +0300
42220 +++ lighttpd-1.5.0/src/mod_skeleton.c   2006-07-16 00:26:03.000000000 +0300
42221 @@ -14,13 +14,13 @@
42222  
42223  /**
42224   * this is a skeleton for a lighttpd plugin
42225 - * 
42226 + *
42227   * just replaces every occurance of 'skeleton' by your plugin name
42228 - * 
42229 + *
42230   * e.g. in vim:
42231 - * 
42232 + *
42233   *   :%s/skeleton/myhandler/
42234 - * 
42235 + *
42236   */
42237  
42238  
42239 @@ -33,12 +33,12 @@
42240  
42241  typedef struct {
42242         PLUGIN_DATA;
42243 -       
42244 +
42245         buffer *match_buf;
42246 -       
42247 +
42248         plugin_config **config_storage;
42249 -       
42250 -       plugin_config conf; 
42251 +
42252 +       plugin_config conf;
42253  } plugin_data;
42254  
42255  typedef struct {
42256 @@ -47,36 +47,36 @@
42257  
42258  static handler_ctx * handler_ctx_init() {
42259         handler_ctx * hctx;
42260 -       
42261 +
42262         hctx = calloc(1, sizeof(*hctx));
42263 -       
42264 +
42265         return hctx;
42266  }
42267  
42268  static void handler_ctx_free(handler_ctx *hctx) {
42269 -       
42270 +
42271         free(hctx);
42272  }
42273  
42274  /* init the plugin data */
42275  INIT_FUNC(mod_skeleton_init) {
42276         plugin_data *p;
42277 -       
42278 +
42279         p = calloc(1, sizeof(*p));
42280 -       
42281 +
42282         p->match_buf = buffer_init();
42283 -       
42284 +
42285         return p;
42286  }
42287  
42288  /* detroy the plugin data */
42289  FREE_FUNC(mod_skeleton_free) {
42290         plugin_data *p = p_d;
42291 -       
42292 +
42293         UNUSED(srv);
42294  
42295         if (!p) return HANDLER_GO_ON;
42296 -       
42297 +
42298         if (p->config_storage) {
42299                 size_t i;
42300  
42301 @@ -84,18 +84,18 @@
42302                         plugin_config *s = p->config_storage[i];
42303  
42304                         if (!s) continue;
42305 -                       
42306 +
42307                         array_free(s->match);
42308 -                       
42309 +
42310                         free(s);
42311                 }
42312                 free(p->config_storage);
42313         }
42314 -       
42315 +
42316         buffer_free(p->match_buf);
42317 -       
42318 +
42319         free(p);
42320 -       
42321 +
42322         return HANDLER_GO_ON;
42323  }
42324  
42325 @@ -104,91 +104,88 @@
42326  SETDEFAULTS_FUNC(mod_skeleton_set_defaults) {
42327         plugin_data *p = p_d;
42328         size_t i = 0;
42329 -       
42330 -       config_values_t cv[] = { 
42331 +
42332 +       config_values_t cv[] = {
42333                 { "skeleton.array",             NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
42334                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
42335         };
42336 -       
42337 +
42338         if (!p) return HANDLER_ERROR;
42339 -       
42340 +
42341         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
42342 -       
42343 +
42344         for (i = 0; i < srv->config_context->used; i++) {
42345                 plugin_config *s;
42346 -               
42347 +
42348                 s = calloc(1, sizeof(plugin_config));
42349                 s->match    = array_init();
42350 -               
42351 +
42352                 cv[0].destination = s->match;
42353 -               
42354 +
42355                 p->config_storage[i] = s;
42356 -       
42357 +
42358                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
42359                         return HANDLER_ERROR;
42360                 }
42361         }
42362 -       
42363 +
42364         return HANDLER_GO_ON;
42365  }
42366  
42367 -#define PATCH(x) \
42368 -       p->conf.x = s->x;
42369  static int mod_skeleton_patch_connection(server *srv, connection *con, plugin_data *p) {
42370         size_t i, j;
42371         plugin_config *s = p->config_storage[0];
42372 -       
42373 -       PATCH(match);
42374 -       
42375 +
42376 +       PATCH_OPTION(match);
42377 +
42378         /* skip the first, the global context */
42379         for (i = 1; i < srv->config_context->used; i++) {
42380                 data_config *dc = (data_config *)srv->config_context->data[i];
42381                 s = p->config_storage[i];
42382 -               
42383 +
42384                 /* condition didn't match */
42385                 if (!config_check_cond(srv, con, dc)) continue;
42386 -               
42387 +
42388                 /* merge config */
42389                 for (j = 0; j < dc->value->used; j++) {
42390                         data_unset *du = dc->value->data[j];
42391 -                       
42392 +
42393                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("skeleton.array"))) {
42394 -                               PATCH(match);
42395 +                               PATCH_OPTION(match);
42396                         }
42397                 }
42398         }
42399 -       
42400 +
42401         return 0;
42402  }
42403 -#undef PATCH
42404  
42405  URIHANDLER_FUNC(mod_skeleton_uri_handler) {
42406         plugin_data *p = p_d;
42407         int s_len;
42408         size_t k, i;
42409 -       
42410 +
42411         UNUSED(srv);
42412  
42413         if (con->uri.path->used == 0) return HANDLER_GO_ON;
42414 -       
42415 +
42416         mod_skeleton_patch_connection(srv, con, p);
42417  
42418         s_len = con->uri.path->used - 1;
42419 -       
42420 +
42421         for (k = 0; k < p->conf.match->used; k++) {
42422                 data_string *ds = (data_string *)p->conf.match->data[k];
42423                 int ct_len = ds->value->used - 1;
42424 -               
42425 +
42426                 if (ct_len > s_len) continue;
42427                 if (ds->value->used == 0) continue;
42428 -               
42429 +
42430                 if (0 == strncmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
42431                         con->http_status = 403;
42432 -       
42433 +
42434                         return HANDLER_FINISHED;
42435                 }
42436         }
42437 -       
42438 +
42439         /* not found */
42440         return HANDLER_GO_ON;
42441  }
42442 @@ -198,13 +195,13 @@
42443  int mod_skeleton_plugin_init(plugin *p) {
42444         p->version     = LIGHTTPD_VERSION_ID;
42445         p->name        = buffer_init_string("skeleton");
42446 -       
42447 +
42448         p->init        = mod_skeleton_init;
42449         p->handle_uri_clean  = mod_skeleton_uri_handler;
42450         p->set_defaults  = mod_skeleton_set_defaults;
42451         p->cleanup     = mod_skeleton_free;
42452 -       
42453 +
42454         p->data        = NULL;
42455 -       
42456 +
42457         return 0;
42458  }
42459 --- ../lighttpd-1.4.11/src/mod_sql_vhost_core.c 1970-01-01 03:00:00.000000000 +0300
42460 +++ lighttpd-1.5.0/src/mod_sql_vhost_core.c     2006-07-20 00:57:20.000000000 +0300
42461 @@ -0,0 +1,211 @@
42462 +#include <stdio.h>
42463 +#include <errno.h>
42464 +#include <fcntl.h>
42465 +#include <string.h>
42466 +
42467 +#ifdef HAVE_CONFIG_H
42468 +#include "config.h"
42469 +#endif
42470 +
42471 +#include "plugin.h"
42472 +#include "log.h"
42473 +
42474 +#include "stat_cache.h"
42475 +
42476 +#include "mod_sql_vhost_core.h"
42477 +
42478 +#define plugin_data mod_sql_vhost_core_plugin_data
42479 +#define plugin_config mod_sql_vhost_core_plugin_config
42480 +
42481 +/* init the plugin data */
42482 +INIT_FUNC(mod_sql_vhost_core_init) {
42483 +       plugin_data *p;
42484 +
42485 +       p = calloc(1, sizeof(*p));
42486 +
42487 +       p->docroot = buffer_init();
42488 +       p->host = buffer_init();
42489 +
42490 +       return p;
42491 +}
42492 +
42493 +/* cleanup the plugin data */
42494 +SERVER_FUNC(mod_sql_vhost_core_cleanup) {
42495 +       plugin_data *p = p_d;
42496 +
42497 +       UNUSED(srv);
42498 +
42499 +       if (!p) return HANDLER_GO_ON;
42500 +
42501 +       if (p->config_storage) {
42502 +               size_t i;
42503 +               for (i = 0; i < srv->config_context->used; i++) {
42504 +                       plugin_config *s = p->config_storage[i];
42505 +
42506 +                       if (!s) continue;
42507 +
42508 +                       buffer_free(s->db);
42509 +                       buffer_free(s->user);
42510 +                       buffer_free(s->pass);
42511 +                       buffer_free(s->sock);
42512 +                       buffer_free(s->backend);
42513 +                       buffer_free(s->hostname);
42514 +                       buffer_free(s->select_vhost);
42515 +
42516 +                       free(s);
42517 +               }
42518 +               free(p->config_storage);
42519 +       }
42520 +       buffer_free(p->docroot);
42521 +       buffer_free(p->host);
42522 +
42523 +       free(p);
42524 +
42525 +       return HANDLER_GO_ON;
42526 +}
42527 +
42528 +/* set configuration values */
42529 +SERVER_FUNC(mod_sql_vhost_core_set_defaults) {
42530 +       plugin_data *p = p_d;
42531 +
42532 +       size_t i = 0;
42533 +
42534 +       config_values_t cv[] = {
42535 +               { "sql-vhost.db",       NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 0 * e.g. vhost */
42536 +               { "sql-vhost.user",     NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 1 * lighty */
42537 +               { "sql-vhost.pass",     NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 2 * secrect */
42538 +               { "sql-vhost.sock",     NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 3 * /tmp/mysql.sock */
42539 +               { "sql-vhost.select-vhost", NULL, T_CONFIG_STRING,      T_CONFIG_SCOPE_SERVER }, /* 4 * SELECT ... FROM hosts WHERE hostname = ? */
42540 +               { "sql-vhost.hostname", NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 5 * 127.0.0.1 */
42541 +               { "sql-vhost.port",     NULL, T_CONFIG_SHORT,   T_CONFIG_SCOPE_SERVER }, /* 6 * 3306 */
42542 +               { "sql-vhost.backend",  NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 7 * mysql */
42543 +
42544 +               /* backward compat */
42545 +               { "mysql-vhost.db",     NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 8 == 0 */
42546 +               { "mysql-vhost.user",   NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 9 == 1 */
42547 +               { "mysql-vhost.pass",   NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 10 == 2 */
42548 +               { "mysql-vhost.sock",   NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 11 == 3 */
42549 +               { "mysql-vhost.sql",    NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER }, /* 12 == 4 */
42550 +               { "mysql-vhost.hostname", NULL, T_CONFIG_STRING,T_CONFIG_SCOPE_SERVER }, /* 13 == 5 */
42551 +               { "mysql-vhost.port",   NULL, T_CONFIG_SHORT,   T_CONFIG_SCOPE_SERVER }, /* 14 == 6 */
42552 +
42553 +                { NULL,                        NULL, T_CONFIG_UNSET,   T_CONFIG_SCOPE_UNSET }
42554 +        };
42555 +
42556 +       p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
42557 +
42558 +       for (i = 0; i < srv->config_context->used; i++) {
42559 +               plugin_config *s;
42560 +
42561 +               s = calloc(1, sizeof(plugin_config));
42562 +               s->db = buffer_init();
42563 +               s->user = buffer_init();
42564 +               s->pass = buffer_init();
42565 +               s->sock = buffer_init();
42566 +               s->hostname = buffer_init();
42567 +               s->backend = buffer_init();
42568 +               s->port   = 0;               /* default port for mysql */
42569 +               s->select_vhost = buffer_init();
42570 +               s->backend_data = NULL;
42571 +
42572 +               cv[0].destination = s->db;
42573 +               cv[1].destination = s->user;
42574 +               cv[2].destination = s->pass;
42575 +               cv[3].destination = s->sock;
42576 +               cv[4].destination = s->select_vhost;
42577 +               cv[5].destination = s->hostname;
42578 +               cv[6].destination = &(s->port);
42579 +               cv[7].destination = s->backend;
42580 +
42581 +               /* backend compat */
42582 +               cv[8].destination = cv[0].destination;
42583 +               cv[9].destination = cv[1].destination;
42584 +               cv[10].destination = cv[2].destination;
42585 +               cv[11].destination = cv[3].destination;
42586 +               cv[12].destination = cv[4].destination;
42587 +               cv[13].destination = cv[5].destination;
42588 +               cv[14].destination = cv[6].destination;
42589 +
42590 +               p->config_storage[i] = s;
42591 +
42592 +               if (config_insert_values_global(srv,
42593 +                       ((data_config *)srv->config_context->data[i])->value,
42594 +                       cv)) return HANDLER_ERROR;
42595 +
42596 +               /* we only parse the config, the backend plugin will patch itself into the plugin-struct */
42597 +       }
42598 +
42599 +        return HANDLER_GO_ON;
42600 +}
42601 +
42602 +static int mod_sql_vhost_core_patch_connection(server *srv, connection *con, plugin_data *p) {
42603 +       size_t i;
42604 +       plugin_config *s = p->config_storage[0];
42605 +
42606 +       PATCH_OPTION(backend_data);
42607 +       PATCH_OPTION(get_vhost);
42608 +
42609 +       /* skip the first, the global context */
42610 +       for (i = 1; i < srv->config_context->used; i++) {
42611 +               data_config *dc = (data_config *)srv->config_context->data[i];
42612 +               s = p->config_storage[i];
42613 +
42614 +               /* condition didn't match */
42615 +               if (!config_check_cond(srv, con, dc)) continue;
42616 +
42617 +               if (s->backend_data) {
42618 +                       PATCH_OPTION(backend_data);
42619 +                       PATCH_OPTION(get_vhost);
42620 +               }
42621 +       }
42622 +
42623 +       return 0;
42624 +}
42625 +
42626 +/* handle document root request */
42627 +CONNECTION_FUNC(mod_sql_vhost_core_handle_docroot) {
42628 +       plugin_data *p = p_d;
42629 +       stat_cache_entry *sce;
42630 +
42631 +       /* no host specified? */
42632 +       if (!con->uri.authority->used) return HANDLER_GO_ON;
42633 +
42634 +       mod_sql_vhost_core_patch_connection(srv, con, p);
42635 +
42636 +       /* do we have backend ? */
42637 +       if (!p->conf.get_vhost) return HANDLER_GO_ON;
42638 +
42639 +       /* ask the backend for the data */
42640 +       if (0 != p->conf.get_vhost(srv, con, p->conf.backend_data, p->docroot, p->host)) {
42641 +               return HANDLER_GO_ON;
42642 +       }
42643 +
42644 +       if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->docroot, &sce)) {
42645 +               log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->docroot);
42646 +               return HANDLER_GO_ON;
42647 +       }
42648 +        if (!S_ISDIR(sce->st.st_mode)) {
42649 +               log_error_write(srv, __FILE__, __LINE__, "sb", "Not a directory", p->docroot);
42650 +               return HANDLER_GO_ON;
42651 +       }
42652 +
42653 +       buffer_copy_string_buffer(con->server_name, p->host);
42654 +       buffer_copy_string_buffer(con->physical.doc_root, p->docroot);
42655 +
42656 +       return HANDLER_GO_ON;
42657 +}
42658 +
42659 +/* this function is called at dlopen() time and inits the callbacks */
42660 +int mod_sql_vhost_core_plugin_init(plugin *p) {
42661 +       p->version     = LIGHTTPD_VERSION_ID;
42662 +       p->name                         = buffer_init_string("mod_sql_vhost_core");
42663 +
42664 +       p->init                         = mod_sql_vhost_core_init;
42665 +       p->cleanup                      = mod_sql_vhost_core_cleanup;
42666 +
42667 +       p->set_defaults                 = mod_sql_vhost_core_set_defaults;
42668 +       p->handle_docroot               = mod_sql_vhost_core_handle_docroot;
42669 +
42670 +       return 0;
42671 +}
42672 +
42673 --- ../lighttpd-1.4.11/src/mod_sql_vhost_core.h 1970-01-01 03:00:00.000000000 +0300
42674 +++ lighttpd-1.5.0/src/mod_sql_vhost_core.h     2006-07-16 00:26:04.000000000 +0300
42675 @@ -0,0 +1,49 @@
42676 +#ifndef _MOD_SQL_VHOST_CORE_H_
42677 +#define _MOD_SQL_VHOST_CORE_H_
42678 +
42679 +#include "buffer.h"
42680 +#include "plugin.h"
42681 +
42682 +#define SQLVHOST_BACKEND_GETVHOST_PARAMS \
42683 +       (server *srv, connection *con, void *p_d, buffer *docroot, buffer *host)
42684 +
42685 +#define SQLVHOST_BACKEND_GETVHOST_RETVAL handler_t
42686 +
42687 +#define SQLVHOST_BACKEND_GETVHOST(name) \
42688 +       SQLVHOST_BACKEND_GETVHOST_RETVAL name SQLVHOST_BACKEND_GETVHOST_PARAMS
42689 +
42690 +#define SQLVHOST_BACKEND_GETVHOST_PTR(name) \
42691 +       SQLVHOST_BACKEND_GETVHOST_RETVAL (* name)SQLVHOST_BACKEND_GETVHOST_PARAMS
42692 +
42693 +typedef struct {
42694 +       buffer  *db;
42695 +       buffer  *user;
42696 +       buffer  *pass;
42697 +       buffer  *sock;
42698 +
42699 +       buffer  *hostname;
42700 +       unsigned short port;
42701 +
42702 +       buffer  *backend;
42703 +       void *backend_data;
42704 +
42705 +       buffer *select_vhost;
42706 +
42707 +       SQLVHOST_BACKEND_GETVHOST_PTR(get_vhost);
42708 +} mod_sql_vhost_core_plugin_config;
42709 +
42710 +/* global plugin data */
42711 +typedef struct {
42712 +       PLUGIN_DATA;
42713 +
42714 +       buffer  *docroot;
42715 +       buffer  *host;
42716 +
42717 +       mod_sql_vhost_core_plugin_config **config_storage;
42718 +
42719 +       mod_sql_vhost_core_plugin_config conf;
42720 +} mod_sql_vhost_core_plugin_data;
42721 +
42722 +
42723 +
42724 +#endif
42725 --- ../lighttpd-1.4.11/src/mod_ssi.c    2006-03-04 17:09:48.000000000 +0200
42726 +++ lighttpd-1.5.0/src/mod_ssi.c        2006-09-07 00:57:05.000000000 +0300
42727 @@ -6,7 +6,6 @@
42728  #include <string.h>
42729  #include <errno.h>
42730  #include <time.h>
42731 -#include <unistd.h>
42732  
42733  #include "base.h"
42734  #include "log.h"
42735 @@ -23,6 +22,8 @@
42736  #include "inet_ntop_cache.h"
42737  
42738  #include "sys-socket.h"
42739 +#include "sys-strings.h"
42740 +#include "sys-files.h"
42741  
42742  #ifdef HAVE_PWD_H
42743  #include <pwd.h>
42744 @@ -39,15 +40,15 @@
42745  /* init the plugin data */
42746  INIT_FUNC(mod_ssi_init) {
42747         plugin_data *p;
42748 -       
42749 +
42750         p = calloc(1, sizeof(*p));
42751 -       
42752 +
42753         p->timefmt = buffer_init();
42754         p->stat_fn = buffer_init();
42755 -       
42756 +
42757         p->ssi_vars = array_init();
42758         p->ssi_cgi_env = array_init();
42759 -       
42760 +
42761         return p;
42762  }
42763  
42764 @@ -55,21 +56,21 @@
42765  FREE_FUNC(mod_ssi_free) {
42766         plugin_data *p = p_d;
42767         UNUSED(srv);
42768 -       
42769 +
42770         if (!p) return HANDLER_GO_ON;
42771 -       
42772 +
42773         if (p->config_storage) {
42774                 size_t i;
42775                 for (i = 0; i < srv->config_context->used; i++) {
42776                         plugin_config *s = p->config_storage[i];
42777 -                       
42778 +
42779                         array_free(s->ssi_extension);
42780 -                       
42781 +
42782                         free(s);
42783                 }
42784                 free(p->config_storage);
42785         }
42786 -       
42787 +
42788         array_free(p->ssi_vars);
42789         array_free(p->ssi_cgi_env);
42790  #ifdef HAVE_PCRE_H
42791 @@ -77,9 +78,9 @@
42792  #endif
42793         buffer_free(p->timefmt);
42794         buffer_free(p->stat_fn);
42795 -       
42796 +
42797         free(p);
42798 -       
42799 +
42800         return HANDLER_GO_ON;
42801  }
42802  
42803 @@ -92,36 +93,36 @@
42804         const char *errptr;
42805         int erroff;
42806  #endif
42807 -       
42808 -       config_values_t cv[] = { 
42809 +
42810 +       config_values_t cv[] = {
42811                 { "ssi.extension",              NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
42812                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
42813         };
42814 -       
42815 +
42816         if (!p) return HANDLER_ERROR;
42817 -       
42818 +
42819         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
42820 -       
42821 +
42822         for (i = 0; i < srv->config_context->used; i++) {
42823                 plugin_config *s;
42824 -               
42825 +
42826                 s = calloc(1, sizeof(plugin_config));
42827                 s->ssi_extension  = array_init();
42828 -               
42829 +
42830                 cv[0].destination = s->ssi_extension;
42831 -               
42832 +
42833                 p->config_storage[i] = s;
42834 -       
42835 +
42836                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
42837                         return HANDLER_ERROR;
42838                 }
42839         }
42840 -       
42841 +
42842  #ifdef HAVE_PCRE_H
42843         /* allow 2 params */
42844         if (NULL == (p->ssi_regex = pcre_compile("<!--#([a-z]+)\\s+(?:([a-z]+)=\"(.*?)(?<!\\\\)\"\\s*)?(?:([a-z]+)=\"(.*?)(?<!\\\\)\"\\s*)?-->", 0, &errptr, &erroff, NULL))) {
42845                 log_error_write(srv, __FILE__, __LINE__, "sds",
42846 -                               "ssi: pcre ", 
42847 +                               "ssi: pcre ",
42848                                 erroff, errptr);
42849                 return HANDLER_ERROR;
42850         }
42851 @@ -130,52 +131,52 @@
42852                         "mod_ssi: pcre support is missing, please recompile with pcre support or remove mod_ssi from the list of modules");
42853         return HANDLER_ERROR;
42854  #endif
42855 -       
42856 +
42857         return HANDLER_GO_ON;
42858  }
42859  
42860  int ssi_env_add(array *env, const char *key, const char *val) {
42861         data_string *ds;
42862 -                       
42863 +
42864         if (NULL == (ds = (data_string *)array_get_unused_element(env, TYPE_STRING))) {
42865                 ds = data_string_init();
42866         }
42867         buffer_copy_string(ds->key,   key);
42868         buffer_copy_string(ds->value, val);
42869 -       
42870 +
42871         array_insert_unique(env, (data_unset *)ds);
42872 -       
42873 +
42874         return 0;
42875  }
42876  
42877  /**
42878   *
42879   *  the next two functions are take from fcgi.c
42880 - * 
42881 + *
42882   */
42883  
42884  static int ssi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
42885         size_t i;
42886 -       
42887 +
42888         for (i = 0; i < con->request.headers->used; i++) {
42889                 data_string *ds;
42890 -               
42891 +
42892                 ds = (data_string *)con->request.headers->data[i];
42893 -               
42894 +
42895                 if (ds->value->used && ds->key->used) {
42896                         size_t j;
42897                         buffer_reset(srv->tmp_buf);
42898 -                       
42899 +
42900                         /* don't forward the Authorization: Header */
42901                         if (0 == strcasecmp(ds->key->ptr, "AUTHORIZATION")) {
42902                                 continue;
42903                         }
42904 -                       
42905 +
42906                         if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
42907                                 buffer_copy_string(srv->tmp_buf, "HTTP_");
42908                                 srv->tmp_buf->used--;
42909                         }
42910 -                       
42911 +
42912                         buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
42913                         for (j = 0; j < ds->key->used - 1; j++) {
42914                                 char c = '_';
42915 @@ -189,33 +190,33 @@
42916                                 srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
42917                         }
42918                         srv->tmp_buf->ptr[srv->tmp_buf->used] = '\0';
42919 -                       
42920 +
42921                         ssi_env_add(p->ssi_cgi_env, srv->tmp_buf->ptr, ds->value->ptr);
42922                 }
42923         }
42924 -       
42925 +
42926         return 0;
42927  }
42928  
42929  static int build_ssi_cgi_vars(server *srv, connection *con, plugin_data *p) {
42930         char buf[32];
42931 -       
42932 +
42933         server_socket *srv_sock = con->srv_socket;
42934 -       
42935 +
42936  #ifdef HAVE_IPV6
42937         char b2[INET6_ADDRSTRLEN + 1];
42938  #endif
42939  
42940  #define CONST_STRING(x) \
42941                 x
42942 -       
42943 +
42944         array_reset(p->ssi_cgi_env);
42945 -       
42946 +
42947         ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_SOFTWARE"), PACKAGE_NAME"/"PACKAGE_VERSION);
42948         ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_NAME"),
42949  #ifdef HAVE_IPV6
42950 -                    inet_ntop(srv_sock->addr.plain.sa_family, 
42951 -                              srv_sock->addr.plain.sa_family == AF_INET6 ? 
42952 +                    inet_ntop(srv_sock->addr.plain.sa_family,
42953 +                              srv_sock->addr.plain.sa_family == AF_INET6 ?
42954                                (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
42955                                (const void *) &(srv_sock->addr.ipv4.sin_addr),
42956                                b2, sizeof(b2)-1)
42957 @@ -224,28 +225,28 @@
42958  #endif
42959                      );
42960         ssi_env_add(p->ssi_cgi_env, CONST_STRING("GATEWAY_INTERFACE"), "CGI/1.1");
42961 -               
42962 -       ltostr(buf, 
42963 +
42964 +       ltostr(buf,
42965  #ifdef HAVE_IPV6
42966                ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
42967  #else
42968                ntohs(srv_sock->addr.ipv4.sin_port)
42969  #endif
42970                );
42971 -       
42972 +
42973         ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_PORT"), buf);
42974 -       
42975 +
42976         ssi_env_add(p->ssi_cgi_env, CONST_STRING("REMOTE_ADDR"),
42977                     inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
42978 -       
42979 +
42980         if (con->authed_user->used) {
42981                 ssi_env_add(p->ssi_cgi_env, CONST_STRING("REMOTE_USER"),
42982                              con->authed_user->ptr);
42983         }
42984 -       
42985 +
42986         if (con->request.content_length > 0) {
42987                 /* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */
42988 -               
42989 +
42990                 /* request.content_length < SSIZE_MAX, see request.c */
42991                 ltostr(buf, con->request.content_length);
42992                 ssi_env_add(p->ssi_cgi_env, CONST_STRING("CONTENT_LENGTH"), buf);
42993 @@ -271,30 +272,30 @@
42994         if (con->request.pathinfo->used) {
42995                 ssi_env_add(p->ssi_cgi_env, CONST_STRING("PATH_INFO"), con->request.pathinfo->ptr);
42996         }
42997 -               
42998 +
42999         ssi_env_add(p->ssi_cgi_env, CONST_STRING("SCRIPT_FILENAME"), con->physical.path->ptr);
43000         ssi_env_add(p->ssi_cgi_env, CONST_STRING("DOCUMENT_ROOT"), con->physical.doc_root->ptr);
43001 -       
43002 +
43003         ssi_env_add(p->ssi_cgi_env, CONST_STRING("REQUEST_URI"), con->request.uri->ptr);
43004         ssi_env_add(p->ssi_cgi_env, CONST_STRING("QUERY_STRING"), con->uri.query->used ? con->uri.query->ptr : "");
43005         ssi_env_add(p->ssi_cgi_env, CONST_STRING("REQUEST_METHOD"), get_http_method_name(con->request.http_method));
43006         ssi_env_add(p->ssi_cgi_env, CONST_STRING("REDIRECT_STATUS"), "200");
43007         ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_PROTOCOL"), get_http_version_name(con->request.http_version));
43008 -       
43009 +
43010         ssi_env_add_request_headers(srv, con, p);
43011 -       
43012 +
43013         return 0;
43014  }
43015  
43016 -static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, 
43017 +static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
43018                             const char **l, size_t n) {
43019         size_t i, ssicmd = 0;
43020         char buf[255];
43021         buffer *b = NULL;
43022 -       
43023 -       struct { 
43024 +
43025 +       struct {
43026                 const char *var;
43027 -               enum { SSI_UNSET, SSI_ECHO, SSI_FSIZE, SSI_INCLUDE, SSI_FLASTMOD, 
43028 +               enum { SSI_UNSET, SSI_ECHO, SSI_FSIZE, SSI_INCLUDE, SSI_FLASTMOD,
43029                                 SSI_CONFIG, SSI_PRINTENV, SSI_SET, SSI_IF, SSI_ELIF,
43030                                 SSI_ELSE, SSI_ENDIF, SSI_EXEC } type;
43031         } ssicmds[] = {
43032 @@ -310,27 +311,27 @@
43033                 { "endif",    SSI_ENDIF },
43034                 { "else",     SSI_ELSE },
43035                 { "exec",     SSI_EXEC },
43036 -               
43037 +
43038                 { NULL, SSI_UNSET }
43039         };
43040 -       
43041 +
43042         for (i = 0; ssicmds[i].var; i++) {
43043                 if (0 == strcmp(l[1], ssicmds[i].var)) {
43044                         ssicmd = ssicmds[i].type;
43045                         break;
43046                 }
43047         }
43048 -       
43049 +
43050         switch(ssicmd) {
43051         case SSI_ECHO: {
43052                 /* echo */
43053                 int var = 0, enc = 0;
43054                 const char *var_val = NULL;
43055                 stat_cache_entry *sce = NULL;
43056 -               
43057 -               struct { 
43058 +
43059 +               struct {
43060                         const char *var;
43061 -                       enum { SSI_ECHO_UNSET, SSI_ECHO_DATE_GMT, SSI_ECHO_DATE_LOCAL, SSI_ECHO_DOCUMENT_NAME, SSI_ECHO_DOCUMENT_URI, 
43062 +                       enum { SSI_ECHO_UNSET, SSI_ECHO_DATE_GMT, SSI_ECHO_DATE_LOCAL, SSI_ECHO_DOCUMENT_NAME, SSI_ECHO_DOCUMENT_URI,
43063                                         SSI_ECHO_LAST_MODIFIED, SSI_ECHO_USER_NAME } type;
43064                 } echovars[] = {
43065                         { "DATE_GMT",      SSI_ECHO_DATE_GMT },
43066 @@ -339,27 +340,27 @@
43067                         { "DOCUMENT_URI",  SSI_ECHO_DOCUMENT_URI },
43068                         { "LAST_MODIFIED", SSI_ECHO_LAST_MODIFIED },
43069                         { "USER_NAME",     SSI_ECHO_USER_NAME },
43070 -                       
43071 +
43072                         { NULL, SSI_ECHO_UNSET }
43073                 };
43074 -               
43075 -               struct { 
43076 +
43077 +               struct {
43078                         const char *var;
43079                         enum { SSI_ENC_UNSET, SSI_ENC_URL, SSI_ENC_NONE, SSI_ENC_ENTITY } type;
43080                 } encvars[] = {
43081                         { "url",          SSI_ENC_URL },
43082                         { "none",         SSI_ENC_NONE },
43083                         { "entity",       SSI_ENC_ENTITY },
43084 -                       
43085 +
43086                         { NULL, SSI_ENC_UNSET }
43087                 };
43088 -               
43089 +
43090                 for (i = 2; i < n; i += 2) {
43091                         if (0 == strcmp(l[i], "var")) {
43092                                 int j;
43093 -                               
43094 +
43095                                 var_val = l[i+1];
43096 -                               
43097 +
43098                                 for (j = 0; echovars[j].var; j++) {
43099                                         if (0 == strcmp(l[i+1], echovars[j].var)) {
43100                                                 var = echovars[j].type;
43101 @@ -368,7 +369,7 @@
43102                                 }
43103                         } else if (0 == strcmp(l[i], "encoding")) {
43104                                 int j;
43105 -                               
43106 +
43107                                 for (j = 0; encvars[j].var; j++) {
43108                                         if (0 == strcmp(l[i+1], encvars[j].var)) {
43109                                                 enc = encvars[j].type;
43110 @@ -377,27 +378,27 @@
43111                                 }
43112                         } else {
43113                                 log_error_write(srv, __FILE__, __LINE__, "sss",
43114 -                                               "ssi: unknow attribute for ", 
43115 +                                               "ssi: unknow attribute for ",
43116                                                 l[1], l[i]);
43117                         }
43118                 }
43119 -               
43120 +
43121                 if (p->if_is_false) break;
43122 -               
43123 +
43124                 if (!var_val) {
43125                         log_error_write(srv, __FILE__, __LINE__, "sss",
43126 -                                       "ssi: ", 
43127 +                                       "ssi: ",
43128                                         l[1], "var is missing");
43129                         break;
43130                 }
43131  
43132                 stat_cache_get_entry(srv, con, con->physical.path, &sce);
43133 -               
43134 +
43135                 switch(var) {
43136                 case SSI_ECHO_USER_NAME: {
43137                         struct passwd *pw;
43138 -                       
43139 -                       b = chunkqueue_get_append_buffer(con->write_queue);
43140 +
43141 +                       b = chunkqueue_get_append_buffer(con->send);
43142  #ifdef HAVE_PWD_H
43143                         if (NULL == (pw = getpwuid(sce->st.st_uid))) {
43144                                 buffer_copy_long(b, sce->st.st_uid);
43145 @@ -411,8 +412,8 @@
43146                 }
43147                 case SSI_ECHO_LAST_MODIFIED:    {
43148                         time_t t = sce->st.st_mtime;
43149 -                       
43150 -                       b = chunkqueue_get_append_buffer(con->write_queue);
43151 +
43152 +                       b = chunkqueue_get_append_buffer(con->send);
43153                         if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
43154                                 buffer_copy_string(b, "(none)");
43155                         } else {
43156 @@ -422,8 +423,8 @@
43157                 }
43158                 case SSI_ECHO_DATE_LOCAL: {
43159                         time_t t = time(NULL);
43160 -                       
43161 -                       b = chunkqueue_get_append_buffer(con->write_queue);
43162 +
43163 +                       b = chunkqueue_get_append_buffer(con->send);
43164                         if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
43165                                 buffer_copy_string(b, "(none)");
43166                         } else {
43167 @@ -433,8 +434,8 @@
43168                 }
43169                 case SSI_ECHO_DATE_GMT: {
43170                         time_t t = time(NULL);
43171 -                       
43172 -                       b = chunkqueue_get_append_buffer(con->write_queue);
43173 +
43174 +                       b = chunkqueue_get_append_buffer(con->send);
43175                         if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, gmtime(&t))) {
43176                                 buffer_copy_string(b, "(none)");
43177                         } else {
43178 @@ -444,8 +445,8 @@
43179                 }
43180                 case SSI_ECHO_DOCUMENT_NAME: {
43181                         char *sl;
43182 -                       
43183 -                       b = chunkqueue_get_append_buffer(con->write_queue);
43184 +
43185 +                       b = chunkqueue_get_append_buffer(con->send);
43186                         if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) {
43187                                 buffer_copy_string_buffer(b, con->physical.path);
43188                         } else {
43189 @@ -454,22 +455,22 @@
43190                         break;
43191                 }
43192                 case SSI_ECHO_DOCUMENT_URI: {
43193 -                       b = chunkqueue_get_append_buffer(con->write_queue);
43194 +                       b = chunkqueue_get_append_buffer(con->send);
43195                         buffer_copy_string_buffer(b, con->uri.path);
43196                         break;
43197                 }
43198                 default: {
43199                         data_string *ds;
43200                         /* check if it is a cgi-var */
43201 -                       
43202 -                       b = chunkqueue_get_append_buffer(con->write_queue);
43203 -                       
43204 +
43205 +                       b = chunkqueue_get_append_buffer(con->send);
43206 +
43207                         if (NULL != (ds = (data_string *)array_get_element(p->ssi_cgi_env, var_val))) {
43208                                 buffer_copy_string_buffer(b, ds->value);
43209                         } else {
43210                                 buffer_copy_string(b, "(none)");
43211                         }
43212 -                       
43213 +
43214                         break;
43215                 }
43216                 }
43217 @@ -481,7 +482,7 @@
43218                 const char * file_path = NULL, *virt_path = NULL;
43219                 struct stat st;
43220                 char *sl;
43221 -               
43222 +
43223                 for (i = 2; i < n; i += 2) {
43224                         if (0 == strcmp(l[i], "file")) {
43225                                 file_path = l[i+1];
43226 @@ -489,28 +490,28 @@
43227                                 virt_path = l[i+1];
43228                         } else {
43229                                 log_error_write(srv, __FILE__, __LINE__, "sss",
43230 -                                               "ssi: unknow attribute for ", 
43231 +                                               "ssi: unknow attribute for ",
43232                                                 l[1], l[i]);
43233                         }
43234                 }
43235 -               
43236 +
43237                 if (!file_path && !virt_path) {
43238                         log_error_write(srv, __FILE__, __LINE__, "sss",
43239 -                                       "ssi: ", 
43240 +                                       "ssi: ",
43241                                         l[1], "file or virtual are missing");
43242                         break;
43243                 }
43244 -               
43245 +
43246                 if (file_path && virt_path) {
43247                         log_error_write(srv, __FILE__, __LINE__, "sss",
43248 -                                       "ssi: ", 
43249 +                                       "ssi: ",
43250                                         l[1], "only one of file and virtual is allowed here");
43251                         break;
43252                 }
43253 -               
43254 -               
43255 +
43256 +
43257                 if (p->if_is_false) break;
43258 -               
43259 +
43260                 if (file_path) {
43261                         /* current doc-root */
43262                         if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) {
43263 @@ -519,46 +520,46 @@
43264                                 buffer_copy_string_len(p->stat_fn, con->physical.path->ptr, sl - con->physical.path->ptr + 1);
43265                         }
43266  
43267 -                       buffer_copy_string(srv->tmp_buf, file_path); 
43268 +                       buffer_copy_string(srv->tmp_buf, file_path);
43269                         buffer_urldecode_path(srv->tmp_buf);
43270 -                       buffer_path_simplify(srv->tmp_buf, srv->tmp_buf); 
43271 -                       buffer_append_string_buffer(p->stat_fn, srv->tmp_buf); 
43272 +                       buffer_path_simplify(srv->tmp_buf, srv->tmp_buf);
43273 +                       buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
43274                 } else {
43275                         /* virtual */
43276 -                       
43277 +
43278                         if (virt_path[0] == '/') {
43279                                 buffer_copy_string(p->stat_fn, virt_path);
43280                         } else {
43281                                 /* there is always a / */
43282                                 sl = strrchr(con->uri.path->ptr, '/');
43283 -                               
43284 +
43285                                 buffer_copy_string_len(p->stat_fn, con->uri.path->ptr, sl - con->uri.path->ptr + 1);
43286                                 buffer_append_string(p->stat_fn, virt_path);
43287                         }
43288 -                       
43289 +
43290                         buffer_urldecode_path(p->stat_fn);
43291                         buffer_path_simplify(srv->tmp_buf, p->stat_fn);
43292 -                       
43293 +
43294                         /* we have an uri */
43295 -                       
43296 +
43297                         buffer_copy_string_buffer(p->stat_fn, con->physical.doc_root);
43298                         buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
43299                 }
43300 -               
43301 +
43302                 if (0 == stat(p->stat_fn->ptr, &st)) {
43303                         time_t t = st.st_mtime;
43304 -                       
43305 +
43306                         switch (ssicmd) {
43307                         case SSI_FSIZE:
43308 -                               b = chunkqueue_get_append_buffer(con->write_queue);
43309 +                               b = chunkqueue_get_append_buffer(con->send);
43310                                 if (p->sizefmt) {
43311                                         int j = 0;
43312                                         const char *abr[] = { " B", " kB", " MB", " GB", " TB", NULL };
43313 -                                       
43314 +
43315                                         off_t s = st.st_size;
43316 -                                       
43317 +
43318                                         for (j = 0; s > 1024 && abr[j+1]; s /= 1024, j++);
43319 -                                       
43320 +
43321                                         buffer_copy_off_t(b, s);
43322                                         buffer_append_string(b, abr[j]);
43323                                 } else {
43324 @@ -566,7 +567,7 @@
43325                                 }
43326                                 break;
43327                         case SSI_FLASTMOD:
43328 -                               b = chunkqueue_get_append_buffer(con->write_queue);
43329 +                               b = chunkqueue_get_append_buffer(con->send);
43330                                 if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
43331                                         buffer_copy_string(b, "(none)");
43332                                 } else {
43333 @@ -574,12 +575,12 @@
43334                                 }
43335                                 break;
43336                         case SSI_INCLUDE:
43337 -                               chunkqueue_append_file(con->write_queue, p->stat_fn, 0, st.st_size);
43338 +                               chunkqueue_append_file(con->send, p->stat_fn, 0, st.st_size);
43339                                 break;
43340                         }
43341                 } else {
43342                         log_error_write(srv, __FILE__, __LINE__, "sbs",
43343 -                                       "ssi: stating failed ", 
43344 +                                       "ssi: stating failed ",
43345                                         p->stat_fn, strerror(errno));
43346                 }
43347                 break;
43348 @@ -593,33 +594,33 @@
43349                                 val = l[i+1];
43350                         } else {
43351                                 log_error_write(srv, __FILE__, __LINE__, "sss",
43352 -                                               "ssi: unknow attribute for ", 
43353 +                                               "ssi: unknow attribute for ",
43354                                                 l[1], l[i]);
43355                         }
43356                 }
43357 -               
43358 +
43359                 if (p->if_is_false) break;
43360 -               
43361 +
43362                 if (key && val) {
43363                         data_string *ds;
43364 -                       
43365 +
43366                         if (NULL == (ds = (data_string *)array_get_unused_element(p->ssi_vars, TYPE_STRING))) {
43367                                 ds = data_string_init();
43368                         }
43369                         buffer_copy_string(ds->key,   key);
43370                         buffer_copy_string(ds->value, val);
43371 -                       
43372 +
43373                         array_insert_unique(p->ssi_vars, (data_unset *)ds);
43374                 } else {
43375                         log_error_write(srv, __FILE__, __LINE__, "sss",
43376 -                                       "ssi: var and value have to be set in", 
43377 +                                       "ssi: var and value have to be set in",
43378                                         l[0], l[1]);
43379                 }
43380                 break;
43381         }
43382 -       case SSI_CONFIG: 
43383 +       case SSI_CONFIG:
43384                 if (p->if_is_false) break;
43385 -               
43386 +
43387                 for (i = 2; i < n; i += 2) {
43388                         if (0 == strcmp(l[i], "timefmt")) {
43389                                 buffer_copy_string(p->timefmt, l[i+1]);
43390 @@ -632,63 +633,65 @@
43391                                         log_error_write(srv, __FILE__, __LINE__, "sssss",
43392                                                         "ssi: unknow value for attribute '",
43393                                                         l[i],
43394 -                                                       "' for ", 
43395 +                                                       "' for ",
43396                                                         l[1], l[i+1]);
43397                                 }
43398                         } else {
43399                                 log_error_write(srv, __FILE__, __LINE__, "sss",
43400 -                                               "ssi: unknow attribute for ", 
43401 +                                               "ssi: unknow attribute for ",
43402                                                 l[1], l[i]);
43403                         }
43404                 }
43405                 break;
43406         case SSI_PRINTENV:
43407                 if (p->if_is_false) break;
43408 -               
43409 -               b = chunkqueue_get_append_buffer(con->write_queue);
43410 +
43411 +               b = chunkqueue_get_append_buffer(con->send);
43412                 buffer_copy_string(b, "<pre>");
43413                 for (i = 0; i < p->ssi_vars->used; i++) {
43414                         data_string *ds = (data_string *)p->ssi_vars->data[p->ssi_vars->sorted[i]];
43415 -                       
43416 +
43417                         buffer_append_string_buffer(b, ds->key);
43418                         buffer_append_string(b, ": ");
43419                         buffer_append_string_buffer(b, ds->value);
43420                         buffer_append_string(b, "<br />");
43421 -                                       
43422 +
43423                 }
43424                 buffer_append_string(b, "</pre>");
43425 -               
43426 +
43427                 break;
43428         case SSI_EXEC: {
43429 +#ifndef _WIN32
43430 +
43431                 const char *cmd = NULL;
43432                 pid_t pid;
43433                 int from_exec_fds[2];
43434 -               
43435 +
43436                 for (i = 2; i < n; i += 2) {
43437                         if (0 == strcmp(l[i], "cmd")) {
43438                                 cmd = l[i+1];
43439                         } else {
43440                                 log_error_write(srv, __FILE__, __LINE__, "sss",
43441 -                                               "ssi: unknow attribute for ", 
43442 +                                               "ssi: unknow attribute for ",
43443                                                 l[1], l[i]);
43444                         }
43445                 }
43446 -               
43447 +
43448                 if (p->if_is_false) break;
43449 -               
43450 +
43451                 /* create a return pipe and send output to the html-page
43452 -                * 
43453 -                * as exec is assumed evil it is implemented synchronously 
43454 +                *
43455 +                * as exec is assumed evil it is implemented synchronously
43456                  */
43457 -               
43458 +
43459                 if (!cmd) break;
43460 -#ifdef HAVE_FORK       
43461 +
43462                 if (pipe(from_exec_fds)) {
43463 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
43464 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
43465                                         "pipe failed: ", strerror(errno));
43466                         return -1;
43467                 }
43468 -       
43469 +
43470                 /* fork, execve */
43471                 switch (pid = fork()) {
43472                 case 0: {
43473 @@ -698,14 +701,14 @@
43474                         close(from_exec_fds[1]);
43475                         /* not needed */
43476                         close(from_exec_fds[0]);
43477 -                       
43478 +
43479                         /* close stdin */
43480                         close(STDIN_FILENO);
43481 -               
43482 +
43483                         execl("/bin/sh", "sh", "-c", cmd, NULL);
43484 -                       
43485 +
43486                         log_error_write(srv, __FILE__, __LINE__, "sss", "spawing exec failed:", strerror(errno), cmd);
43487 -               
43488 +
43489                         /* */
43490                         SEGFAULT();
43491                         break;
43492 @@ -718,9 +721,9 @@
43493                         /* father */
43494                         int status;
43495                         ssize_t r;
43496 -                       
43497 +
43498                         close(from_exec_fds[1]);
43499 -                       
43500 +
43501                         /* wait for the client to end */
43502                         if (-1 == waitpid(pid, &status, 0)) {
43503                                 log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed:", strerror(errno));
43504 @@ -730,18 +733,18 @@
43505  
43506                                 while(1) {
43507                                         if (ioctl(from_exec_fds[0], FIONREAD, &toread)) {
43508 -                                               log_error_write(srv, __FILE__, __LINE__, "s", 
43509 +                                               log_error_write(srv, __FILE__, __LINE__, "s",
43510                                                         "unexpected end-of-file (perhaps the ssi-exec process died)");
43511                                                 return -1;
43512                                         }
43513  
43514                                         if (toread > 0) {
43515 -                                               b = chunkqueue_get_append_buffer(con->write_queue);
43516 +                                               b = chunkqueue_get_append_buffer(con->send);
43517  
43518 -                                               buffer_prepare_copy(b, toread + 1); 
43519 +                                               buffer_prepare_copy(b, toread + 1);
43520  
43521                                                 if ((r = read(from_exec_fds[0], b->ptr, b->size - 1)) < 0) {
43522 -                                                       /* read failed */ 
43523 +                                                       /* read failed */
43524                                                         break;
43525                                                 } else {
43526                                                         b->used = r;
43527 @@ -755,59 +758,58 @@
43528                                 log_error_write(srv, __FILE__, __LINE__, "s", "process exited abnormally");
43529                         }
43530                         close(from_exec_fds[0]);
43531 -                       
43532 +
43533                         break;
43534                 }
43535                 }
43536  #else
43537 -
43538                 return -1;
43539  #endif
43540 -               
43541 +
43542                 break;
43543         }
43544         case SSI_IF: {
43545                 const char *expr = NULL;
43546 -               
43547 +
43548                 for (i = 2; i < n; i += 2) {
43549                         if (0 == strcmp(l[i], "expr")) {
43550                                 expr = l[i+1];
43551                         } else {
43552                                 log_error_write(srv, __FILE__, __LINE__, "sss",
43553 -                                               "ssi: unknow attribute for ", 
43554 +                                               "ssi: unknow attribute for ",
43555                                                 l[1], l[i]);
43556                         }
43557                 }
43558 -               
43559 +
43560                 if (!expr) {
43561                         log_error_write(srv, __FILE__, __LINE__, "sss",
43562 -                                       "ssi: ", 
43563 +                                       "ssi: ",
43564                                         l[1], "expr missing");
43565                         break;
43566                 }
43567 -               
43568 +
43569                 if ((!p->if_is_false) &&
43570 -                   ((p->if_is_false_level == 0) || 
43571 +                   ((p->if_is_false_level == 0) ||
43572                      (p->if_level < p->if_is_false_level))) {
43573                         switch (ssi_eval_expr(srv, con, p, expr)) {
43574                         case -1:
43575 -                       case 0: 
43576 -                               p->if_is_false = 1; 
43577 +                       case 0:
43578 +                               p->if_is_false = 1;
43579                                 p->if_is_false_level = p->if_level;
43580                                 break;
43581 -                       case 1: 
43582 -                               p->if_is_false = 0; 
43583 +                       case 1:
43584 +                               p->if_is_false = 0;
43585                                 break;
43586                         }
43587                 }
43588 -               
43589 +
43590                 p->if_level++;
43591 -               
43592 +
43593                 break;
43594         }
43595         case SSI_ELSE:
43596                 p->if_level--;
43597 -               
43598 +
43599                 if (p->if_is_false) {
43600                         if ((p->if_level == p->if_is_false_level) &&
43601                             (p->if_is_false_endif == 0)) {
43602 @@ -815,11 +817,11 @@
43603                         }
43604                 } else {
43605                         p->if_is_false = 1;
43606 -                       
43607 +
43608                         p->if_is_false_level = p->if_level;
43609                 }
43610                 p->if_level++;
43611 -               
43612 +
43613                 break;
43614         case SSI_ELIF: {
43615                 const char *expr = NULL;
43616 @@ -828,52 +830,52 @@
43617                                 expr = l[i+1];
43618                         } else {
43619                                 log_error_write(srv, __FILE__, __LINE__, "sss",
43620 -                                               "ssi: unknow attribute for ", 
43621 +                                               "ssi: unknow attribute for ",
43622                                                 l[1], l[i]);
43623                         }
43624                 }
43625 -               
43626 +
43627                 if (!expr) {
43628                         log_error_write(srv, __FILE__, __LINE__, "sss",
43629 -                                       "ssi: ", 
43630 +                                       "ssi: ",
43631                                         l[1], "expr missing");
43632                         break;
43633                 }
43634 -               
43635 +
43636                 p->if_level--;
43637 -               
43638 +
43639                 if (p->if_level == p->if_is_false_level) {
43640                         if ((p->if_is_false) &&
43641                             (p->if_is_false_endif == 0)) {
43642                                 switch (ssi_eval_expr(srv, con, p, expr)) {
43643                                 case -1:
43644 -                               case 0: 
43645 -                                       p->if_is_false = 1; 
43646 +                               case 0:
43647 +                                       p->if_is_false = 1;
43648                                         p->if_is_false_level = p->if_level;
43649                                         break;
43650 -                               case 1: 
43651 -                                       p->if_is_false = 0; 
43652 +                               case 1:
43653 +                                       p->if_is_false = 0;
43654                                         break;
43655                                 }
43656                         } else {
43657 -                               p->if_is_false = 1; 
43658 +                               p->if_is_false = 1;
43659                                 p->if_is_false_level = p->if_level;
43660                                 p->if_is_false_endif = 1;
43661                         }
43662                 }
43663 -               
43664 +
43665                 p->if_level++;
43666 -               
43667 +
43668                 break;
43669         }
43670         case SSI_ENDIF:
43671                 p->if_level--;
43672 -               
43673 +
43674                 if (p->if_level == p->if_is_false_level) {
43675                         p->if_is_false = 0;
43676                         p->if_is_false_endif = 0;
43677                 }
43678 -                       
43679 +
43680                 break;
43681         default:
43682                 log_error_write(srv, __FILE__, __LINE__, "ss",
43683 @@ -881,41 +883,41 @@
43684                                 l[1]);
43685                 break;
43686         }
43687 -       
43688 +
43689         return 0;
43690 -       
43691 +
43692  }
43693  
43694  static int mod_ssi_handle_request(server *srv, connection *con, plugin_data *p) {
43695         stream s;
43696  #ifdef  HAVE_PCRE_H
43697         int i, n;
43698 -       
43699 +
43700  #define N 10
43701         int ovec[N * 3];
43702  #endif
43703 -       
43704 +
43705         /* get a stream to the file */
43706 -       
43707 +
43708         array_reset(p->ssi_vars);
43709         array_reset(p->ssi_cgi_env);
43710         buffer_copy_string(p->timefmt, "%a, %d %b %Y %H:%M:%S %Z");
43711         p->sizefmt = 0;
43712         build_ssi_cgi_vars(srv, con, p);
43713         p->if_is_false = 0;
43714 -       
43715 +
43716         if (-1 == stream_open(&s, con->physical.path)) {
43717                 log_error_write(srv, __FILE__, __LINE__, "sb",
43718                                 "stream-open: ", con->physical.path);
43719                 return -1;
43720         }
43721 -       
43722 -       
43723 +
43724 +
43725         /**
43726 -        * <!--#element attribute=value attribute=value ... --> 
43727 -        * 
43728 +        * <!--#element attribute=value attribute=value ... -->
43729 +        *
43730          * config       DONE
43731 -        *   errmsg     -- missing 
43732 +        *   errmsg     -- missing
43733          *   sizefmt    DONE
43734          *   timefmt    DONE
43735          * echo         DONE
43736 @@ -937,13 +939,13 @@
43737          * set          DONE
43738          *   var        DONE
43739          *   value      DONE
43740 -        * 
43741 +        *
43742          * if           DONE
43743          * elif         DONE
43744          * else         DONE
43745          * endif        DONE
43746 -        * 
43747 -        * 
43748 +        *
43749 +        *
43750          * expressions
43751          * AND, OR      DONE
43752          * comp         DONE
43753 @@ -951,118 +953,115 @@
43754          * $...         DONE
43755          * '...'        DONE
43756          * ( ... )      DONE
43757 -        * 
43758 -        * 
43759 -        * 
43760 +        *
43761 +        *
43762 +        *
43763          * ** all DONE **
43764 -        * DATE_GMT 
43765 -        *   The current date in Greenwich Mean Time. 
43766 -        * DATE_LOCAL 
43767 -        *   The current date in the local time zone. 
43768 -        * DOCUMENT_NAME 
43769 -        *   The filename (excluding directories) of the document requested by the user. 
43770 -        * DOCUMENT_URI 
43771 -        *   The (%-decoded) URL path of the document requested by the user. Note that in the case of nested include files, this is not then URL for the current document. 
43772 -        * LAST_MODIFIED 
43773 -        *   The last modification date of the document requested by the user. 
43774 -        * USER_NAME 
43775 +        * DATE_GMT
43776 +        *   The current date in Greenwich Mean Time.
43777 +        * DATE_LOCAL
43778 +        *   The current date in the local time zone.
43779 +        * DOCUMENT_NAME
43780 +        *   The filename (excluding directories) of the document requested by the user.
43781 +        * DOCUMENT_URI
43782 +        *   The (%-decoded) URL path of the document requested by the user. Note that in the case of nested include files, this is not then URL for the current document.
43783 +        * LAST_MODIFIED
43784 +        *   The last modification date of the document requested by the user.
43785 +        * USER_NAME
43786          *   Contains the owner of the file which included it.
43787 -        * 
43788 +        *
43789          */
43790 -#ifdef HAVE_PCRE_H     
43791 +#ifdef HAVE_PCRE_H
43792         for (i = 0; (n = pcre_exec(p->ssi_regex, NULL, s.start, s.size, i, 0, ovec, N * 3)) > 0; i = ovec[1]) {
43793                 const char **l;
43794                 /* take everything from last offset to current match pos */
43795 -               
43796 -               if (!p->if_is_false) chunkqueue_append_file(con->write_queue, con->physical.path, i, ovec[0] - i);
43797 -               
43798 +
43799 +               if (!p->if_is_false) chunkqueue_append_file(con->send, con->physical.path, i, ovec[0] - i);
43800 +
43801                 pcre_get_substring_list(s.start, ovec, n, &l);
43802                 process_ssi_stmt(srv, con, p, l, n);
43803                 pcre_free_substring_list(l);
43804         }
43805 -       
43806 +
43807         switch(n) {
43808         case PCRE_ERROR_NOMATCH:
43809                 /* copy everything/the rest */
43810 -               chunkqueue_append_file(con->write_queue, con->physical.path, i, s.size - i);
43811 -               
43812 +               chunkqueue_append_file(con->send, con->physical.path, i, s.size - i);
43813 +
43814                 break;
43815         default:
43816                 log_error_write(srv, __FILE__, __LINE__, "sd",
43817                                 "execution error while matching: ", n);
43818                 break;
43819         }
43820 -#endif 
43821 -       
43822 -       
43823 +#endif
43824 +
43825 +
43826         stream_close(&s);
43827 -       
43828 +
43829         con->file_started  = 1;
43830 -       con->file_finished = 1;
43831 -       
43832 +       con->send->is_closed = 1;
43833 +
43834         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
43835 -       
43836 +
43837         /* reset physical.path */
43838         buffer_reset(con->physical.path);
43839 -       
43840 +
43841         return 0;
43842  }
43843  
43844 -#define PATCH(x) \
43845 -       p->conf.x = s->x;
43846  static int mod_ssi_patch_connection(server *srv, connection *con, plugin_data *p) {
43847         size_t i, j;
43848         plugin_config *s = p->config_storage[0];
43849 -       
43850 -       PATCH(ssi_extension);
43851 -       
43852 +
43853 +       PATCH_OPTION(ssi_extension);
43854 +
43855         /* skip the first, the global context */
43856         for (i = 1; i < srv->config_context->used; i++) {
43857                 data_config *dc = (data_config *)srv->config_context->data[i];
43858                 s = p->config_storage[i];
43859 -               
43860 +
43861                 /* condition didn't match */
43862                 if (!config_check_cond(srv, con, dc)) continue;
43863 -               
43864 +
43865                 /* merge config */
43866                 for (j = 0; j < dc->value->used; j++) {
43867                         data_unset *du = dc->value->data[j];
43868 -                       
43869 +
43870                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssi.extension"))) {
43871 -                               PATCH(ssi_extension);
43872 +                               PATCH_OPTION(ssi_extension);
43873                         }
43874                 }
43875         }
43876 -       
43877 +
43878         return 0;
43879  }
43880 -#undef PATCH
43881  
43882  URIHANDLER_FUNC(mod_ssi_physical_path) {
43883         plugin_data *p = p_d;
43884         size_t k;
43885 -       
43886 +
43887         if (con->physical.path->used == 0) return HANDLER_GO_ON;
43888 -       
43889 +
43890         mod_ssi_patch_connection(srv, con, p);
43891 -       
43892 +
43893         for (k = 0; k < p->conf.ssi_extension->used; k++) {
43894                 data_string *ds = (data_string *)p->conf.ssi_extension->data[k];
43895 -               
43896 +
43897                 if (ds->value->used == 0) continue;
43898 -               
43899 +
43900                 if (buffer_is_equal_right_len(con->physical.path, ds->value, ds->value->used - 1)) {
43901                         /* handle ssi-request */
43902 -                       
43903 +
43904                         if (mod_ssi_handle_request(srv, con, p)) {
43905                                 /* on error */
43906                                 con->http_status = 500;
43907                         }
43908 -                       
43909 +
43910                         return HANDLER_FINISHED;
43911                 }
43912         }
43913 -       
43914 +
43915         /* not found */
43916         return HANDLER_GO_ON;
43917  }
43918 @@ -1072,13 +1071,13 @@
43919  int mod_ssi_plugin_init(plugin *p) {
43920         p->version     = LIGHTTPD_VERSION_ID;
43921         p->name        = buffer_init_string("ssi");
43922 -       
43923 +
43924         p->init        = mod_ssi_init;
43925 -       p->handle_subrequest_start = mod_ssi_physical_path;
43926 +       p->handle_start_backend = mod_ssi_physical_path;
43927         p->set_defaults  = mod_ssi_set_defaults;
43928         p->cleanup     = mod_ssi_free;
43929 -       
43930 +
43931         p->data        = NULL;
43932 -       
43933 +
43934         return 0;
43935  }
43936 --- ../lighttpd-1.4.11/src/mod_ssi.h    2005-08-11 01:26:39.000000000 +0300
43937 +++ lighttpd-1.5.0/src/mod_ssi.h        2006-07-16 00:26:04.000000000 +0300
43938 @@ -19,23 +19,23 @@
43939  
43940  typedef struct {
43941         PLUGIN_DATA;
43942 -       
43943 -#ifdef HAVE_PCRE_H     
43944 +
43945 +#ifdef HAVE_PCRE_H
43946         pcre *ssi_regex;
43947 -#endif 
43948 +#endif
43949         buffer *timefmt;
43950         int sizefmt;
43951 -       
43952 +
43953         buffer *stat_fn;
43954 -       
43955 +
43956         array *ssi_vars;
43957         array *ssi_cgi_env;
43958 -       
43959 +
43960         int if_level, if_is_false_level, if_is_false, if_is_false_endif;
43961 -       
43962 +
43963         plugin_config **config_storage;
43964 -       
43965 -       plugin_config conf; 
43966 +
43967 +       plugin_config conf;
43968  } plugin_data;
43969  
43970  int ssi_eval_expr(server *srv, connection *con, plugin_data *p, const char *expr);
43971 --- ../lighttpd-1.4.11/src/mod_ssi_expr.c       2005-08-11 01:26:48.000000000 +0300
43972 +++ lighttpd-1.5.0/src/mod_ssi_expr.c   2006-07-16 00:26:04.000000000 +0300
43973 @@ -11,9 +11,9 @@
43974         const char *input;
43975         size_t offset;
43976         size_t size;
43977 -       
43978 +
43979         int line_pos;
43980 -       
43981 +
43982         int in_key;
43983         int in_brace;
43984         int in_cond;
43985 @@ -21,15 +21,15 @@
43986  
43987  ssi_val_t *ssi_val_init() {
43988         ssi_val_t *s;
43989 -       
43990 +
43991         s = calloc(1, sizeof(*s));
43992 -       
43993 +
43994         return s;
43995  }
43996  
43997  void ssi_val_free(ssi_val_t *s) {
43998         if (s->str) buffer_free(s->str);
43999 -       
44000 +
44001         free(s);
44002  }
44003  
44004 @@ -45,175 +45,175 @@
44005                               ssi_tokenizer_t *t, int *token_id, buffer *token) {
44006         int tid = 0;
44007         size_t i;
44008 -       
44009 +
44010         UNUSED(con);
44011  
44012         for (tid = 0; tid == 0 && t->offset < t->size && t->input[t->offset] ; ) {
44013                 char c = t->input[t->offset];
44014                 data_string *ds;
44015 -               
44016 +
44017                 switch (c) {
44018 -               case '=': 
44019 +               case '=':
44020                         tid = TK_EQ;
44021 -                       
44022 +
44023                         t->offset++;
44024                         t->line_pos++;
44025 -                       
44026 +
44027                         buffer_copy_string(token, "(=)");
44028 -                       
44029 +
44030                         break;
44031                 case '>':
44032                         if (t->input[t->offset + 1] == '=') {
44033                                 t->offset += 2;
44034                                 t->line_pos += 2;
44035 -                               
44036 +
44037                                 tid = TK_GE;
44038 -                               
44039 +
44040                                 buffer_copy_string(token, "(>=)");
44041                         } else {
44042                                 t->offset += 1;
44043                                 t->line_pos += 1;
44044 -                               
44045 +
44046                                 tid = TK_GT;
44047 -                               
44048 +
44049                                 buffer_copy_string(token, "(>)");
44050                         }
44051 -                       
44052 +
44053                         break;
44054                 case '<':
44055                         if (t->input[t->offset + 1] == '=') {
44056                                 t->offset += 2;
44057                                 t->line_pos += 2;
44058 -                               
44059 +
44060                                 tid = TK_LE;
44061 -                               
44062 +
44063                                 buffer_copy_string(token, "(<=)");
44064                         } else {
44065                                 t->offset += 1;
44066                                 t->line_pos += 1;
44067 -                               
44068 +
44069                                 tid = TK_LT;
44070 -                               
44071 +
44072                                 buffer_copy_string(token, "(<)");
44073                         }
44074 -                       
44075 +
44076                         break;
44077 -                       
44078 +
44079                 case '!':
44080                         if (t->input[t->offset + 1] == '=') {
44081                                 t->offset += 2;
44082                                 t->line_pos += 2;
44083 -                               
44084 +
44085                                 tid = TK_NE;
44086 -                               
44087 +
44088                                 buffer_copy_string(token, "(!=)");
44089                         } else {
44090                                 t->offset += 1;
44091                                 t->line_pos += 1;
44092 -                               
44093 +
44094                                 tid = TK_NOT;
44095 -                               
44096 +
44097                                 buffer_copy_string(token, "(!)");
44098                         }
44099 -                       
44100 +
44101                         break;
44102                 case '&':
44103                         if (t->input[t->offset + 1] == '&') {
44104                                 t->offset += 2;
44105                                 t->line_pos += 2;
44106 -                               
44107 +
44108                                 tid = TK_AND;
44109 -                               
44110 +
44111                                 buffer_copy_string(token, "(&&)");
44112                         } else {
44113 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
44114 -                                               "pos:", t->line_pos, 
44115 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
44116 +                                               "pos:", t->line_pos,
44117                                                 "missing second &");
44118                                 return -1;
44119                         }
44120 -                       
44121 +
44122                         break;
44123                 case '|':
44124                         if (t->input[t->offset + 1] == '|') {
44125                                 t->offset += 2;
44126                                 t->line_pos += 2;
44127 -                               
44128 +
44129                                 tid = TK_OR;
44130 -                               
44131 +
44132                                 buffer_copy_string(token, "(||)");
44133                         } else {
44134 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
44135 -                                               "pos:", t->line_pos, 
44136 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
44137 +                                               "pos:", t->line_pos,
44138                                                 "missing second |");
44139                                 return -1;
44140                         }
44141 -                       
44142 +
44143                         break;
44144                 case '\t':
44145                 case ' ':
44146                         t->offset++;
44147                         t->line_pos++;
44148                         break;
44149 -                       
44150 +
44151                 case '\'':
44152                         /* search for the terminating " */
44153                         for (i = 1; t->input[t->offset + i] && t->input[t->offset + i] != '\'';  i++);
44154 -                       
44155 +
44156                         if (t->input[t->offset + i]) {
44157                                 tid = TK_VALUE;
44158 -                               
44159 +
44160                                 buffer_copy_string_len(token, t->input + t->offset + 1, i-1);
44161 -                               
44162 +
44163                                 t->offset += i + 1;
44164                                 t->line_pos += i + 1;
44165                         } else {
44166                                 /* ERROR */
44167 -                               
44168 -                               log_error_write(srv, __FILE__, __LINE__, "sds", 
44169 -                                               "pos:", t->line_pos, 
44170 +
44171 +                               log_error_write(srv, __FILE__, __LINE__, "sds",
44172 +                                               "pos:", t->line_pos,
44173                                                 "missing closing quote");
44174 -                               
44175 +
44176                                 return -1;
44177                         }
44178 -                       
44179 +
44180                         break;
44181                 case '(':
44182                         t->offset++;
44183                         t->in_brace++;
44184 -                               
44185 +
44186                         tid = TK_LPARAN;
44187 -                               
44188 +
44189                         buffer_copy_string(token, "(");
44190                         break;
44191                 case ')':
44192                         t->offset++;
44193                         t->in_brace--;
44194 -                               
44195 +
44196                         tid = TK_RPARAN;
44197 -                               
44198 +
44199                         buffer_copy_string(token, ")");
44200                         break;
44201                 case '$':
44202                         if (t->input[t->offset + 1] == '{') {
44203                                 for (i = 2; t->input[t->offset + i] && t->input[t->offset + i] != '}';  i++);
44204 -                               
44205 +
44206                                 if (t->input[t->offset + i] != '}') {
44207 -                                       log_error_write(srv, __FILE__, __LINE__, "sds", 
44208 -                                                       "pos:", t->line_pos, 
44209 +                                       log_error_write(srv, __FILE__, __LINE__, "sds",
44210 +                                                       "pos:", t->line_pos,
44211                                                         "missing closing quote");
44212 -                                       
44213 +
44214                                         return -1;
44215                                 }
44216 -                               
44217 +
44218                                 buffer_copy_string_len(token, t->input + t->offset + 2, i-3);
44219                         } else {
44220                                 for (i = 1; isalpha(t->input[t->offset + i]) || t->input[t->offset + i] == '_';  i++);
44221 -                               
44222 +
44223                                 buffer_copy_string_len(token, t->input + t->offset + 1, i-1);
44224                         }
44225 -                       
44226 +
44227                         tid = TK_VALUE;
44228 -                       
44229 +
44230                         if (NULL != (ds = (data_string *)array_get_element(p->ssi_cgi_env, token->ptr))) {
44231                                 buffer_copy_string_buffer(token, ds->value);
44232                         } else if (NULL != (ds = (data_string *)array_get_element(p->ssi_vars, token->ptr))) {
44233 @@ -221,16 +221,16 @@
44234                         } else {
44235                                 buffer_copy_string(token, "");
44236                         }
44237 -                               
44238 +
44239                         t->offset += i;
44240                         t->line_pos += i;
44241 -                       
44242 +
44243                         break;
44244                 default:
44245                         for (i = 0; isgraph(t->input[t->offset + i]);  i++) {
44246                                 char d = t->input[t->offset + i];
44247                                 switch(d) {
44248 -                               case ' ': 
44249 +                               case ' ':
44250                                 case '\t':
44251                                 case ')':
44252                                 case '(':
44253 @@ -244,25 +244,25 @@
44254                                         break;
44255                                 }
44256                         }
44257 -                       
44258 +
44259                         tid = TK_VALUE;
44260 -                               
44261 +
44262                         buffer_copy_string_len(token, t->input + t->offset, i);
44263 -                               
44264 +
44265                         t->offset += i;
44266                         t->line_pos += i;
44267 -                       
44268 +
44269                         break;
44270                 }
44271         }
44272 -                       
44273 +
44274         if (tid) {
44275                 *token_id = tid;
44276 -               
44277 +
44278                 return 1;
44279         } else if (t->offset < t->size) {
44280 -               log_error_write(srv, __FILE__, __LINE__, "sds", 
44281 -                               "pos:", t->line_pos, 
44282 +               log_error_write(srv, __FILE__, __LINE__, "sds",
44283 +                               "pos:", t->line_pos,
44284                                 "foobar");
44285         }
44286         return 0;
44287 @@ -275,50 +275,50 @@
44288         buffer *token;
44289         ssi_ctx_t context;
44290         int ret;
44291 -       
44292 +
44293         t.input = expr;
44294         t.offset = 0;
44295         t.size = strlen(expr);
44296         t.line_pos = 1;
44297 -       
44298 +
44299         t.in_key = 1;
44300         t.in_brace = 0;
44301         t.in_cond = 0;
44302 -       
44303 +
44304         context.ok = 1;
44305         context.srv = srv;
44306 -       
44307 +
44308         /* default context */
44309 -       
44310 +
44311         pParser = ssiexprparserAlloc( malloc );
44312         token = buffer_init();
44313         while((1 == (ret = ssi_expr_tokenizer(srv, con, p, &t, &token_id, token))) && context.ok) {
44314                 ssiexprparser(pParser, token_id, token, &context);
44315 -               
44316 +
44317                 token = buffer_init();
44318         }
44319         ssiexprparser(pParser, 0, token, &context);
44320         ssiexprparserFree(pParser, free );
44321 -       
44322 +
44323         buffer_free(token);
44324 -       
44325 +
44326         if (ret == -1) {
44327 -               log_error_write(srv, __FILE__, __LINE__, "s", 
44328 +               log_error_write(srv, __FILE__, __LINE__, "s",
44329                                 "expr parser failed");
44330                 return -1;
44331         }
44332 -       
44333 +
44334         if (context.ok == 0) {
44335 -               log_error_write(srv, __FILE__, __LINE__, "sds", 
44336 -                               "pos:", t.line_pos, 
44337 +               log_error_write(srv, __FILE__, __LINE__, "sds",
44338 +                               "pos:", t.line_pos,
44339                                 "parser failed somehow near here");
44340                 return -1;
44341         }
44342  #if 0
44343 -       log_error_write(srv, __FILE__, __LINE__, "ssd", 
44344 +       log_error_write(srv, __FILE__, __LINE__, "ssd",
44345                         "expr: ",
44346                         expr,
44347                         context.val.bo);
44348 -#endif 
44349 +#endif
44350         return context.val.bo;
44351  }
44352 --- ../lighttpd-1.4.11/src/mod_ssi_expr.h       2005-08-11 01:26:48.000000000 +0300
44353 +++ lighttpd-1.5.0/src/mod_ssi_expr.h   2006-07-16 00:26:04.000000000 +0300
44354 @@ -5,16 +5,16 @@
44355  
44356  typedef struct {
44357         enum { SSI_TYPE_UNSET, SSI_TYPE_BOOL, SSI_TYPE_STRING } type;
44358 -       
44359 +
44360         buffer *str;
44361         int     bo;
44362  } ssi_val_t;
44363  
44364  typedef struct {
44365         int     ok;
44366 -       
44367 +
44368         ssi_val_t val;
44369 -       
44370 +
44371         void   *srv;
44372  } ssi_ctx_t;
44373  
44374 --- ../lighttpd-1.4.11/src/mod_ssi_exprparser.c 2005-10-03 00:40:25.000000000 +0300
44375 +++ lighttpd-1.5.0/src/mod_ssi_exprparser.c     2006-07-17 22:02:23.000000000 +0300
44376 @@ -18,10 +18,10 @@
44377  /* Next is all token values, in a form suitable for use by makeheaders.
44378  ** This section will be null unless lemon is run with the -m switch.
44379  */
44380 -/* 
44381 +/*
44382  ** These constants (all generated automatically by the parser generator)
44383  ** specify the various kinds of tokens (terminals) that the parser
44384 -** understands. 
44385 +** understands.
44386  **
44387  ** Each symbol here is a terminal symbol in the grammar.
44388  */
44389 @@ -38,7 +38,7 @@
44390  **                       and nonterminals.  "int" is used otherwise.
44391  **    YYNOCODE           is a number of type YYCODETYPE which corresponds
44392  **                       to no legal terminal or nonterminal number.  This
44393 -**                       number is used to fill in empty slots of the hash 
44394 +**                       number is used to fill in empty slots of the hash
44395  **                       table.
44396  **    YYFALLBACK         If defined, this indicates that one or more tokens
44397  **                       have fall-back values which should be used if the
44398 @@ -47,7 +47,7 @@
44399  **                       and nonterminal numbers.  "unsigned char" is
44400  **                       used if there are fewer than 250 rules and
44401  **                       states combined.  "int" is used otherwise.
44402 -**    ssiexprparserTOKENTYPE     is the data type used for minor tokens given 
44403 +**    ssiexprparserTOKENTYPE     is the data type used for minor tokens given
44404  **                       directly to the parser from the tokenizer.
44405  **    YYMINORTYPE        is the data type used for all minor tokens.
44406  **                       This is typically a union of many types, one of
44407 @@ -91,7 +91,7 @@
44408  /* Next are that tables used to determine what action to take based on the
44409  ** current state and lookahead token.  These tables are used to implement
44410  ** functions that take a state number and lookahead value and return an
44411 -** action integer.  
44412 +** action integer.
44413  **
44414  ** Suppose the action integer is N.  Then the action is determined as
44415  ** follows
44416 @@ -116,7 +116,7 @@
44417  ** If the index value yy_shift_ofst[S]+X is out of range or if the value
44418  ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
44419  ** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
44420 -** and that yy_default[S] should be used instead.  
44421 +** and that yy_default[S] should be used instead.
44422  **
44423  ** The formula above is for computing the action when the lookahead is
44424  ** a terminal symbol.  If the lookahead is a non-terminal (as occurs after
44425 @@ -168,7 +168,7 @@
44426  
44427  /* The next table maps tokens into fallback tokens.  If a construct
44428  ** like the following:
44429 -** 
44430 +**
44431  **      %fallback ID X Y Z.
44432  **
44433  ** appears in the grammer, then ID becomes a fallback token for X, Y,
44434 @@ -219,10 +219,10 @@
44435  #endif /* NDEBUG */
44436  
44437  #ifndef NDEBUG
44438 -/* 
44439 +/*
44440  ** Turn parser tracing on by giving a stream to which to write the trace
44441  ** and a prompt to preface each trace message.  Tracing is turned off
44442 -** by making either argument NULL 
44443 +** by making either argument NULL
44444  **
44445  ** Inputs:
44446  ** <ul>
44447 @@ -247,7 +247,7 @@
44448  #ifndef NDEBUG
44449  /* For tracing shifts, the names of all terminals and nonterminals
44450  ** are required.  The following table supplies these names */
44451 -static const char *yyTokenName[] = { 
44452 +static const char *yyTokenName[] = {
44453    "$",             "AND",           "OR",            "EQ",          
44454    "NE",            "GT",            "GE",            "LT",          
44455    "LE",            "NOT",           "LPARAN",        "RPARAN",      
44456 @@ -295,7 +295,7 @@
44457  #endif
44458  }
44459  
44460 -/* 
44461 +/*
44462  ** This function allocates a new parser.
44463  ** The only argument is a pointer to a function which works like
44464  ** malloc.
44465 @@ -326,7 +326,7 @@
44466      /* Here is inserted the actions which take place when a
44467      ** terminal or non-terminal is destroyed.  This can happen
44468      ** when the symbol is popped from the stack during a
44469 -    ** reduce or during error processing or when a parser is 
44470 +    ** reduce or during error processing or when a parser is
44471      ** being destroyed before it is finished parsing.
44472      **
44473      ** Note: during a reduce, the only symbols destroyed are those
44474 @@ -379,7 +379,7 @@
44475    return yymajor;
44476  }
44477  
44478 -/* 
44479 +/*
44480  ** Deallocate and destroy a parser.  Destructors are all called for
44481  ** all stack elements before shutting the parser down.
44482  **
44483 @@ -415,7 +415,7 @@
44484  ){
44485    int i;
44486    int stateno = pParser->yystack[pParser->yyidx].stateno;
44487
44488 +
44489    /* if( pParser->yyidx<0 ) return YY_NO_ACTION;  */
44490    i = yy_shift_ofst[stateno];
44491    if( i==YY_SHIFT_USE_DFLT ){
44492 @@ -459,7 +459,7 @@
44493  ){
44494    int i;
44495    int stateno = pParser->yystack[pParser->yyidx].stateno;
44496
44497 +
44498    i = yy_reduce_ofst[stateno];
44499    if( i==YY_REDUCE_USE_DFLT ){
44500      return yy_default[stateno];
44501 @@ -559,7 +559,7 @@
44502    ssiexprparserARG_FETCH;
44503    yymsp = &yypParser->yystack[yypParser->yyidx];
44504  #ifndef NDEBUG
44505 -  if( yyTraceFILE && yyruleno>=0 
44506 +  if( yyTraceFILE && yyruleno>=0
44507          && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
44508      fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
44509        yyRuleName[yyruleno]);
44510 @@ -872,7 +872,7 @@
44511  #ifdef YYERRORSYMBOL
44512        /* A syntax error has occurred.
44513        ** The response to an error depends upon whether or not the
44514 -      ** grammar defines an error token "ERROR".  
44515 +      ** grammar defines an error token "ERROR".
44516        **
44517        ** This is what we do if the grammar does define ERROR:
44518        **
44519 --- ../lighttpd-1.4.11/src/mod_staticfile.c     2006-02-15 14:31:14.000000000 +0200
44520 +++ lighttpd-1.5.0/src/mod_staticfile.c 2006-09-07 00:57:05.000000000 +0300
44521 @@ -11,12 +11,15 @@
44522  
44523  #include "stat_cache.h"
44524  #include "etag.h"
44525 -#include "http_chunk.h"
44526  #include "response.h"
44527  
44528 +#include "sys-files.h"
44529 +#include "sys-strings.h"
44530 +
44531 +#include "http_req_range.h"
44532  /**
44533   * this is a staticfile for a lighttpd plugin
44534 - * 
44535 + *
44536   */
44537  
44538  
44539 @@ -29,48 +32,48 @@
44540  
44541  typedef struct {
44542         PLUGIN_DATA;
44543 -       
44544 +
44545         buffer *range_buf;
44546 -       
44547 +
44548         plugin_config **config_storage;
44549 -       
44550 -       plugin_config conf; 
44551 +
44552 +       plugin_config conf;
44553  } plugin_data;
44554  
44555  /* init the plugin data */
44556  INIT_FUNC(mod_staticfile_init) {
44557         plugin_data *p;
44558 -       
44559 +
44560         p = calloc(1, sizeof(*p));
44561 -       
44562 +
44563         p->range_buf = buffer_init();
44564 -       
44565 +
44566         return p;
44567  }
44568  
44569 -/* detroy the plugin data */
44570 +/* destroy the plugin data */
44571  FREE_FUNC(mod_staticfile_free) {
44572         plugin_data *p = p_d;
44573 -       
44574 +
44575         UNUSED(srv);
44576  
44577         if (!p) return HANDLER_GO_ON;
44578 -       
44579 +
44580         if (p->config_storage) {
44581                 size_t i;
44582                 for (i = 0; i < srv->config_context->used; i++) {
44583                         plugin_config *s = p->config_storage[i];
44584 -                       
44585 +
44586                         array_free(s->exclude_ext);
44587 -                       
44588 +
44589                         free(s);
44590                 }
44591                 free(p->config_storage);
44592         }
44593         buffer_free(p->range_buf);
44594 -       
44595 +
44596         free(p);
44597 -       
44598 +
44599         return HANDLER_GO_ON;
44600  }
44601  
44602 @@ -79,263 +82,222 @@
44603  SETDEFAULTS_FUNC(mod_staticfile_set_defaults) {
44604         plugin_data *p = p_d;
44605         size_t i = 0;
44606 -       
44607 -       config_values_t cv[] = { 
44608 +
44609 +       config_values_t cv[] = {
44610                 { "static-file.exclude-extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
44611                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
44612         };
44613 -       
44614 +
44615         if (!p) return HANDLER_ERROR;
44616 -       
44617 +
44618         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
44619 -       
44620 +
44621         for (i = 0; i < srv->config_context->used; i++) {
44622                 plugin_config *s;
44623 -               
44624 +
44625                 s = calloc(1, sizeof(plugin_config));
44626                 s->exclude_ext    = array_init();
44627 -               
44628 +
44629                 cv[0].destination = s->exclude_ext;
44630 -               
44631 +
44632                 p->config_storage[i] = s;
44633 -       
44634 +
44635                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
44636                         return HANDLER_ERROR;
44637                 }
44638         }
44639 -       
44640 +
44641         return HANDLER_GO_ON;
44642  }
44643  
44644 -#define PATCH(x) \
44645 -       p->conf.x = s->x;
44646  static int mod_staticfile_patch_connection(server *srv, connection *con, plugin_data *p) {
44647         size_t i, j;
44648         plugin_config *s = p->config_storage[0];
44649 -       
44650 -       PATCH(exclude_ext);
44651 -       
44652 +
44653 +       PATCH_OPTION(exclude_ext);
44654 +
44655         /* skip the first, the global context */
44656         for (i = 1; i < srv->config_context->used; i++) {
44657                 data_config *dc = (data_config *)srv->config_context->data[i];
44658                 s = p->config_storage[i];
44659 -               
44660 +
44661                 /* condition didn't match */
44662                 if (!config_check_cond(srv, con, dc)) continue;
44663 -               
44664 +
44665                 /* merge config */
44666                 for (j = 0; j < dc->value->used; j++) {
44667                         data_unset *du = dc->value->data[j];
44668 -                       
44669 +
44670                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("static-file.exclude-extensions"))) {
44671 -                               PATCH(exclude_ext);
44672 +                               PATCH_OPTION(exclude_ext);
44673                         }
44674                 }
44675         }
44676 -       
44677 +
44678         return 0;
44679  }
44680 -#undef PATCH
44681  
44682  static int http_response_parse_range(server *srv, connection *con, plugin_data *p) {
44683         int multipart = 0;
44684 -       int error;
44685 -       off_t start, end;
44686 -       const char *s, *minus;
44687         char *boundary = "fkj49sn38dcn3";
44688         data_string *ds;
44689         stat_cache_entry *sce = NULL;
44690         buffer *content_type = NULL;
44691 -       
44692 +       buffer *range = NULL;
44693 +       http_req_range *ranges, *r;
44694 +
44695 +       if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Range"))) {
44696 +               range = ds->value;
44697 +       } else {
44698 +               /* we don't have a Range header */
44699 +
44700 +               return -1;
44701 +       }
44702 +
44703         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
44704                 SEGFAULT();
44705         }
44706 -       
44707 -       start = 0;
44708 -       end = sce->st.st_size - 1;
44709 -       
44710 +
44711         con->response.content_length = 0;
44712 -       
44713 +
44714         if (NULL != (ds = (data_string *)array_get_element(con->response.headers, "Content-Type"))) {
44715                 content_type = ds->value;
44716         }
44717 -       
44718 -       for (s = con->request.http_range, error = 0;
44719 -            !error && *s && NULL != (minus = strchr(s, '-')); ) {
44720 -               char *err;
44721 -               off_t la, le;
44722 -               
44723 -               if (s == minus) {
44724 -                       /* -<stop> */
44725 -                       
44726 -                       le = strtoll(s, &err, 10);
44727 -                       
44728 -                       if (le == 0) {
44729 -                               /* RFC 2616 - 14.35.1 */
44730 -                               
44731 -                               con->http_status = 416;
44732 -                               error = 1;
44733 -                       } else if (*err == '\0') {
44734 -                               /* end */
44735 -                               s = err;
44736 -                               
44737 -                               end = sce->st.st_size - 1;
44738 -                               start = sce->st.st_size + le;
44739 -                       } else if (*err == ',') {
44740 -                               multipart = 1;
44741 -                               s = err + 1;
44742 -                               
44743 -                               end = sce->st.st_size - 1;
44744 -                               start = sce->st.st_size + le;
44745 -                       } else {
44746 -                               error = 1;
44747 -                       }
44748 -                       
44749 -               } else if (*(minus+1) == '\0' || *(minus+1) == ',') {
44750 -                       /* <start>- */
44751 -                       
44752 -                       la = strtoll(s, &err, 10);
44753 -                       
44754 -                       if (err == minus) {
44755 -                               /* ok */
44756 -                               
44757 -                               if (*(err + 1) == '\0') {
44758 -                                       s = err + 1;
44759 -                                       
44760 -                                       end = sce->st.st_size - 1;
44761 -                                       start = la;
44762 -                                       
44763 -                               } else if (*(err + 1) == ',') {
44764 -                                       multipart = 1;
44765 -                                       s = err + 2;
44766 -                                       
44767 -                                       end = sce->st.st_size - 1;
44768 -                                       start = la;
44769 -                               } else {
44770 -                                       error = 1;
44771 -                               }
44772 -                       } else {
44773 -                               /* error */
44774 -                               error = 1;
44775 -                       }
44776 -               } else {
44777 -                       /* <start>-<stop> */
44778 -                       
44779 -                       la = strtoll(s, &err, 10);
44780 -                       
44781 -                       if (err == minus) {
44782 -                               le = strtoll(minus+1, &err, 10);
44783 -                               
44784 -                               /* RFC 2616 - 14.35.1 */
44785 -                               if (la > le) {
44786 -                                       error = 1;
44787 -                               }
44788 -                                       
44789 -                               if (*err == '\0') {
44790 -                                       /* ok, end*/
44791 -                                       s = err;
44792 -                                       
44793 -                                       end = le;
44794 -                                       start = la;
44795 -                               } else if (*err == ',') {
44796 -                                       multipart = 1;
44797 -                                       s = err + 1;
44798 -                                       
44799 -                                       end = le;
44800 -                                       start = la;
44801 -                               } else {
44802 -                                       /* error */
44803 +
44804 +       /* start the range-header parser
44805 +        * bytes=<num>  */
44806 +
44807 +       ranges = http_request_range_init();
44808 +       switch (http_request_range_parse(range, ranges)) {
44809 +       case PARSE_ERROR:
44810 +               return -1; /* no range valid Range Header */
44811 +       case PARSE_SUCCESS:
44812 +               break;
44813 +       default:
44814 +               TRACE("%s", "foobar");
44815 +               return -1;
44816 +       }
44817 +
44818 +       if (ranges->next) {
44819 +               multipart = 1;
44820 +       }
44821 +
44822 +       /* patch the '-1' */
44823 +       for (r = ranges; r; r = r->next) {
44824 +               if (r->start == -1) {
44825 +                       /* -<end>
44826 +                        *
44827 +                        * the last <end> bytes  */
44828 +                       r->start = sce->st.st_size - r->end;
44829 +                       r->end = sce->st.st_size - 1;
44830 +               } 
44831 +               if (r->end == -1) {
44832 +                       /* <start>-
44833 +                        * all but the first <start> bytes */
44834                                         
44835 -                                       error = 1;
44836 -                               }
44837 -                       } else {
44838 -                               /* error */
44839 -                               
44840 -                               error = 1;
44841 -                       }
44842 +                       r->end = sce->st.st_size - 1;
44843                 }
44844 -               
44845 -               if (!error) {
44846 -                       if (start < 0) start = 0;
44847 -                       
44848 -                       /* RFC 2616 - 14.35.1 */
44849 -                       if (end > sce->st.st_size - 1) end = sce->st.st_size - 1;
44850 -                       
44851 -                       if (start > sce->st.st_size - 1) {
44852 -                               error = 1;
44853 -                               
44854 -                               con->http_status = 416;
44855 -                       }
44856 +
44857 +               if (r->end > sce->st.st_size - 1) {
44858 +                       /* RFC 2616 - 14.35.1
44859 +                        *
44860 +                        * if last-byte-pos not present or > size-of-file 
44861 +                        * take the size-of-file
44862 +                        *
44863 +                        *  */
44864 +                       r->end = sce->st.st_size - 1;
44865                 }
44866 -               
44867 -               if (!error) {
44868 -                       if (multipart) {
44869 -                               /* write boundary-header */
44870 -                               buffer *b;
44871 -                               
44872 -                               b = chunkqueue_get_append_buffer(con->write_queue);
44873 -                               
44874 -                               buffer_copy_string(b, "\r\n--");
44875 -                               buffer_append_string(b, boundary);
44876 -                               
44877 -                               /* write Content-Range */
44878 -                               buffer_append_string(b, "\r\nContent-Range: bytes ");
44879 -                               buffer_append_off_t(b, start);
44880 -                               buffer_append_string(b, "-");
44881 -                               buffer_append_off_t(b, end);
44882 -                               buffer_append_string(b, "/");
44883 -                               buffer_append_off_t(b, sce->st.st_size);
44884 -                               
44885 -                               buffer_append_string(b, "\r\nContent-Type: ");
44886 -                               buffer_append_string_buffer(b, content_type);
44887 -                               
44888 -                               /* write END-OF-HEADER */
44889 -                               buffer_append_string(b, "\r\n\r\n");
44890 -                               
44891 -                               con->response.content_length += b->used - 1;
44892 -                               
44893 -                       }
44894 -                       
44895 -                       chunkqueue_append_file(con->write_queue, con->physical.path, start, end - start + 1);
44896 -                       con->response.content_length += end - start + 1;
44897 +
44898 +               if (r->start > sce->st.st_size - 1) {
44899 +                       /* RFC 2616 - 14.35.1
44900 +                        *
44901 +                        * if first-byte-pos > file-size, 416
44902 +                        */
44903 +
44904 +                       con->http_status = 416;
44905 +                       return -1;
44906 +               }
44907 +
44908 +               if (r->start > r->end) {
44909 +                       /* RFC 2616 - 14.35.1
44910 +                        *
44911 +                        * if last-byte-pos is present, it has to be >= first-byte-pos
44912 +                        * 
44913 +                        * invalid ranges have to be handle as no Range specified
44914 +                        *  */
44915 +
44916 +                       return -1;
44917                 }
44918         }
44919 -       
44920 -       /* something went wrong */
44921 -       if (error) return -1;
44922 -       
44923 +
44924 +       if (r) {
44925 +               /* we ran into an range violation */
44926 +               return -1;
44927 +       }
44928 +
44929         if (multipart) {
44930 -               /* add boundary end */
44931                 buffer *b;
44932 -               
44933 -               b = chunkqueue_get_append_buffer(con->write_queue);
44934 -               
44935 +               for (r = ranges; r; r = r->next) {
44936 +                       /* write boundary-header */
44937 +
44938 +                       b = chunkqueue_get_append_buffer(con->send);
44939 +
44940 +                       buffer_copy_string(b, "\r\n--");
44941 +                       buffer_append_string(b, boundary);
44942 +
44943 +                       /* write Content-Range */
44944 +                       buffer_append_string(b, "\r\nContent-Range: bytes ");
44945 +                       buffer_append_off_t(b, r->start);
44946 +                       buffer_append_string(b, "-");
44947 +                       buffer_append_off_t(b, r->end);
44948 +                       buffer_append_string(b, "/");
44949 +                       buffer_append_off_t(b, sce->st.st_size);
44950 +
44951 +                       buffer_append_string(b, "\r\nContent-Type: ");
44952 +                       buffer_append_string_buffer(b, content_type);
44953 +
44954 +                       /* write END-OF-HEADER */
44955 +                       buffer_append_string(b, "\r\n\r\n");
44956 +
44957 +                       con->response.content_length += b->used - 1;
44958 +
44959 +                       chunkqueue_append_file(con->send, con->physical.path, r->start, r->end - r->start + 1);
44960 +                       con->response.content_length += r->end - r->start + 1;
44961 +               }
44962 +
44963 +               /* add boundary end */
44964 +               b = chunkqueue_get_append_buffer(con->send);
44965 +
44966                 buffer_copy_string_len(b, "\r\n--", 4);
44967                 buffer_append_string(b, boundary);
44968                 buffer_append_string_len(b, "--\r\n", 4);
44969 -               
44970 +
44971                 con->response.content_length += b->used - 1;
44972 -               
44973 +
44974                 /* set header-fields */
44975 -               
44976 +
44977                 buffer_copy_string(p->range_buf, "multipart/byteranges; boundary=");
44978                 buffer_append_string(p->range_buf, boundary);
44979 -               
44980 +
44981                 /* overwrite content-type */
44982                 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(p->range_buf));
44983 +
44984         } else {
44985 -               /* add Content-Range-header */
44986 -               
44987 +               r = ranges;
44988 +
44989 +               chunkqueue_append_file(con->send, con->physical.path, r->start, r->end - r->start + 1);
44990 +               con->response.content_length += r->end - r->start + 1;
44991 +
44992                 buffer_copy_string(p->range_buf, "bytes ");
44993 -               buffer_append_off_t(p->range_buf, start);
44994 +               buffer_append_off_t(p->range_buf, r->start);
44995                 buffer_append_string(p->range_buf, "-");
44996 -               buffer_append_off_t(p->range_buf, end);
44997 +               buffer_append_off_t(p->range_buf, r->end);
44998                 buffer_append_string(p->range_buf, "/");
44999                 buffer_append_off_t(p->range_buf, sce->st.st_size);
45000 -               
45001 +
45002                 response_header_insert(srv, con, CONST_STR_LEN("Content-Range"), CONST_BUF_LEN(p->range_buf));
45003         }
45004 -
45005 +       
45006         /* ok, the file is set-up */
45007         return 0;
45008  }
45009 @@ -347,12 +309,12 @@
45010         stat_cache_entry *sce = NULL;
45011         buffer *mtime;
45012         data_string *ds;
45013 -       
45014 +
45015         /* someone else has done a decision for us */
45016         if (con->http_status != 0) return HANDLER_GO_ON;
45017         if (con->uri.path->used == 0) return HANDLER_GO_ON;
45018         if (con->physical.path->used == 0) return HANDLER_GO_ON;
45019 -       
45020 +
45021         /* someone else has handled this request */
45022         if (con->mode != DIRECT) return HANDLER_GO_ON;
45023  
45024 @@ -365,52 +327,67 @@
45025         default:
45026                 return HANDLER_GO_ON;
45027         }
45028 -       
45029 +
45030         mod_staticfile_patch_connection(srv, con, p);
45031 -       
45032 +
45033         s_len = con->uri.path->used - 1;
45034 -       
45035 +
45036         /* ignore certain extensions */
45037         for (k = 0; k < p->conf.exclude_ext->used; k++) {
45038 -               ds = (data_string *)p->conf.exclude_ext->data[k]; 
45039 -               
45040 +               ds = (data_string *)p->conf.exclude_ext->data[k];
45041 +
45042                 if (ds->value->used == 0) continue;
45043  
45044                 if (buffer_is_equal_right_len(con->physical.path, ds->value, ds->value->used - 1)) {
45045 -                       return HANDLER_GO_ON;
45046 +                       con->http_status = 403;
45047 +
45048 +                       return HANDLER_FINISHED;
45049                 }
45050         }
45051 -       
45052 +
45053  
45054         if (con->conf.log_request_handling) {
45055                 log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling file as static file");
45056         }
45057 -       
45058 +
45059         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
45060                 con->http_status = 403;
45061 -               
45062 +
45063                 log_error_write(srv, __FILE__, __LINE__, "sbsb",
45064                                 "not a regular file:", con->uri.path,
45065                                 "->", con->physical.path);
45066 -               
45067 +
45068                 return HANDLER_FINISHED;
45069         }
45070 -       
45071 -       /* we only handline regular files */
45072 +
45073 +       /* we only handle regular files */
45074 +#ifdef HAVE_LSTAT
45075 +       if ((sce->is_symlink == 1) && !con->conf.follow_symlink) {
45076 +               con->http_status = 403;
45077 +
45078 +               if (con->conf.log_request_handling) {
45079 +                       log_error_write(srv, __FILE__, __LINE__,  "s",  "-- access denied due symlink restriction");
45080 +                       log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
45081 +               }
45082 +
45083 +               buffer_reset(con->physical.path);
45084 +               return HANDLER_FINISHED;
45085 +       }
45086 +#endif
45087         if (!S_ISREG(sce->st.st_mode)) {
45088                 con->http_status = 404;
45089 -               
45090 +
45091                 if (con->conf.log_file_not_found) {
45092                         log_error_write(srv, __FILE__, __LINE__, "sbsb",
45093                                         "not a regular file:", con->uri.path,
45094                                         "->", sce->name);
45095                 }
45096 -               
45097 +
45098                 return HANDLER_FINISHED;
45099         }
45100  
45101 -       /* mod_compress might set several data directly, don't overwrite them */
45102 -       
45103 +       /* mod_compress might set several parameters directly; don't overwrite them */
45104 +
45105         /* set response content-type, if not set already */
45106  
45107         if (NULL == array_get_element(con->response.headers, "Content-Type")) {
45108 @@ -420,15 +397,15 @@
45109                         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
45110                 }
45111         }
45112 -       
45113 +
45114         if (NULL == array_get_element(con->response.headers, "ETag")) {
45115                 /* generate e-tag */
45116                 etag_mutate(con->physical.etag, sce->etag);
45117 -       
45118 +
45119                 response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
45120         }
45121         response_header_overwrite(srv, con, CONST_STR_LEN("Accept-Ranges"), CONST_STR_LEN("bytes"));
45122 -       
45123 +
45124         /* prepare header */
45125         if (NULL == (ds = (data_string *)array_get_element(con->response.headers, "Last-Modified"))) {
45126                 mtime = strftime_cache_get(srv, sce->st.st_mtime);
45127 @@ -439,54 +416,104 @@
45128  
45129         if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) {
45130                 return HANDLER_FINISHED;
45131 -       } else if (con->request.http_range && con->conf.range_requests) {
45132 +       } else if (con->conf.range_requests && 
45133 +                  NULL != array_get_element(con->request.headers, "Range")) {
45134                 int do_range_request = 1;
45135                 /* check if we have a conditional GET */
45136  
45137                 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If-Range"))) {
45138 -                       /* if the value is the same as our ETag, we do a Range-request, 
45139 +                       /* if the value is the same as our ETag, we do a Range-request,
45140                          * otherwise a full 200 */
45141  
45142                         if (!buffer_is_equal(ds->value, con->physical.etag)) {
45143                                 do_range_request = 0;
45144                         }
45145                 }
45146 -       
45147 +
45148                 if (do_range_request) {
45149                         /* content prepared, I'm done */
45150 -                       con->file_finished = 1;
45151 -               
45152 +                       con->send->is_closed = 1;
45153 +
45154                         if (0 == http_response_parse_range(srv, con, p)) {
45155                                 con->http_status = 206;
45156                         }
45157                         return HANDLER_FINISHED;
45158                 }
45159         }
45160 -       
45161 +
45162         /* if we are still here, prepare body */
45163 -       
45164 -       /* we add it here for all requests 
45165 -        * the HEAD request will drop it afterwards again 
45166 +
45167 +       /* we add it here for all requests
45168 +        * the HEAD request will drop it afterwards again
45169          */
45170 -       http_chunk_append_file(srv, con, con->physical.path, 0, sce->st.st_size);
45171 -       
45172 -       con->file_finished = 1;
45173 -       
45174 +       chunkqueue_append_file(con->send, con->physical.path, 0, sce->st.st_size);
45175 +
45176 +       con->send->is_closed = 1;
45177 +
45178         return HANDLER_FINISHED;
45179  }
45180  
45181 +/**
45182 + * mark all the content as read
45183 + */
45184 +CONNECTION_FUNC(mod_staticfile_dev_null) {
45185 +       chunk *c;
45186 +       off_t offset;
45187 +       chunkqueue *in = con->recv;
45188 +
45189 +       /* there is nothing that we have to send out anymore */
45190 +       if (in->bytes_in == in->bytes_out && 
45191 +           in->is_closed) return HANDLER_GO_ON;
45192 +
45193 +       for (c = in->first; in->bytes_out < in->bytes_in; c = c->next) {
45194 +               off_t weWant = in->bytes_in - in->bytes_out;
45195 +               off_t weHave = 0;
45196 +
45197 +               /* we announce toWrite octects
45198 +                * now take all the request_content chunk that we need to fill this request
45199 +                */
45200 +
45201 +               switch (c->type) {
45202 +               case FILE_CHUNK:
45203 +                       weHave = c->file.length - c->offset;
45204 +
45205 +                       if (weHave > weWant) weHave = weWant;
45206 +
45207 +                       c->offset += weHave;
45208 +                       in->bytes_out += weHave;
45209 +
45210 +                       break;
45211 +               case MEM_CHUNK:
45212 +                       /* append to the buffer */
45213 +                       weHave = c->mem->used - 1 - c->offset;
45214 +
45215 +                       if (weHave > weWant) weHave = weWant;
45216 +
45217 +                       c->offset += weHave;
45218 +                       in->bytes_out += weHave;
45219 +
45220 +                       break;
45221 +               default:
45222 +                       break;
45223 +               }
45224 +       }
45225 +
45226 +       return HANDLER_GO_ON;
45227 +
45228 +}
45229  /* this function is called at dlopen() time and inits the callbacks */
45230  
45231  int mod_staticfile_plugin_init(plugin *p) {
45232         p->version     = LIGHTTPD_VERSION_ID;
45233         p->name        = buffer_init_string("staticfile");
45234 -       
45235 +
45236         p->init        = mod_staticfile_init;
45237 -       p->handle_subrequest_start = mod_staticfile_subrequest;
45238 +       p->handle_start_backend = mod_staticfile_subrequest;
45239 +       p->handle_send_request_content = mod_staticfile_dev_null;
45240         p->set_defaults  = mod_staticfile_set_defaults;
45241         p->cleanup     = mod_staticfile_free;
45242 -       
45243 +
45244         p->data        = NULL;
45245 -       
45246 +
45247         return 0;
45248  }
45249 --- ../lighttpd-1.4.11/src/mod_status.c 2006-01-10 21:45:32.000000000 +0200
45250 +++ lighttpd-1.5.0/src/mod_status.c     2006-09-07 00:57:05.000000000 +0300
45251 @@ -4,7 +4,6 @@
45252  #include <fcntl.h>
45253  #include <stdlib.h>
45254  #include <string.h>
45255 -#include <unistd.h>
45256  #include <errno.h>
45257  #include <time.h>
45258  #include <stdio.h>
45259 @@ -14,6 +13,7 @@
45260  #include "response.h"
45261  #include "connections.h"
45262  #include "log.h"
45263 +#include "status_counter.h"
45264  
45265  #include "plugin.h"
45266  
45267 @@ -29,114 +29,114 @@
45268  
45269  typedef struct {
45270         PLUGIN_DATA;
45271 -       
45272 +
45273         double traffic_out;
45274         double requests;
45275 -       
45276 +
45277         double mod_5s_traffic_out[5];
45278         double mod_5s_requests[5];
45279         size_t mod_5s_ndx;
45280 -       
45281 +
45282         double rel_traffic_out;
45283         double rel_requests;
45284 -       
45285 +
45286         double abs_traffic_out;
45287         double abs_requests;
45288 -       
45289 +
45290         double bytes_written;
45291 -       
45292 +
45293         buffer *module_list;
45294 -       
45295 +
45296         plugin_config **config_storage;
45297 -       
45298 -       plugin_config conf; 
45299 +
45300 +       plugin_config conf;
45301  } plugin_data;
45302  
45303  INIT_FUNC(mod_status_init) {
45304         plugin_data *p;
45305         size_t i;
45306 -       
45307 +
45308         p = calloc(1, sizeof(*p));
45309 -       
45310 +
45311         p->traffic_out = p->requests = 0;
45312         p->rel_traffic_out = p->rel_requests = 0;
45313         p->abs_traffic_out = p->abs_requests = 0;
45314         p->bytes_written = 0;
45315         p->module_list = buffer_init();
45316 -       
45317 +
45318         for (i = 0; i < 5; i++) {
45319                 p->mod_5s_traffic_out[i] = p->mod_5s_requests[i] = 0;
45320         }
45321 -       
45322 +
45323         return p;
45324  }
45325  
45326  FREE_FUNC(mod_status_free) {
45327         plugin_data *p = p_d;
45328 -       
45329 +
45330         UNUSED(srv);
45331  
45332         if (!p) return HANDLER_GO_ON;
45333 -       
45334 +
45335         buffer_free(p->module_list);
45336 -       
45337 +
45338         if (p->config_storage) {
45339                 size_t i;
45340                 for (i = 0; i < srv->config_context->used; i++) {
45341                         plugin_config *s = p->config_storage[i];
45342 -                       
45343 +
45344                         buffer_free(s->status_url);
45345                         buffer_free(s->statistics_url);
45346                         buffer_free(s->config_url);
45347 -                       
45348 +
45349                         free(s);
45350                 }
45351                 free(p->config_storage);
45352         }
45353 -       
45354 -       
45355 +
45356 +
45357         free(p);
45358 -       
45359 +
45360         return HANDLER_GO_ON;
45361  }
45362  
45363  SETDEFAULTS_FUNC(mod_status_set_defaults) {
45364         plugin_data *p = p_d;
45365         size_t i;
45366 -       
45367 -       config_values_t cv[] = { 
45368 +
45369 +       config_values_t cv[] = {
45370                 { "status.status-url",           NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
45371                 { "status.config-url",           NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
45372                 { "status.enable-sort",          NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
45373                 { "status.statistics-url",       NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
45374                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
45375         };
45376 -       
45377 +
45378         if (!p) return HANDLER_ERROR;
45379 -       
45380 +
45381         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
45382 -       
45383 +
45384         for (i = 0; i < srv->config_context->used; i++) {
45385                 plugin_config *s;
45386 -               
45387 +
45388                 s = calloc(1, sizeof(plugin_config));
45389                 s->config_url    = buffer_init();
45390                 s->status_url    = buffer_init();
45391                 s->sort          = 1;
45392                 s->statistics_url    = buffer_init();
45393 -               
45394 +
45395                 cv[0].destination = s->status_url;
45396                 cv[1].destination = s->config_url;
45397                 cv[2].destination = &(s->sort);
45398                 cv[3].destination = s->statistics_url;
45399 -               
45400 +
45401                 p->config_storage[i] = s;
45402 -       
45403 +
45404                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
45405                         return HANDLER_ERROR;
45406                 }
45407         }
45408 -       
45409 +
45410         return HANDLER_GO_ON;
45411  }
45412  
45413 @@ -151,7 +151,7 @@
45414         buffer_append_string(b, value);
45415         BUFFER_APPEND_STRING_CONST(b, "</td>\n");
45416         BUFFER_APPEND_STRING_CONST(b, "   </tr>\n");
45417 -       
45418 +
45419         return 0;
45420  }
45421  
45422 @@ -161,13 +161,13 @@
45423         buffer_append_string(b, key);
45424         BUFFER_APPEND_STRING_CONST(b, "</th>\n");
45425         BUFFER_APPEND_STRING_CONST(b, "   </tr>\n");
45426 -       
45427 +
45428         return 0;
45429  }
45430  
45431  static int mod_status_header_append_sort(buffer *b, void *p_d, const char* key) {
45432         plugin_data *p = p_d;
45433 -       
45434 +
45435         if (p->conf.sort) {
45436                 BUFFER_APPEND_STRING_CONST(b, "<th class=\"status\"><a href=\"#\" class=\"sortheader\" onclick=\"resort(this);return false;\">");
45437                 buffer_append_string(b, key);
45438 @@ -177,13 +177,13 @@
45439                 buffer_append_string(b, key);
45440                 BUFFER_APPEND_STRING_CONST(b, "</th>\n");
45441         }
45442 -       
45443 +
45444         return 0;
45445  }
45446  
45447  static int mod_status_get_multiplier(double *avg, char *multiplier, int size) {
45448         *multiplier = ' ';
45449 -       
45450 +
45451         if (*avg > size) { *avg /= size; *multiplier = 'k'; }
45452         if (*avg > size) { *avg /= size; *multiplier = 'M'; }
45453         if (*avg > size) { *avg /= size; *multiplier = 'G'; }
45454 @@ -202,21 +202,21 @@
45455         size_t j;
45456         double avg;
45457         char multiplier = '\0';
45458 -       char buf[32];
45459 +       char buf[128];
45460         time_t ts;
45461 -       
45462 +
45463         int days, hours, mins, seconds;
45464 -       
45465 -       b = chunkqueue_get_append_buffer(con->write_queue);
45466  
45467 -       BUFFER_COPY_STRING_CONST(b, 
45468 +       b = chunkqueue_get_append_buffer(con->send);
45469 +
45470 +       BUFFER_COPY_STRING_CONST(b,
45471                                  "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
45472                                  "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
45473                                  "         \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
45474                                  "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"
45475                                  " <head>\n"
45476                                  "  <title>Status</title>\n");
45477 -       
45478 +
45479         BUFFER_APPEND_STRING_CONST(b,
45480                                    "  <style type=\"text/css\">\n"
45481                                    "    table.status { border: black solid thin; }\n"
45482 @@ -226,14 +226,14 @@
45483                                    "    a.sortheader { background-color: black; color: white; font-weight: bold; text-decoration: none; display: block; }\n"
45484                                    "    span.sortarrow { color: white; text-decoration: none; }\n"
45485                                    "  </style>\n");
45486 -       
45487 +
45488         if (p->conf.sort) {
45489                 BUFFER_APPEND_STRING_CONST(b,
45490                                            "<script type=\"text/javascript\">\n"
45491                                            "// <!--\n"
45492                                            "var sort_column;\n"
45493                                            "var prev_span = null;\n");
45494 -               
45495 +
45496                 BUFFER_APPEND_STRING_CONST(b,
45497                                            "function get_inner_text(el) {\n"
45498                                            " if((typeof el == 'string')||(typeof el == 'undefined'))\n"
45499 @@ -251,7 +251,7 @@
45500                                            " }\n"
45501                                            " return str;\n"
45502                                            "}\n");
45503 -               
45504 +
45505                 BUFFER_APPEND_STRING_CONST(b,
45506                                            "function sortfn(a,b) {\n"
45507                                            " var at = get_inner_text(a.cells[sort_column]);\n"
45508 @@ -266,7 +266,7 @@
45509                                            "  else return 1;\n"
45510                                            " }\n"
45511                                            "}\n");
45512 -               
45513 +
45514                 BUFFER_APPEND_STRING_CONST(b,
45515                                            "function resort(lnk) {\n"
45516                                            " var span = lnk.childNodes[1];\n"
45517 @@ -276,7 +276,7 @@
45518                                            "  rows[j-1] = table.rows[j];\n"
45519                                            " sort_column = lnk.parentNode.cellIndex;\n"
45520                                            " rows.sort(sortfn);\n");
45521 -               
45522 +
45523                 BUFFER_APPEND_STRING_CONST(b,
45524                                            " if (prev_span != null) prev_span.innerHTML = '';\n"
45525                                            " if (span.getAttribute('sortdir')=='down') {\n"
45526 @@ -294,175 +294,175 @@
45527                                            "// -->\n"
45528                                            "</script>\n");
45529         }
45530 -       
45531 -       BUFFER_APPEND_STRING_CONST(b, 
45532 +
45533 +       BUFFER_APPEND_STRING_CONST(b,
45534                                  " </head>\n"
45535                                  " <body>\n");
45536 -       
45537 -       
45538 -       
45539 +
45540 +
45541 +
45542         /* connection listing */
45543         BUFFER_APPEND_STRING_CONST(b, "<h1>Server-Status</h1>");
45544 -       
45545 -       BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\">");
45546 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Hostname</td><td class=\"string\">");
45547 +
45548 +       BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\" id=\"status\" summary=\"Server Status\">");
45549 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Hostname</td><td class=\"string\"><span id=\"host_addr\">");
45550         buffer_append_string_buffer(b, con->uri.authority);
45551 -       BUFFER_APPEND_STRING_CONST(b, " (");
45552 +       BUFFER_APPEND_STRING_CONST(b, "</span> (<span id=\"host_name\">");
45553         buffer_append_string_buffer(b, con->server_name);
45554 -       BUFFER_APPEND_STRING_CONST(b, ")</td></tr>\n");
45555 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Uptime</td><td class=\"string\">");
45556 -       
45557 +       BUFFER_APPEND_STRING_CONST(b, "</span>)</td></tr>\n");
45558 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Uptime</td><td class=\"string\" id=\"uptime\">");
45559 +
45560         ts = srv->cur_ts - srv->startup_ts;
45561 -       
45562 +
45563         days = ts / (60 * 60 * 24);
45564         ts %= (60 * 60 * 24);
45565 -       
45566 +
45567         hours = ts / (60 * 60);
45568         ts %= (60 * 60);
45569 -       
45570 +
45571         mins = ts / (60);
45572         ts %= (60);
45573 -       
45574 +
45575         seconds = ts;
45576 -       
45577 +
45578         if (days) {
45579                 buffer_append_long(b, days);
45580                 BUFFER_APPEND_STRING_CONST(b, " days ");
45581         }
45582 -       
45583 +
45584         if (hours) {
45585                 buffer_append_long(b, hours);
45586                 BUFFER_APPEND_STRING_CONST(b, " hours ");
45587         }
45588 -       
45589 +
45590         if (mins) {
45591                 buffer_append_long(b, mins);
45592                 BUFFER_APPEND_STRING_CONST(b, " min ");
45593         }
45594 -       
45595 +
45596         buffer_append_long(b, seconds);
45597         BUFFER_APPEND_STRING_CONST(b, " s");
45598 -       
45599 +
45600         BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n");
45601         BUFFER_APPEND_STRING_CONST(b, "<tr><td>Started at</td><td class=\"string\">");
45602 -       
45603 +
45604         ts = srv->startup_ts;
45605 -       
45606 -       strftime(buf, sizeof(buf) - 1, "%Y-%m-%d %H:%M:%S", localtime(&ts));
45607 +
45608 +       strftime(buf, sizeof(buf) - 1, "<span id=\"start_date\">%Y-%m-%d</span> <span id=\"start_time\">%H:%M:%S</span>", localtime(&ts));
45609         buffer_append_string(b, buf);
45610         BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n");
45611 -       
45612 -       
45613 +
45614 +
45615         BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">absolute (since start)</th></tr>\n");
45616 -       
45617 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">");
45618 +
45619 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\" ><span id=\"requests\">");
45620         avg = p->abs_requests;
45621  
45622         mod_status_get_multiplier(&avg, &multiplier, 1000);
45623 -       
45624 +
45625         buffer_append_long(b, avg);
45626 -       BUFFER_APPEND_STRING_CONST(b, " ");
45627 +       BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"requests_mult\">");
45628         if (multiplier) buffer_append_string_len(b, &multiplier, 1);
45629 -       BUFFER_APPEND_STRING_CONST(b, "req</td></tr>\n");
45630 -       
45631 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">");
45632 +       BUFFER_APPEND_STRING_CONST(b, "</span>req</td></tr>\n");
45633 +
45634 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\"><span id=\"traffic\">");
45635         avg = p->abs_traffic_out;
45636  
45637         mod_status_get_multiplier(&avg, &multiplier, 1024);
45638  
45639         sprintf(buf, "%.2f", avg);
45640         buffer_append_string(b, buf);
45641 -       BUFFER_APPEND_STRING_CONST(b, " ");
45642 +       BUFFER_APPEND_STRING_CONST(b, "</span>  <span id=\"traffic_mult\">");
45643         if (multiplier) buffer_append_string_len(b, &multiplier, 1);
45644 -       BUFFER_APPEND_STRING_CONST(b, "byte</td></tr>\n");
45645 +       BUFFER_APPEND_STRING_CONST(b, "</span>byte</td></tr>\n");
45646  
45647  
45648  
45649         BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">average (since start)</th></tr>\n");
45650 -       
45651 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">");
45652 +
45653 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\"><span id=\"requests_avg\">");
45654         avg = p->abs_requests / (srv->cur_ts - srv->startup_ts);
45655  
45656         mod_status_get_multiplier(&avg, &multiplier, 1000);
45657  
45658         buffer_append_long(b, avg);
45659 -       BUFFER_APPEND_STRING_CONST(b, " ");
45660 +       BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"requests_avg_mult\">");
45661         if (multiplier) buffer_append_string_len(b, &multiplier, 1);
45662 -       BUFFER_APPEND_STRING_CONST(b, "req/s</td></tr>\n");
45663 -       
45664 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">");
45665 +       BUFFER_APPEND_STRING_CONST(b, "</span>req/s</td></tr>\n");
45666 +
45667 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\"><span id=\"traffic_avg\">");
45668         avg = p->abs_traffic_out / (srv->cur_ts - srv->startup_ts);
45669  
45670         mod_status_get_multiplier(&avg, &multiplier, 1024);
45671  
45672         sprintf(buf, "%.2f", avg);
45673         buffer_append_string(b, buf);
45674 -       BUFFER_APPEND_STRING_CONST(b, " ");
45675 +       BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"traffic_avg_mult\">");
45676         if (multiplier) buffer_append_string_len(b, &multiplier, 1);
45677 -       BUFFER_APPEND_STRING_CONST(b, "byte/s</td></tr>\n");
45678 +       BUFFER_APPEND_STRING_CONST(b, "</span>byte/s</td></tr>\n");
45679 +
45680 +
45681  
45682 -       
45683 -       
45684         BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">average (5s sliding average)</th></tr>\n");
45685         for (j = 0, avg = 0; j < 5; j++) {
45686                 avg += p->mod_5s_requests[j];
45687         }
45688 -       
45689 +
45690         avg /= 5;
45691 -       
45692 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">");
45693 +
45694 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\"><span id=\"requests_sliding_avg\">");
45695  
45696         mod_status_get_multiplier(&avg, &multiplier, 1000);
45697  
45698         buffer_append_long(b, avg);
45699 -       BUFFER_APPEND_STRING_CONST(b, " ");
45700 +       BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"requests_sliding_avg_mult\">");
45701         if (multiplier) buffer_append_string_len(b, &multiplier, 1);
45702 -       
45703 -       BUFFER_APPEND_STRING_CONST(b, "req/s</td></tr>\n");
45704 -       
45705 +
45706 +       BUFFER_APPEND_STRING_CONST(b, "</span>req/s</td></tr>\n");
45707 +
45708         for (j = 0, avg = 0; j < 5; j++) {
45709                 avg += p->mod_5s_traffic_out[j];
45710         }
45711 -       
45712 +
45713         avg /= 5;
45714 -       
45715 -       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">");
45716 +
45717 +       BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\"><span id=\"requests_sliding_traffic\">");
45718  
45719         mod_status_get_multiplier(&avg, &multiplier, 1024);
45720  
45721         sprintf(buf, "%.2f", avg);
45722         buffer_append_string(b, buf);
45723 -       BUFFER_APPEND_STRING_CONST(b, " ");
45724 +       BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"requests_sliding_traffic_mult\">");
45725         if (multiplier) buffer_append_string_len(b, &multiplier, 1);
45726 -       BUFFER_APPEND_STRING_CONST(b, "byte/s</td></tr>\n");
45727 -       
45728 +       BUFFER_APPEND_STRING_CONST(b, "</span>byte/s</td></tr>\n");
45729 +
45730         BUFFER_APPEND_STRING_CONST(b, "</table>\n");
45731 -       
45732 -       
45733 +
45734 +
45735         BUFFER_APPEND_STRING_CONST(b, "<hr />\n<pre><b>legend</b>\n");
45736         BUFFER_APPEND_STRING_CONST(b, ". = connect, C = close, E = hard error\n");
45737         BUFFER_APPEND_STRING_CONST(b, "r = read, R = read-POST, W = write, h = handle-request\n");
45738         BUFFER_APPEND_STRING_CONST(b, "q = request-start,  Q = request-end\n");
45739         BUFFER_APPEND_STRING_CONST(b, "s = response-start, S = response-end\n");
45740 -       
45741 -       BUFFER_APPEND_STRING_CONST(b, "<b>");
45742 +
45743 +       BUFFER_APPEND_STRING_CONST(b, "<strong><span id=\"connections\">");
45744         buffer_append_long(b, srv->conns->used);
45745 -       BUFFER_APPEND_STRING_CONST(b, " connections</b>\n");
45746 -       
45747 +       BUFFER_APPEND_STRING_CONST(b, "</span> connections</strong>\n");
45748 +
45749         for (j = 0; j < srv->conns->used; j++) {
45750                 connection *c = srv->conns->ptr[j];
45751                 const char *state = connection_get_short_state(c->state);
45752 -               
45753 +
45754                 buffer_append_string_len(b, state, 1);
45755 -               
45756 +
45757                 if (((j + 1) % 50) == 0) {
45758                         BUFFER_APPEND_STRING_CONST(b, "\n");
45759                 }
45760         }
45761 -       
45762 +
45763         BUFFER_APPEND_STRING_CONST(b, "\n</pre><hr />\n<h2>Connections</h2>\n");
45764 -       
45765 -       BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\">\n");
45766 +
45767 +       BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\" summary=\"Current connections\" id=\"clients\">\n");
45768         BUFFER_APPEND_STRING_CONST(b, "<tr>");
45769         mod_status_header_append_sort(b, p_d, "Client IP");
45770         mod_status_header_append_sort(b, p_d, "Read");
45771 @@ -473,72 +473,72 @@
45772         mod_status_header_append_sort(b, p_d, "URI");
45773         mod_status_header_append_sort(b, p_d, "File");
45774         BUFFER_APPEND_STRING_CONST(b, "</tr>\n");
45775 -       
45776 +
45777         for (j = 0; j < srv->conns->used; j++) {
45778                 connection *c = srv->conns->ptr[j];
45779 -               
45780 -               BUFFER_APPEND_STRING_CONST(b, "<tr><td class=\"string\">");
45781 -               
45782 +
45783 +               BUFFER_APPEND_STRING_CONST(b, "<tr><td class=\"string ip\">");
45784 +
45785                 buffer_append_string(b, inet_ntop_cache_get_ip(srv, &(c->dst_addr)));
45786 -               
45787 -               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">");
45788 -               
45789 -               if (con->request.content_length) {
45790 -                       buffer_append_long(b, c->request_content_queue->bytes_in);
45791 +
45792 +               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int bytes_read\">");
45793 +
45794 +               if (c->request.content_length != -1) {
45795 +                       buffer_append_long(b, c->recv->bytes_in);
45796                         BUFFER_APPEND_STRING_CONST(b, "/");
45797                         buffer_append_long(b, c->request.content_length);
45798                 } else {
45799                         BUFFER_APPEND_STRING_CONST(b, "0/0");
45800                 }
45801 -       
45802 -               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">");
45803 -               
45804 -               buffer_append_off_t(b, chunkqueue_written(c->write_queue));
45805 +
45806 +               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int bytes_written\">");
45807 +
45808 +               buffer_append_off_t(b, chunkqueue_written(c->send_raw));
45809                 BUFFER_APPEND_STRING_CONST(b, "/");
45810 -               buffer_append_off_t(b, chunkqueue_length(c->write_queue));
45811 -               
45812 -               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
45813 -               
45814 +               buffer_append_off_t(b, chunkqueue_length(c->send_raw));
45815 +
45816 +               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string state\">");
45817 +
45818                 buffer_append_string(b, connection_get_state(c->state));
45819 -               
45820 -               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">");
45821 -               
45822 +
45823 +               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int time\">");
45824 +
45825                 buffer_append_long(b, srv->cur_ts - c->request_start);
45826 -               
45827 -               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
45828 -               
45829 +
45830 +               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string host\">");
45831 +
45832                 if (buffer_is_empty(c->server_name)) {
45833                         buffer_append_string_buffer(b, c->uri.authority);
45834                 }
45835                 else {
45836                         buffer_append_string_buffer(b, c->server_name);
45837                 }
45838 -               
45839 -               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
45840 -               
45841 +
45842 +               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string uri\">");
45843 +
45844                 if (!buffer_is_empty(c->uri.path)) {
45845                         buffer_append_string_encoded(b, CONST_BUF_LEN(c->uri.path), ENCODING_HTML);
45846                 }
45847 -               
45848 -               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
45849 -               
45850 +
45851 +               BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string file\">");
45852 +
45853                 buffer_append_string_buffer(b, c->physical.path);
45854 -               
45855 +
45856                 BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n");
45857         }
45858 -       
45859 -       
45860 -       BUFFER_APPEND_STRING_CONST(b, 
45861 +
45862 +
45863 +       BUFFER_APPEND_STRING_CONST(b,
45864                       "</table>\n");
45865 -       
45866 -       
45867 -       BUFFER_APPEND_STRING_CONST(b, 
45868 +
45869 +
45870 +       BUFFER_APPEND_STRING_CONST(b,
45871                       " </body>\n"
45872                       "</html>\n"
45873                       );
45874 -       
45875 +
45876         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
45877 -       
45878 +
45879         return 0;
45880  }
45881  
45882 @@ -548,27 +548,27 @@
45883         buffer *b;
45884         double avg;
45885         time_t ts;
45886 -       
45887 -       b = chunkqueue_get_append_buffer(con->write_queue);
45888 +
45889 +       b = chunkqueue_get_append_buffer(con->send);
45890  
45891         /* output total number of requests */
45892         BUFFER_APPEND_STRING_CONST(b, "Total Accesses: ");
45893         avg = p->abs_requests;
45894         buffer_append_long(b, avg);
45895         BUFFER_APPEND_STRING_CONST(b, "\n");
45896 -       
45897 +
45898         /* output total traffic out in kbytes */
45899         BUFFER_APPEND_STRING_CONST(b, "Total kBytes: ");
45900         avg = p->abs_traffic_out / 1024;
45901         buffer_append_long(b, avg);
45902         BUFFER_APPEND_STRING_CONST(b, "\n");
45903 -       
45904 +
45905         /* output uptime */
45906         BUFFER_APPEND_STRING_CONST(b, "Uptime: ");
45907         ts = srv->cur_ts - srv->startup_ts;
45908         buffer_append_long(b, ts);
45909         BUFFER_APPEND_STRING_CONST(b, "\n");
45910 -       
45911 +
45912         /* output busy servers */
45913         BUFFER_APPEND_STRING_CONST(b, "BusyServers: ");
45914         buffer_append_long(b, srv->conns->used);
45915 @@ -577,7 +577,7 @@
45916         /* set text/plain output */
45917  
45918         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain"));
45919 -       
45920 +
45921         return 0;
45922  }
45923  
45924 @@ -585,17 +585,17 @@
45925         plugin_data *p = p_d;
45926         buffer *b, *m = p->module_list;
45927         size_t i;
45928 -       array *st = srv->status;
45929 +       array *st = status_counter_get_array();
45930  
45931         if (0 == st->used) {
45932                 /* we have nothing to send */
45933                 con->http_status = 204;
45934 -               con->file_finished = 1;
45935 -       
45936 +               con->send->is_closed = 1;
45937 +
45938                 return HANDLER_FINISHED;
45939         }
45940 -       
45941 -       b = chunkqueue_get_append_buffer(con->write_queue);
45942 +
45943 +       b = chunkqueue_get_append_buffer(con->send);
45944  
45945         for (i = 0; i < st->used; i++) {
45946                 size_t ndx = st->sorted[i];
45947 @@ -605,27 +605,27 @@
45948                 buffer_append_long(b, ((data_integer *)(st->data[ndx]))->value);
45949                 buffer_append_string(b, "\n");
45950         }
45951 -       
45952 +
45953         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain"));
45954 -       
45955 +
45956         con->http_status = 200;
45957 -       con->file_finished = 1;
45958 -       
45959 +       con->send->is_closed = 1;
45960 +
45961         return HANDLER_FINISHED;
45962  }
45963  
45964  
45965  static handler_t mod_status_handle_server_status(server *srv, connection *con, void *p_d) {
45966 -       
45967 +
45968         if (buffer_is_equal_string(con->uri.query, CONST_STR_LEN("auto"))) {
45969                 mod_status_handle_server_status_text(srv, con, p_d);
45970         } else {
45971                 mod_status_handle_server_status_html(srv, con, p_d);
45972         }
45973 -       
45974 +
45975         con->http_status = 200;
45976 -       con->file_finished = 1;
45977 -       
45978 +       con->send->is_closed = 1;
45979 +
45980         return HANDLER_FINISHED;
45981  }
45982  
45983 @@ -634,9 +634,9 @@
45984         plugin_data *p = p_d;
45985         buffer *b, *m = p->module_list;
45986         size_t i;
45987 -       
45988 -       struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] = 
45989 -       { 
45990 +
45991 +       struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
45992 +       {
45993                 /* - poll is most reliable
45994                  * - select works everywhere
45995                  * - linux-* are experimental
45996 @@ -661,10 +661,10 @@
45997  #endif
45998                 { FDEVENT_HANDLER_UNSET,          NULL }
45999         };
46000 -       
46001 -       b = chunkqueue_get_append_buffer(con->write_queue);
46002 -       
46003 -       BUFFER_COPY_STRING_CONST(b, 
46004 +
46005 +       b = chunkqueue_get_append_buffer(con->send);
46006 +
46007 +       BUFFER_COPY_STRING_CONST(b,
46008                            "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
46009                            "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
46010                            "         \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
46011 @@ -675,7 +675,7 @@
46012                            " <body>\n"
46013                            "  <h1>" PACKAGE_NAME " " PACKAGE_VERSION "</h1>\n"
46014                            "  <table border=\"1\">\n");
46015 -       
46016 +
46017         mod_status_header_append(b, "Server-Features");
46018  #ifdef HAVE_PCRE_H
46019         mod_status_row_append(b, "RegEx Conditionals", "enabled");
46020 @@ -683,21 +683,21 @@
46021         mod_status_row_append(b, "RegEx Conditionals", "disabled - pcre missing");
46022  #endif
46023         mod_status_header_append(b, "Network Engine");
46024 -       
46025 +
46026         for (i = 0; event_handlers[i].name; i++) {
46027                 if (event_handlers[i].et == srv->event_handler) {
46028                         mod_status_row_append(b, "fd-Event-Handler", event_handlers[i].name);
46029                         break;
46030                 }
46031         }
46032 -       
46033 +
46034         mod_status_header_append(b, "Config-File-Settings");
46035 -       
46036 +
46037         for (i = 0; i < srv->plugins.used; i++) {
46038                 plugin **ps = srv->plugins.ptr;
46039 -               
46040 +
46041                 plugin *pl = ps[i];
46042 -       
46043 +
46044                 if (i == 0) {
46045                         buffer_copy_string_buffer(m, pl->name);
46046                 } else {
46047 @@ -705,137 +705,135 @@
46048                         buffer_append_string_buffer(m, pl->name);
46049                 }
46050         }
46051 -       
46052 +
46053         mod_status_row_append(b, "Loaded Modules", m->ptr);
46054 -       
46055 +
46056         BUFFER_APPEND_STRING_CONST(b, "  </table>\n");
46057 -       
46058 -       BUFFER_APPEND_STRING_CONST(b, 
46059 +
46060 +       BUFFER_APPEND_STRING_CONST(b,
46061                       " </body>\n"
46062                       "</html>\n"
46063                       );
46064 -       
46065 +
46066         response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
46067 -       
46068 +
46069         con->http_status = 200;
46070 -       con->file_finished = 1;
46071 -       
46072 +       con->send->is_closed = 1;
46073 +
46074         return HANDLER_FINISHED;
46075  }
46076  
46077 -#define PATCH(x) \
46078 -       p->conf.x = s->x;
46079  static int mod_status_patch_connection(server *srv, connection *con, plugin_data *p) {
46080         size_t i, j;
46081         plugin_config *s = p->config_storage[0];
46082 -       
46083 -       PATCH(status_url);
46084 -       PATCH(config_url);
46085 -       PATCH(sort);
46086 -       PATCH(statistics_url);
46087 -       
46088 +
46089 +       PATCH_OPTION(status_url);
46090 +       PATCH_OPTION(config_url);
46091 +       PATCH_OPTION(sort);
46092 +       PATCH_OPTION(statistics_url);
46093 +
46094         /* skip the first, the global context */
46095         for (i = 1; i < srv->config_context->used; i++) {
46096                 data_config *dc = (data_config *)srv->config_context->data[i];
46097                 s = p->config_storage[i];
46098 -               
46099 +
46100                 /* condition didn't match */
46101                 if (!config_check_cond(srv, con, dc)) continue;
46102 -               
46103 +
46104                 /* merge config */
46105                 for (j = 0; j < dc->value->used; j++) {
46106                         data_unset *du = dc->value->data[j];
46107 -                       
46108 +
46109                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.status-url"))) {
46110 -                               PATCH(status_url);
46111 +                               PATCH_OPTION(status_url);
46112                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.config-url"))) {
46113 -                               PATCH(config_url);
46114 +                               PATCH_OPTION(config_url);
46115                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.enable-sort"))) {
46116 -                               PATCH(sort);
46117 +                               PATCH_OPTION(sort);
46118                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.statistics-url"))) {
46119 -                               PATCH(statistics_url);
46120 -                       } 
46121 +                               PATCH_OPTION(statistics_url);
46122 +                       }
46123                 }
46124         }
46125 -       
46126 +
46127         return 0;
46128  }
46129  
46130  static handler_t mod_status_handler(server *srv, connection *con, void *p_d) {
46131         plugin_data *p = p_d;
46132 -       
46133 +
46134         mod_status_patch_connection(srv, con, p);
46135 -       
46136 -       if (!buffer_is_empty(p->conf.status_url) && 
46137 +
46138 +       if (!buffer_is_empty(p->conf.status_url) &&
46139             buffer_is_equal(p->conf.status_url, con->uri.path)) {
46140                 return mod_status_handle_server_status(srv, con, p_d);
46141 -       } else if (!buffer_is_empty(p->conf.config_url) && 
46142 +       } else if (!buffer_is_empty(p->conf.config_url) &&
46143             buffer_is_equal(p->conf.config_url, con->uri.path)) {
46144                 return mod_status_handle_server_config(srv, con, p_d);
46145 -       } else if (!buffer_is_empty(p->conf.statistics_url) && 
46146 +       } else if (!buffer_is_empty(p->conf.statistics_url) &&
46147             buffer_is_equal(p->conf.statistics_url, con->uri.path)) {
46148                 return mod_status_handle_server_statistics(srv, con, p_d);
46149         }
46150 -       
46151 +
46152         return HANDLER_GO_ON;
46153  }
46154  
46155  TRIGGER_FUNC(mod_status_trigger) {
46156         plugin_data *p = p_d;
46157         size_t i;
46158 -       
46159 +
46160         /* check all connections */
46161         for (i = 0; i < srv->conns->used; i++) {
46162                 connection *c = srv->conns->ptr[i];
46163 -               
46164 +
46165                 p->bytes_written += c->bytes_written_cur_second;
46166         }
46167 -       
46168 +
46169         /* a sliding average */
46170         p->mod_5s_traffic_out[p->mod_5s_ndx] = p->bytes_written;
46171         p->mod_5s_requests   [p->mod_5s_ndx] = p->requests;
46172 -       
46173 +
46174         p->mod_5s_ndx = (p->mod_5s_ndx+1) % 5;
46175 -       
46176 +
46177         p->abs_traffic_out += p->bytes_written;
46178         p->rel_traffic_out += p->bytes_written;
46179 -       
46180 +
46181         p->bytes_written = 0;
46182 -       
46183 +
46184         /* reset storage - second */
46185         p->traffic_out = 0;
46186         p->requests    = 0;
46187 -       
46188 +
46189         return HANDLER_GO_ON;
46190  }
46191  
46192  REQUESTDONE_FUNC(mod_status_account) {
46193         plugin_data *p = p_d;
46194 -       
46195 +
46196         UNUSED(srv);
46197  
46198         p->requests++;
46199         p->rel_requests++;
46200         p->abs_requests++;
46201 -       
46202 +
46203         p->bytes_written += con->bytes_written_cur_second;
46204 -       
46205 +
46206         return HANDLER_GO_ON;
46207  }
46208  
46209  int mod_status_plugin_init(plugin *p) {
46210         p->version     = LIGHTTPD_VERSION_ID;
46211         p->name        = buffer_init_string("status");
46212 -       
46213 +
46214         p->init        = mod_status_init;
46215         p->cleanup     = mod_status_free;
46216         p->set_defaults= mod_status_set_defaults;
46217 -       
46218 +
46219         p->handle_uri_clean    = mod_status_handler;
46220         p->handle_trigger      = mod_status_trigger;
46221 -       p->handle_request_done = mod_status_account;
46222 -       
46223 +       p->handle_response_done = mod_status_account;
46224 +
46225         p->data        = NULL;
46226 -       
46227 +
46228         return 0;
46229  }
46230 --- ../lighttpd-1.4.11/src/mod_trigger_b4_dl.c  2005-09-23 22:53:55.000000000 +0300
46231 +++ lighttpd-1.5.0/src/mod_trigger_b4_dl.c      2006-07-16 00:26:03.000000000 +0300
46232 @@ -24,18 +24,18 @@
46233  
46234  /**
46235   * this is a trigger_b4_dl for a lighttpd plugin
46236 - * 
46237 + *
46238   */
46239  
46240  /* plugin config for all request/connections */
46241  
46242  typedef struct {
46243         buffer *db_filename;
46244 -       
46245 +
46246         buffer *trigger_url;
46247         buffer *download_url;
46248         buffer *deny_url;
46249 -       
46250 +
46251         array  *mc_hosts;
46252         buffer *mc_namespace;
46253  #if defined(HAVE_PCRE_H)
46254 @@ -46,58 +46,58 @@
46255         GDBM_FILE db;
46256  #endif
46257  
46258 -#if defined(HAVE_MEMCACHE_H) 
46259 +#if defined(HAVE_MEMCACHE_H)
46260         struct memcache *mc;
46261  #endif
46262 -       
46263 +
46264         unsigned short trigger_timeout;
46265         unsigned short debug;
46266  } plugin_config;
46267  
46268  typedef struct {
46269         PLUGIN_DATA;
46270 -       
46271 +
46272         buffer *tmp_buf;
46273 -       
46274 +
46275         plugin_config **config_storage;
46276 -       
46277 -       plugin_config conf; 
46278 +
46279 +       plugin_config conf;
46280  } plugin_data;
46281  
46282  /* init the plugin data */
46283  INIT_FUNC(mod_trigger_b4_dl_init) {
46284         plugin_data *p;
46285 -       
46286 +
46287         p = calloc(1, sizeof(*p));
46288 -       
46289 +
46290         p->tmp_buf = buffer_init();
46291 -       
46292 +
46293         return p;
46294  }
46295  
46296  /* detroy the plugin data */
46297  FREE_FUNC(mod_trigger_b4_dl_free) {
46298         plugin_data *p = p_d;
46299 -       
46300 +
46301         UNUSED(srv);
46302  
46303         if (!p) return HANDLER_GO_ON;
46304 -       
46305 +
46306         if (p->config_storage) {
46307                 size_t i;
46308                 for (i = 0; i < srv->config_context->used; i++) {
46309                         plugin_config *s = p->config_storage[i];
46310  
46311                         if (!s) continue;
46312 -                       
46313 +
46314                         buffer_free(s->db_filename);
46315                         buffer_free(s->download_url);
46316                         buffer_free(s->trigger_url);
46317                         buffer_free(s->deny_url);
46318 -                       
46319 +
46320                         buffer_free(s->mc_namespace);
46321                         array_free(s->mc_hosts);
46322 -                       
46323 +
46324  #if defined(HAVE_PCRE_H)
46325                         if (s->trigger_regex) pcre_free(s->trigger_regex);
46326                         if (s->download_regex) pcre_free(s->download_regex);
46327 @@ -108,16 +108,16 @@
46328  #if defined(HAVE_MEMCACHE_H)
46329                         if (s->mc) mc_free(s->mc);
46330  #endif
46331 -                       
46332 +
46333                         free(s);
46334                 }
46335                 free(p->config_storage);
46336         }
46337 -       
46338 +
46339         buffer_free(p->tmp_buf);
46340 -       
46341 +
46342         free(p);
46343 -       
46344 +
46345         return HANDLER_GO_ON;
46346  }
46347  
46348 @@ -126,9 +126,9 @@
46349  SETDEFAULTS_FUNC(mod_trigger_b4_dl_set_defaults) {
46350         plugin_data *p = p_d;
46351         size_t i = 0;
46352 -       
46353 -       
46354 -       config_values_t cv[] = { 
46355 +
46356 +
46357 +       config_values_t cv[] = {
46358                 { "trigger-before-download.gdbm-filename",   NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
46359                 { "trigger-before-download.trigger-url",     NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
46360                 { "trigger-before-download.download-url",    NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
46361 @@ -139,18 +139,18 @@
46362                 { "trigger-before-download.debug",           NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },      /* 7 */
46363                 { NULL,                        NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
46364         };
46365 -       
46366 +
46367         if (!p) return HANDLER_ERROR;
46368 -       
46369 +
46370         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
46371 -       
46372 +
46373         for (i = 0; i < srv->config_context->used; i++) {
46374                 plugin_config *s;
46375  #if defined(HAVE_PCRE_H)
46376                 const char *errptr;
46377                 int erroff;
46378  #endif
46379 -               
46380 +
46381                 s = calloc(1, sizeof(plugin_config));
46382                 s->db_filename    = buffer_init();
46383                 s->download_url   = buffer_init();
46384 @@ -158,7 +158,7 @@
46385                 s->deny_url       = buffer_init();
46386                 s->mc_hosts       = array_init();
46387                 s->mc_namespace   = buffer_init();
46388 -               
46389 +
46390                 cv[0].destination = s->db_filename;
46391                 cv[1].destination = s->trigger_url;
46392                 cv[2].destination = s->download_url;
46393 @@ -167,41 +167,41 @@
46394                 cv[5].destination = s->mc_hosts;
46395                 cv[6].destination = s->mc_namespace;
46396                 cv[7].destination = &(s->debug);
46397 -               
46398 +
46399                 p->config_storage[i] = s;
46400 -       
46401 +
46402                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
46403                         return HANDLER_ERROR;
46404                 }
46405  #if defined(HAVE_GDBM_H)
46406                 if (!buffer_is_empty(s->db_filename)) {
46407                         if (NULL == (s->db = gdbm_open(s->db_filename->ptr, 4096, GDBM_WRCREAT | GDBM_NOLOCK, S_IRUSR | S_IWUSR, 0))) {
46408 -                               log_error_write(srv, __FILE__, __LINE__, "s", 
46409 +                               log_error_write(srv, __FILE__, __LINE__, "s",
46410                                                 "gdbm-open failed");
46411                                 return HANDLER_ERROR;
46412                         }
46413                 }
46414  #endif
46415 -#if defined(HAVE_PCRE_H)               
46416 +#if defined(HAVE_PCRE_H)
46417                 if (!buffer_is_empty(s->download_url)) {
46418                         if (NULL == (s->download_regex = pcre_compile(s->download_url->ptr,
46419                                                                       0, &errptr, &erroff, NULL))) {
46420 -                               
46421 -                               log_error_write(srv, __FILE__, __LINE__, "sbss", 
46422 -                                               "compiling regex for download-url failed:", 
46423 +
46424 +                               log_error_write(srv, __FILE__, __LINE__, "sbss",
46425 +                                               "compiling regex for download-url failed:",
46426                                                 s->download_url, "pos:", erroff);
46427                                 return HANDLER_ERROR;
46428                         }
46429                 }
46430 -               
46431 +
46432                 if (!buffer_is_empty(s->trigger_url)) {
46433                         if (NULL == (s->trigger_regex = pcre_compile(s->trigger_url->ptr,
46434                                                                      0, &errptr, &erroff, NULL))) {
46435 -                               
46436 -                               log_error_write(srv, __FILE__, __LINE__, "sbss", 
46437 -                                               "compiling regex for trigger-url failed:", 
46438 +
46439 +                               log_error_write(srv, __FILE__, __LINE__, "sbss",
46440 +                                               "compiling regex for trigger-url failed:",
46441                                                 s->trigger_url, "pos:", erroff);
46442 -                               
46443 +
46444                                 return HANDLER_ERROR;
46445                         }
46446                 }
46447 @@ -211,100 +211,97 @@
46448  #if defined(HAVE_MEMCACHE_H)
46449                         size_t k;
46450                         s->mc = mc_new();
46451 -               
46452 +
46453                         for (k = 0; k < s->mc_hosts->used; k++) {
46454                                 data_string *ds = (data_string *)s->mc_hosts->data[k];
46455 -                               
46456 +
46457                                 if (0 != mc_server_add4(s->mc, ds->value->ptr)) {
46458 -                                       log_error_write(srv, __FILE__, __LINE__, "sb", 
46459 -                                                       "connection to host failed:", 
46460 +                                       log_error_write(srv, __FILE__, __LINE__, "sb",
46461 +                                                       "connection to host failed:",
46462                                                         ds->value);
46463 -                                       
46464 +
46465                                         return HANDLER_ERROR;
46466                                 }
46467                         }
46468  #else
46469 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
46470 +                       log_error_write(srv, __FILE__, __LINE__, "s",
46471                                         "memcache support is not compiled in but trigger-before-download.memcache-hosts is set, aborting");
46472                         return HANDLER_ERROR;
46473  #endif
46474                 }
46475 -               
46476 +
46477  
46478  #if (!defined(HAVE_GDBM_H) && !defined(HAVE_MEMCACHE_H)) || !defined(HAVE_PCRE_H)
46479 -               log_error_write(srv, __FILE__, __LINE__, "s", 
46480 +               log_error_write(srv, __FILE__, __LINE__, "s",
46481                                 "(either gdbm or libmemcache) and pcre are require, but were not found, aborting");
46482                 return HANDLER_ERROR;
46483  #endif
46484         }
46485 -       
46486 +
46487         return HANDLER_GO_ON;
46488  }
46489  
46490 -#define PATCH(x) \
46491 -       p->conf.x = s->x;
46492  static int mod_trigger_b4_dl_patch_connection(server *srv, connection *con, plugin_data *p) {
46493         size_t i, j;
46494         plugin_config *s = p->config_storage[0];
46495 -       
46496 +
46497  #if defined(HAVE_GDBM)
46498 -       PATCH(db);
46499 -#endif 
46500 +       PATCH_OPTION(db);
46501 +#endif
46502  #if defined(HAVE_PCRE_H)
46503 -       PATCH(download_regex);
46504 -       PATCH(trigger_regex);
46505 -#endif 
46506 -       PATCH(trigger_timeout);
46507 -       PATCH(deny_url);
46508 -       PATCH(mc_namespace);
46509 -       PATCH(debug);
46510 +       PATCH_OPTION(download_regex);
46511 +       PATCH_OPTION(trigger_regex);
46512 +#endif
46513 +       PATCH_OPTION(trigger_timeout);
46514 +       PATCH_OPTION(deny_url);
46515 +       PATCH_OPTION(mc_namespace);
46516 +       PATCH_OPTION(debug);
46517  #if defined(HAVE_MEMCACHE_H)
46518 -       PATCH(mc);
46519 +       PATCH_OPTION(mc);
46520  #endif
46521 -       
46522 +
46523         /* skip the first, the global context */
46524         for (i = 1; i < srv->config_context->used; i++) {
46525                 data_config *dc = (data_config *)srv->config_context->data[i];
46526                 s = p->config_storage[i];
46527 -               
46528 +
46529                 /* condition didn't match */
46530                 if (!config_check_cond(srv, con, dc)) continue;
46531 -               
46532 +
46533                 /* merge config */
46534                 for (j = 0; j < dc->value->used; j++) {
46535                         data_unset *du = dc->value->data[j];
46536  
46537                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.download-url"))) {
46538  #if defined(HAVE_PCRE_H)
46539 -                               PATCH(download_regex);
46540 +                               PATCH_OPTION(download_regex);
46541  #endif
46542                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.trigger-url"))) {
46543  # if defined(HAVE_PCRE_H)
46544 -                               PATCH(trigger_regex);
46545 +                               PATCH_OPTION(trigger_regex);
46546  # endif
46547                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.gdbm-filename"))) {
46548  #if defined(HAVE_GDBM_H)
46549 -                               PATCH(db);
46550 +                               PATCH_OPTION(db);
46551  #endif
46552                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.trigger-timeout"))) {
46553 -                               PATCH(trigger_timeout);
46554 +                               PATCH_OPTION(trigger_timeout);
46555                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.debug"))) {
46556 -                               PATCH(debug);
46557 +                               PATCH_OPTION(debug);
46558                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.deny-url"))) {
46559 -                               PATCH(deny_url);
46560 +                               PATCH_OPTION(deny_url);
46561                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.memcache-namespace"))) {
46562 -                               PATCH(mc_namespace);
46563 +                               PATCH_OPTION(mc_namespace);
46564                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.memcache-hosts"))) {
46565  #if defined(HAVE_MEMCACHE_H)
46566 -                               PATCH(mc);
46567 +                               PATCH_OPTION(mc);
46568  #endif
46569                         }
46570                 }
46571         }
46572 -       
46573 +
46574         return 0;
46575  }
46576 -#undef PATCH
46577  
46578  URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
46579         plugin_data *p = p_d;
46580 @@ -315,20 +312,20 @@
46581         int n;
46582  # define N 10
46583         int ovec[N * 3];
46584 -       
46585 +
46586         if (con->uri.path->used == 0) return HANDLER_GO_ON;
46587 -       
46588 +
46589         mod_trigger_b4_dl_patch_connection(srv, con, p);
46590 -       
46591 +
46592         if (!p->conf.trigger_regex || !p->conf.download_regex) return HANDLER_GO_ON;
46593 -       
46594 +
46595  # if !defined(HAVE_GDBM_H) && !defined(HAVE_MEMCACHE_H)
46596         return HANDLER_GO_ON;
46597  # elif defined(HAVE_GDBM_H) && defined(HAVE_MEMCACHE_H)
46598         if (!p->conf.db && !p->conf.mc) return HANDLER_GO_ON;
46599         if (p->conf.db && p->conf.mc) {
46600                 /* can't decide which one */
46601 -               
46602 +
46603                 return HANDLER_GO_ON;
46604         }
46605  # elif defined(HAVE_GDBM_H)
46606 @@ -336,12 +333,12 @@
46607  # else
46608         if (!p->conf.mc) return HANDLER_GO_ON;
46609  # endif
46610 -       
46611 +
46612         if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "X-Forwarded-For"))) {
46613                 /* X-Forwarded-For contains the ip behind the proxy */
46614 -               
46615 +
46616                 remote_ip = ds->value->ptr;
46617 -               
46618 +
46619                 /* memcache can't handle spaces */
46620         } else {
46621                 remote_ip = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
46622 @@ -350,13 +347,13 @@
46623         if (p->conf.debug) {
46624                 log_error_write(srv, __FILE__, __LINE__, "ss", "(debug) remote-ip:", remote_ip);
46625         }
46626 -               
46627 +
46628         /* check if URL is a trigger -> insert IP into DB */
46629         if ((n = pcre_exec(p->conf.trigger_regex, NULL, con->uri.path->ptr, con->uri.path->used - 1, 0, 0, ovec, 3 * N)) < 0) {
46630                 if (n != PCRE_ERROR_NOMATCH) {
46631                         log_error_write(srv, __FILE__, __LINE__, "sd",
46632                                         "execution error while matching:", n);
46633 -                       
46634 +
46635                         return HANDLER_ERROR;
46636                 }
46637         } else {
46638 @@ -364,34 +361,34 @@
46639                 if (p->conf.db) {
46640                         /* the trigger matched */
46641                         datum key, val;
46642 -                       
46643 +
46644                         key.dptr = (char *)remote_ip;
46645                         key.dsize = strlen(remote_ip);
46646 -                       
46647 +
46648                         val.dptr = (char *)&(srv->cur_ts);
46649                         val.dsize = sizeof(srv->cur_ts);
46650 -                       
46651 +
46652                         if (0 != gdbm_store(p->conf.db, key, val, GDBM_REPLACE)) {
46653                                 log_error_write(srv, __FILE__, __LINE__, "s",
46654                                                 "insert failed");
46655                         }
46656                 }
46657  # endif
46658 -# if defined(HAVE_MEMCACHE_H)          
46659 +# if defined(HAVE_MEMCACHE_H)
46660                 if (p->conf.mc) {
46661                         size_t i;
46662                         buffer_copy_string_buffer(p->tmp_buf, p->conf.mc_namespace);
46663                         buffer_append_string(p->tmp_buf, remote_ip);
46664 -                       
46665 +
46666                         for (i = 0; i < p->tmp_buf->used - 1; i++) {
46667                                 if (p->tmp_buf->ptr[i] == ' ') p->tmp_buf->ptr[i] = '-';
46668                         }
46669 -                       
46670 +
46671                         if (p->conf.debug) {
46672                                 log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) triggered IP:", p->tmp_buf);
46673                         }
46674  
46675 -                       if (0 != mc_set(p->conf.mc, 
46676 +                       if (0 != mc_set(p->conf.mc,
46677                                         CONST_BUF_LEN(p->tmp_buf),
46678                                         (char *)&(srv->cur_ts), sizeof(srv->cur_ts),
46679                                         p->conf.trigger_timeout, 0)) {
46680 @@ -401,7 +398,7 @@
46681                 }
46682  # endif
46683         }
46684 -               
46685 +
46686         /* check if URL is a download -> check IP in DB, update timestamp */
46687         if ((n = pcre_exec(p->conf.download_regex, NULL, con->uri.path->ptr, con->uri.path->used - 1, 0, 0, ovec, 3 * N)) < 0) {
46688                 if (n != PCRE_ERROR_NOMATCH) {
46689 @@ -411,93 +408,93 @@
46690                 }
46691         } else {
46692                 /* the download uri matched */
46693 -# if defined(HAVE_GDBM_H)              
46694 +# if defined(HAVE_GDBM_H)
46695                 if (p->conf.db) {
46696                         datum key, val;
46697                         time_t last_hit;
46698 -               
46699 +
46700                         key.dptr = (char *)remote_ip;
46701                         key.dsize = strlen(remote_ip);
46702 -                       
46703 +
46704                         val = gdbm_fetch(p->conf.db, key);
46705 -               
46706 +
46707                         if (val.dptr == NULL) {
46708                                 /* not found, redirect */
46709 -                               
46710 +
46711                                 response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
46712 -                               
46713 +
46714                                 con->http_status = 307;
46715 -                               
46716 +
46717                                 return HANDLER_FINISHED;
46718                         }
46719 -                       
46720 +
46721                         last_hit = *(time_t *)(val.dptr);
46722 -                       
46723 +
46724                         free(val.dptr);
46725 -                       
46726 +
46727                         if (srv->cur_ts - last_hit > p->conf.trigger_timeout) {
46728                                 /* found, but timeout, redirect */
46729 -                               
46730 +
46731                                 response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
46732                                 con->http_status = 307;
46733 -                               
46734 +
46735                                 if (p->conf.db) {
46736                                         if (0 != gdbm_delete(p->conf.db, key)) {
46737                                                 log_error_write(srv, __FILE__, __LINE__, "s",
46738                                                                 "delete failed");
46739                                         }
46740                                 }
46741 -                               
46742 +
46743                                 return HANDLER_FINISHED;
46744                         }
46745 -                       
46746 +
46747                         val.dptr = (char *)&(srv->cur_ts);
46748                         val.dsize = sizeof(srv->cur_ts);
46749 -                       
46750 +
46751                         if (0 != gdbm_store(p->conf.db, key, val, GDBM_REPLACE)) {
46752                                 log_error_write(srv, __FILE__, __LINE__, "s",
46753                                                 "insert failed");
46754                         }
46755                 }
46756  # endif
46757 -               
46758 -# if defined(HAVE_MEMCACHE_H)          
46759 +
46760 +# if defined(HAVE_MEMCACHE_H)
46761                 if (p->conf.mc) {
46762                         void *r;
46763                         size_t i;
46764 -                       
46765 +
46766                         buffer_copy_string_buffer(p->tmp_buf, p->conf.mc_namespace);
46767                         buffer_append_string(p->tmp_buf, remote_ip);
46768 -                       
46769 +
46770                         for (i = 0; i < p->tmp_buf->used - 1; i++) {
46771                                 if (p->tmp_buf->ptr[i] == ' ') p->tmp_buf->ptr[i] = '-';
46772                         }
46773 -                       
46774 +
46775                         if (p->conf.debug) {
46776                                 log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) checking IP:", p->tmp_buf);
46777                         }
46778  
46779                         /**
46780 -                        * 
46781 +                        *
46782                          * memcached is do expiration for us, as long as we can fetch it every thing is ok
46783 -                        * and the timestamp is updated 
46784 -                        * 
46785 +                        * and the timestamp is updated
46786 +                        *
46787                          */
46788 -                       if (NULL == (r = mc_aget(p->conf.mc, 
46789 +                       if (NULL == (r = mc_aget(p->conf.mc,
46790                                                  CONST_BUF_LEN(p->tmp_buf)
46791                                                  ))) {
46792 -                               
46793 +
46794                                 response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
46795 -                               
46796 +
46797                                 con->http_status = 307;
46798 -                               
46799 +
46800                                 return HANDLER_FINISHED;
46801                         }
46802 -                       
46803 +
46804                         free(r);
46805 -                       
46806 +
46807                         /* set a new timeout */
46808 -                       if (0 != mc_set(p->conf.mc, 
46809 +                       if (0 != mc_set(p->conf.mc,
46810                                         CONST_BUF_LEN(p->tmp_buf),
46811                                         (char *)&(srv->cur_ts), sizeof(srv->cur_ts),
46812                                         p->conf.trigger_timeout, 0)) {
46813 @@ -507,13 +504,13 @@
46814                 }
46815  # endif
46816         }
46817 -       
46818 +
46819  #else
46820         UNUSED(srv);
46821         UNUSED(con);
46822         UNUSED(p_d);
46823  #endif
46824 -       
46825 +
46826         return HANDLER_GO_ON;
46827  }
46828  
46829 @@ -521,21 +518,21 @@
46830  TRIGGER_FUNC(mod_trigger_b4_dl_handle_trigger) {
46831         plugin_data *p = p_d;
46832         size_t i;
46833 -       
46834 +
46835         /* check DB each minute */
46836         if (srv->cur_ts % 60 != 0) return HANDLER_GO_ON;
46837 -       
46838 +
46839         /* cleanup */
46840         for (i = 0; i < srv->config_context->used; i++) {
46841                 plugin_config *s = p->config_storage[i];
46842                 datum key, val, okey;
46843 -               
46844 +
46845                 if (!s->db) continue;
46846 -               
46847 +
46848                 okey.dptr = NULL;
46849 -               
46850 -               /* according to the manual this loop + delete does delete all entries on its way 
46851 -                * 
46852 +
46853 +               /* according to the manual this loop + delete does delete all entries on its way
46854 +                *
46855                  * we don't care as the next round will remove them. We don't have to perfect here.
46856                  */
46857                 for (key = gdbm_firstkey(s->db); key.dptr; key = gdbm_nextkey(s->db, okey)) {
46858 @@ -544,21 +541,21 @@
46859                                 free(okey.dptr);
46860                                 okey.dptr = NULL;
46861                         }
46862 -                       
46863 +
46864                         val = gdbm_fetch(s->db, key);
46865 -                       
46866 +
46867                         last_hit = *(time_t *)(val.dptr);
46868 -                       
46869 +
46870                         free(val.dptr);
46871 -                       
46872 +
46873                         if (srv->cur_ts - last_hit > s->trigger_timeout) {
46874                                 gdbm_delete(s->db, key);
46875                         }
46876 -                       
46877 +
46878                         okey = key;
46879                 }
46880                 if (okey.dptr) free(okey.dptr);
46881 -               
46882 +
46883                 /* reorg once a day */
46884                 if ((srv->cur_ts % (60 * 60 * 24) != 0)) gdbm_reorganize(s->db);
46885         }
46886 @@ -571,7 +568,7 @@
46887  int mod_trigger_b4_dl_plugin_init(plugin *p) {
46888         p->version     = LIGHTTPD_VERSION_ID;
46889         p->name        = buffer_init_string("trigger_b4_dl");
46890 -       
46891 +
46892         p->init        = mod_trigger_b4_dl_init;
46893         p->handle_uri_clean  = mod_trigger_b4_dl_uri_handler;
46894         p->set_defaults  = mod_trigger_b4_dl_set_defaults;
46895 @@ -579,8 +576,8 @@
46896         p->handle_trigger  = mod_trigger_b4_dl_handle_trigger;
46897  #endif
46898         p->cleanup     = mod_trigger_b4_dl_free;
46899 -       
46900 +
46901         p->data        = NULL;
46902 -       
46903 +
46904         return 0;
46905  }
46906 --- ../lighttpd-1.4.11/src/mod_uploadprogress.c 1970-01-01 03:00:00.000000000 +0300
46907 +++ lighttpd-1.5.0/src/mod_uploadprogress.c     2006-09-07 00:57:05.000000000 +0300
46908 @@ -0,0 +1,420 @@
46909 +#include <ctype.h>
46910 +#include <stdlib.h>
46911 +#include <string.h>
46912 +
46913 +#include "base.h"
46914 +#include "log.h"
46915 +#include "buffer.h"
46916 +
46917 +#include "plugin.h"
46918 +
46919 +#include "response.h"
46920 +#include "stat_cache.h"
46921 +
46922 +/**
46923 + * this is a uploadprogress for a lighttpd plugin
46924 + *
46925 + */
46926 +
46927 +typedef struct {
46928 +       buffer     *con_id;
46929 +       connection *con;
46930 +} connection_map_entry;
46931 +
46932 +typedef struct {
46933 +       connection_map_entry **ptr;
46934 +
46935 +       size_t used;
46936 +       size_t size;
46937 +} connection_map;
46938 +
46939 +/* plugin config for all request/connections */
46940 +
46941 +typedef struct {
46942 +       buffer *progress_url;
46943 +} plugin_config;
46944 +
46945 +typedef struct {
46946 +       PLUGIN_DATA;
46947 +
46948 +       connection_map *con_map;
46949 +
46950 +       plugin_config **config_storage;
46951 +
46952 +       plugin_config conf;
46953 +} plugin_data;
46954 +
46955 +/**
46956 + *
46957 + * connection maps
46958 + *
46959 + */
46960 +
46961 +/* init the plugin data */
46962 +connection_map *connection_map_init() {
46963 +       connection_map *cm;
46964 +
46965 +       cm = calloc(1, sizeof(*cm));
46966 +
46967 +       return cm;
46968 +}
46969 +
46970 +void connection_map_free(connection_map *cm) {
46971 +       size_t i;
46972 +       for (i = 0; i < cm->size; i++) {
46973 +               connection_map_entry *cme = cm->ptr[i];
46974 +
46975 +               if (!cme) break;
46976 +
46977 +               if (cme->con_id) {
46978 +                       buffer_free(cme->con_id);
46979 +               }
46980 +               free(cme);
46981 +       }
46982 +
46983 +       free(cm);
46984 +}
46985 +
46986 +int connection_map_insert(connection_map *cm, connection *con, buffer *con_id) {
46987 +       connection_map_entry *cme;
46988 +       size_t i;
46989 +
46990 +       if (cm->size == 0) {
46991 +               cm->size = 16;
46992 +               cm->ptr = malloc(cm->size * sizeof(*(cm->ptr)));
46993 +               for (i = 0; i < cm->size; i++) {
46994 +                       cm->ptr[i] = NULL;
46995 +               }
46996 +       } else if (cm->used == cm->size) {
46997 +               cm->size += 16;
46998 +               cm->ptr = realloc(cm->ptr, cm->size * sizeof(*(cm->ptr)));
46999 +               for (i = cm->used; i < cm->size; i++) {
47000 +                       cm->ptr[i] = NULL;
47001 +               }
47002 +       }
47003 +
47004 +       if (cm->ptr[cm->used]) {
47005 +               /* is already alloced, just reuse it */
47006 +               cme = cm->ptr[cm->used];
47007 +       } else {
47008 +               cme = malloc(sizeof(*cme));
47009 +       }
47010 +       cme->con_id = buffer_init();
47011 +       buffer_copy_string_buffer(cme->con_id, con_id);
47012 +       cme->con = con;
47013 +
47014 +       cm->ptr[cm->used++] = cme;
47015 +
47016 +       return 0;
47017 +}
47018 +
47019 +connection *connection_map_get_connection(connection_map *cm, buffer *con_id) {
47020 +       size_t i;
47021 +
47022 +       for (i = 0; i < cm->used; i++) {
47023 +               connection_map_entry *cme = cm->ptr[i];
47024 +
47025 +               if (buffer_is_equal(cme->con_id, con_id)) {
47026 +                       /* found connection */
47027 +
47028 +                       return cme->con;
47029 +               }
47030 +       }
47031 +       return NULL;
47032 +}
47033 +
47034 +int connection_map_remove_connection(connection_map *cm, connection *con) {
47035 +       size_t i;
47036 +
47037 +       for (i = 0; i < cm->used; i++) {
47038 +               connection_map_entry *cme = cm->ptr[i];
47039 +
47040 +               if (cme->con == con) {
47041 +                       /* found connection */
47042 +
47043 +                       buffer_reset(cme->con_id);
47044 +                       cme->con = NULL;
47045 +
47046 +                       cm->used--;
47047 +
47048 +                       /* swap positions with the last entry */
47049 +                       if (cm->used) {
47050 +                               cm->ptr[i] = cm->ptr[cm->used];
47051 +                               cm->ptr[cm->used] = cme;
47052 +                       }
47053 +
47054 +                       return 1;
47055 +               }
47056 +       }
47057 +
47058 +       return 0;
47059 +}
47060 +
47061 +/* init the plugin data */
47062 +INIT_FUNC(mod_uploadprogress_init) {
47063 +       plugin_data *p;
47064 +
47065 +       p = calloc(1, sizeof(*p));
47066 +
47067 +       p->con_map = connection_map_init();
47068 +
47069 +       return p;
47070 +}
47071 +
47072 +/* detroy the plugin data */
47073 +FREE_FUNC(mod_uploadprogress_free) {
47074 +       plugin_data *p = p_d;
47075 +
47076 +       UNUSED(srv);
47077 +
47078 +       if (!p) return HANDLER_GO_ON;
47079 +
47080 +       if (p->config_storage) {
47081 +               size_t i;
47082 +               for (i = 0; i < srv->config_context->used; i++) {
47083 +                       plugin_config *s = p->config_storage[i];
47084 +
47085 +                       buffer_free(s->progress_url);
47086 +
47087 +                       free(s);
47088 +               }
47089 +               free(p->config_storage);
47090 +       }
47091 +
47092 +       connection_map_free(p->con_map);
47093 +
47094 +       free(p);
47095 +
47096 +       return HANDLER_GO_ON;
47097 +}
47098 +
47099 +/* handle plugin config and check values */
47100 +
47101 +SETDEFAULTS_FUNC(mod_uploadprogress_set_defaults) {
47102 +       plugin_data *p = p_d;
47103 +       size_t i = 0;
47104 +
47105 +       config_values_t cv[] = {
47106 +               { "upload-progress.progress-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
47107 +               { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
47108 +       };
47109 +
47110 +       if (!p) return HANDLER_ERROR;
47111 +
47112 +       p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
47113 +
47114 +       for (i = 0; i < srv->config_context->used; i++) {
47115 +               plugin_config *s;
47116 +
47117 +               s = calloc(1, sizeof(plugin_config));
47118 +               s->progress_url    = buffer_init();
47119 +
47120 +               cv[0].destination = s->progress_url;
47121 +
47122 +               p->config_storage[i] = s;
47123 +
47124 +               if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
47125 +                       return HANDLER_ERROR;
47126 +               }
47127 +       }
47128 +
47129 +       return HANDLER_GO_ON;
47130 +}
47131 +
47132 +static int mod_uploadprogress_patch_connection(server *srv, connection *con, plugin_data *p) {
47133 +       size_t i, j;
47134 +       plugin_config *s = p->config_storage[0];
47135 +
47136 +       PATCH_OPTION(progress_url);
47137 +
47138 +       /* skip the first, the global context */
47139 +       for (i = 1; i < srv->config_context->used; i++) {
47140 +               data_config *dc = (data_config *)srv->config_context->data[i];
47141 +               s = p->config_storage[i];
47142 +
47143 +               /* condition didn't match */
47144 +               if (!config_check_cond(srv, con, dc)) continue;
47145 +
47146 +               /* merge config */
47147 +               for (j = 0; j < dc->value->used; j++) {
47148 +                       data_unset *du = dc->value->data[j];
47149 +
47150 +                       if (buffer_is_equal_string(du->key, CONST_STR_LEN("upload-progress.progress-url"))) {
47151 +                               PATCH_OPTION(progress_url);
47152 +                       }
47153 +               }
47154 +       }
47155 +
47156 +       return 0;
47157 +}
47158 +
47159 +/**
47160 + *
47161 + * the idea:
47162 + *
47163 + * for the first request we check if it is a post-request
47164 + *
47165 + * if no, move out, don't care about them
47166 + *
47167 + * if yes, take the connection structure and register it locally
47168 + * in the progress-struct together with an session-id (md5 ... )
47169 + *
47170 + * if the connections closes, cleanup the entry in the progress-struct
47171 + *
47172 + * a second request can now get the info about the size of the upload,
47173 + * the received bytes
47174 + *
47175 + */
47176 +
47177 +URIHANDLER_FUNC(mod_uploadprogress_uri_handler) {
47178 +       plugin_data *p = p_d;
47179 +       size_t i;
47180 +       data_string *ds;
47181 +       buffer *b, *tracking_id;
47182 +       connection *post_con = NULL;
47183 +
47184 +       UNUSED(srv);
47185 +
47186 +       if (con->uri.path->used == 0) return HANDLER_GO_ON;
47187 +
47188 +       mod_uploadprogress_patch_connection(srv, con, p);
47189 +
47190 +       /* check if this is a POST request */
47191 +       switch(con->request.http_method) {
47192 +       case HTTP_METHOD_POST:
47193 +               /* the request has to contain a 32byte ID */
47194 +
47195 +               if (NULL == (ds = (data_string *)array_get_element(con->request.headers, "X-Progress-ID"))) {
47196 +                       if (!buffer_is_empty(con->uri.query)) {
47197 +                               /* perhaps the POST request is using the querystring to pass the X-Progress-ID */
47198 +                               b = con->uri.query;
47199 +                       } else {
47200 +                               return HANDLER_GO_ON;
47201 +                       }
47202 +               } else {
47203 +                       b = ds->value;
47204 +               }
47205 +
47206 +               if (b->used != 32 + 1) {
47207 +                       ERROR("the Progress-ID has to be 32 characters long, got %d characters", b->used - 1);
47208 +
47209 +                       return HANDLER_GO_ON;
47210 +               }
47211 +
47212 +               for (i = 0; i < b->used - 1; i++) {
47213 +                       char c = b->ptr[i];
47214 +
47215 +                       if (!light_isxdigit(c)) {
47216 +                               ERROR("only hex-digits are allowed (0-9 + a-f): (ascii: %d)", c);
47217 +
47218 +                               return HANDLER_GO_ON;
47219 +                       }
47220 +               }
47221 +
47222 +               connection_map_insert(p->con_map, con, b);
47223 +
47224 +               return HANDLER_GO_ON;
47225 +       case HTTP_METHOD_GET:
47226 +               if (!buffer_is_equal(con->uri.path, p->conf.progress_url)) {
47227 +                       return HANDLER_GO_ON;
47228 +               }
47229 +
47230 +               if (NULL == (ds = (data_string *)array_get_element(con->request.headers, "X-Progress-ID"))) {
47231 +                       if (!buffer_is_empty(con->uri.query)) {
47232 +                               /* perhaps the GET request is using the querystring to pass the X-Progress-ID */
47233 +                               tracking_id = con->uri.query;
47234 +                       } else {
47235 +                               return HANDLER_GO_ON;
47236 +                       }
47237 +               } else {
47238 +                       tracking_id = ds->value;
47239 +               }
47240 +
47241 +               if (tracking_id->used != 32 + 1) {
47242 +                       ERROR("the Progress-ID has to be 32 characters long, got %d characters", tracking_id->used - 1);
47243 +
47244 +                       return HANDLER_GO_ON;
47245 +               }
47246 +
47247 +               for (i = 0; i < tracking_id->used - 1; i++) {
47248 +                       char c = tracking_id->ptr[i];
47249 +
47250 +                       if (!light_isxdigit(c)) {
47251 +                               ERROR("only hex-digits are allowed (0-9 + a-f): (ascii: %d)", c);
47252 +
47253 +                               return HANDLER_GO_ON;
47254 +                       }
47255 +               }
47256 +
47257 +               buffer_reset(con->physical.path);
47258 +
47259 +               con->file_started = 1;
47260 +               con->http_status = 200;
47261 +               con->send->is_closed = 1;
47262 +
47263 +               /* send JSON content */
47264 +
47265 +               response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/javascript"));
47266 +
47267 +               /* just an attempt the force the IE/proxies to NOT cache the request */
47268 +               response_header_overwrite(srv, con, CONST_STR_LEN("Pragma"), CONST_STR_LEN("no-cache"));
47269 +               response_header_overwrite(srv, con, CONST_STR_LEN("Expires"), CONST_STR_LEN("Thu, 19 Nov 1981 08:52:00 GMT"));
47270 +               response_header_overwrite(srv, con, CONST_STR_LEN("Cache-Control"), 
47271 +                               CONST_STR_LEN("no-store, no-cache, must-revalidate, post-check=0, pre-check=0"));
47272 +
47273 +               b = chunkqueue_get_append_buffer(con->send);
47274 +
47275 +               /* get the connection */
47276 +               if (NULL == (post_con = connection_map_get_connection(p->con_map, tracking_id))) {
47277 +                       BUFFER_APPEND_STRING_CONST(b, "new Object({ 'status' : 'starting' })\r\n");
47278 +
47279 +                       return HANDLER_FINISHED;
47280 +               }
47281 +
47282 +               /* prepare XML */
47283 +               BUFFER_COPY_STRING_CONST(b, "new Object({ 'state' : ");
47284 +               buffer_append_string(b, post_con->recv->is_closed ? "'done'" : "'uploading'");
47285 +               BUFFER_APPEND_STRING_CONST(b, ", 'size' : ");
47286 +               buffer_append_off_t(b, post_con->request.content_length == -1 ? 0 : post_con->request.content_length);
47287 +               BUFFER_APPEND_STRING_CONST(b, ", 'received' : ");
47288 +               buffer_append_off_t(b, post_con->recv->bytes_in);
47289 +               BUFFER_APPEND_STRING_CONST(b, "})\r\n");
47290 +
47291 +               return HANDLER_FINISHED;
47292 +       default:
47293 +               break;
47294 +       }
47295 +
47296 +       return HANDLER_GO_ON;
47297 +}
47298 +
47299 +REQUESTDONE_FUNC(mod_uploadprogress_request_done) {
47300 +       plugin_data *p = p_d;
47301 +
47302 +       UNUSED(srv);
47303 +
47304 +       if (con->uri.path->used == 0) return HANDLER_GO_ON;
47305 +
47306 +       if (connection_map_remove_connection(p->con_map, con)) {
47307 +               /* removed */
47308 +       }
47309 +
47310 +       return HANDLER_GO_ON;
47311 +}
47312 +
47313 +/* this function is called at dlopen() time and inits the callbacks */
47314 +
47315 +int mod_uploadprogress_plugin_init(plugin *p) {
47316 +       p->version     = LIGHTTPD_VERSION_ID;
47317 +       p->name        = buffer_init_string("uploadprogress");
47318 +
47319 +       p->init        = mod_uploadprogress_init;
47320 +       p->handle_uri_clean = mod_uploadprogress_uri_handler;
47321 +       p->handle_response_done  = mod_uploadprogress_request_done;
47322 +       p->set_defaults  = mod_uploadprogress_set_defaults;
47323 +       p->cleanup     = mod_uploadprogress_free;
47324 +
47325 +       p->data        = NULL;
47326 +
47327 +       return 0;
47328 +}
47329 --- ../lighttpd-1.4.11/src/mod_userdir.c        2005-10-28 16:48:28.000000000 +0300
47330 +++ lighttpd-1.5.0/src/mod_userdir.c    2006-07-16 00:26:04.000000000 +0300
47331 @@ -10,6 +10,7 @@
47332  #include "response.h"
47333  
47334  #include "plugin.h"
47335 +#include "sys-files.h"
47336  
47337  #ifdef HAVE_PWD_H
47338  #include <pwd.h>
47339 @@ -25,54 +26,54 @@
47340  
47341  typedef struct {
47342         PLUGIN_DATA;
47343 -       
47344 +
47345         buffer *username;
47346         buffer *temp_path;
47347 -       
47348 +
47349         plugin_config **config_storage;
47350 -       
47351 -       plugin_config conf; 
47352 +
47353 +       plugin_config conf;
47354  } plugin_data;
47355  
47356  /* init the plugin data */
47357  INIT_FUNC(mod_userdir_init) {
47358         plugin_data *p;
47359 -       
47360 +
47361         p = calloc(1, sizeof(*p));
47362 -       
47363 +
47364         p->username = buffer_init();
47365         p->temp_path = buffer_init();
47366 -       
47367 +
47368         return p;
47369  }
47370  
47371  /* detroy the plugin data */
47372  FREE_FUNC(mod_userdir_free) {
47373         plugin_data *p = p_d;
47374 -       
47375 +
47376         if (!p) return HANDLER_GO_ON;
47377 -       
47378 +
47379         if (p->config_storage) {
47380                 size_t i;
47381 -               
47382 +
47383                 for (i = 0; i < srv->config_context->used; i++) {
47384                         plugin_config *s = p->config_storage[i];
47385 -                       
47386 +
47387                         array_free(s->include_user);
47388                         array_free(s->exclude_user);
47389                         buffer_free(s->path);
47390                         buffer_free(s->basepath);
47391 -                       
47392 +
47393                         free(s);
47394                 }
47395                 free(p->config_storage);
47396         }
47397 -       
47398 +
47399         buffer_free(p->username);
47400         buffer_free(p->temp_path);
47401 -       
47402 +
47403         free(p);
47404 -       
47405 +
47406         return HANDLER_GO_ON;
47407  }
47408  
47409 @@ -81,81 +82,78 @@
47410  SETDEFAULTS_FUNC(mod_userdir_set_defaults) {
47411         plugin_data *p = p_d;
47412         size_t i;
47413 -       
47414 -       config_values_t cv[] = { 
47415 +
47416 +       config_values_t cv[] = {
47417                 { "userdir.path",               NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
47418                 { "userdir.exclude-user",       NULL, T_CONFIG_ARRAY,  T_CONFIG_SCOPE_CONNECTION },       /* 1 */
47419                 { "userdir.include-user",       NULL, T_CONFIG_ARRAY,  T_CONFIG_SCOPE_CONNECTION },       /* 2 */
47420                 { "userdir.basepath",           NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 3 */
47421                 { NULL,                         NULL, T_CONFIG_UNSET,  T_CONFIG_SCOPE_UNSET }
47422         };
47423 -       
47424 +
47425         if (!p) return HANDLER_ERROR;
47426 -       
47427 +
47428         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
47429 -       
47430 +
47431         for (i = 0; i < srv->config_context->used; i++) {
47432                 plugin_config *s;
47433 -               
47434 +
47435                 s = calloc(1, sizeof(plugin_config));
47436                 s->exclude_user = array_init();
47437                 s->include_user = array_init();
47438                 s->path = buffer_init();
47439                 s->basepath = buffer_init();
47440 -       
47441 +
47442                 cv[0].destination = s->path;
47443                 cv[1].destination = s->exclude_user;
47444                 cv[2].destination = s->include_user;
47445                 cv[3].destination = s->basepath;
47446 -               
47447 +
47448                 p->config_storage[i] = s;
47449 -       
47450 +
47451                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
47452                         return HANDLER_ERROR;
47453                 }
47454         }
47455 -       
47456 +
47457         return HANDLER_GO_ON;
47458  }
47459  
47460 -#define PATCH(x) \
47461 -       p->conf.x = s->x;
47462  static int mod_userdir_patch_connection(server *srv, connection *con, plugin_data *p) {
47463         size_t i, j;
47464         plugin_config *s = p->config_storage[0];
47465 -       
47466 -       PATCH(path);
47467 -       PATCH(exclude_user);
47468 -       PATCH(include_user);
47469 -       PATCH(basepath);
47470 -       
47471 +
47472 +       PATCH_OPTION(path);
47473 +       PATCH_OPTION(exclude_user);
47474 +       PATCH_OPTION(include_user);
47475 +       PATCH_OPTION(basepath);
47476 +
47477         /* skip the first, the global context */
47478         for (i = 1; i < srv->config_context->used; i++) {
47479                 data_config *dc = (data_config *)srv->config_context->data[i];
47480                 s = p->config_storage[i];
47481 -               
47482 +
47483                 /* condition didn't match */
47484                 if (!config_check_cond(srv, con, dc)) continue;
47485 -               
47486 +
47487                 /* merge config */
47488                 for (j = 0; j < dc->value->used; j++) {
47489                         data_unset *du = dc->value->data[j];
47490 -                       
47491 +
47492                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.path"))) {
47493 -                               PATCH(path);
47494 +                               PATCH_OPTION(path);
47495                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.exclude-user"))) {
47496 -                               PATCH(exclude_user);
47497 +                               PATCH_OPTION(exclude_user);
47498                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.include-user"))) {
47499 -                               PATCH(include_user);
47500 +                               PATCH_OPTION(include_user);
47501                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.basepath"))) {
47502 -                               PATCH(basepath);
47503 +                               PATCH_OPTION(basepath);
47504                         }
47505                 }
47506         }
47507 -       
47508 +
47509         return 0;
47510  }
47511 -#undef PATCH
47512  
47513  URIHANDLER_FUNC(mod_userdir_docroot_handler) {
47514         plugin_data *p = p_d;
47515 @@ -169,18 +167,18 @@
47516         if (con->uri.path->used == 0) return HANDLER_GO_ON;
47517  
47518         mod_userdir_patch_connection(srv, con, p);
47519 -       
47520 +
47521         uri_len = con->uri.path->used - 1;
47522 -       
47523 +
47524         /* /~user/foo.html -> /home/user/public_html/foo.html */
47525 -       
47526 +
47527         if (con->uri.path->ptr[0] != '/' ||
47528             con->uri.path->ptr[1] != '~') return HANDLER_GO_ON;
47529 -       
47530 +
47531         if (NULL == (rel_url = strchr(con->uri.path->ptr + 2, '/'))) {
47532                 /* / is missing -> redirect to .../ as we are a user - DIRECTORY ! :) */
47533                 http_response_redirect_to_directory(srv, con);
47534 -               
47535 +
47536                 return HANDLER_FINISHED;
47537         }
47538  
47539 @@ -188,10 +186,10 @@
47540         if (0 == rel_url - (con->uri.path->ptr + 2)) {
47541                 return HANDLER_GO_ON;
47542         }
47543 -       
47544 +
47545         buffer_copy_string_len(p->username, con->uri.path->ptr + 2, rel_url - (con->uri.path->ptr + 2));
47546 -       
47547 -       if (buffer_is_empty(p->conf.basepath) 
47548 +
47549 +       if (buffer_is_empty(p->conf.basepath)
47550  #ifdef HAVE_PWD_H
47551             && NULL == (pwd = getpwnam(p->username->ptr))
47552  #endif
47553 @@ -200,31 +198,31 @@
47554                 return HANDLER_GO_ON;
47555         }
47556  
47557 -       
47558 +
47559         for (k = 0; k < p->conf.exclude_user->used; k++) {
47560                 data_string *ds = (data_string *)p->conf.exclude_user->data[k];
47561 -               
47562 +
47563                 if (buffer_is_equal(ds->value, p->username)) {
47564                         /* user in exclude list */
47565                         return HANDLER_GO_ON;
47566                 }
47567         }
47568 -       
47569 +
47570         if (p->conf.include_user->used) {
47571                 int found_user = 0;
47572                 for (k = 0; k < p->conf.include_user->used; k++) {
47573                         data_string *ds = (data_string *)p->conf.include_user->data[k];
47574 -                       
47575 +
47576                         if (buffer_is_equal(ds->value, p->username)) {
47577                                 /* user in include list */
47578                                 found_user = 1;
47579                                 break;
47580                         }
47581                 }
47582 -               
47583 +
47584                 if (!found_user) return HANDLER_GO_ON;
47585         }
47586 -       
47587 +
47588         /* we build the physical path */
47589  
47590         if (buffer_is_empty(p->conf.basepath)) {
47591 @@ -252,23 +250,23 @@
47592                 }
47593  
47594                 buffer_copy_string_buffer(p->temp_path, p->conf.basepath);
47595 -               BUFFER_APPEND_SLASH(p->temp_path);
47596 +               PATHNAME_APPEND_SLASH(p->temp_path);
47597                 buffer_append_string_buffer(p->temp_path, p->username);
47598         }
47599 -       BUFFER_APPEND_SLASH(p->temp_path);
47600 -       buffer_append_string_buffer(p->temp_path, p->conf.path); 
47601 +       PATHNAME_APPEND_SLASH(p->temp_path);
47602 +       buffer_append_string_buffer(p->temp_path, p->conf.path);
47603  
47604         if (buffer_is_empty(p->conf.basepath)) {
47605                 struct stat st;
47606                 int ret;
47607 -               
47608 +
47609                 ret = stat(p->temp_path->ptr, &st);
47610                 if (ret < 0 || S_ISDIR(st.st_mode) != 1) {
47611                         return HANDLER_GO_ON;
47612 -               } 
47613 +               }
47614         }
47615  
47616 -       BUFFER_APPEND_SLASH(p->temp_path);
47617 +       PATHNAME_APPEND_SLASH(p->temp_path);
47618         buffer_append_string(p->temp_path, rel_url + 1); /* skip the / */
47619         buffer_copy_string_buffer(con->physical.path, p->temp_path);
47620  
47621 @@ -282,13 +280,13 @@
47622  int mod_userdir_plugin_init(plugin *p) {
47623         p->version     = LIGHTTPD_VERSION_ID;
47624         p->name        = buffer_init_string("userdir");
47625 -       
47626 +
47627         p->init           = mod_userdir_init;
47628         p->handle_physical = mod_userdir_docroot_handler;
47629         p->set_defaults   = mod_userdir_set_defaults;
47630         p->cleanup        = mod_userdir_free;
47631 -       
47632 +
47633         p->data        = NULL;
47634 -       
47635 +
47636         return 0;
47637  }
47638 --- ../lighttpd-1.4.11/src/mod_usertrack.c      2006-01-31 15:01:20.000000000 +0200
47639 +++ lighttpd-1.5.0/src/mod_usertrack.c  2006-07-16 00:26:04.000000000 +0300
47640 @@ -24,44 +24,44 @@
47641  
47642  typedef struct {
47643         PLUGIN_DATA;
47644 -       
47645 +
47646         plugin_config **config_storage;
47647 -       
47648 -       plugin_config conf; 
47649 +
47650 +       plugin_config conf;
47651  } plugin_data;
47652  
47653  /* init the plugin data */
47654  INIT_FUNC(mod_usertrack_init) {
47655         plugin_data *p;
47656 -       
47657 +
47658         p = calloc(1, sizeof(*p));
47659 -       
47660 +
47661         return p;
47662  }
47663  
47664  /* detroy the plugin data */
47665  FREE_FUNC(mod_usertrack_free) {
47666         plugin_data *p = p_d;
47667 -       
47668 +
47669         UNUSED(srv);
47670 -       
47671 +
47672         if (!p) return HANDLER_GO_ON;
47673 -       
47674 +
47675         if (p->config_storage) {
47676                 size_t i;
47677                 for (i = 0; i < srv->config_context->used; i++) {
47678                         plugin_config *s = p->config_storage[i];
47679 -                       
47680 +
47681                         buffer_free(s->cookie_name);
47682                         buffer_free(s->cookie_domain);
47683 -                       
47684 +
47685                         free(s);
47686                 }
47687                 free(p->config_storage);
47688         }
47689 -       
47690 +
47691         free(p);
47692 -       
47693 +
47694         return HANDLER_GO_ON;
47695  }
47696  
47697 @@ -70,38 +70,38 @@
47698  SETDEFAULTS_FUNC(mod_usertrack_set_defaults) {
47699         plugin_data *p = p_d;
47700         size_t i = 0;
47701 -       
47702 -       config_values_t cv[] = { 
47703 +
47704 +       config_values_t cv[] = {
47705                 { "usertrack.cookie-name",       NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
47706                 { "usertrack.cookie-max-age",    NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 1 */
47707                 { "usertrack.cookie-domain",     NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
47708 -               
47709 -               { "usertrack.cookiename",        NULL, T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_CONNECTION },   
47710 +
47711 +               { "usertrack.cookiename",        NULL, T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_CONNECTION },
47712                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
47713         };
47714 -       
47715 +
47716         if (!p) return HANDLER_ERROR;
47717 -       
47718 +
47719         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
47720 -       
47721 +
47722         for (i = 0; i < srv->config_context->used; i++) {
47723                 plugin_config *s;
47724 -               
47725 +
47726                 s = calloc(1, sizeof(plugin_config));
47727                 s->cookie_name    = buffer_init();
47728                 s->cookie_domain  = buffer_init();
47729                 s->cookie_max_age = 0;
47730 -               
47731 +
47732                 cv[0].destination = s->cookie_name;
47733                 cv[1].destination = &(s->cookie_max_age);
47734                 cv[2].destination = s->cookie_domain;
47735 -               
47736 +
47737                 p->config_storage[i] = s;
47738 -       
47739 +
47740                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
47741                         return HANDLER_ERROR;
47742                 }
47743 -       
47744 +
47745                 if (buffer_is_empty(s->cookie_name)) {
47746                         buffer_copy_string(s->cookie_name, "TRACKID");
47747                 } else {
47748 @@ -109,68 +109,65 @@
47749                         for (j = 0; j < s->cookie_name->used - 1; j++) {
47750                                 char c = s->cookie_name->ptr[j] | 32;
47751                                 if (c < 'a' || c > 'z') {
47752 -                                       log_error_write(srv, __FILE__, __LINE__, "sb", 
47753 -                                                       "invalid character in usertrack.cookie-name:", 
47754 +                                       log_error_write(srv, __FILE__, __LINE__, "sb",
47755 +                                                       "invalid character in usertrack.cookie-name:",
47756                                                         s->cookie_name);
47757 -                                       
47758 +
47759                                         return HANDLER_ERROR;
47760                                 }
47761                         }
47762                 }
47763 -               
47764 +
47765                 if (!buffer_is_empty(s->cookie_domain)) {
47766                         size_t j;
47767                         for (j = 0; j < s->cookie_domain->used - 1; j++) {
47768                                 char c = s->cookie_domain->ptr[j];
47769                                 if (c <= 32 || c >= 127 || c == '"' || c == '\\') {
47770 -                                       log_error_write(srv, __FILE__, __LINE__, "sb", 
47771 -                                                       "invalid character in usertrack.cookie-domain:", 
47772 +                                       log_error_write(srv, __FILE__, __LINE__, "sb",
47773 +                                                       "invalid character in usertrack.cookie-domain:",
47774                                                         s->cookie_domain);
47775 -                                       
47776 +
47777                                         return HANDLER_ERROR;
47778                                 }
47779                         }
47780                 }
47781         }
47782 -               
47783 +
47784         return HANDLER_GO_ON;
47785  }
47786  
47787 -#define PATCH(x) \
47788 -       p->conf.x = s->x;
47789  static int mod_usertrack_patch_connection(server *srv, connection *con, plugin_data *p) {
47790         size_t i, j;
47791         plugin_config *s = p->config_storage[0];
47792 -       
47793 -       PATCH(cookie_name);
47794 -       PATCH(cookie_domain);
47795 -       PATCH(cookie_max_age);
47796 -       
47797 +
47798 +       PATCH_OPTION(cookie_name);
47799 +       PATCH_OPTION(cookie_domain);
47800 +       PATCH_OPTION(cookie_max_age);
47801 +
47802         /* skip the first, the global context */
47803         for (i = 1; i < srv->config_context->used; i++) {
47804                 data_config *dc = (data_config *)srv->config_context->data[i];
47805                 s = p->config_storage[i];
47806 -               
47807 +
47808                 /* condition didn't match */
47809                 if (!config_check_cond(srv, con, dc)) continue;
47810 -               
47811 +
47812                 /* merge config */
47813                 for (j = 0; j < dc->value->used; j++) {
47814                         data_unset *du = dc->value->data[j];
47815 -                       
47816 +
47817                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-name"))) {
47818 -                               PATCH(cookie_name);
47819 +                               PATCH_OPTION(cookie_name);
47820                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-max-age"))) {
47821 -                               PATCH(cookie_max_age);
47822 +                               PATCH_OPTION(cookie_max_age);
47823                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-domain"))) {
47824 -                               PATCH(cookie_domain);
47825 +                               PATCH_OPTION(cookie_domain);
47826                         }
47827                 }
47828         }
47829 -       
47830 +
47831         return 0;
47832  }
47833 -#undef PATCH
47834  
47835  URIHANDLER_FUNC(mod_usertrack_uri_handler) {
47836         plugin_data *p = p_d;
47837 @@ -178,38 +175,38 @@
47838         unsigned char h[16];
47839         MD5_CTX Md5Ctx;
47840         char hh[32];
47841 -       
47842 +
47843         if (con->uri.path->used == 0) return HANDLER_GO_ON;
47844 -       
47845 +
47846         mod_usertrack_patch_connection(srv, con, p);
47847 -       
47848 +
47849         if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Cookie"))) {
47850                 char *g;
47851                 /* we have a cookie, does it contain a valid name ? */
47852 -               
47853 -               /* parse the cookie 
47854 -                * 
47855 +
47856 +               /* parse the cookie
47857 +                *
47858                  * check for cookiename + (WS | '=')
47859 -                * 
47860 +                *
47861                  */
47862 -               
47863 +
47864                 if (NULL != (g = strstr(ds->value->ptr, p->conf.cookie_name->ptr))) {
47865                         char *nc;
47866 -                       
47867 +
47868                         /* skip WS */
47869                         for (nc = g + p->conf.cookie_name->used-1; *nc == ' ' || *nc == '\t'; nc++);
47870 -                       
47871 +
47872                         if (*nc == '=') {
47873                                 /* ok, found the key of our own cookie */
47874 -                               
47875 +
47876                                 if (strlen(nc) > 32) {
47877                                         /* i'm lazy */
47878                                         return HANDLER_GO_ON;
47879                                 }
47880                         }
47881                 }
47882 -       } 
47883 -       
47884 +       }
47885 +
47886         /* set a cookie */
47887         if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
47888                 ds = data_response_init();
47889 @@ -217,39 +214,39 @@
47890         buffer_copy_string(ds->key, "Set-Cookie");
47891         buffer_copy_string_buffer(ds->value, p->conf.cookie_name);
47892         buffer_append_string(ds->value, "=");
47893 -       
47894 +
47895  
47896         /* taken from mod_auth.c */
47897 -       
47898 +
47899         /* generate shared-secret */
47900         MD5_Init(&Md5Ctx);
47901         MD5_Update(&Md5Ctx, (unsigned char *)con->uri.path->ptr, con->uri.path->used - 1);
47902         MD5_Update(&Md5Ctx, (unsigned char *)"+", 1);
47903 -       
47904 +
47905         /* we assume sizeof(time_t) == 4 here, but if not it ain't a problem at all */
47906         ltostr(hh, srv->cur_ts);
47907         MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
47908         ltostr(hh, rand());
47909         MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
47910 -       
47911 +
47912         MD5_Final(h, &Md5Ctx);
47913 -       
47914 +
47915         buffer_append_string_encoded(ds->value, (char *)h, 16, ENCODING_HEX);
47916         buffer_append_string(ds->value, "; Path=/");
47917         buffer_append_string(ds->value, "; Version=1");
47918 -       
47919 +
47920         if (!buffer_is_empty(p->conf.cookie_domain)) {
47921                 buffer_append_string(ds->value, "; Domain=");
47922                 buffer_append_string_encoded(ds->value, CONST_BUF_LEN(p->conf.cookie_domain), ENCODING_REL_URI);
47923         }
47924 -       
47925 +
47926         if (p->conf.cookie_max_age) {
47927                 buffer_append_string(ds->value, "; max-age=");
47928                 buffer_append_long(ds->value, p->conf.cookie_max_age);
47929         }
47930 -       
47931 +
47932         array_insert_unique(con->response.headers, (data_unset *)ds);
47933 -       
47934 +
47935         return HANDLER_GO_ON;
47936  }
47937  
47938 @@ -258,13 +255,13 @@
47939  int mod_usertrack_plugin_init(plugin *p) {
47940         p->version     = LIGHTTPD_VERSION_ID;
47941         p->name        = buffer_init_string("usertrack");
47942 -       
47943 +
47944         p->init        = mod_usertrack_init;
47945         p->handle_uri_clean  = mod_usertrack_uri_handler;
47946         p->set_defaults  = mod_usertrack_set_defaults;
47947         p->cleanup     = mod_usertrack_free;
47948 -       
47949 +
47950         p->data        = NULL;
47951 -       
47952 +
47953         return 0;
47954  }
47955 --- ../lighttpd-1.4.11/src/mod_webdav.c 2006-03-03 01:28:58.000000000 +0200
47956 +++ lighttpd-1.5.0/src/mod_webdav.c     2006-09-07 00:57:05.000000000 +0300
47957 @@ -3,13 +3,10 @@
47958  #include <ctype.h>
47959  #include <stdlib.h>
47960  #include <string.h>
47961 -#include <dirent.h>
47962  #include <errno.h>
47963 -#include <unistd.h>
47964  #include <fcntl.h>
47965  #include <stdio.h>
47966  #include <assert.h>
47967 -#include <sys/mman.h>
47968  
47969  #ifdef HAVE_CONFIG_H
47970  #include "config.h"
47971 @@ -23,6 +20,11 @@
47972  #include <sqlite3.h>
47973  #endif
47974  
47975 +#if defined(HAVE_LIBXML_H) && defined(HAVE_SQLITE3_H) && defined(HAVE_UUID_H)
47976 +#define USE_LOCKS
47977 +#include <uuid/uuid.h>
47978 +#endif
47979 +
47980  #include "base.h"
47981  #include "log.h"
47982  #include "buffer.h"
47983 @@ -33,13 +35,16 @@
47984  #include "stream.h"
47985  #include "stat_cache.h"
47986  
47987 +#include "sys-files.h"
47988 +#include "sys-mmap.h"
47989 +#include "sys-strings.h"
47990  
47991  /**
47992   * this is a webdav for a lighttpd plugin
47993   *
47994 - * at least a very basic one. 
47995 + * at least a very basic one.
47996   * - for now it is read-only and we only support PROPFIND
47997 - * 
47998 + *
47999   */
48000  
48001  
48002 @@ -58,64 +63,70 @@
48003         sqlite3_stmt *stmt_delete_prop;
48004         sqlite3_stmt *stmt_select_prop;
48005         sqlite3_stmt *stmt_select_propnames;
48006 -       
48007 +
48008         sqlite3_stmt *stmt_delete_uri;
48009         sqlite3_stmt *stmt_move_uri;
48010         sqlite3_stmt *stmt_copy_uri;
48011 +
48012 +       sqlite3_stmt *stmt_remove_lock;
48013 +       sqlite3_stmt *stmt_create_lock;
48014 +       sqlite3_stmt *stmt_read_lock;
48015 +       sqlite3_stmt *stmt_read_lock_by_uri;
48016 +       sqlite3_stmt *stmt_refresh_lock;
48017  #endif
48018  } plugin_config;
48019  
48020  typedef struct {
48021         PLUGIN_DATA;
48022 -       
48023 +
48024         buffer *tmp_buf;
48025         request_uri uri;
48026         physical physical;
48027  
48028         plugin_config **config_storage;
48029 -       
48030 -       plugin_config conf; 
48031 +
48032 +       plugin_config conf;
48033  } plugin_data;
48034  
48035  /* init the plugin data */
48036  INIT_FUNC(mod_webdav_init) {
48037         plugin_data *p;
48038 -       
48039 +
48040         p = calloc(1, sizeof(*p));
48041 -       
48042 +
48043         p->tmp_buf = buffer_init();
48044  
48045         p->uri.scheme = buffer_init();
48046         p->uri.path_raw = buffer_init();
48047         p->uri.path = buffer_init();
48048         p->uri.authority = buffer_init();
48049 -       
48050 +
48051         p->physical.path = buffer_init();
48052         p->physical.rel_path = buffer_init();
48053         p->physical.doc_root = buffer_init();
48054         p->physical.basedir = buffer_init();
48055 -       
48056 +
48057         return p;
48058  }
48059  
48060  /* detroy the plugin data */
48061  FREE_FUNC(mod_webdav_free) {
48062         plugin_data *p = p_d;
48063 -       
48064 +
48065         UNUSED(srv);
48066  
48067         if (!p) return HANDLER_GO_ON;
48068 -       
48069 +
48070         if (p->config_storage) {
48071                 size_t i;
48072                 for (i = 0; i < srv->config_context->used; i++) {
48073                         plugin_config *s = p->config_storage[i];
48074  
48075                         if (!s) continue;
48076 -       
48077 +
48078                         buffer_free(s->sqlite_db_name);
48079  #ifdef USE_PROPPATCH
48080 -                       if (s->sql) {   
48081 +                       if (s->sql) {
48082                                 sqlite3_finalize(s->stmt_delete_prop);
48083                                 sqlite3_finalize(s->stmt_delete_uri);
48084                                 sqlite3_finalize(s->stmt_copy_uri);
48085 @@ -123,9 +134,15 @@
48086                                 sqlite3_finalize(s->stmt_update_prop);
48087                                 sqlite3_finalize(s->stmt_select_prop);
48088                                 sqlite3_finalize(s->stmt_select_propnames);
48089 +
48090 +                               sqlite3_finalize(s->stmt_read_lock);
48091 +                               sqlite3_finalize(s->stmt_read_lock_by_uri);
48092 +                               sqlite3_finalize(s->stmt_create_lock);
48093 +                               sqlite3_finalize(s->stmt_remove_lock);
48094 +                               sqlite3_finalize(s->stmt_refresh_lock);
48095                                 sqlite3_close(s->sql);
48096                         }
48097 -#endif 
48098 +#endif
48099                         free(s);
48100                 }
48101                 free(p->config_storage);
48102 @@ -135,16 +152,16 @@
48103         buffer_free(p->uri.path_raw);
48104         buffer_free(p->uri.path);
48105         buffer_free(p->uri.authority);
48106 -       
48107 +
48108         buffer_free(p->physical.path);
48109         buffer_free(p->physical.rel_path);
48110         buffer_free(p->physical.doc_root);
48111         buffer_free(p->physical.basedir);
48112 -       
48113 +
48114         buffer_free(p->tmp_buf);
48115 -       
48116 +
48117         free(p);
48118 -       
48119 +
48120         return HANDLER_GO_ON;
48121  }
48122  
48123 @@ -153,32 +170,32 @@
48124  SETDEFAULTS_FUNC(mod_webdav_set_defaults) {
48125         plugin_data *p = p_d;
48126         size_t i = 0;
48127 -       
48128 -       config_values_t cv[] = { 
48129 +
48130 +       config_values_t cv[] = {
48131                 { "webdav.activate",            NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
48132                 { "webdav.is-readonly",         NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
48133                 { "webdav.sqlite-db-name",      NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_CONNECTION },       /* 2 */
48134                 { "webdav.log-xml",             NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },       /* 3 */
48135                 { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
48136         };
48137 -       
48138 +
48139         if (!p) return HANDLER_ERROR;
48140 -       
48141 +
48142         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
48143 -       
48144 +
48145         for (i = 0; i < srv->config_context->used; i++) {
48146                 plugin_config *s;
48147 -               
48148 +
48149                 s = calloc(1, sizeof(plugin_config));
48150                 s->sqlite_db_name = buffer_init();
48151 -               
48152 +
48153                 cv[0].destination = &(s->enabled);
48154                 cv[1].destination = &(s->is_readonly);
48155                 cv[2].destination = s->sqlite_db_name;
48156                 cv[3].destination = &(s->log_xml);
48157 -               
48158 +
48159                 p->config_storage[i] = s;
48160 -       
48161 +
48162                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
48163                         return HANDLER_ERROR;
48164                 }
48165 @@ -193,8 +210,26 @@
48166                                 return HANDLER_ERROR;
48167                         }
48168  
48169 -                       if (SQLITE_OK != sqlite3_prepare(s->sql, 
48170 -                               CONST_STR_LEN("SELECT value FROM properties WHERE resource = ? AND prop = ? AND ns = ?"), 
48171 +                       if (SQLITE_OK != sqlite3_exec(s->sql,
48172 +                                       "CREATE TABLE properties ("
48173 +                                       "  resource TEXT NOT NULL,"
48174 +                                       "  prop TEXT NOT NULL,"
48175 +                                       "  ns TEXT NOT NULL,"
48176 +                                       "  value TEXT NOT NULL,"
48177 +                                       "  PRIMARY KEY(resource, prop, ns))",
48178 +                                       NULL, NULL, &err)) {
48179 +
48180 +                               if (0 != strcmp(err, "table properties already exists")) {
48181 +                                       log_error_write(srv, __FILE__, __LINE__, "ss", "can't open transaction:", err);
48182 +                                       sqlite3_free(err);
48183 +
48184 +                                       return HANDLER_ERROR;
48185 +                               }
48186 +                               sqlite3_free(err);
48187 +                       }
48188 +
48189 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
48190 +                               CONST_STR_LEN("SELECT value FROM properties WHERE resource = ? AND prop = ? AND ns = ?"),
48191                                 &(s->stmt_select_prop), &next_stmt)) {
48192                                 /* prepare failed */
48193  
48194 @@ -202,8 +237,8 @@
48195                                 return HANDLER_ERROR;
48196                         }
48197  
48198 -                       if (SQLITE_OK != sqlite3_prepare(s->sql, 
48199 -                               CONST_STR_LEN("SELECT ns, prop FROM properties WHERE resource = ?"), 
48200 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
48201 +                               CONST_STR_LEN("SELECT ns, prop FROM properties WHERE resource = ?"),
48202                                 &(s->stmt_select_propnames), &next_stmt)) {
48203                                 /* prepare failed */
48204  
48205 @@ -211,16 +246,67 @@
48206                                 return HANDLER_ERROR;
48207                         }
48208  
48209 -                       if (SQLITE_OK != sqlite3_exec(s->sql, 
48210 -                                       "CREATE TABLE properties ("
48211 +
48212 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
48213 +                               CONST_STR_LEN("REPLACE INTO properties (resource, prop, ns, value) VALUES (?, ?, ?, ?)"),
48214 +                               &(s->stmt_update_prop), &next_stmt)) {
48215 +                               /* prepare failed */
48216 +
48217 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed:", sqlite3_errmsg(s->sql));
48218 +                               return HANDLER_ERROR;
48219 +                       }
48220 +
48221 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
48222 +                               CONST_STR_LEN("DELETE FROM properties WHERE resource = ? AND prop = ? AND ns = ?"),
48223 +                               &(s->stmt_delete_prop), &next_stmt)) {
48224 +                               /* prepare failed */
48225 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
48226 +
48227 +                               return HANDLER_ERROR;
48228 +                       }
48229 +
48230 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
48231 +                               CONST_STR_LEN("DELETE FROM properties WHERE resource = ?"),
48232 +                               &(s->stmt_delete_uri), &next_stmt)) {
48233 +                               /* prepare failed */
48234 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
48235 +
48236 +                               return HANDLER_ERROR;
48237 +                       }
48238 +
48239 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
48240 +                               CONST_STR_LEN("INSERT INTO properties SELECT ?, prop, ns, value FROM properties WHERE resource = ?"),
48241 +                               &(s->stmt_copy_uri), &next_stmt)) {
48242 +                               /* prepare failed */
48243 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
48244 +
48245 +                               return HANDLER_ERROR;
48246 +                       }
48247 +
48248 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
48249 +                               CONST_STR_LEN("UPDATE properties SET resource = ? WHERE resource = ?"),
48250 +                               &(s->stmt_move_uri), &next_stmt)) {
48251 +                               /* prepare failed */
48252 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
48253 +
48254 +                               return HANDLER_ERROR;
48255 +                       }
48256 +
48257 +                       /* LOCKS */
48258 +
48259 +                       if (SQLITE_OK != sqlite3_exec(s->sql,
48260 +                                       "CREATE TABLE locks ("
48261 +                                       "  locktoken TEXT NOT NULL,"
48262                                         "  resource TEXT NOT NULL,"
48263 -                                       "  prop TEXT NOT NULL,"
48264 -                                       "  ns TEXT NOT NULL,"
48265 -                                       "  value TEXT NOT NULL,"
48266 -                                       "  PRIMARY KEY(resource, prop, ns))",
48267 +                                       "  lockscope TEXT NOT NULL,"
48268 +                                       "  locktype TEXT NOT NULL,"
48269 +                                       "  owner TEXT NOT NULL,"
48270 +                                       "  depth INT NOT NULL,"
48271 +                                       "  timeout TIMESTAMP NOT NULL,"
48272 +                                       "  PRIMARY KEY(locktoken))",
48273                                         NULL, NULL, &err)) {
48274  
48275 -                               if (0 != strcmp(err, "table properties already exists")) {
48276 +                               if (0 != strcmp(err, "table locks already exists")) {
48277                                         log_error_write(srv, __FILE__, __LINE__, "ss", "can't open transaction:", err);
48278                                         sqlite3_free(err);
48279  
48280 @@ -228,127 +314,138 @@
48281                                 }
48282                                 sqlite3_free(err);
48283                         }
48284 -       
48285 -                       if (SQLITE_OK != sqlite3_prepare(s->sql, 
48286 -                               CONST_STR_LEN("REPLACE INTO properties (resource, prop, ns, value) VALUES (?, ?, ?, ?)"), 
48287 -                               &(s->stmt_update_prop), &next_stmt)) {
48288 +
48289 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
48290 +                               CONST_STR_LEN("INSERT INTO locks (locktoken, resource, lockscope, locktype, owner, depth, timeout) VALUES (?,?,?,?,?,?, CURRENT_TIME + 600)"),
48291 +                               &(s->stmt_create_lock), &next_stmt)) {
48292                                 /* prepare failed */
48293 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
48294  
48295 -                               log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed:", sqlite3_errmsg(s->sql));
48296                                 return HANDLER_ERROR;
48297                         }
48298  
48299 -                       if (SQLITE_OK != sqlite3_prepare(s->sql, 
48300 -                               CONST_STR_LEN("DELETE FROM properties WHERE resource = ? AND prop = ? AND ns = ?"), 
48301 -                               &(s->stmt_delete_prop), &next_stmt)) {
48302 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
48303 +                               CONST_STR_LEN("DELETE FROM locks WHERE locktoken = ?"),
48304 +                               &(s->stmt_remove_lock), &next_stmt)) {
48305                                 /* prepare failed */
48306                                 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
48307  
48308                                 return HANDLER_ERROR;
48309                         }
48310  
48311 -                       if (SQLITE_OK != sqlite3_prepare(s->sql, 
48312 -                               CONST_STR_LEN("DELETE FROM properties WHERE resource = ?"), 
48313 -                               &(s->stmt_delete_uri), &next_stmt)) {
48314 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
48315 +                               CONST_STR_LEN("SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout FROM locks WHERE locktoken = ?"),
48316 +                               &(s->stmt_read_lock), &next_stmt)) {
48317                                 /* prepare failed */
48318                                 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
48319  
48320                                 return HANDLER_ERROR;
48321                         }
48322  
48323 -                       if (SQLITE_OK != sqlite3_prepare(s->sql, 
48324 -                               CONST_STR_LEN("INSERT INTO properties SELECT ?, prop, ns, value FROM properties WHERE resource = ?"), 
48325 -                               &(s->stmt_copy_uri), &next_stmt)) {
48326 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
48327 +                               CONST_STR_LEN("SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout FROM locks WHERE resource = ?"),
48328 +                               &(s->stmt_read_lock_by_uri), &next_stmt)) {
48329                                 /* prepare failed */
48330                                 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
48331  
48332                                 return HANDLER_ERROR;
48333                         }
48334  
48335 -                       if (SQLITE_OK != sqlite3_prepare(s->sql, 
48336 -                               CONST_STR_LEN("UPDATE properties SET resource = ? WHERE resource = ?"), 
48337 -                               &(s->stmt_move_uri), &next_stmt)) {
48338 +                       if (SQLITE_OK != sqlite3_prepare(s->sql,
48339 +                               CONST_STR_LEN("UPDATE locks SET timeout = CURRENT_TIME + 600 WHERE locktoken = ?"),
48340 +                               &(s->stmt_refresh_lock), &next_stmt)) {
48341                                 /* prepare failed */
48342                                 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
48343  
48344                                 return HANDLER_ERROR;
48345                         }
48346 +
48347 +
48348  #else
48349                         log_error_write(srv, __FILE__, __LINE__, "s", "Sorry, no sqlite3 and libxml2 support include, compile with --with-webdav-props");
48350                         return HANDLER_ERROR;
48351  #endif
48352                 }
48353         }
48354 -       
48355 +
48356         return HANDLER_GO_ON;
48357  }
48358  
48359 -#define PATCH(x) \
48360 -       p->conf.x = s->x;
48361  static int mod_webdav_patch_connection(server *srv, connection *con, plugin_data *p) {
48362         size_t i, j;
48363         plugin_config *s = p->config_storage[0];
48364 -       
48365 -       PATCH(enabled);
48366 -       PATCH(is_readonly);
48367 -       PATCH(log_xml);
48368 -       
48369 +
48370 +       PATCH_OPTION(enabled);
48371 +       PATCH_OPTION(is_readonly);
48372 +       PATCH_OPTION(log_xml);
48373 +
48374  #ifdef USE_PROPPATCH
48375 -       PATCH(sql);
48376 -       PATCH(stmt_update_prop);
48377 -       PATCH(stmt_delete_prop);
48378 -       PATCH(stmt_select_prop);
48379 -       PATCH(stmt_select_propnames);
48380 -
48381 -       PATCH(stmt_delete_uri);
48382 -       PATCH(stmt_move_uri);
48383 -       PATCH(stmt_copy_uri);
48384 +       PATCH_OPTION(sql);
48385 +       PATCH_OPTION(stmt_update_prop);
48386 +       PATCH_OPTION(stmt_delete_prop);
48387 +       PATCH_OPTION(stmt_select_prop);
48388 +       PATCH_OPTION(stmt_select_propnames);
48389 +
48390 +       PATCH_OPTION(stmt_delete_uri);
48391 +       PATCH_OPTION(stmt_move_uri);
48392 +       PATCH_OPTION(stmt_copy_uri);
48393 +
48394 +       PATCH_OPTION(stmt_remove_lock);
48395 +       PATCH_OPTION(stmt_refresh_lock);
48396 +       PATCH_OPTION(stmt_create_lock);
48397 +       PATCH_OPTION(stmt_read_lock);
48398 +       PATCH_OPTION(stmt_read_lock_by_uri);
48399  #endif
48400         /* skip the first, the global context */
48401         for (i = 1; i < srv->config_context->used; i++) {
48402                 data_config *dc = (data_config *)srv->config_context->data[i];
48403                 s = p->config_storage[i];
48404 -               
48405 +
48406                 /* condition didn't match */
48407                 if (!config_check_cond(srv, con, dc)) continue;
48408 -               
48409 +
48410                 /* merge config */
48411                 for (j = 0; j < dc->value->used; j++) {
48412                         data_unset *du = dc->value->data[j];
48413 -                       
48414 +
48415                         if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.activate"))) {
48416 -                               PATCH(enabled);
48417 +                               PATCH_OPTION(enabled);
48418                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.is-readonly"))) {
48419 -                               PATCH(is_readonly);
48420 +                               PATCH_OPTION(is_readonly);
48421                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.log-xml"))) {
48422 -                               PATCH(log_xml);
48423 +                               PATCH_OPTION(log_xml);
48424                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.sqlite-db-name"))) {
48425  #ifdef USE_PROPPATCH
48426 -                               PATCH(sql);
48427 -                               PATCH(stmt_update_prop);
48428 -                               PATCH(stmt_delete_prop);
48429 -                               PATCH(stmt_select_prop);
48430 -                               PATCH(stmt_select_propnames);
48431 -                               
48432 -                               PATCH(stmt_delete_uri);
48433 -                               PATCH(stmt_move_uri);
48434 -                               PATCH(stmt_copy_uri);
48435 +                               PATCH_OPTION(sql);
48436 +                               PATCH_OPTION(stmt_update_prop);
48437 +                               PATCH_OPTION(stmt_delete_prop);
48438 +                               PATCH_OPTION(stmt_select_prop);
48439 +                               PATCH_OPTION(stmt_select_propnames);
48440 +
48441 +                               PATCH_OPTION(stmt_delete_uri);
48442 +                               PATCH_OPTION(stmt_move_uri);
48443 +                               PATCH_OPTION(stmt_copy_uri);
48444 +
48445 +                               PATCH_OPTION(stmt_remove_lock);
48446 +                               PATCH_OPTION(stmt_refresh_lock);
48447 +                               PATCH_OPTION(stmt_create_lock);
48448 +                               PATCH_OPTION(stmt_read_lock);
48449 +                               PATCH_OPTION(stmt_read_lock_by_uri);
48450  #endif
48451                         }
48452                 }
48453         }
48454 -       
48455 +
48456         return 0;
48457  }
48458 -#undef PATCH
48459  
48460  URIHANDLER_FUNC(mod_webdav_uri_handler) {
48461         plugin_data *p = p_d;
48462 -       
48463 +
48464         UNUSED(srv);
48465  
48466         if (con->uri.path->used == 0) return HANDLER_GO_ON;
48467 -       
48468 +
48469         mod_webdav_patch_connection(srv, con, p);
48470  
48471         if (!p->conf.enabled) return HANDLER_GO_ON;
48472 @@ -362,20 +459,20 @@
48473                 if (p->conf.is_readonly) {
48474                         response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("PROPFIND"));
48475                 } else {
48476 -                       response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("PROPFIND, DELETE, MKCOL, PUT, MOVE, COPY, PROPPATCH"));
48477 +                       response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("PROPFIND, DELETE, MKCOL, PUT, MOVE, COPY, PROPPATCH, LOCK, UNLOCK"));
48478                 }
48479                 break;
48480         default:
48481                 break;
48482         }
48483 -       
48484 +
48485         /* not found */
48486         return HANDLER_GO_ON;
48487  }
48488 -static int webdav_gen_prop_tag(server *srv, connection *con, 
48489 -               char *prop_name, 
48490 -               char *prop_ns, 
48491 -               char *value, 
48492 +static int webdav_gen_prop_tag(server *srv, connection *con,
48493 +               char *prop_name,
48494 +               char *prop_ns,
48495 +               char *value,
48496                 buffer *b) {
48497  
48498         UNUSED(srv);
48499 @@ -414,7 +511,7 @@
48500         buffer_append_string_buffer(b, dst->rel_path);
48501         buffer_append_string(b,"</D:href>\n");
48502         buffer_append_string(b,"<D:status>\n");
48503 -       
48504 +
48505         if (con->request.http_version == HTTP_VERSION_1_1) {
48506                 BUFFER_COPY_STRING_CONST(b, "HTTP/1.1 ");
48507         } else {
48508 @@ -458,14 +555,13 @@
48509  
48510                         /* bind the values to the insert */
48511  
48512 -                       sqlite3_bind_text(stmt, 1, 
48513 -                                         dst->rel_path->ptr, 
48514 +                       sqlite3_bind_text(stmt, 1,
48515 +                                         dst->rel_path->ptr,
48516                                           dst->rel_path->used - 1,
48517                                           SQLITE_TRANSIENT);
48518 -                                                                       
48519 +
48520                         if (SQLITE_DONE != sqlite3_step(stmt)) {
48521                                 /* */
48522 -                               WP();
48523                         }
48524                 }
48525  #endif
48526 @@ -493,14 +589,14 @@
48527                             (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')) {
48528                                 continue;
48529                                 /* ignore the parent dir */
48530 -                       } 
48531 +                       }
48532  
48533                         buffer_copy_string_buffer(d.path, dst->path);
48534 -                       BUFFER_APPEND_SLASH(d.path);
48535 +                       PATHNAME_APPEND_SLASH(d.path);
48536                         buffer_append_string(d.path, de->d_name);
48537 -                       
48538 +
48539                         buffer_copy_string_buffer(d.rel_path, dst->rel_path);
48540 -                       BUFFER_APPEND_SLASH(d.rel_path);
48541 +                       PATHNAME_APPEND_SLASH(d.rel_path);
48542                         buffer_append_string(d.rel_path, de->d_name);
48543  
48544                         /* stat and unlink afterwards */
48545 @@ -508,7 +604,7 @@
48546                                 /* don't about it yet, rmdir will fail too */
48547                         } else if (S_ISDIR(st.st_mode)) {
48548                                 have_multi_status = webdav_delete_dir(srv, con, p, &d, b);
48549 -                                       
48550 +
48551                                 /* try to unlink it */
48552                                 if (-1 == rmdir(d.path->ptr)) {
48553                                         switch(errno) {
48554 @@ -535,14 +631,13 @@
48555  
48556                                                 /* bind the values to the insert */
48557  
48558 -                                               sqlite3_bind_text(stmt, 1, 
48559 -                                                                 d.rel_path->ptr, 
48560 +                                               sqlite3_bind_text(stmt, 1,
48561 +                                                                 d.rel_path->ptr,
48562                                                                   d.rel_path->used - 1,
48563                                                                   SQLITE_TRANSIENT);
48564 -                                                                                                       
48565 +
48566                                                 if (SQLITE_DONE != sqlite3_step(stmt)) {
48567                                                         /* */
48568 -                                                       WP();
48569                                                 }
48570                                         }
48571  #endif
48572 @@ -569,7 +664,7 @@
48573         if (stream_open(&s, src->path)) {
48574                 return 403;
48575         }
48576 -                       
48577 +
48578         if (-1 == (ofd = open(dst->path->ptr, O_WRONLY|O_TRUNC|O_CREAT|(overwrite ? 0 : O_EXCL), 0600))) {
48579                 /* opening the destination failed for some reason */
48580                 switch(errno) {
48581 @@ -601,7 +696,7 @@
48582                         break;
48583                 }
48584         }
48585 -       
48586 +
48587         stream_close(&s);
48588         close(ofd);
48589  
48590 @@ -614,19 +709,18 @@
48591                         sqlite3_reset(stmt);
48592  
48593                         /* bind the values to the insert */
48594 -                       sqlite3_bind_text(stmt, 1, 
48595 -                                         dst->rel_path->ptr, 
48596 +                       sqlite3_bind_text(stmt, 1,
48597 +                                         dst->rel_path->ptr,
48598                                           dst->rel_path->used - 1,
48599                                           SQLITE_TRANSIENT);
48600  
48601 -                       sqlite3_bind_text(stmt, 2, 
48602 -                                         src->rel_path->ptr, 
48603 +                       sqlite3_bind_text(stmt, 2,
48604 +                                         src->rel_path->ptr,
48605                                           src->rel_path->used - 1,
48606                                           SQLITE_TRANSIENT);
48607 -                                                                                                       
48608 +
48609                         if (SQLITE_DONE != sqlite3_step(stmt)) {
48610                                 /* */
48611 -                               WP();
48612                         }
48613                 }
48614         }
48615 @@ -655,21 +749,21 @@
48616                             (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')) {
48617                                 continue;
48618                         }
48619 -                       
48620 +
48621                         buffer_copy_string_buffer(s.path, src->path);
48622 -                       BUFFER_APPEND_SLASH(s.path);
48623 +                       PATHNAME_APPEND_SLASH(s.path);
48624                         buffer_append_string(s.path, de->d_name);
48625  
48626                         buffer_copy_string_buffer(d.path, dst->path);
48627 -                       BUFFER_APPEND_SLASH(d.path);
48628 +                       PATHNAME_APPEND_SLASH(d.path);
48629                         buffer_append_string(d.path, de->d_name);
48630  
48631                         buffer_copy_string_buffer(s.rel_path, src->rel_path);
48632 -                       BUFFER_APPEND_SLASH(s.rel_path);
48633 +                       PATHNAME_APPEND_SLASH(s.rel_path);
48634                         buffer_append_string(s.rel_path, de->d_name);
48635  
48636                         buffer_copy_string_buffer(d.rel_path, dst->rel_path);
48637 -                       BUFFER_APPEND_SLASH(d.rel_path);
48638 +                       PATHNAME_APPEND_SLASH(d.rel_path);
48639                         buffer_append_string(d.rel_path, de->d_name);
48640  
48641                         if (-1 == stat(s.path->ptr, &st)) {
48642 @@ -692,19 +786,18 @@
48643                                                 sqlite3_reset(stmt);
48644  
48645                                                 /* bind the values to the insert */
48646 -                                               sqlite3_bind_text(stmt, 1, 
48647 -                                                         dst->rel_path->ptr, 
48648 +                                               sqlite3_bind_text(stmt, 1,
48649 +                                                         dst->rel_path->ptr,
48650                                                           dst->rel_path->used - 1,
48651                                                           SQLITE_TRANSIENT);
48652  
48653 -                                               sqlite3_bind_text(stmt, 2, 
48654 -                                                         src->rel_path->ptr, 
48655 +                                               sqlite3_bind_text(stmt, 2,
48656 +                                                         src->rel_path->ptr,
48657                                                           src->rel_path->used - 1,
48658                                                           SQLITE_TRANSIENT);
48659 -                                                                                                       
48660 +
48661                                                 if (SQLITE_DONE != sqlite3_step(stmt)) {
48662                                                         /* */
48663 -                                                       WP();
48664                                                 }
48665                                         }
48666  #endif
48667 @@ -721,7 +814,7 @@
48668                 buffer_free(s.rel_path);
48669                 buffer_free(d.path);
48670                 buffer_free(d.rel_path);
48671 -               
48672 +
48673                 closedir(srcdir);
48674         }
48675  
48676 @@ -748,12 +841,12 @@
48677                         if (S_ISDIR(sce->st.st_mode)) {
48678                                 buffer_append_string(b, "<D:getcontenttype>httpd/unix-directory</D:getcontenttype>");
48679                                 found = 1;
48680 -                       } else if(S_ISREG(sce->st.st_mode)) { 
48681 +                       } else if(S_ISREG(sce->st.st_mode)) {
48682                                 for (k = 0; k < con->conf.mimetypes->used; k++) {
48683                                         data_string *ds = (data_string *)con->conf.mimetypes->data[k];
48684 -               
48685 +
48686                                         if (ds->key->used == 0) continue;
48687 -                               
48688 +
48689                                         if (buffer_is_equal_right_len(dst->path, ds->key, ds->key->used - 1)) {
48690                                                 buffer_append_string(b,"<D:getcontenttype>");
48691                                                 buffer_append_string_buffer(b, ds->value);
48692 @@ -807,23 +900,23 @@
48693  
48694                         /* bind the values to the insert */
48695  
48696 -                       sqlite3_bind_text(stmt, 1, 
48697 -                                         dst->rel_path->ptr, 
48698 +                       sqlite3_bind_text(stmt, 1,
48699 +                                         dst->rel_path->ptr,
48700                                           dst->rel_path->used - 1,
48701                                           SQLITE_TRANSIENT);
48702 -                       sqlite3_bind_text(stmt, 2, 
48703 +                       sqlite3_bind_text(stmt, 2,
48704                                           prop_name,
48705                                           strlen(prop_name),
48706                                           SQLITE_TRANSIENT);
48707 -                       sqlite3_bind_text(stmt, 3, 
48708 +                       sqlite3_bind_text(stmt, 3,
48709                                           prop_ns,
48710                                           strlen(prop_ns),
48711                                           SQLITE_TRANSIENT);
48712  
48713                         /* it is the PK */
48714 -                       while (SQLITE_ROW == sqlite3_step(p->conf.stmt_select_prop)) {
48715 +                       while (SQLITE_ROW == sqlite3_step(stmt)) {
48716                                 /* there is a row for us, we only expect a single col 'value' */
48717 -                               webdav_gen_prop_tag(srv, con, prop_name, prop_ns, (char *)sqlite3_column_text(p->conf.stmt_select_prop, 0), b);
48718 +                               webdav_gen_prop_tag(srv, con, prop_name, prop_ns, (char *)sqlite3_column_text(stmt, 0), b);
48719                                 found = 1;
48720                         }
48721                 }
48722 @@ -840,7 +933,7 @@
48723         char *prop;
48724  } webdav_property;
48725  
48726 -webdav_property live_properties[] = { 
48727 +webdav_property live_properties[] = {
48728         { "DAV:", "creationdate" },
48729         { "DAV:", "displayname" },
48730         { "DAV:", "getcontentlanguage" },
48731 @@ -871,8 +964,8 @@
48732                         webdav_property *prop;
48733  
48734                         prop = props->ptr[i];
48735 -                       
48736 -                       if (0 != webdav_get_property(srv, con, p, 
48737 +
48738 +                       if (0 != webdav_get_property(srv, con, p,
48739                                 dst, prop->prop, prop->ns, b_200)) {
48740                                 webdav_gen_prop_tag(srv, con, prop->prop, prop->ns, NULL, b_404);
48741                         }
48742 @@ -916,12 +1009,12 @@
48743                                 if (-1 == c->file.fd &&  /* open the file if not already open */
48744                                     -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
48745                                         log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
48746 -               
48747 +
48748                                         return -1;
48749                                 }
48750 -       
48751 +
48752                                 if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
48753 -                                       log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ", 
48754 +                                       log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
48755                                                         strerror(errno), c->file.name,  c->file.fd);
48756  
48757                                         return -1;
48758 @@ -938,7 +1031,7 @@
48759                         if (XML_ERR_OK != (err = xmlParseChunk(ctxt, c->file.mmap.start + c->offset, weHave, 0))) {
48760                                 log_error_write(srv, __FILE__, __LINE__, "sddd", "xmlParseChunk failed at:", cq->bytes_out, weHave, err);
48761                         }
48762 -                       
48763 +
48764                         c->offset += weHave;
48765                         cq->bytes_out += weHave;
48766  
48767 @@ -956,7 +1049,7 @@
48768                         if (XML_ERR_OK != (err = xmlParseChunk(ctxt, c->mem->ptr + c->offset, weHave, 0))) {
48769                                 log_error_write(srv, __FILE__, __LINE__, "sddd", "xmlParseChunk failed at:", cq->bytes_out, weHave, err);
48770                         }
48771 -                       
48772 +
48773                         c->offset += weHave;
48774                         cq->bytes_out += weHave;
48775  
48776 @@ -991,6 +1084,113 @@
48777  }
48778  #endif
48779  
48780 +int webdav_lockdiscovery(server *srv, connection *con,
48781 +               buffer *locktoken, const char *lockscope, const char *locktype, int depth) {
48782 +
48783 +       buffer *b;
48784 +
48785 +       response_header_overwrite(srv, con, CONST_STR_LEN("Lock-Token"), CONST_BUF_LEN(locktoken));
48786 +
48787 +       response_header_overwrite(srv, con,
48788 +               CONST_STR_LEN("Content-Type"),
48789 +               CONST_STR_LEN("text/xml; charset=\"utf-8\""));
48790 +
48791 +       b = chunkqueue_get_append_buffer(con->send);
48792 +
48793 +       buffer_copy_string(b, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
48794 +
48795 +       buffer_append_string(b,"<D:prop xmlns:D=\"DAV:\" xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\">\n");
48796 +       buffer_append_string(b,"<D:lockdiscovery>\n");
48797 +       buffer_append_string(b,"<D:activelock>\n");
48798 +
48799 +       buffer_append_string(b,"<D:lockscope>");
48800 +       buffer_append_string(b,"<D:");
48801 +       buffer_append_string(b, lockscope);
48802 +       buffer_append_string(b, "/>");
48803 +       buffer_append_string(b,"</D:lockscope>\n");
48804 +
48805 +       buffer_append_string(b,"<D:locktype>");
48806 +       buffer_append_string(b,"<D:");
48807 +       buffer_append_string(b, locktype);
48808 +       buffer_append_string(b, "/>");
48809 +       buffer_append_string(b,"</D:locktype>\n");
48810 +
48811 +       buffer_append_string(b,"<D:depth>");
48812 +       buffer_append_string(b, depth == 0 ? "0" : "infinity");
48813 +       buffer_append_string(b,"</D:depth>\n");
48814 +
48815 +       buffer_append_string(b,"<D:timeout>");
48816 +       buffer_append_string(b, "Second-600");
48817 +       buffer_append_string(b,"</D:timeout>\n");
48818 +
48819 +       buffer_append_string(b,"<D:owner>");
48820 +       buffer_append_string(b,"</D:owner>\n");
48821 +
48822 +       buffer_append_string(b,"<D:locktoken>");
48823 +       buffer_append_string(b, "<D:href>");
48824 +       buffer_append_string_buffer(b, locktoken);
48825 +       buffer_append_string(b, "</D:href>");
48826 +       buffer_append_string(b,"</D:locktoken>\n");
48827 +
48828 +       buffer_append_string(b,"</D:activelock>\n");
48829 +       buffer_append_string(b,"</D:lockdiscovery>\n");
48830 +       buffer_append_string(b,"</D:prop>\n");
48831 +
48832 +       return 0;
48833 +}
48834 +/**
48835 + * check if resource is having the right locks to access to resource
48836 + *
48837 + *
48838 + *
48839 + */
48840 +int webdav_has_lock(server *srv, connection *con, plugin_data *p, buffer *uri) {
48841 +       int has_lock = 1;
48842 +
48843 +#ifdef USE_LOCKS
48844 +       data_string *ds;
48845 +
48846 +       /**
48847 +        * If can have
48848 +        * - <lock-token>
48849 +        * - [etag]
48850 +        *
48851 +        * there is NOT, AND and OR
48852 +        * and a list can be tagged
48853 +        *
48854 +        * (<lock-token>) is untagged
48855 +        * <tag> (<lock-token>) is tagged
48856 +        *
48857 +        * as long as we don't handle collections it is simple. :)
48858 +        *
48859 +        * X-Litmus: locks: 11 (owner_modify)
48860 +        * If: <http://127.0.0.1:1025/dav/litmus/lockme> (<opaquelocktoken:2165478d-0611-49c4-be92-e790d68a38f1>)
48861 +        *
48862 +        * X-Litmus: locks: 16 (fail_cond_put)
48863 +        * If: (<DAV:no-lock> ["-1622396671"])
48864 +        */
48865 +       if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If"))) {
48866 +       } else {
48867 +               /* we didn't provided a lock-token -> */
48868 +               /* if the resource is locked -> 423 */
48869 +
48870 +               sqlite3_stmt *stmt = p->conf.stmt_read_lock_by_uri;
48871 +
48872 +               sqlite3_reset(stmt);
48873 +
48874 +               sqlite3_bind_text(stmt, 1,
48875 +                         CONST_BUF_LEN(uri),
48876 +                         SQLITE_TRANSIENT);
48877 +
48878 +               while (SQLITE_ROW == sqlite3_step(stmt)) {
48879 +                       has_lock = 0;
48880 +               }
48881 +       }
48882 +#endif
48883 +
48884 +       return has_lock;
48885 +}
48886 +
48887  URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
48888         plugin_data *p = p_d;
48889         buffer *b;
48890 @@ -1001,7 +1201,8 @@
48891         buffer *prop_200;
48892         buffer *prop_404;
48893         webdav_properties *req_props;
48894 -       
48895 +       stat_cache_entry *sce = NULL;
48896 +
48897         UNUSED(srv);
48898  
48899         if (!p->conf.enabled) return HANDLER_GO_ON;
48900 @@ -1019,13 +1220,25 @@
48901                 req_props = NULL;
48902  
48903                 /* is there a content-body ? */
48904 -       
48905 +
48906 +               switch (stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
48907 +               case HANDLER_ERROR:
48908 +                       if (errno == ENOENT) {
48909 +                               con->http_status = 404;
48910 +                               return HANDLER_FINISHED;
48911 +                       }
48912 +                       break;
48913 +               default:
48914 +                       break;
48915 +               }
48916 +
48917 +
48918  #ifdef USE_PROPPATCH
48919                 /* any special requests or just allprop ? */
48920                 if (con->request.content_length) {
48921                         xmlDocPtr xml;
48922  
48923 -                       if (1 == webdav_parse_chunkqueue(srv, con, p, con->request_content_queue, &xml)) {
48924 +                       if (1 == webdav_parse_chunkqueue(srv, con, p, con->recv, &xml)) {
48925                                 xmlNode *rootnode = xmlDocGetRootElement(xml);
48926  
48927                                 assert(rootnode);
48928 @@ -1087,14 +1300,13 @@
48929                                                                 /* get all property names (EMPTY) */
48930                                                                 sqlite3_reset(stmt);
48931                                                                 /* bind the values to the insert */
48932 -       
48933 -                                                               sqlite3_bind_text(stmt, 1, 
48934 -                                                                                 con->uri.path->ptr, 
48935 +
48936 +                                                               sqlite3_bind_text(stmt, 1,
48937 +                                                                                 con->uri.path->ptr,
48938                                                                                   con->uri.path->used - 1,
48939                                                                                   SQLITE_TRANSIENT);
48940 -                                               
48941 +
48942                                                                 if (SQLITE_DONE != sqlite3_step(stmt)) {
48943 -                                                                       WP();
48944                                                                 }
48945                                                         }
48946                                                 } else if (0 == xmlStrcmp(cmd->name, BAD_CAST "allprop")) {
48947 @@ -1114,14 +1326,14 @@
48948  
48949                 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
48950  
48951 -               b = chunkqueue_get_append_buffer(con->write_queue);
48952 -                               
48953 +               b = chunkqueue_get_append_buffer(con->send);
48954 +
48955                 buffer_copy_string(b, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
48956  
48957                 buffer_append_string(b,"<D:multistatus xmlns:D=\"DAV:\" xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\">\n");
48958  
48959                 /* allprop */
48960 -               
48961 +
48962                 prop_200 = buffer_init();
48963                 prop_404 = buffer_init();
48964  
48965 @@ -1129,7 +1341,7 @@
48966                 case 0:
48967                         /* Depth: 0 */
48968                         webdav_get_props(srv, con, p, &(con->physical), req_props, prop_200, prop_404);
48969 -       
48970 +
48971                         buffer_append_string(b,"<D:response>\n");
48972                         buffer_append_string(b,"<D:href>");
48973                         buffer_append_string_buffer(b, con->uri.scheme);
48974 @@ -1145,9 +1357,9 @@
48975                                 buffer_append_string_buffer(b, prop_200);
48976  
48977                                 buffer_append_string(b,"</D:prop>\n");
48978 -       
48979 +
48980                                 buffer_append_string(b,"<D:status>HTTP/1.1 200 OK</D:status>\n");
48981 -       
48982 +
48983                                 buffer_append_string(b,"</D:propstat>\n");
48984                         }
48985                         if (!buffer_is_empty(prop_404)) {
48986 @@ -1157,16 +1369,16 @@
48987                                 buffer_append_string_buffer(b, prop_404);
48988  
48989                                 buffer_append_string(b,"</D:prop>\n");
48990 -       
48991 +
48992                                 buffer_append_string(b,"<D:status>HTTP/1.1 404 Not Found</D:status>\n");
48993 -       
48994 +
48995                                 buffer_append_string(b,"</D:propstat>\n");
48996                         }
48997  
48998                         buffer_append_string(b,"</D:response>\n");
48999  
49000                         break;
49001 -               case 1: 
49002 +               case 1:
49003                         if (NULL != (dir = opendir(con->physical.path->ptr))) {
49004                                 struct dirent *de;
49005                                 physical d;
49006 @@ -1179,16 +1391,16 @@
49007                                         if (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0') {
49008                                                 continue;
49009                                                 /* ignore the parent dir */
49010 -                                       } 
49011 +                                       }
49012  
49013                                         buffer_copy_string_buffer(d.path, dst->path);
49014 -                                       BUFFER_APPEND_SLASH(d.path);
49015 +                                       PATHNAME_APPEND_SLASH(d.path);
49016  
49017                                         buffer_copy_string_buffer(d.rel_path, dst->rel_path);
49018 -                                       BUFFER_APPEND_SLASH(d.rel_path);
49019 +                                       PATHNAME_APPEND_SLASH(d.rel_path);
49020  
49021                                         if (de->d_name[0] == '.' && de->d_name[1] == '\0') {
49022 -                                               /* don't append the . */ 
49023 +                                               /* don't append the . */
49024                                         } else {
49025                                                 buffer_append_string(d.path, de->d_name);
49026                                                 buffer_append_string(d.rel_path, de->d_name);
49027 @@ -1198,7 +1410,7 @@
49028                                         buffer_reset(prop_404);
49029  
49030                                         webdav_get_props(srv, con, p, &d, req_props, prop_200, prop_404);
49031 -                                       
49032 +
49033                                         buffer_append_string(b,"<D:response>\n");
49034                                         buffer_append_string(b,"<D:href>");
49035                                         buffer_append_string_buffer(b, con->uri.scheme);
49036 @@ -1214,9 +1426,9 @@
49037                                                 buffer_append_string_buffer(b, prop_200);
49038  
49039                                                 buffer_append_string(b,"</D:prop>\n");
49040 -                       
49041 +
49042                                                 buffer_append_string(b,"<D:status>HTTP/1.1 200 OK</D:status>\n");
49043 -                       
49044 +
49045                                                 buffer_append_string(b,"</D:propstat>\n");
49046                                         }
49047                                         if (!buffer_is_empty(prop_404)) {
49048 @@ -1226,9 +1438,9 @@
49049                                                 buffer_append_string_buffer(b, prop_404);
49050  
49051                                                 buffer_append_string(b,"</D:prop>\n");
49052 -       
49053 +
49054                                                 buffer_append_string(b,"<D:status>HTTP/1.1 404 Not Found</D:status>\n");
49055 -       
49056 +
49057                                                 buffer_append_string(b,"</D:propstat>\n");
49058                                         }
49059  
49060 @@ -1260,7 +1472,7 @@
49061                 if (p->conf.log_xml) {
49062                         log_error_write(srv, __FILE__, __LINE__, "sb", "XML-response-body:", b);
49063                 }
49064 -               con->file_finished = 1;
49065 +               con->send->is_closed = 1;
49066  
49067                 return HANDLER_FINISHED;
49068         case HTTP_METHOD_MKCOL:
49069 @@ -1275,7 +1487,7 @@
49070  
49071                         return HANDLER_FINISHED;
49072                 }
49073 -       
49074 +
49075                 /* let's create the directory */
49076  
49077                 if (-1 == mkdir(con->physical.path->ptr, 0700)) {
49078 @@ -1294,7 +1506,7 @@
49079                         }
49080                 } else {
49081                         con->http_status = 201;
49082 -                       con->file_finished = 1;
49083 +                       con->send->is_closed = 1;
49084                 }
49085  
49086                 return HANDLER_FINISHED;
49087 @@ -1303,7 +1515,13 @@
49088                         con->http_status = 403;
49089                         return HANDLER_FINISHED;
49090                 }
49091 -               
49092 +
49093 +               /* does the client have a lock for this connection ? */
49094 +               if (!webdav_has_lock(srv, con, p, con->uri.path)) {
49095 +                       con->http_status = 423;
49096 +                       return HANDLER_FINISHED;
49097 +               }
49098 +
49099                 /* stat and unlink afterwards */
49100                 if (-1 == stat(con->physical.path->ptr, &st)) {
49101                         /* don't about it yet, unlink will fail too */
49102 @@ -1322,8 +1540,8 @@
49103                                 /* we got an error somewhere in between, build a 207 */
49104                                 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
49105  
49106 -                               b = chunkqueue_get_append_buffer(con->write_queue);
49107 -                       
49108 +                               b = chunkqueue_get_append_buffer(con->send);
49109 +
49110                                 buffer_copy_string(b, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
49111  
49112                                 buffer_append_string(b,"<D:multistatus xmlns:D=\"DAV:\">\n");
49113 @@ -1331,16 +1549,16 @@
49114                                 buffer_append_string_buffer(b, multi_status_resp);
49115  
49116                                 buffer_append_string(b,"</D:multistatus>\n");
49117 -                       
49118 +
49119                                 if (p->conf.log_xml) {
49120                                         log_error_write(srv, __FILE__, __LINE__, "sb", "XML-response-body:", b);
49121                                 }
49122  
49123                                 con->http_status = 207;
49124 -                               con->file_finished = 1;
49125 +                               con->send->is_closed = 1;
49126                         } else {
49127                                 /* everything went fine, remove the directory */
49128 -       
49129 +
49130                                 if (-1 == rmdir(con->physical.path->ptr)) {
49131                                         switch(errno) {
49132                                         case ENOENT:
49133 @@ -1374,98 +1592,175 @@
49134                 return HANDLER_FINISHED;
49135         case HTTP_METHOD_PUT: {
49136                 int fd;
49137 -               chunkqueue *cq = con->request_content_queue;
49138 +               chunkqueue *cq = con->recv;
49139 +               chunk *c;
49140 +               data_string *ds_range;
49141  
49142                 if (p->conf.is_readonly) {
49143                         con->http_status = 403;
49144                         return HANDLER_FINISHED;
49145                 }
49146  
49147 +               /* is a exclusive lock set on the source */
49148 +               if (!webdav_has_lock(srv, con, p, con->uri.path)) {
49149 +                       con->http_status = 423;
49150 +                       return HANDLER_FINISHED;
49151 +               }
49152 +
49153 +
49154                 assert(chunkqueue_length(cq) == (off_t)con->request.content_length);
49155  
49156 -               /* taken what we have in the request-body and write it to a file */
49157 -               if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_CREAT|O_TRUNC, 0600))) {
49158 -                       /* we can't open the file */
49159 -                       con->http_status = 403;
49160 -               } else {
49161 -                       chunk *c;
49162 +               /* RFC2616 Section 9.6 PUT requires us to send 501 on all Content-* we don't support
49163 +                * - most important Content-Range
49164 +                *
49165 +                *
49166 +                * Example: Content-Range: bytes 100-1037/1038 */
49167  
49168 -                       con->http_status = 201; /* created */
49169 -                       con->file_finished = 1;
49170 +               if (NULL != (ds_range = (data_string *)array_get_element(con->request.headers, "Content-Range"))) {
49171 +                       const char *num = ds_range->value->ptr;
49172 +                       off_t offset;
49173 +                       char *err = NULL;
49174  
49175 -                       for (c = cq->first; c; c = cq->first) {
49176 -                               int r = 0; 
49177 +                       if (0 != strncmp(num, "bytes ", 6)) {
49178 +                               con->http_status = 501; /* not implemented */
49179  
49180 -                               /* copy all chunks */
49181 -                               switch(c->type) {
49182 -                               case FILE_CHUNK:
49183 -
49184 -                                       if (c->file.mmap.start == MAP_FAILED) {
49185 -                                               if (-1 == c->file.fd &&  /* open the file if not already open */
49186 -                                                   -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
49187 -                                                       log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
49188 -                                       
49189 -                                                       return -1;
49190 -                                               }
49191 -                               
49192 -                                               if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
49193 -                                                       log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ", 
49194 -                                                                       strerror(errno), c->file.name,  c->file.fd);
49195 +                               return HANDLER_FINISHED;
49196 +                       }
49197  
49198 -                                                       return -1;
49199 -                                               }
49200 +                       /* we only support <num>- ... */
49201  
49202 -                                               c->file.mmap.length = c->file.length;
49203 +                       num += 6;
49204  
49205 -                                               close(c->file.fd);
49206 -                                               c->file.fd = -1;
49207 -       
49208 -                                               /* chunk_reset() or chunk_free() will cleanup for us */
49209 -                                       }
49210 -
49211 -                                       if ((r = write(fd, c->file.mmap.start + c->offset, c->file.length - c->offset)) < 0) {
49212 -                                               switch(errno) {
49213 -                                               case ENOSPC:
49214 -                                                       con->http_status = 507;
49215 -               
49216 -                                                       break;
49217 -                                               default:
49218 -                                                       con->http_status = 403;
49219 -                                                       break;
49220 -                                               }
49221 -                                       }
49222 -                                       break;
49223 -                               case MEM_CHUNK:
49224 -                                       if ((r = write(fd, c->mem->ptr + c->offset, c->mem->used - c->offset - 1)) < 0) {
49225 -                                               switch(errno) {
49226 -                                               case ENOSPC:
49227 -                                                       con->http_status = 507;
49228 -               
49229 -                                                       break;
49230 -                                               default:
49231 -                                                       con->http_status = 403;
49232 -                                                       break;
49233 -                                               }
49234 -                                       }
49235 +                       /* skip WS */
49236 +                       while (*num == ' ' || *num == '\t') num++;
49237 +
49238 +                       if (*num == '\0') {
49239 +                               con->http_status = 501; /* not implemented */
49240 +
49241 +                               return HANDLER_FINISHED;
49242 +                       }
49243 +
49244 +                       offset = strtoll(num, &err, 10);
49245 +
49246 +                       if (*err != '-' || offset < 0) {
49247 +                               con->http_status = 501; /* not implemented */
49248 +
49249 +                               return HANDLER_FINISHED;
49250 +                       }
49251 +
49252 +                       if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY, 0600))) {
49253 +                               switch (errno) {
49254 +                               case ENOENT:
49255 +                                       con->http_status = 404; /* not found */
49256                                         break;
49257 -                               case UNUSED_CHUNK:
49258 +                               default:
49259 +                                       con->http_status = 403; /* not found */
49260                                         break;
49261                                 }
49262 +                               return HANDLER_FINISHED;
49263 +                       }
49264 +
49265 +                       if (-1 == lseek(fd, offset, SEEK_SET)) {
49266 +                               con->http_status = 501; /* not implemented */
49267 +
49268 +                               close(fd);
49269 +
49270 +                               return HANDLER_FINISHED;
49271 +                       }
49272 +                       con->http_status = 200; /* modified */
49273 +               } else {
49274 +                       /* take what we have in the request-body and write it to a file */
49275  
49276 -                               if (r > 0) {
49277 -                                       c->offset += r;
49278 -                                       cq->bytes_out += r;
49279 +                       /* if the file doesn't exist, create it */
49280 +                       if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_TRUNC, 0600))) {
49281 +                               if (errno == ENOENT &&
49282 +                                   -1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0600))) {
49283 +                                       /* we can't open the file */
49284 +                                       con->http_status = 403;
49285 +
49286 +                                       return HANDLER_FINISHED;
49287                                 } else {
49288 -                                       break;
49289 +                                       con->http_status = 201; /* created */
49290                                 }
49291 -                               chunkqueue_remove_finished_chunks(cq);
49292 +                       } else {
49293 +                               con->http_status = 200; /* modified */
49294                         }
49295 -                       close(fd);
49296 +               }
49297 +
49298 +               con->send->is_closed = 1;
49299 +
49300 +               for (c = cq->first; c; c = cq->first) {
49301 +                       int r = 0;
49302 +
49303 +                       /* copy all chunks */
49304 +                       switch(c->type) {
49305 +                       case FILE_CHUNK:
49306 +
49307 +                               if (c->file.mmap.start == MAP_FAILED) {
49308 +                                       if (-1 == c->file.fd &&  /* open the file if not already open */
49309 +                                           -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
49310 +                                               log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
49311 +
49312 +                                               return -1;
49313 +                                       }
49314 +
49315 +                                       if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
49316 +                                               log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
49317 +                                                               strerror(errno), c->file.name,  c->file.fd);
49318  
49319 +                                               return -1;
49320 +                                       }
49321 +
49322 +                                       c->file.mmap.length = c->file.length;
49323 +
49324 +                                       close(c->file.fd);
49325 +                                       c->file.fd = -1;
49326 +
49327 +                                       /* chunk_reset() or chunk_free() will cleanup for us */
49328 +                               }
49329 +
49330 +                               if ((r = write(fd, c->file.mmap.start + c->offset, c->file.length - c->offset)) < 0) {
49331 +                                       switch(errno) {
49332 +                                       case ENOSPC:
49333 +                                               con->http_status = 507;
49334 +
49335 +                                               break;
49336 +                                       default:
49337 +                                               con->http_status = 403;
49338 +                                               break;
49339 +                                       }
49340 +                               }
49341 +                               break;
49342 +                       case MEM_CHUNK:
49343 +                               if ((r = write(fd, c->mem->ptr + c->offset, c->mem->used - c->offset - 1)) < 0) {
49344 +                                       switch(errno) {
49345 +                                       case ENOSPC:
49346 +                                               con->http_status = 507;
49347 +
49348 +                                               break;
49349 +                                       default:
49350 +                                               con->http_status = 403;
49351 +                                               break;
49352 +                                       }
49353 +                               }
49354 +                               break;
49355 +                       case UNUSED_CHUNK:
49356 +                               break;
49357 +                       }
49358 +
49359 +                       if (r > 0) {
49360 +                               c->offset += r;
49361 +                               cq->bytes_out += r;
49362 +                       } else {
49363 +                               break;
49364 +                       }
49365 +                       chunkqueue_remove_finished_chunks(cq);
49366                 }
49367 +               close(fd);
49368 +
49369                 return HANDLER_FINISHED;
49370         }
49371 -       case HTTP_METHOD_MOVE: 
49372 +       case HTTP_METHOD_MOVE:
49373         case HTTP_METHOD_COPY: {
49374                 buffer *destination = NULL;
49375                 char *sep, *start;
49376 @@ -1475,7 +1770,15 @@
49377                         con->http_status = 403;
49378                         return HANDLER_FINISHED;
49379                 }
49380 -               
49381 +
49382 +               /* is a exclusive lock set on the source */
49383 +               if (con->request.http_method == HTTP_METHOD_MOVE) {
49384 +                       if (!webdav_has_lock(srv, con, p, con->uri.path)) {
49385 +                               con->http_status = 423;
49386 +                               return HANDLER_FINISHED;
49387 +                       }
49388 +               }
49389 +
49390                 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Destination"))) {
49391                         destination = ds->value;
49392                 } else {
49393 @@ -1549,10 +1852,10 @@
49394                 }
49395  
49396                 buffer_copy_string_buffer(p->physical.path, p->physical.doc_root);
49397 -               BUFFER_APPEND_SLASH(p->physical.path);
49398 +               PATHNAME_APPEND_SLASH(p->physical.path);
49399                 buffer_copy_string_buffer(p->physical.basedir, p->physical.path);
49400  
49401 -               /* don't add a second / */ 
49402 +               /* don't add a second / */
49403                 if (p->physical.rel_path->ptr[0] == '/') {
49404                         buffer_append_string_len(p->physical.path, p->physical.rel_path->ptr + 1, p->physical.rel_path->used - 2);
49405                 } else {
49406 @@ -1608,11 +1911,17 @@
49407                                 rmdir(con->physical.path->ptr);
49408                         }
49409                         con->http_status = 201;
49410 -                       con->file_finished = 1;
49411 +                       con->send->is_closed = 1;
49412                 } else {
49413                         /* it is just a file, good */
49414                         int r;
49415  
49416 +                       /* does the client have a lock for this connection ? */
49417 +                       if (!webdav_has_lock(srv, con, p, p->uri.path)) {
49418 +                               con->http_status = 423;
49419 +                               return HANDLER_FINISHED;
49420 +                       }
49421 +
49422                         /* destination exists */
49423                         if (0 == (r = stat(p->physical.path->ptr, &st))) {
49424                                 if (S_ISDIR(st.st_mode)) {
49425 @@ -1628,7 +1937,7 @@
49426  
49427                         if (-1 == r) {
49428                                 con->http_status = 201; /* we will create a new one */
49429 -                               con->file_finished = 1;
49430 +                               con->send->is_closed = 1;
49431  
49432                                 switch(errno) {
49433                                 case ENOTDIR:
49434 @@ -1636,7 +1945,7 @@
49435                                         return HANDLER_FINISHED;
49436                                 }
49437                         } else if (overwrite == 0) {
49438 -                               /* destination exists, but overwrite is not set */ 
49439 +                               /* destination exists, but overwrite is not set */
49440                                 con->http_status = 412;
49441                                 return HANDLER_FINISHED;
49442                         } else {
49443 @@ -1655,16 +1964,16 @@
49444                                                 sqlite3_reset(stmt);
49445  
49446                                                 /* bind the values to the insert */
49447 -                                               sqlite3_bind_text(stmt, 1, 
49448 -                                                                 p->uri.path->ptr, 
49449 +                                               sqlite3_bind_text(stmt, 1,
49450 +                                                                 p->uri.path->ptr,
49451                                                                   p->uri.path->used - 1,
49452                                                                   SQLITE_TRANSIENT);
49453  
49454 -                                               sqlite3_bind_text(stmt, 2, 
49455 -                                                                 con->uri.path->ptr, 
49456 +                                               sqlite3_bind_text(stmt, 2,
49457 +                                                                 con->uri.path->ptr,
49458                                                                   con->uri.path->used - 1,
49459                                                                   SQLITE_TRANSIENT);
49460 -                                               
49461 +
49462                                                 if (SQLITE_DONE != sqlite3_step(stmt)) {
49463                                                         log_error_write(srv, __FILE__, __LINE__, "ss", "sql-move failed:", sqlite3_errmsg(p->conf.sql));
49464                                                 }
49465 @@ -1691,12 +2000,17 @@
49466  
49467                 return HANDLER_FINISHED;
49468         }
49469 -       case HTTP_METHOD_PROPPATCH: {
49470 +       case HTTP_METHOD_PROPPATCH:
49471                 if (p->conf.is_readonly) {
49472                         con->http_status = 403;
49473                         return HANDLER_FINISHED;
49474                 }
49475  
49476 +               if (!webdav_has_lock(srv, con, p, con->uri.path)) {
49477 +                       con->http_status = 423;
49478 +                       return HANDLER_FINISHED;
49479 +               }
49480 +
49481                 /* check if destination exists */
49482                 if (-1 == stat(con->physical.path->ptr, &st)) {
49483                         switch(errno) {
49484 @@ -1710,7 +2024,7 @@
49485                 if (con->request.content_length) {
49486                         xmlDocPtr xml;
49487  
49488 -                       if (1 == webdav_parse_chunkqueue(srv, con, p, con->request_content_queue, &xml)) {
49489 +                       if (1 == webdav_parse_chunkqueue(srv, con, p, con->recv, &xml)) {
49490                                 xmlNode *rootnode = xmlDocGetRootElement(xml);
49491  
49492                                 if (0 == xmlStrcmp(rootnode->name, BAD_CAST "propertyupdate")) {
49493 @@ -1737,7 +2051,7 @@
49494  
49495                                                         sqlite3_stmt *stmt;
49496  
49497 -                                                       stmt = (0 == xmlStrcmp(cmd->name, BAD_CAST "remove")) ? 
49498 +                                                       stmt = (0 == xmlStrcmp(cmd->name, BAD_CAST "remove")) ?
49499                                                                 p->conf.stmt_delete_prop : p->conf.stmt_update_prop;
49500  
49501                                                         for (props = cmd->children; props; props = props->next) {
49502 @@ -1762,34 +2076,35 @@
49503  
49504                                                                         /* bind the values to the insert */
49505  
49506 -                                                                       sqlite3_bind_text(stmt, 1, 
49507 -                                                                                         con->uri.path->ptr, 
49508 +                                                                       sqlite3_bind_text(stmt, 1,
49509 +                                                                                         con->uri.path->ptr,
49510                                                                                           con->uri.path->used - 1,
49511                                                                                           SQLITE_TRANSIENT);
49512 -                                                                       sqlite3_bind_text(stmt, 2, 
49513 +                                                                       sqlite3_bind_text(stmt, 2,
49514                                                                                           (char *)prop->name,
49515                                                                                           strlen((char *)prop->name),
49516                                                                                           SQLITE_TRANSIENT);
49517                                                                         if (prop->ns) {
49518 -                                                                               sqlite3_bind_text(stmt, 3, 
49519 +                                                                               sqlite3_bind_text(stmt, 3,
49520                                                                                                   (char *)prop->ns->href,
49521                                                                                                   strlen((char *)prop->ns->href),
49522                                                                                                   SQLITE_TRANSIENT);
49523                                                                         } else {
49524 -                                                                               sqlite3_bind_text(stmt, 3, 
49525 +                                                                               sqlite3_bind_text(stmt, 3,
49526                                                                                                   "",
49527                                                                                                   0,
49528                                                                                                   SQLITE_TRANSIENT);
49529                                                                         }
49530                                                                         if (stmt == p->conf.stmt_update_prop) {
49531 -                                                                               sqlite3_bind_text(stmt, 4, 
49532 +                                                                               sqlite3_bind_text(stmt, 4,
49533                                                                                           (char *)xmlNodeGetContent(prop),
49534                                                                                           strlen((char *)xmlNodeGetContent(prop)),
49535                                                                                           SQLITE_TRANSIENT);
49536                                                                         }
49537 -                                                               
49538 +
49539                                                                         if (SQLITE_DONE != (r = sqlite3_step(stmt))) {
49540 -                                                                               log_error_write(srv, __FILE__, __LINE__, "ss", "sql-set failed:", sqlite3_errmsg(p->conf.sql));
49541 +                                                                               log_error_write(srv, __FILE__, __LINE__, "ss",
49542 +                                                                                               "sql-set failed:", sqlite3_errmsg(p->conf.sql));
49543                                                                         }
49544                                                                 }
49545                                                         }
49546 @@ -1804,7 +2119,7 @@
49547  
49548                                                         goto propmatch_cleanup;
49549                                                 }
49550 -       
49551 +
49552                                                 con->http_status = 400;
49553                                         } else {
49554                                                 if (SQLITE_OK != sqlite3_exec(p->conf.sql, "COMMIT", NULL, NULL, &err)) {
49555 @@ -1815,12 +2130,13 @@
49556                                                 }
49557                                                 con->http_status = 200;
49558                                         }
49559 -                                       con->file_finished = 1;
49560 +                                       con->send->is_closed = 1;
49561  
49562                                         return HANDLER_FINISHED;
49563                                 }
49564  
49565  propmatch_cleanup:
49566 +
49567                                 xmlFreeDoc(xml);
49568                         } else {
49569                                 con->http_status = 400;
49570 @@ -1830,11 +2146,307 @@
49571  #endif
49572                 con->http_status = 501;
49573                 return HANDLER_FINISHED;
49574 -       }
49575 +       case HTTP_METHOD_LOCK:
49576 +               /**
49577 +                * a mac wants to write
49578 +                *
49579 +                * LOCK /dav/expire.txt HTTP/1.1\r\n
49580 +                * User-Agent: WebDAVFS/1.3 (01308000) Darwin/8.1.0 (Power Macintosh)\r\n
49581 +                * Accept: * / *\r\n
49582 +                * Depth: 0\r\n
49583 +                * Timeout: Second-600\r\n
49584 +                * Content-Type: text/xml; charset=\"utf-8\"\r\n
49585 +                * Content-Length: 229\r\n
49586 +                * Connection: keep-alive\r\n
49587 +                * Host: 192.168.178.23:1025\r\n
49588 +                * \r\n
49589 +                * <?xml version=\"1.0\" encoding=\"utf-8\"?>\n
49590 +                * <D:lockinfo xmlns:D=\"DAV:\">\n
49591 +                *  <D:lockscope><D:exclusive/></D:lockscope>\n
49592 +                *  <D:locktype><D:write/></D:locktype>\n
49593 +                *  <D:owner>\n
49594 +                *   <D:href>http://www.apple.com/webdav_fs/</D:href>\n
49595 +                *  </D:owner>\n
49596 +                * </D:lockinfo>\n
49597 +                */
49598 +
49599 +               if (depth != 0 && depth != -1) {
49600 +                       con->http_status = 400;
49601 +
49602 +                       return HANDLER_FINISHED;
49603 +               }
49604 +
49605 +#ifdef USE_LOCKS
49606 +               if (con->request.content_length) {
49607 +                       xmlDocPtr xml;
49608 +                       buffer *hdr_if = NULL;
49609 +
49610 +                       if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If"))) {
49611 +                               hdr_if = ds->value;
49612 +                       }
49613 +
49614 +                       /* we don't support Depth: Infinity on locks */
49615 +                       if (hdr_if == NULL && depth == -1) {
49616 +                               con->http_status = 409; /* Conflict */
49617 +
49618 +                               return HANDLER_FINISHED;
49619 +                       }
49620 +
49621 +                       if (1 == webdav_parse_chunkqueue(srv, con, p, con->recv, &xml)) {
49622 +                               xmlNode *rootnode = xmlDocGetRootElement(xml);
49623 +
49624 +                               assert(rootnode);
49625 +
49626 +                               if (0 == xmlStrcmp(rootnode->name, BAD_CAST "lockinfo")) {
49627 +                                       xmlNode *lockinfo;
49628 +                                       const xmlChar *lockscope = NULL, *locktype = NULL, *owner = NULL;
49629 +
49630 +                                       for (lockinfo = rootnode->children; lockinfo; lockinfo = lockinfo->next) {
49631 +                                               if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "lockscope")) {
49632 +                                                       xmlNode *value;
49633 +                                                       for (value = lockinfo->children; value; value = value->next) {
49634 +                                                               if ((0 == xmlStrcmp(value->name, BAD_CAST "exclusive")) ||
49635 +                                                                   (0 == xmlStrcmp(value->name, BAD_CAST "shared"))) {
49636 +                                                                       lockscope = value->name;
49637 +                                                               } else {
49638 +                                                                       con->http_status = 400;
49639 +
49640 +                                                                       xmlFreeDoc(xml);
49641 +                                                                       return HANDLER_FINISHED;
49642 +                                                               }
49643 +                                                       }
49644 +                                               } else if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "locktype")) {
49645 +                                                       xmlNode *value;
49646 +                                                       for (value = lockinfo->children; value; value = value->next) {
49647 +                                                               if ((0 == xmlStrcmp(value->name, BAD_CAST "write"))) {
49648 +                                                                       locktype = value->name;
49649 +                                                               } else {
49650 +                                                                       con->http_status = 400;
49651 +
49652 +                                                                       xmlFreeDoc(xml);
49653 +                                                                       return HANDLER_FINISHED;
49654 +                                                               }
49655 +                                                       }
49656 +
49657 +                                               } else if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "owner")) {
49658 +                                               }
49659 +                                       }
49660 +
49661 +                                       if (lockscope && locktype) {
49662 +                                               sqlite3_stmt *stmt = p->conf.stmt_read_lock_by_uri;
49663 +
49664 +                                               /* is this resourse already locked ? */
49665 +
49666 +                                               /* SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout
49667 +                                                *   FROM locks
49668 +                                                *  WHERE resource = ? */
49669 +
49670 +                                               if (stmt) {
49671 +
49672 +                                                       sqlite3_reset(stmt);
49673 +
49674 +                                                       sqlite3_bind_text(stmt, 1,
49675 +                                                                         p->uri.path->ptr,
49676 +                                                                         p->uri.path->used - 1,
49677 +                                                                         SQLITE_TRANSIENT);
49678 +
49679 +                                                       /* it is the PK */
49680 +                                                       while (SQLITE_ROW == sqlite3_step(stmt)) {
49681 +                                                               /* we found a lock
49682 +                                                                * 1. is it compatible ?
49683 +                                                                * 2. is it ours */
49684 +                                                               char *sql_lockscope = (char *)sqlite3_column_text(stmt, 2);
49685 +
49686 +                                                               if (strcmp(sql_lockscope, "exclusive")) {
49687 +                                                                       con->http_status = 423;
49688 +                                                               } else if (0 == xmlStrcmp(lockscope, BAD_CAST "exclusive")) {
49689 +                                                                       /* resourse is locked with a shared lock
49690 +                                                                        * client wants exclusive */
49691 +                                                                       con->http_status = 423;
49692 +                                                               }
49693 +                                                       }
49694 +                                                       if (con->http_status == 423) {
49695 +                                                               xmlFreeDoc(xml);
49696 +                                                               return HANDLER_FINISHED;
49697 +                                                       }
49698 +                                               }
49699 +
49700 +                                               stmt = p->conf.stmt_create_lock;
49701 +                                               if (stmt) {
49702 +                                                       /* create a lock-token */
49703 +                                                       uuid_t id;
49704 +                                                       char uuid[37] /* 36 + \0 */;
49705 +
49706 +                                                       uuid_generate(id);
49707 +                                                       uuid_unparse(id, uuid);
49708 +
49709 +                                                       buffer_copy_string(p->tmp_buf, "opaquelocktoken:");
49710 +                                                       buffer_append_string(p->tmp_buf, uuid);
49711 +
49712 +                                                       /* "CREATE TABLE locks ("
49713 +                                                        * "  locktoken TEXT NOT NULL,"
49714 +                                                        * "  resource TEXT NOT NULL,"
49715 +                                                        * "  lockscope TEXT NOT NULL,"
49716 +                                                        * "  locktype TEXT NOT NULL,"
49717 +                                                        * "  owner TEXT NOT NULL,"
49718 +                                                        * "  depth INT NOT NULL,"
49719 +                                                        */
49720 +
49721 +                                                       sqlite3_reset(stmt);
49722 +
49723 +                                                       sqlite3_bind_text(stmt, 1,
49724 +                                                                         CONST_BUF_LEN(p->tmp_buf),
49725 +                                                                         SQLITE_TRANSIENT);
49726 +
49727 +                                                       sqlite3_bind_text(stmt, 2,
49728 +                                                                         CONST_BUF_LEN(con->uri.path),
49729 +                                                                         SQLITE_TRANSIENT);
49730 +
49731 +                                                       sqlite3_bind_text(stmt, 3,
49732 +                                                                         lockscope,
49733 +                                                                         xmlStrlen(lockscope),
49734 +                                                                         SQLITE_TRANSIENT);
49735 +
49736 +                                                       sqlite3_bind_text(stmt, 4,
49737 +                                                                         locktype,
49738 +                                                                         xmlStrlen(locktype),
49739 +                                                                         SQLITE_TRANSIENT);
49740 +
49741 +                                                       /* owner */
49742 +                                                       sqlite3_bind_text(stmt, 5,
49743 +                                                                         "",
49744 +                                                                         0,
49745 +                                                                         SQLITE_TRANSIENT);
49746 +
49747 +                                                       /* depth */
49748 +                                                       sqlite3_bind_int(stmt, 6,
49749 +                                                                        depth);
49750 +
49751 +
49752 +                                                       if (SQLITE_DONE != sqlite3_step(stmt)) {
49753 +                                                               log_error_write(srv, __FILE__, __LINE__, "ss",
49754 +                                                                               "create lock:", sqlite3_errmsg(p->conf.sql));
49755 +                                                       }
49756 +
49757 +                                                       /* looks like we survived */
49758 +                                                       webdav_lockdiscovery(srv, con, p->tmp_buf, lockscope, locktype, depth);
49759 +
49760 +                                                       con->http_status = 201;
49761 +                                                       con->send->is_closed = 1;
49762 +                                               }
49763 +                                       }
49764 +                               }
49765 +
49766 +                               xmlFreeDoc(xml);
49767 +                               return HANDLER_FINISHED;
49768 +                       } else {
49769 +                               con->http_status = 400;
49770 +                               return HANDLER_FINISHED;
49771 +                       }
49772 +               } else {
49773 +
49774 +                       if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If"))) {
49775 +                               buffer *locktoken = ds->value;
49776 +                               sqlite3_stmt *stmt = p->conf.stmt_refresh_lock;
49777 +
49778 +                               /* remove the < > around the token */
49779 +                               if (locktoken->used < 6) {
49780 +                                       con->http_status = 400;
49781 +
49782 +                                       return HANDLER_FINISHED;
49783 +                               }
49784 +
49785 +                               buffer_copy_string_len(p->tmp_buf, locktoken->ptr + 2, locktoken->used - 5);
49786 +
49787 +                               sqlite3_reset(stmt);
49788 +
49789 +                               sqlite3_bind_text(stmt, 1,
49790 +                                         CONST_BUF_LEN(p->tmp_buf),
49791 +                                         SQLITE_TRANSIENT);
49792 +
49793 +                               if (SQLITE_DONE != sqlite3_step(stmt)) {
49794 +                                       log_error_write(srv, __FILE__, __LINE__, "ss",
49795 +                                               "refresh lock:", sqlite3_errmsg(p->conf.sql));
49796 +                               }
49797 +
49798 +                               webdav_lockdiscovery(srv, con, p->tmp_buf, "exclusive", "write", 0);
49799 +
49800 +                               con->http_status = 200;
49801 +                               con->send->is_closed = 1;
49802 +                               return HANDLER_FINISHED;
49803 +                       } else {
49804 +                               /* we need a lock-token to refresh */
49805 +                               con->http_status = 400;
49806 +
49807 +                               return HANDLER_FINISHED;
49808 +                       }
49809 +               }
49810 +               break;
49811 +#else
49812 +               con->http_status = 501;
49813 +               return HANDLER_FINISHED;
49814 +#endif
49815 +       case HTTP_METHOD_UNLOCK:
49816 +#ifdef USE_LOCKS
49817 +               if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Lock-Token"))) {
49818 +                       buffer *locktoken = ds->value;
49819 +                       sqlite3_stmt *stmt = p->conf.stmt_remove_lock;
49820 +
49821 +                       /* remove the < > around the token */
49822 +                       if (locktoken->used < 4) {
49823 +                               con->http_status = 400;
49824 +
49825 +                               return HANDLER_FINISHED;
49826 +                       }
49827 +
49828 +                       /**
49829 +                        * FIXME:
49830 +                        *
49831 +                        * if the resourse is locked:
49832 +                        * - by us: unlock
49833 +                        * - by someone else: 401
49834 +                        * if the resource is not locked:
49835 +                        * - 412
49836 +                        *  */
49837 +
49838 +                       buffer_copy_string_len(p->tmp_buf, locktoken->ptr + 1, locktoken->used - 3);
49839 +
49840 +                       sqlite3_reset(stmt);
49841 +
49842 +                       sqlite3_bind_text(stmt, 1,
49843 +                                 CONST_BUF_LEN(p->tmp_buf),
49844 +                                 SQLITE_TRANSIENT);
49845 +
49846 +                       sqlite3_bind_text(stmt, 2,
49847 +                                 CONST_BUF_LEN(con->uri.path),
49848 +                                 SQLITE_TRANSIENT);
49849 +
49850 +                       if (SQLITE_DONE != sqlite3_step(stmt)) {
49851 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
49852 +                                       "remove lock:", sqlite3_errmsg(p->conf.sql));
49853 +                       }
49854 +
49855 +                       if (0 == sqlite3_changes(p->conf.sql)) {
49856 +                               con->http_status = 401;
49857 +                       } else {
49858 +                               con->http_status = 204;
49859 +                       }
49860 +                       return HANDLER_FINISHED;
49861 +               } else {
49862 +                       /* we need a lock-token to unlock */
49863 +                       con->http_status = 400;
49864 +
49865 +                       return HANDLER_FINISHED;
49866 +               }
49867 +               break;
49868 +#else
49869 +               con->http_status = 501;
49870 +               return HANDLER_FINISHED;
49871 +#endif
49872         default:
49873                 break;
49874         }
49875 -       
49876 +
49877         /* not found */
49878         return HANDLER_GO_ON;
49879  }
49880 @@ -1845,14 +2457,14 @@
49881  int mod_webdav_plugin_init(plugin *p) {
49882         p->version     = LIGHTTPD_VERSION_ID;
49883         p->name        = buffer_init_string("webdav");
49884 -       
49885 +
49886         p->init        = mod_webdav_init;
49887         p->handle_uri_clean  = mod_webdav_uri_handler;
49888         p->handle_physical   = mod_webdav_subrequest_handler;
49889         p->set_defaults  = mod_webdav_set_defaults;
49890         p->cleanup     = mod_webdav_free;
49891 -       
49892 +
49893         p->data        = NULL;
49894 -       
49895 +
49896         return 0;
49897  }
49898 --- ../lighttpd-1.4.11/src/network.c    2006-03-04 16:45:46.000000000 +0200
49899 +++ lighttpd-1.5.0/src/network.c        2006-09-07 00:57:05.000000000 +0300
49900 @@ -1,14 +1,14 @@
49901  #include <sys/types.h>
49902  #include <sys/stat.h>
49903 -#include <sys/time.h>
49904  
49905  #include <errno.h>
49906  #include <fcntl.h>
49907 -#include <unistd.h>
49908  #include <string.h>
49909  #include <stdlib.h>
49910  #include <assert.h>
49911  
49912 +#include <stdio.h>
49913 +
49914  #include "network.h"
49915  #include "fdevent.h"
49916  #include "log.h"
49917 @@ -19,11 +19,12 @@
49918  #include "network_backends.h"
49919  #include "sys-mmap.h"
49920  #include "sys-socket.h"
49921 +#include "sys-files.h"
49922  
49923  #ifdef USE_OPENSSL
49924 -# include <openssl/ssl.h> 
49925 -# include <openssl/err.h> 
49926 -# include <openssl/rand.h> 
49927 +# include <openssl/ssl.h>
49928 +# include <openssl/err.h>
49929 +# include <openssl/rand.h>
49930  #endif
49931  
49932  handler_t network_server_handle_fdevent(void *s, void *context, int revents) {
49933 @@ -31,25 +32,25 @@
49934         server_socket *srv_socket = (server_socket *)context;
49935         connection *con;
49936         int loops = 0;
49937 -       
49938 +
49939         UNUSED(context);
49940 -       
49941 +
49942         if (revents != FDEVENT_IN) {
49943 -               log_error_write(srv, __FILE__, __LINE__, "sdd", 
49944 +               log_error_write(srv, __FILE__, __LINE__, "sdd",
49945                                 "strange event for server socket",
49946 -                               srv_socket->fd,
49947 +                               srv_socket->sock->fd,
49948                                 revents);
49949                 return HANDLER_ERROR;
49950         }
49951  
49952         /* accept()s at most 100 connections directly
49953          *
49954 -        * we jump out after 100 to give the waiting connections a chance */    
49955 +        * we jump out after 100 to give the waiting connections a chance */
49956         for (loops = 0; loops < 100 && NULL != (con = connection_accept(srv, srv_socket)); loops++) {
49957                 handler_t r;
49958 -               
49959 +
49960                 connection_state_machine(srv, con);
49961 -               
49962 +
49963                 switch(r = plugins_call_handle_joblist(srv, con)) {
49964                 case HANDLER_FINISHED:
49965                 case HANDLER_GO_ON:
49966 @@ -72,18 +73,18 @@
49967         buffer *b;
49968         int is_unix_domain_socket = 0;
49969         int fd;
49970 -       
49971 +
49972  #ifdef SO_ACCEPTFILTER
49973         struct accept_filter_arg afa;
49974  #endif
49975  
49976 -#ifdef __WIN32
49977 +#ifdef _WIN32
49978         WORD wVersionRequested;
49979         WSADATA wsaData;
49980         int err;
49981 -        
49982 +
49983         wVersionRequested = MAKEWORD( 2, 2 );
49984 -        
49985 +
49986         err = WSAStartup( wVersionRequested, &wsaData );
49987         if ( err != 0 ) {
49988                     /* Tell the user that we could not find a usable */
49989 @@ -91,37 +92,37 @@
49990                     return -1;
49991         }
49992  #endif
49993 -       
49994 +
49995         srv_socket = calloc(1, sizeof(*srv_socket));
49996 -       srv_socket->fd = -1;
49997 -       
49998 +       srv_socket->sock = iosocket_init();
49999 +
50000         srv_socket->srv_token = buffer_init();
50001         buffer_copy_string_buffer(srv_socket->srv_token, host_token);
50002 -       
50003 +
50004         b = buffer_init();
50005         buffer_copy_string_buffer(b, host_token);
50006 -       
50007 -       /* ipv4:port 
50008 +
50009 +       /* ipv4:port
50010          * [ipv6]:port
50011          */
50012         if (NULL == (sp = strrchr(b->ptr, ':'))) {
50013                 log_error_write(srv, __FILE__, __LINE__, "sb", "value of $SERVER[\"socket\"] has to be \"ip:port\".", b);
50014 -               
50015 +
50016                 return -1;
50017         }
50018 -       
50019 +
50020         host = b->ptr;
50021 -       
50022 +
50023         /* check for [ and ] */
50024         if (b->ptr[0] == '[' && *(sp-1) == ']') {
50025                 *(sp-1) = '\0';
50026                 host++;
50027 -               
50028 +
50029                 s->use_ipv6 = 1;
50030         }
50031 -       
50032 +
50033         *(sp++) = '\0';
50034 -       
50035 +
50036         port = strtol(sp, NULL, 10);
50037  
50038         if (host[0] == '/') {
50039 @@ -129,18 +130,18 @@
50040                 is_unix_domain_socket = 1;
50041         } else if (port == 0 || port > 65535) {
50042                 log_error_write(srv, __FILE__, __LINE__, "sd", "port out of range:", port);
50043 -       
50044 +
50045                 return -1;
50046         }
50047 -       
50048 +
50049         if (*host == '\0') host = NULL;
50050  
50051         if (is_unix_domain_socket) {
50052  #ifdef HAVE_SYS_UN_H
50053  
50054                 srv_socket->addr.plain.sa_family = AF_UNIX;
50055 -               
50056 -               if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, 0))) {
50057 +
50058 +               if (-1 == (srv_socket->sock->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, 0))) {
50059                         log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
50060                         return -1;
50061                 }
50062 @@ -154,32 +155,32 @@
50063  #ifdef HAVE_IPV6
50064         if (s->use_ipv6) {
50065                 srv_socket->addr.plain.sa_family = AF_INET6;
50066 -               
50067 -               if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
50068 +
50069 +               if (-1 == (srv_socket->sock->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
50070                         log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
50071                         return -1;
50072                 }
50073                 srv_socket->use_ipv6 = 1;
50074         }
50075  #endif
50076 -                               
50077 -       if (srv_socket->fd == -1) {
50078 +
50079 +       if (srv_socket->sock->fd == -1) {
50080                 srv_socket->addr.plain.sa_family = AF_INET;
50081 -               if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
50082 +               if (-1 == (srv_socket->sock->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
50083                         log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
50084                         return -1;
50085                 }
50086         }
50087 -       
50088 +
50089         /* */
50090 -       srv->cur_fds = srv_socket->fd;
50091 -       
50092 +       srv->cur_fds = srv_socket->sock->fd;
50093 +
50094         val = 1;
50095 -       if (setsockopt(srv_socket->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
50096 +       if (setsockopt(srv_socket->sock->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
50097                 log_error_write(srv, __FILE__, __LINE__, "ss", "socketsockopt failed:", strerror(errno));
50098                 return -1;
50099         }
50100 -       
50101 +
50102         switch(srv_socket->addr.plain.sa_family) {
50103  #ifdef HAVE_IPV6
50104         case AF_INET6:
50105 @@ -190,23 +191,23 @@
50106                 } else {
50107                         struct addrinfo hints, *res;
50108                         int r;
50109 -                       
50110 +
50111                         memset(&hints, 0, sizeof(hints));
50112 -                       
50113 +
50114                         hints.ai_family   = AF_INET6;
50115                         hints.ai_socktype = SOCK_STREAM;
50116                         hints.ai_protocol = IPPROTO_TCP;
50117 -                       
50118 +
50119                         if (0 != (r = getaddrinfo(host, NULL, &hints, &res))) {
50120 -                               log_error_write(srv, __FILE__, __LINE__, 
50121 -                                               "sssss", "getaddrinfo failed: ", 
50122 +                               log_error_write(srv, __FILE__, __LINE__,
50123 +                                               "sssss", "getaddrinfo failed: ",
50124                                                 gai_strerror(r), "'", host, "'");
50125 -                               
50126 +
50127                                 return -1;
50128                         }
50129 -                       
50130 +
50131                         memcpy(&(srv_socket->addr), res->ai_addr, res->ai_addrlen);
50132 -                       
50133 +
50134                         freeaddrinfo(res);
50135                 }
50136                 srv_socket->addr.ipv6.sin6_port = htons(port);
50137 @@ -221,33 +222,34 @@
50138                 } else {
50139                         struct hostent *he;
50140                         if (NULL == (he = gethostbyname(host))) {
50141 -                               log_error_write(srv, __FILE__, __LINE__, 
50142 -                                               "sds", "gethostbyname failed: ", 
50143 +                               log_error_write(srv, __FILE__, __LINE__,
50144 +                                               "sds", "gethostbyname failed: ",
50145                                                 h_errno, host);
50146                                 return -1;
50147                         }
50148 -                       
50149 +
50150                         if (he->h_addrtype != AF_INET) {
50151                                 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype);
50152                                 return -1;
50153                         }
50154 -                       
50155 +
50156                         if (he->h_length != sizeof(struct in_addr)) {
50157                                 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length);
50158                                 return -1;
50159                         }
50160 -                       
50161 +
50162                         memcpy(&(srv_socket->addr.ipv4.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
50163                 }
50164                 srv_socket->addr.ipv4.sin_port = htons(port);
50165 -               
50166 +
50167                 addr_len = sizeof(struct sockaddr_in);
50168 -               
50169 +
50170                 break;
50171 +#ifndef _WIN32
50172         case AF_UNIX:
50173                 srv_socket->addr.un.sun_family = AF_UNIX;
50174                 strcpy(srv_socket->addr.un.sun_path, host);
50175 -               
50176 +
50177  #ifdef SUN_LEN
50178                 addr_len = SUN_LEN(&srv_socket->addr.un);
50179  #else
50180 @@ -256,11 +258,11 @@
50181  #endif
50182  
50183                 /* check if the socket exists and try to connect to it. */
50184 -               if (-1 != (fd = connect(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len))) {
50185 +               if (-1 != (fd = connect(srv_socket->sock->fd, (struct sockaddr *) &(srv_socket->addr), addr_len))) {
50186                         close(fd);
50187  
50188 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
50189 -                               "server socket is still in use:", 
50190 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
50191 +                               "server socket is still in use:",
50192                                 host);
50193  
50194  
50195 @@ -275,88 +277,89 @@
50196                 case ENOENT:
50197                         break;
50198                 default:
50199 -                       log_error_write(srv, __FILE__, __LINE__, "sds", 
50200 -                               "testing socket failed:", 
50201 +                       log_error_write(srv, __FILE__, __LINE__, "sds",
50202 +                               "testing socket failed:",
50203                                 host, strerror(errno));
50204  
50205                         return -1;
50206                 }
50207  
50208                 break;
50209 +#endif
50210         default:
50211                 addr_len = 0;
50212 -               
50213 +
50214                 return -1;
50215         }
50216 -       
50217 -       if (0 != bind(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) {
50218 +
50219 +       if (0 != bind(srv_socket->sock->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) {
50220                 switch(srv_socket->addr.plain.sa_family) {
50221                 case AF_UNIX:
50222 -                       log_error_write(srv, __FILE__, __LINE__, "sds", 
50223 -                                       "can't bind to socket:", 
50224 +                       log_error_write(srv, __FILE__, __LINE__, "sds",
50225 +                                       "can't bind to socket:",
50226                                         host, strerror(errno));
50227                         break;
50228                 default:
50229 -                       log_error_write(srv, __FILE__, __LINE__, "ssds", 
50230 -                                       "can't bind to port:", 
50231 +                       log_error_write(srv, __FILE__, __LINE__, "ssds",
50232 +                                       "can't bind to port:",
50233                                         host, port, strerror(errno));
50234                         break;
50235                 }
50236                 return -1;
50237         }
50238 -       
50239 -       if (-1 == listen(srv_socket->fd, 128 * 8)) {
50240 +
50241 +       if (-1 == listen(srv_socket->sock->fd, 128 * 8)) {
50242                 log_error_write(srv, __FILE__, __LINE__, "ss", "listen failed: ", strerror(errno));
50243                 return -1;
50244         }
50245 -       
50246 +
50247         if (s->is_ssl) {
50248  #ifdef USE_OPENSSL
50249                 if (srv->ssl_is_init == 0) {
50250                         SSL_load_error_strings();
50251                         SSL_library_init();
50252                         srv->ssl_is_init = 1;
50253 -                       
50254 +
50255                         if (0 == RAND_status()) {
50256 -                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", 
50257 +                               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
50258                                                 "not enough entropy in the pool");
50259                                 return -1;
50260                         }
50261                 }
50262 -               
50263 +
50264                 if (NULL == (s->ssl_ctx = SSL_CTX_new(SSLv23_server_method()))) {
50265 -                       log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", 
50266 +                       log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
50267                                         ERR_error_string(ERR_get_error(), NULL));
50268                         return -1;
50269                 }
50270 -               
50271 +
50272                 if (buffer_is_empty(s->ssl_pemfile)) {
50273                         log_error_write(srv, __FILE__, __LINE__, "s", "ssl.pemfile has to be set");
50274                         return -1;
50275                 }
50276 -               
50277 +
50278                 if (!buffer_is_empty(s->ssl_ca_file)) {
50279                         if (1 != SSL_CTX_load_verify_locations(s->ssl_ctx, s->ssl_ca_file->ptr, NULL)) {
50280 -                               log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", 
50281 +                               log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
50282                                                 ERR_error_string(ERR_get_error(), NULL), s->ssl_ca_file);
50283                                 return -1;
50284                         }
50285                 }
50286 -               
50287 +
50288                 if (SSL_CTX_use_certificate_file(s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) {
50289 -                       log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", 
50290 +                       log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
50291                                         ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
50292                         return -1;
50293                 }
50294 -               
50295 +
50296                 if (SSL_CTX_use_PrivateKey_file (s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) {
50297 -                       log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", 
50298 +                       log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
50299                                         ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
50300                         return -1;
50301                 }
50302 -               
50303 +
50304                 if (SSL_CTX_check_private_key(s->ssl_ctx) != 1) {
50305 -                       log_error_write(srv, __FILE__, __LINE__, "sssb", "SSL:", 
50306 +                       log_error_write(srv, __FILE__, __LINE__, "sssb", "SSL:",
50307                                         "Private key does not match the certificate public key, reason:",
50308                                         ERR_error_string(ERR_get_error(), NULL),
50309                                         s->ssl_pemfile);
50310 @@ -364,15 +367,15 @@
50311                 }
50312                 srv_socket->ssl_ctx = s->ssl_ctx;
50313  #else
50314 -               
50315 +
50316                 buffer_free(srv_socket->srv_token);
50317                 free(srv_socket);
50318 -               
50319 +
50320                 buffer_free(b);
50321 -               
50322 -               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", 
50323 +
50324 +               log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
50325                                 "ssl requested but openssl support is not compiled in");
50326 -               
50327 +
50328                 return -1;
50329  #endif
50330         } else {
50331 @@ -383,17 +386,16 @@
50332                  */
50333                 memset(&afa, 0, sizeof(afa));
50334                 strcpy(afa.af_name, "httpready");
50335 -               if (setsockopt(srv_socket->fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)) < 0) {
50336 +               if (setsockopt(srv_socket->sock->fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)) < 0) {
50337                         if (errno != ENOENT) {
50338                                 log_error_write(srv, __FILE__, __LINE__, "ss", "can't set accept-filter 'httpready': ", strerror(errno));
50339                         }
50340                 }
50341  #endif
50342         }
50343 -       
50344 +
50345         srv_socket->is_ssl = s->is_ssl;
50346 -       srv_socket->fde_ndx = -1;
50347 -       
50348 +
50349         if (srv->srv_sockets.size == 0) {
50350                 srv->srv_sockets.size = 4;
50351                 srv->srv_sockets.used = 0;
50352 @@ -402,11 +404,10 @@
50353                 srv->srv_sockets.size += 4;
50354                 srv->srv_sockets.ptr = realloc(srv->srv_sockets.ptr, srv->srv_sockets.size * sizeof(server_socket));
50355         }
50356 -       
50357 +
50358         srv->srv_sockets.ptr[srv->srv_sockets.used++] = srv_socket;
50359 -       
50360         buffer_free(b);
50361 -       
50362 +
50363         return 0;
50364  }
50365  
50366 @@ -414,45 +415,60 @@
50367         size_t i;
50368         for (i = 0; i < srv->srv_sockets.used; i++) {
50369                 server_socket *srv_socket = srv->srv_sockets.ptr[i];
50370 -               
50371 -               if (srv_socket->fd != -1) {
50372 +
50373 +               if (srv_socket->sock->fd != -1) {
50374                         /* check if server fd are already registered */
50375 -                       if (srv_socket->fde_ndx != -1) {
50376 -                               fdevent_event_del(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd);
50377 -                               fdevent_unregister(srv->ev, srv_socket->fd);
50378 +                       if (srv_socket->sock->fde_ndx != -1) {
50379 +                               fdevent_event_del(srv->ev, srv_socket->sock);
50380 +                               fdevent_unregister(srv->ev, srv_socket->sock);
50381                         }
50382 -               
50383 -                       close(srv_socket->fd);
50384 +
50385 +                       closesocket(srv_socket->sock->fd);
50386 +               }
50387 +
50388 +               if (srv_socket->is_ssl) {
50389 +#ifdef USE_OPENSSL
50390 +                       SSL_CTX_free(srv_socket->ssl_ctx);
50391 +#endif
50392                 }
50393 -               
50394 +
50395 +               iosocket_free(srv_socket->sock);
50396 +
50397                 buffer_free(srv_socket->srv_token);
50398 -               
50399 +
50400                 free(srv_socket);
50401         }
50402 -       
50403 +
50404 +#ifdef USE_OPENSSL
50405 +       ERR_free_strings();
50406 +#endif
50407         free(srv->srv_sockets.ptr);
50408 -       
50409 +
50410         return 0;
50411  }
50412  
50413  typedef enum {
50414         NETWORK_BACKEND_UNSET,
50415 +
50416         NETWORK_BACKEND_WRITE,
50417         NETWORK_BACKEND_WRITEV,
50418         NETWORK_BACKEND_LINUX_SENDFILE,
50419         NETWORK_BACKEND_FREEBSD_SENDFILE,
50420 -       NETWORK_BACKEND_SOLARIS_SENDFILEV
50421 +       NETWORK_BACKEND_SOLARIS_SENDFILEV,
50422 +
50423 +    NETWORK_BACKEND_WIN32_SEND,
50424 +    NETWORK_BACKEND_WIN32_TRANSMITFILE,
50425  } network_backend_t;
50426  
50427  int network_init(server *srv) {
50428         buffer *b;
50429         size_t i;
50430         network_backend_t backend;
50431 -       
50432 -       struct nb_map { 
50433 -               network_backend_t nb; 
50434 -               const char *name; 
50435 -       } network_backends[] = { 
50436 +
50437 +       struct nb_map {
50438 +               network_backend_t nb;
50439 +               const char *name;
50440 +       } network_backends[] = {
50441                 /* lowest id wins */
50442  #if defined USE_LINUX_SENDFILE
50443                 { NETWORK_BACKEND_LINUX_SENDFILE,       "linux-sendfile" },
50444 @@ -466,21 +482,30 @@
50445  #if defined USE_WRITEV
50446                 { NETWORK_BACKEND_WRITEV,               "writev" },
50447  #endif
50448 +#if defined USE_WRITE
50449                 { NETWORK_BACKEND_WRITE,                "write" },
50450 +#endif
50451 +#if defined USE_WIN32_TRANSMITFILE
50452 +               { NETWORK_BACKEND_WIN32_TRANSMITFILE,   "win32-transmitfile" },
50453 +#endif
50454 +#if defined USE_WIN32_SEND
50455 +               { NETWORK_BACKEND_WIN32_SEND,           "win32-send" },
50456 +#endif
50457 +
50458                 { NETWORK_BACKEND_UNSET,                NULL }
50459         };
50460 -       
50461 +
50462         b = buffer_init();
50463 -               
50464 +
50465         buffer_copy_string_buffer(b, srv->srvconf.bindhost);
50466         buffer_append_string(b, ":");
50467         buffer_append_long(b, srv->srvconf.port);
50468 -       
50469 +
50470         if (0 != network_server_init(srv, b, srv->config_storage[0])) {
50471                 return -1;
50472         }
50473         buffer_free(b);
50474 -               
50475 +
50476  #ifdef USE_OPENSSL
50477         srv->network_ssl_backend_write = network_write_chunkqueue_openssl;
50478  #endif
50479 @@ -500,54 +525,80 @@
50480                 if (NULL == network_backends[i].name) {
50481                         /* we don't know it */
50482  
50483 -                       log_error_write(srv, __FILE__, __LINE__, "sb", 
50484 -                                       "server.network-backend has a unknown value:", 
50485 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
50486 +                                       "server.network-backend has a unknown value:",
50487                                         srv->srvconf.network_backend);
50488  
50489                         return -1;
50490                 }
50491         }
50492  
50493 +#define SET_NETWORK_BACKEND(read, write) \
50494 +    srv->network_backend_write = network_write_chunkqueue_##write;\
50495 +    srv->network_backend_read = network_read_chunkqueue_##read
50496 +
50497 +#define SET_NETWORK_BACKEND_SSL(read, write) \
50498 +    srv->network_ssl_backend_write = network_write_chunkqueue_##write;\
50499 +    srv->network_ssl_backend_read = network_read_chunkqueue_##read
50500 +
50501         switch(backend) {
50502 +
50503 +#ifdef USE_WIN32_SEND
50504 +       case NETWORK_BACKEND_WIN32_SEND:
50505 +        SET_NETWORK_BACKEND(win32recv, win32send);
50506 +               break;
50507 +#ifdef USE_WIN32_TRANSMITFILE
50508 +       case NETWORK_BACKEND_WIN32_TRANSMITFILE:
50509 +        SET_NETWORK_BACKEND(win32recv, win32transmitfile);
50510 +               break;
50511 +#endif
50512 +#endif
50513 +
50514 +#ifdef USE_WRITE
50515         case NETWORK_BACKEND_WRITE:
50516 -               srv->network_backend_write = network_write_chunkqueue_write;
50517 +        SET_NETWORK_BACKEND(read, write);
50518                 break;
50519 +
50520  #ifdef USE_WRITEV
50521         case NETWORK_BACKEND_WRITEV:
50522 -               srv->network_backend_write = network_write_chunkqueue_writev;
50523 +        SET_NETWORK_BACKEND(read, writev);
50524                 break;
50525  #endif
50526  #ifdef USE_LINUX_SENDFILE
50527         case NETWORK_BACKEND_LINUX_SENDFILE:
50528 -               srv->network_backend_write = network_write_chunkqueue_linuxsendfile; 
50529 +        SET_NETWORK_BACKEND(read, linuxsendfile);
50530                 break;
50531  #endif
50532  #ifdef USE_FREEBSD_SENDFILE
50533         case NETWORK_BACKEND_FREEBSD_SENDFILE:
50534 -               srv->network_backend_write = network_write_chunkqueue_freebsdsendfile; 
50535 +        SET_NETWORK_BACKEND(read, freebsdsendfile);
50536                 break;
50537  #endif
50538  #ifdef USE_SOLARIS_SENDFILEV
50539         case NETWORK_BACKEND_SOLARIS_SENDFILEV:
50540 -               srv->network_backend_write = network_write_chunkqueue_solarissendfilev; 
50541 +        SET_NETWORK_BACKEND(read, solarissendfilev);
50542                 break;
50543  #endif
50544 +#endif
50545         default:
50546                 return -1;
50547         }
50548 +#ifdef USE_OPENSSL
50549 +        SET_NETWORK_BACKEND_SSL(openssl, openssl);
50550 +#endif
50551  
50552         /* check for $SERVER["socket"] */
50553         for (i = 1; i < srv->config_context->used; i++) {
50554                 data_config *dc = (data_config *)srv->config_context->data[i];
50555                 specific_config *s = srv->config_storage[i];
50556                 size_t j;
50557 -               
50558 +
50559                 /* not our stage */
50560                 if (COMP_SERVER_SOCKET != dc->comp) continue;
50561 -               
50562 +
50563                 if (dc->cond != CONFIG_COND_EQ) {
50564                         log_error_write(srv, __FILE__, __LINE__, "s", "only == is allowed for $SERVER[\"socket\"].");
50565 -                       
50566 +
50567                         return -1;
50568                 }
50569  
50570 @@ -558,36 +609,47 @@
50571                                 break;
50572                         }
50573                 }
50574 -               
50575 +
50576                 if (j == srv->srv_sockets.used) {
50577                         if (0 != network_server_init(srv, dc->string, s)) return -1;
50578                 }
50579         }
50580 -       
50581 +
50582         return 0;
50583  }
50584  
50585  int network_register_fdevents(server *srv) {
50586         size_t i;
50587 -       
50588         if (-1 == fdevent_reset(srv->ev)) {
50589                 return -1;
50590         }
50591 -       
50592         /* register fdevents after reset */
50593         for (i = 0; i < srv->srv_sockets.used; i++) {
50594                 server_socket *srv_socket = srv->srv_sockets.ptr[i];
50595 -               
50596 -               fdevent_register(srv->ev, srv_socket->fd, network_server_handle_fdevent, srv_socket);
50597 -               fdevent_event_add(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN);
50598 +               fdevent_register(srv->ev, srv_socket->sock, network_server_handle_fdevent, srv_socket);
50599 +               fdevent_event_add(srv->ev, srv_socket->sock, FDEVENT_IN);
50600         }
50601         return 0;
50602  }
50603  
50604 -int network_write_chunkqueue(server *srv, connection *con, chunkqueue *cq) {
50605 -       int ret = -1;
50606 +network_status_t network_read(server *srv, connection *con, iosocket *sock, chunkqueue *cq) {
50607 +       server_socket *srv_socket = con->srv_socket;
50608 +
50609 +       if (srv_socket->is_ssl) {
50610 +#ifdef USE_OPENSSL
50611 +               return srv->network_ssl_backend_read(srv, con, sock, cq);
50612 +#else
50613 +               return NETWORK_STATUS_FATAL_ERROR;
50614 +#endif
50615 +       } else {
50616 +               return srv->network_backend_read(srv, con, sock, cq);
50617 +       }
50618 +}
50619 +
50620 +network_status_t network_write_chunkqueue(server *srv, connection *con, chunkqueue *cq) {
50621 +       network_status_t ret = NETWORK_STATUS_UNSET;
50622         off_t written = 0;
50623 -#ifdef TCP_CORK        
50624 +#ifdef TCP_CORK
50625         int corked = 0;
50626  #endif
50627         server_socket *srv_socket = con->srv_socket;
50628 @@ -600,37 +662,42 @@
50629                 joblist_append(srv, con);
50630  
50631                 return 1;
50632 -       }  
50633 +       }
50634  
50635         written = cq->bytes_out;
50636  
50637 -#ifdef TCP_CORK        
50638 +#ifdef TCP_CORK
50639         /* Linux: put a cork into the socket as we want to combine the write() calls
50640          * but only if we really have multiple chunks
50641          */
50642         if (cq->first && cq->first->next) {
50643                 corked = 1;
50644 -               setsockopt(con->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
50645 +               setsockopt(con->sock->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
50646         }
50647  #endif
50648 -       
50649 +
50650         if (srv_socket->is_ssl) {
50651  #ifdef USE_OPENSSL
50652 -               ret = srv->network_ssl_backend_write(srv, con, con->ssl, cq);
50653 +               ret = srv->network_ssl_backend_write(srv, con, con->sock, cq);
50654  #endif
50655         } else {
50656 -               ret = srv->network_backend_write(srv, con, con->fd, cq);
50657 +               ret = srv->network_backend_write(srv, con, con->sock, cq);
50658         }
50659 -       
50660 -       if (ret >= 0) {
50661 +
50662 +    switch (ret) {
50663 +    case NETWORK_STATUS_WAIT_FOR_EVENT:
50664 +    case NETWORK_STATUS_SUCCESS:
50665                 chunkqueue_remove_finished_chunks(cq);
50666 -               ret = chunkqueue_is_empty(cq) ? 0 : 1;
50667 +
50668 +        break;
50669 +    default:
50670 +        break;
50671         }
50672 -       
50673 +
50674  #ifdef TCP_CORK
50675         if (corked) {
50676                 corked = 0;
50677 -               setsockopt(con->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
50678 +               setsockopt(con->sock->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
50679         }
50680  #endif
50681  
50682 @@ -639,13 +706,13 @@
50683         con->bytes_written_cur_second += written;
50684  
50685         *(con->conf.global_bytes_per_second_cnt_ptr) += written;
50686 -       
50687 +
50688         if (con->conf.kbytes_per_second &&
50689             (con->bytes_written_cur_second > con->conf.kbytes_per_second * 1024)) {
50690                 /* we reached the traffic limit */
50691  
50692                 con->traffic_limit_reached = 1;
50693                 joblist_append(srv, con);
50694 -       }  
50695 +       }
50696         return ret;
50697  }
50698 --- ../lighttpd-1.4.11/src/network.h    2005-08-11 01:26:42.000000000 +0300
50699 +++ lighttpd-1.5.0/src/network.h        2006-09-07 00:57:05.000000000 +0300
50700 @@ -3,11 +3,13 @@
50701  
50702  #include "server.h"
50703  
50704 -int network_write_chunkqueue(server *srv, connection *con, chunkqueue *c);
50705 +network_status_t network_write_chunkqueue(server *srv, connection *con, chunkqueue *c);
50706 +network_status_t network_read(server *srv, connection *con, iosocket *sock, chunkqueue *c);
50707  
50708  int network_init(server *srv);
50709  int network_close(server *srv);
50710  
50711  int network_register_fdevents(server *srv);
50712 +handler_t network_server_handle_fdevent(void *s, void *context, int revents);
50713  
50714  #endif
50715 --- ../lighttpd-1.4.11/src/network_backends.h   2005-10-24 15:13:51.000000000 +0300
50716 +++ lighttpd-1.5.0/src/network_backends.h       2006-07-18 13:03:40.000000000 +0300
50717 @@ -43,16 +43,47 @@
50718  # define USE_AIX_SENDFILE
50719  #endif
50720  
50721 +/**
50722 +* unix can use read/write or recv/send on sockets
50723 +* win32 only recv/send
50724 +*/
50725 +#ifdef _WIN32
50726 +# define USE_WIN32_SEND
50727 +/* wait for async-io support
50728 +# define USE_WIN32_TRANSMITFILE
50729 +*/
50730 +#else
50731 +# define USE_WRITE
50732 +#endif
50733 +
50734  #include "base.h"
50735 +#include "network.h"
50736 +
50737 +#define NETWORK_BACKEND_WRITE_CHUNK(x) \
50738 +    network_status_t network_write_chunkqueue_##x(server *srv, connection *con, iosocket *sock, chunkqueue *cq, chunk *c)
50739 +
50740 +#define NETWORK_BACKEND_WRITE(x) \
50741 +    network_status_t network_write_chunkqueue_##x(server *srv, connection *con, iosocket *sock, chunkqueue *cq)
50742 +#define NETWORK_BACKEND_READ(x) \
50743 +    network_status_t network_read_chunkqueue_##x(server *srv, connection *con, iosocket *sock, chunkqueue *cq)
50744 +
50745 +NETWORK_BACKEND_WRITE_CHUNK(writev_mem);
50746 +
50747 +NETWORK_BACKEND_WRITE(write);
50748 +NETWORK_BACKEND_WRITE(writev);
50749 +NETWORK_BACKEND_WRITE(linuxsendfile);
50750 +NETWORK_BACKEND_WRITE(freebsdsendfile);
50751 +NETWORK_BACKEND_WRITE(solarissendfilev);
50752 +
50753 +NETWORK_BACKEND_WRITE(win32transmitfile);
50754 +NETWORK_BACKEND_WRITE(win32send);
50755  
50756 +NETWORK_BACKEND_READ(read);
50757 +NETWORK_BACKEND_READ(win32recv);
50758  
50759 -int network_write_chunkqueue_write(server *srv, connection *con, int fd, chunkqueue *cq);
50760 -int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkqueue *cq);
50761 -int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, chunkqueue *cq);
50762 -int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int fd, chunkqueue *cq);
50763 -int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int fd, chunkqueue *cq);
50764  #ifdef USE_OPENSSL
50765 -int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq);
50766 +NETWORK_BACKEND_WRITE(openssl);
50767 +NETWORK_BACKEND_READ(openssl);
50768  #endif
50769  
50770  #endif
50771 --- ../lighttpd-1.4.11/src/network_freebsd_sendfile.c   2005-10-22 12:28:18.000000000 +0300
50772 +++ lighttpd-1.5.0/src/network_freebsd_sendfile.c       2006-09-07 00:57:05.000000000 +0300
50773 @@ -26,182 +26,115 @@
50774  
50775  #ifndef UIO_MAXIOV
50776  # ifdef __FreeBSD__
50777 -/* FreeBSD 4.7, 4.9 defined it in sys/uio.h only if _KERNEL is specified */ 
50778 +/* FreeBSD 4.7, 4.9 defined it in sys/uio.h only if _KERNEL is specified */
50779  #  define UIO_MAXIOV 1024
50780  # endif
50781  #endif
50782  
50783 -int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int fd, chunkqueue *cq) {
50784 +NETWORK_BACKEND_WRITE(freebsdsendfile) {
50785         chunk *c;
50786         size_t chunks_written = 0;
50787 -       
50788 +
50789         for(c = cq->first; c; c = c->next, chunks_written++) {
50790 +               chunk *tc;
50791                 int chunk_finished = 0;
50792 -               
50793 +               network_status_t ret;
50794 +
50795                 switch(c->type) {
50796 -               case MEM_CHUNK: {
50797 -                       char * offset;
50798 -                       size_t toSend;
50799 -                       ssize_t r;
50800 -                       
50801 -                       size_t num_chunks, i;
50802 -                       struct iovec chunks[UIO_MAXIOV];
50803 -                       chunk *tc;
50804 -                       size_t num_bytes = 0;
50805 -                       
50806 -                       /* we can't send more then SSIZE_MAX bytes in one chunk */
50807 -                       
50808 -                       /* build writev list 
50809 -                        * 
50810 -                        * 1. limit: num_chunks < UIO_MAXIOV
50811 -                        * 2. limit: num_bytes < SSIZE_MAX
50812 -                        */
50813 -                       for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
50814 -                       
50815 -                       for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
50816 -                               if (tc->mem->used == 0) {
50817 -                                       chunks[i].iov_base = tc->mem->ptr;
50818 -                                       chunks[i].iov_len  = 0;
50819 -                               } else {
50820 -                                       offset = tc->mem->ptr + tc->offset;
50821 -                                       toSend = tc->mem->used - 1 - tc->offset;
50822 -                                       
50823 -                                       chunks[i].iov_base = offset;
50824 -                                       
50825 -                                       /* protect the return value of writev() */
50826 -                                       if (toSend > SSIZE_MAX ||
50827 -                                           num_bytes + toSend > SSIZE_MAX) {
50828 -                                               chunks[i].iov_len = SSIZE_MAX - num_bytes;
50829 -                                               
50830 -                                               num_chunks = i + 1;
50831 -                                               break;
50832 -                                       } else {
50833 -                                               chunks[i].iov_len = toSend;
50834 -                                       }
50835 -                                
50836 -                                       num_bytes += toSend;
50837 -                               }
50838 -                       }
50839 -                       
50840 -                       if ((r = writev(fd, chunks, num_chunks)) < 0) {
50841 -                               switch (errno) {
50842 -                               case EAGAIN:
50843 -                               case EINTR:
50844 -                                       r = 0;
50845 -                                       break;
50846 -                               case EPIPE:
50847 -                               case ECONNRESET:
50848 -                                       return -2;
50849 -                               default:
50850 -                                       log_error_write(srv, __FILE__, __LINE__, "ssd", 
50851 -                                                       "writev failed:", strerror(errno), fd);
50852 -                                       
50853 -                                       return -1;
50854 -                               }
50855 +               case MEM_CHUNK:
50856 +                       ret = network_write_chunkqueue_writev_mem(srv, con, sock, cq, c);
50857  
50858 -                               r = 0;
50859 -                       }
50860 -                       
50861 -                       /* check which chunks have been written */
50862 -                       cq->bytes_out += r;
50863 -                       
50864 -                       for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
50865 -                               if (r >= (ssize_t)chunks[i].iov_len) {
50866 -                                       /* written */
50867 -                                       r -= chunks[i].iov_len;
50868 -                                       tc->offset += chunks[i].iov_len;
50869 -                                       
50870 +                       /* check which chunks are finished now */
50871 +                       for (tc = c; tc; tc = tc->next) {
50872 +                               /* finished the chunk */
50873 +                               if (tc->offset == tc->mem->used - 1) {
50874 +                                       /* skip the first c->next as that will be done by the c = c->next in the other for()-loop */
50875                                         if (chunk_finished) {
50876 -                                               /* skip the chunks from further touches */
50877 -                                               chunks_written++;
50878                                                 c = c->next;
50879                                         } else {
50880 -                                               /* chunks_written + c = c->next is done in the for()*/
50881 -                                               chunk_finished++;
50882 +                                               chunk_finished = 1;
50883                                         }
50884                                 } else {
50885 -                                       /* partially written */
50886 -                                       
50887 -                                       tc->offset += r;
50888 -                                       chunk_finished = 0;
50889 -                                       
50890                                         break;
50891                                 }
50892                         }
50893 -                       
50894 +
50895 +                       if (ret != NETWORK_STATUS_SUCCESS) {
50896 +                               return ret;
50897 +                       }
50898 +
50899                         break;
50900 -               }
50901                 case FILE_CHUNK: {
50902                         off_t offset, r;
50903                         size_t toSend;
50904                         stat_cache_entry *sce = NULL;
50905                         int ifd;
50906 -                       
50907 +
50908                         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
50909                                 log_error_write(srv, __FILE__, __LINE__, "sb",
50910                                                 strerror(errno), c->file.name);
50911 -                               return -1;
50912 +                               return NETWORK_STATUS_FATAL_ERROR;
50913                         }
50914 -                       
50915 +
50916                         offset = c->file.start + c->offset;
50917                         /* limit the toSend to 2^31-1 bytes in a chunk */
50918 -                       toSend = c->file.length - c->offset > ((1 << 30) - 1) ? 
50919 +                       toSend = c->file.length - c->offset > ((1 << 30) - 1) ?
50920                                 ((1 << 30) - 1) : c->file.length - c->offset;
50921 -                               
50922 +
50923                         if (offset > sce->st.st_size) {
50924                                 log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
50925 -                               
50926 -                               return -1;
50927 +
50928 +                               return NETWORK_STATUS_FATAL_ERROR;
50929                         }
50930 -                       
50931 +
50932                         if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
50933                                 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
50934 -                               
50935 -                               return -1;
50936 +
50937 +                               return NETWORK_STATUS_FATAL_ERROR;
50938                         }
50939 -                       
50940 +
50941                         r = 0;
50942 -                       
50943 +
50944                         /* FreeBSD sendfile() */
50945 -                       if (-1 == sendfile(ifd, fd, offset, toSend, NULL, &r, 0)) {
50946 +                       if (-1 == sendfile(ifd, sock->fd, offset, toSend, NULL, &r, 0)) {
50947                                 switch(errno) {
50948                                 case EAGAIN:
50949                                         break;
50950                                 case ENOTCONN:
50951                                         close(ifd);
50952 -                                       return -2;
50953 +                                       return NETWORK_STATUS_CONNECTION_CLOSE;
50954                                 default:
50955                                         log_error_write(srv, __FILE__, __LINE__, "ssd", "sendfile: ", strerror(errno), errno);
50956                                         close(ifd);
50957 -                                       return -1;
50958 +                                       return NETWORK_STATUS_FATAL_ERROR;
50959                                 }
50960                         }
50961                         close(ifd);
50962 -                       
50963 +
50964                         c->offset += r;
50965                         cq->bytes_out += r;
50966 -                       
50967 +
50968                         if (c->offset == c->file.length) {
50969                                 chunk_finished = 1;
50970                         }
50971 -                       
50972 +
50973                         break;
50974                 }
50975                 default:
50976 -                       
50977 +
50978                         log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
50979 -                       
50980 -                       return -1;
50981 +
50982 +                       return NETWORK_STATUS_FATAL_ERROR;
50983                 }
50984 -               
50985 +
50986                 if (!chunk_finished) {
50987                         /* not finished yet */
50988 -                       
50989 -                       break;
50990 +
50991 +                       return NETWORK_STATUS_WAIT_FOR_EVENT;
50992                 }
50993         }
50994  
50995 -       return chunks_written;
50996 +       return NETWORK_STATUS_SUCCESS;
50997  }
50998  
50999  #endif
51000 --- ../lighttpd-1.4.11/src/network_linux_sendfile.c     2006-02-15 20:02:36.000000000 +0200
51001 +++ lighttpd-1.5.0/src/network_linux_sendfile.c 2006-09-07 00:57:05.000000000 +0300
51002 @@ -26,122 +26,54 @@
51003  /* on linux 2.4.29 + debian/ubuntu we have crashes if this is enabled */
51004  #undef HAVE_POSIX_FADVISE
51005  
51006 -int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, chunkqueue *cq) {
51007 -       chunk *c;
51008 +NETWORK_BACKEND_WRITE(linuxsendfile) {
51009 +       chunk *c, *tc;
51010         size_t chunks_written = 0;
51011 -       
51012 +
51013         for(c = cq->first; c; c = c->next, chunks_written++) {
51014                 int chunk_finished = 0;
51015 -               
51016 +               network_status_t ret;
51017 +
51018                 switch(c->type) {
51019 -               case MEM_CHUNK: {
51020 -                       char * offset;
51021 -                       size_t toSend;
51022 -                       ssize_t r;
51023 -                       
51024 -                       size_t num_chunks, i;
51025 -                       struct iovec chunks[UIO_MAXIOV];
51026 -                       chunk *tc;
51027 -                       size_t num_bytes = 0;
51028 -                       
51029 -                       /* we can't send more then SSIZE_MAX bytes in one chunk */
51030 -                       
51031 -                       /* build writev list 
51032 -                        * 
51033 -                        * 1. limit: num_chunks < UIO_MAXIOV
51034 -                        * 2. limit: num_bytes < SSIZE_MAX
51035 -                        */
51036 -                       for (num_chunks = 0, tc = c; 
51037 -                            tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; 
51038 -                            tc = tc->next, num_chunks++);
51039 -                       
51040 -                       for (tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
51041 -                               if (tc->mem->used == 0) {
51042 -                                       chunks[i].iov_base = tc->mem->ptr;
51043 -                                       chunks[i].iov_len  = 0;
51044 -                               } else {
51045 -                                       offset = tc->mem->ptr + tc->offset;
51046 -                                       toSend = tc->mem->used - 1 - tc->offset;
51047 -                               
51048 -                                       chunks[i].iov_base = offset;
51049 -                                       
51050 -                                       /* protect the return value of writev() */
51051 -                                       if (toSend > SSIZE_MAX ||
51052 -                                           num_bytes + toSend > SSIZE_MAX) {
51053 -                                               chunks[i].iov_len = SSIZE_MAX - num_bytes;
51054 -                                               
51055 -                                               num_chunks = i + 1;
51056 -                                               break;
51057 -                                       } else {
51058 -                                               chunks[i].iov_len = toSend;
51059 -                                       }
51060 -                                
51061 -                                       num_bytes += toSend;
51062 -                               }
51063 -                       }
51064 -                       
51065 -                       if ((r = writev(fd, chunks, num_chunks)) < 0) {
51066 -                               switch (errno) {
51067 -                               case EAGAIN:
51068 -                               case EINTR:
51069 -                                       r = 0;
51070 -                                       break;
51071 -                               case EPIPE:
51072 -                               case ECONNRESET:
51073 -                                       return -2;
51074 -                               default:
51075 -                                       log_error_write(srv, __FILE__, __LINE__, "ssd", 
51076 -                                                       "writev failed:", strerror(errno), fd);
51077 -                               
51078 -                                       return -1;
51079 -                               }
51080 -                       }
51081 -                       
51082 -                       /* check which chunks have been written */
51083 -                       cq->bytes_out += r;
51084 +               case MEM_CHUNK:
51085 +                       ret = network_write_chunkqueue_writev_mem(srv, con, sock, cq, c);
51086  
51087 -                       for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
51088 -                               if (r >= (ssize_t)chunks[i].iov_len) {
51089 -                                       /* written */
51090 -                                       r -= chunks[i].iov_len;
51091 -                                       tc->offset += chunks[i].iov_len;
51092 -                                       
51093 +                       /* check which chunks are finished now */
51094 +                       for (tc = c; tc; tc = tc->next) {
51095 +                               /* finished the chunk */
51096 +                               if (tc->offset == tc->mem->used - 1) {
51097 +                                       /* skip the first c->next as that will be done by the c = c->next in the other for()-loop */
51098                                         if (chunk_finished) {
51099 -                                               /* skip the chunks from further touches */
51100 -                                               chunks_written++;
51101                                                 c = c->next;
51102                                         } else {
51103 -                                               /* chunks_written + c = c->next is done in the for()*/
51104 -                                               chunk_finished++;
51105 +                                               chunk_finished = 1;
51106                                         }
51107                                 } else {
51108 -                                       /* partially written */
51109 -                                       
51110 -                                       tc->offset += r;
51111 -                                       chunk_finished = 0;
51112 -                                       
51113                                         break;
51114                                 }
51115                         }
51116 -                       
51117 +
51118 +                       if (ret != NETWORK_STATUS_SUCCESS) {
51119 +                               return ret;
51120 +                       }
51121 +
51122                         break;
51123 -               }
51124                 case FILE_CHUNK: {
51125                         ssize_t r;
51126                         off_t offset;
51127                         size_t toSend;
51128                         stat_cache_entry *sce = NULL;
51129 -                       
51130 +
51131                         offset = c->file.start + c->offset;
51132                         /* limit the toSend to 2^31-1 bytes in a chunk */
51133 -                       toSend = c->file.length - c->offset > ((1 << 30) - 1) ? 
51134 +                       toSend = c->file.length - c->offset > ((1 << 30) - 1) ?
51135                                 ((1 << 30) - 1) : c->file.length - c->offset;
51136 -                               
51137 -                       /* open file if not already opened */   
51138 +
51139 +                       /* open file if not already opened */
51140                         if (-1 == c->file.fd) {
51141                                 if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
51142                                         log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
51143 -                               
51144 +
51145                                         return -1;
51146                                 }
51147  #ifdef FD_CLOEXEC
51148 @@ -151,26 +83,25 @@
51149                                 /* tell the kernel that we want to stream the file */
51150                                 if (-1 == posix_fadvise(c->file.fd, 0, 0, POSIX_FADV_SEQUENTIAL)) {
51151                                         if (ENOSYS != errno) {
51152 -                                               log_error_write(srv, __FILE__, __LINE__, "ssd", 
51153 +                                               log_error_write(srv, __FILE__, __LINE__, "ssd",
51154                                                         "posix_fadvise failed:", strerror(errno), c->file.fd);
51155                                         }
51156                                 }
51157  #endif
51158                         }
51159  
51160 -                       if (-1 == (r = sendfile(fd, c->file.fd, &offset, toSend))) {
51161 +                       if (-1 == (r = sendfile(sock->fd, c->file.fd, &offset, toSend))) {
51162                                 switch (errno) {
51163                                 case EAGAIN:
51164                                 case EINTR:
51165 -                                       r = 0;
51166 -                                       break;
51167 +                                       return NETWORK_STATUS_WAIT_FOR_EVENT;
51168                                 case EPIPE:
51169                                 case ECONNRESET:
51170 -                                       return -2;
51171 +                                       return NETWORK_STATUS_CONNECTION_CLOSE;
51172                                 default:
51173 -                                       log_error_write(srv, __FILE__, __LINE__, "ssd", 
51174 -                                                       "sendfile failed:", strerror(errno), fd);
51175 -                                       return -1;
51176 +                                       log_error_write(srv, __FILE__, __LINE__, "ssd",
51177 +                                                       "sendfile failed:", strerror(errno), sock->fd);
51178 +                                       return NETWORK_STATUS_FATAL_ERROR;
51179                                 }
51180                         }
51181  
51182 @@ -179,39 +110,39 @@
51183                                  *
51184                                  * - the file shrinked -> error
51185                                  * - the remote side closed inbetween -> remote-close */
51186 -       
51187 +
51188                                 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
51189                                         /* file is gone ? */
51190 -                                       return -1;
51191 +                                       return NETWORK_STATUS_FATAL_ERROR;
51192                                 }
51193  
51194                                 if (offset > sce->st.st_size) {
51195                                         /* file shrinked, close the connection */
51196 -                                       return -1;
51197 +                                       return NETWORK_STATUS_FATAL_ERROR;
51198                                 }
51199  
51200 -                               return -2;
51201 +                               return NETWORK_STATUS_CONNECTION_CLOSE;
51202                         }
51203  
51204  #ifdef HAVE_POSIX_FADVISE
51205  #if 0
51206  #define K * 1024
51207 -#define M * 1024 K     
51208 +#define M * 1024 K
51209  #define READ_AHEAD 4 M
51210                         /* check if we need a new chunk */
51211                         if ((c->offset & ~(READ_AHEAD - 1)) != ((c->offset + r) & ~(READ_AHEAD - 1))) {
51212                                 /* tell the kernel that we want to stream the file */
51213                                 if (-1 == posix_fadvise(c->file.fd, (c->offset + r) & ~(READ_AHEAD - 1), READ_AHEAD, POSIX_FADV_NOREUSE)) {
51214 -                                       log_error_write(srv, __FILE__, __LINE__, "ssd", 
51215 +                                       log_error_write(srv, __FILE__, __LINE__, "ssd",
51216                                                 "posix_fadvise failed:", strerror(errno), c->file.fd);
51217                                 }
51218                         }
51219  #endif
51220  #endif
51221 -                       
51222 +
51223                         c->offset += r;
51224                         cq->bytes_out += r;
51225 -                       
51226 +
51227                         if (c->offset == c->file.length) {
51228                                 chunk_finished = 1;
51229  
51230 @@ -222,24 +153,24 @@
51231                                         c->file.fd = -1;
51232                                 }
51233                         }
51234 -                       
51235 +
51236                         break;
51237                 }
51238                 default:
51239 -                       
51240 +
51241                         log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
51242 -                       
51243 -                       return -1;
51244 +
51245 +                       return NETWORK_STATUS_FATAL_ERROR;
51246                 }
51247 -               
51248 +
51249                 if (!chunk_finished) {
51250                         /* not finished yet */
51251 -                       
51252 -                       break;
51253 +
51254 +                       return NETWORK_STATUS_WAIT_FOR_EVENT;
51255                 }
51256         }
51257  
51258 -       return chunks_written;
51259 +       return NETWORK_STATUS_SUCCESS;
51260  }
51261  
51262  #endif
51263 --- ../lighttpd-1.4.11/src/network_openssl.c    2005-11-17 14:53:29.000000000 +0200
51264 +++ lighttpd-1.5.0/src/network_openssl.c        2006-09-07 00:57:05.000000000 +0300
51265 @@ -23,17 +23,94 @@
51266  #include "log.h"
51267  #include "stat_cache.h"
51268  
51269 -# include <openssl/ssl.h> 
51270 -# include <openssl/err.h> 
51271 +# include <openssl/ssl.h>
51272 +# include <openssl/err.h>
51273  
51274 -int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq) {
51275 +NETWORK_BACKEND_READ(openssl) {
51276 +       buffer *b;
51277 +       off_t len;
51278 +       int read_something = 0;
51279 +       off_t max_read = 256 * 1024;
51280 +
51281 +       off_t start_bytes_in = cq->bytes_in;
51282 +       do {
51283 +               b = chunkqueue_get_append_buffer(cq);
51284 +               buffer_prepare_copy(b, 8192 + 12); /* ssl-chunk-size is 8kb */
51285 +               len = SSL_read(sock->ssl, b->ptr, b->size - 1);
51286 +
51287 +               if (len < 0) {
51288 +                       int r, ssl_err;
51289 +       
51290 +                       switch ((r = SSL_get_error(sock->ssl, len))) {
51291 +                       case SSL_ERROR_WANT_READ:
51292 +                               chunkqueue_remove_empty_last_chunk(cq);
51293 +                               return read_something ? NETWORK_STATUS_SUCCESS : NETWORK_STATUS_WAIT_FOR_EVENT;
51294 +                       case SSL_ERROR_SYSCALL:
51295 +                               /**
51296 +                                * man SSL_get_error()
51297 +                                *
51298 +                                * SSL_ERROR_SYSCALL
51299 +                                *   Some I/O error occurred.  The OpenSSL error queue may contain more
51300 +                                *   information on the error.  If the error queue is empty (i.e.
51301 +                                *   ERR_get_error() returns 0), ret can be used to find out more about
51302 +                                *   the error: If ret == 0, an EOF was observed that violates the
51303 +                                *   protocol.  If ret == -1, the underlying BIO reported an I/O error
51304 +                                *   (for socket I/O on Unix systems, consult errno for details).
51305 +                                *
51306 +                                */
51307 +                               while((ssl_err = ERR_get_error())) {
51308 +                                       /* get all errors from the error-queue */
51309 +                                       ERROR("ssl-errors: %s", ERR_error_string(ssl_err, NULL));
51310 +                               }
51311 +
51312 +                               switch(errno) {
51313 +                               default:
51314 +                                       ERROR("last-errno: (%d) %s", errno, strerror(errno));
51315 +                                       break;
51316 +                               }
51317 +
51318 +                               break;
51319 +                       case SSL_ERROR_ZERO_RETURN:
51320 +                               /* clean shutdown on the remote side */
51321 +       
51322 +                               if (r == 0) {
51323 +                                       /* FIXME: later */
51324 +                               }
51325 +
51326 +                               /* fall through */
51327 +                       default:
51328 +                               while((ssl_err = ERR_get_error())) {
51329 +                                       /* get all errors from the error-queue */
51330 +                                       ERROR("ssl-errors: %s", ERR_error_string(ssl_err, NULL));
51331 +                               }
51332 +
51333 +                               return NETWORK_STATUS_FATAL_ERROR;
51334 +                       }
51335 +               } else if (len == 0) {
51336 +                       return NETWORK_STATUS_FATAL_ERROR;
51337 +               } else {
51338 +                       b->used += len;
51339 +                       b->ptr[b->used++] = '\0';
51340 +
51341 +                       read_something = 1;
51342 +                       cq->bytes_in += len;
51343 +               }
51344 +
51345 +               if (cq->bytes_in - start_bytes_in > max_read) return NETWORK_STATUS_SUCCESS;
51346 +       } while (1);
51347 +
51348 +       return NETWORK_STATUS_FATAL_ERROR;
51349 +}
51350 +
51351 +
51352 +NETWORK_BACKEND_WRITE(openssl) {
51353         int ssl_r;
51354         chunk *c;
51355         size_t chunks_written = 0;
51356  
51357         /* this is a 64k sendbuffer
51358          *
51359 -        * it has to stay at the same location all the time to satisfy the needs 
51360 +        * it has to stay at the same location all the time to satisfy the needs
51361          * of SSL_write to pass the SAME parameter in case of a _WANT_WRITE
51362          *
51363          * the buffer is allocated once, is NOT realloced and is NOT freed at shutdown
51364 @@ -43,59 +120,61 @@
51365          * In reality we would like to use mmap() but we don't have a guarantee that
51366          * we get the same mmap() address for each call. On openbsd the mmap() address
51367          * even randomized.
51368 -        *   That means either we keep the mmap() open or we do a read() into a 
51369 -        * constant buffer 
51370 +        *   That means either we keep the mmap() open or we do a read() into a
51371 +        * constant buffer
51372          * */
51373  #define LOCAL_SEND_BUFSIZE (64 * 1024)
51374         static char *local_send_buffer = NULL;
51375  
51376         /* the remote side closed the connection before without shutdown request
51377 -        * - IE 
51378 +        * - IE
51379          * - wget
51380          * if keep-alive is disabled */
51381  
51382         if (con->keep_alive == 0) {
51383 -               SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
51384 +               SSL_set_shutdown(sock->ssl, SSL_RECEIVED_SHUTDOWN);
51385         }
51386  
51387         for(c = cq->first; c; c = c->next) {
51388                 int chunk_finished = 0;
51389 -               
51390 +
51391                 switch(c->type) {
51392                 case MEM_CHUNK: {
51393                         char * offset;
51394                         size_t toSend;
51395 -                       ssize_t r;
51396 -                       
51397 +                       ssize_t r = 0;
51398 +
51399                         if (c->mem->used == 0) {
51400                                 chunk_finished = 1;
51401                                 break;
51402                         }
51403 -                       
51404 +
51405                         offset = c->mem->ptr + c->offset;
51406                         toSend = c->mem->used - 1 - c->offset;
51407 -                       
51408 +
51409                         /**
51410                          * SSL_write man-page
51411 -                        * 
51412 +                        *
51413                          * WARNING
51414                          *        When an SSL_write() operation has to be repeated because of
51415                          *        SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE, it must be
51416                          *        repeated with the same arguments.
51417 -                        * 
51418 +                        *
51419 +                        * SSL_write(..., 0) return 0 which is handle as an error (Success)
51420 +                        * checking toSend and not calling SSL_write() is simpler
51421                          */
51422 -                       
51423 -                       if ((r = SSL_write(ssl, offset, toSend)) <= 0) {
51424 +
51425 +                       if (toSend != 0 && (r = SSL_write(sock->ssl, offset, toSend)) <= 0) {
51426                                 unsigned long err;
51427  
51428 -                               switch ((ssl_r = SSL_get_error(ssl, r))) {
51429 +                               switch ((ssl_r = SSL_get_error(sock->ssl, r))) {
51430                                 case SSL_ERROR_WANT_WRITE:
51431                                         break;
51432                                 case SSL_ERROR_SYSCALL:
51433                                         /* perhaps we have error waiting in our error-queue */
51434                                         if (0 != (err = ERR_get_error())) {
51435                                                 do {
51436 -                                                       log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", 
51437 +                                                       log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
51438                                                                         ssl_r, r,
51439                                                                         ERR_error_string(err, NULL));
51440                                                 } while((err = ERR_get_error()));
51441 @@ -105,43 +184,43 @@
51442                                                 case EPIPE:
51443                                                         return -2;
51444                                                 default:
51445 -                                                       log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:", 
51446 +                                                       log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
51447                                                                         ssl_r, r, errno,
51448                                                                         strerror(errno));
51449                                                         break;
51450                                                 }
51451                                         } else {
51452                                                 /* neither error-queue nor errno ? */
51453 -                                               log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):", 
51454 +                                               log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
51455                                                                 ssl_r, r, errno,
51456                                                                 strerror(errno));
51457                                         }
51458 -                                       
51459 +
51460                                         return  -1;
51461                                 case SSL_ERROR_ZERO_RETURN:
51462                                         /* clean shutdown on the remote side */
51463 -                                       
51464 +
51465                                         if (r == 0) return -2;
51466 -                                       
51467 +
51468                                         /* fall through */
51469                                 default:
51470                                         while((err = ERR_get_error())) {
51471 -                                               log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", 
51472 +                                               log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
51473                                                                 ssl_r, r,
51474                                                                 ERR_error_string(err, NULL));
51475                                         }
51476 -                                       
51477 +
51478                                         return  -1;
51479                                 }
51480                         } else {
51481                                 c->offset += r;
51482                                 cq->bytes_out += r;
51483                         }
51484 -                       
51485 +
51486                         if (c->offset == (off_t)c->mem->used - 1) {
51487                                 chunk_finished = 1;
51488                         }
51489 -                       
51490 +
51491                         break;
51492                 }
51493                 case FILE_CHUNK: {
51494 @@ -150,7 +229,7 @@
51495                         stat_cache_entry *sce = NULL;
51496                         int ifd;
51497                         int write_wait = 0;
51498 -                       
51499 +
51500                         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
51501                                 log_error_write(srv, __FILE__, __LINE__, "sb",
51502                                                 strerror(errno), c->file.name);
51503 @@ -164,13 +243,13 @@
51504  
51505                         do {
51506                                 off_t offset = c->file.start + c->offset;
51507 -                               off_t toSend = c->file.length - c->offset; 
51508 +                               off_t toSend = c->file.length - c->offset;
51509  
51510                                 if (toSend > LOCAL_SEND_BUFSIZE) toSend = LOCAL_SEND_BUFSIZE;
51511 -                       
51512 +
51513                                 if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
51514                                         log_error_write(srv, __FILE__, __LINE__, "ss", "open failed:", strerror(errno));
51515 -                               
51516 +
51517                                         return -1;
51518                                 }
51519  
51520 @@ -183,13 +262,13 @@
51521                                 }
51522  
51523                                 s = local_send_buffer;
51524 -                       
51525 +
51526                                 close(ifd);
51527 -                       
51528 -                               if ((r = SSL_write(ssl, s, toSend)) <= 0) {
51529 +
51530 +                               if ((r = SSL_write(sock->ssl, s, toSend)) <= 0) {
51531                                         unsigned long err;
51532  
51533 -                                       switch ((ssl_r = SSL_get_error(ssl, r))) {
51534 +                                       switch ((ssl_r = SSL_get_error(sock->ssl, r))) {
51535                                         case SSL_ERROR_WANT_WRITE:
51536                                                 write_wait = 1;
51537                                                 break;
51538 @@ -197,7 +276,7 @@
51539                                                 /* perhaps we have error waiting in our error-queue */
51540                                                 if (0 != (err = ERR_get_error())) {
51541                                                         do {
51542 -                                                               log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", 
51543 +                                                               log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
51544                                                                                 ssl_r, r,
51545                                                                                 ERR_error_string(err, NULL));
51546                                                         } while((err = ERR_get_error()));
51547 @@ -207,62 +286,62 @@
51548                                                         case EPIPE:
51549                                                                 return -2;
51550                                                         default:
51551 -                                                               log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:", 
51552 +                                                               log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
51553                                                                                 ssl_r, r, errno,
51554                                                                                 strerror(errno));
51555                                                                 break;
51556                                                         }
51557                                                 } else {
51558                                                         /* neither error-queue nor errno ? */
51559 -                                                       log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):", 
51560 +                                                       log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
51561                                                                         ssl_r, r, errno,
51562                                                                         strerror(errno));
51563                                                 }
51564 -                                       
51565 +
51566                                                 return  -1;
51567                                         case SSL_ERROR_ZERO_RETURN:
51568                                                 /* clean shutdown on the remote side */
51569 -                                       
51570 +
51571                                                 if (r == 0)  return -2;
51572 -                                       
51573 +
51574                                                 /* fall thourgh */
51575                                         default:
51576                                                 while((err = ERR_get_error())) {
51577 -                                                       log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", 
51578 +                                                       log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
51579                                                                         ssl_r, r,
51580                                                                         ERR_error_string(err, NULL));
51581                                                 }
51582 -                                       
51583 +
51584                                                 return -1;
51585                                         }
51586                                 } else {
51587                                         c->offset += r;
51588                                         cq->bytes_out += r;
51589                                 }
51590 -                       
51591 +
51592                                 if (c->offset == c->file.length) {
51593                                         chunk_finished = 1;
51594                                 }
51595                         } while(!chunk_finished && !write_wait);
51596 -                       
51597 +
51598                         break;
51599                 }
51600                 default:
51601                         log_error_write(srv, __FILE__, __LINE__, "s", "type not known");
51602 -                       
51603 +
51604                         return -1;
51605                 }
51606 -                       
51607 +
51608                 if (!chunk_finished) {
51609                         /* not finished yet */
51610 -                       
51611 +
51612                         break;
51613                 }
51614 -                       
51615 +
51616                 chunks_written++;
51617         }
51618  
51619 -       return chunks_written;
51620 +       return NETWORK_STATUS_SUCCESS;
51621  }
51622  #endif
51623  
51624 --- ../lighttpd-1.4.11/src/network_solaris_sendfilev.c  2005-10-22 12:28:27.000000000 +0300
51625 +++ lighttpd-1.5.0/src/network_solaris_sendfilev.c      2006-07-16 00:26:04.000000000 +0300
51626 @@ -29,114 +29,34 @@
51627  #endif
51628  
51629  /**
51630 - * a very simple sendfilev() interface for solaris which can be optimised a lot more 
51631 + * a very simple sendfilev() interface for solaris which can be optimised a lot more
51632   * as solaris sendfilev() supports 'sending everythin in one syscall()'
51633 - * 
51634 - * If you want such an interface and need the performance, just give me an account on 
51635 - * a solaris box. 
51636 + *
51637 + * If you want such an interface and need the performance, just give me an account on
51638 + * a solaris box.
51639   *   - jan@kneschke.de
51640   */
51641  
51642  
51643 -int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int fd, chunkqueue *cq) {
51644 +NETWORK_BACKEND_WRITE(solarissendfilev) {
51645         chunk *c;
51646         size_t chunks_written = 0;
51647 -       
51648 +
51649         for(c = cq->first; c; c = c->next, chunks_written++) {
51650                 int chunk_finished = 0;
51651 -               
51652 +               network_status_t ret;
51653 +
51654                 switch(c->type) {
51655 -               case MEM_CHUNK: {
51656 -                       char * offset;
51657 -                       size_t toSend;
51658 -                       ssize_t r;
51659 -                       
51660 -                       size_t num_chunks, i;
51661 -                       struct iovec chunks[UIO_MAXIOV];
51662 -                       chunk *tc;
51663 -                       
51664 -                       size_t num_bytes = 0;
51665 -                       
51666 -                       /* we can't send more then SSIZE_MAX bytes in one chunk */
51667 -                       
51668 -                       /* build writev list 
51669 -                        * 
51670 -                        * 1. limit: num_chunks < UIO_MAXIOV
51671 -                        * 2. limit: num_bytes < SSIZE_MAX
51672 -                        */
51673 -                       for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
51674 -                       
51675 -                       for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
51676 -                               if (tc->mem->used == 0) {
51677 -                                       chunks[i].iov_base = tc->mem->ptr;
51678 -                                       chunks[i].iov_len  = 0;
51679 -                               } else {
51680 -                                       offset = tc->mem->ptr + tc->offset;
51681 -                                       toSend = tc->mem->used - 1 - tc->offset;
51682 -                               
51683 -                                       chunks[i].iov_base = offset;
51684 -                                       
51685 -                                       /* protect the return value of writev() */
51686 -                                       if (toSend > SSIZE_MAX ||
51687 -                                           num_bytes + toSend > SSIZE_MAX) {
51688 -                                               chunks[i].iov_len = SSIZE_MAX - num_bytes;
51689 -                                               
51690 -                                               num_chunks = i + 1;
51691 -                                               break;
51692 -                                       } else {
51693 -                                               chunks[i].iov_len = toSend;
51694 -                                       }
51695 -                                       
51696 -                                       num_bytes += toSend;
51697 -                               }
51698 -                       }
51699 -                       
51700 -                       if ((r = writev(fd, chunks, num_chunks)) < 0) {
51701 -                               switch (errno) {
51702 -                               case EAGAIN:
51703 -                               case EINTR:
51704 -                                       r = 0;
51705 -                                       break;
51706 -                               case EPIPE:
51707 -                               case ECONNRESET:
51708 -                                       return -2;
51709 -                               default:
51710 -                                       log_error_write(srv, __FILE__, __LINE__, "ssd", 
51711 -                                                       "writev failed:", strerror(errno), fd);
51712 -                               
51713 -                                       return -1;
51714 -                               }
51715 -                       }
51716 -                       
51717 -                       /* check which chunks have been written */
51718 -                       cq->bytes_out += r;
51719 -                       
51720 -                       for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
51721 -                               if (r >= (ssize_t)chunks[i].iov_len) {
51722 -                                       /* written */
51723 -                                       r -= chunks[i].iov_len;
51724 -                                       tc->offset += chunks[i].iov_len;
51725 -                                       
51726 -                                       if (chunk_finished) {
51727 -                                               /* skip the chunks from further touches */
51728 -                                               chunks_written++;
51729 -                                               c = c->next;
51730 -                                       } else {
51731 -                                               /* chunks_written + c = c->next is done in the for()*/
51732 -                                               chunk_finished++;
51733 -                                       }
51734 -                               } else {
51735 -                                       /* partially written */
51736 -                                       
51737 -                                       tc->offset += r;
51738 -                                       chunk_finished = 0;
51739 -                                       
51740 -                                       break;
51741 -                               }
51742 +               case MEM_CHUNK:
51743 +                       ret = network_write_chunkqueue_writev_mem(srv, con, fd, cq, &c);
51744 +
51745 +                       if (ret != NETWORK_STATUS_SUCCESS) {
51746 +                               return ret;
51747                         }
51748 -                       
51749 +
51750 +                       chunk_finished = 1;
51751 +
51752                         break;
51753 -               }
51754                 case FILE_CHUNK: {
51755                         ssize_t r;
51756                         off_t offset;
51757 @@ -144,25 +64,25 @@
51758                         sendfilevec_t fvec;
51759                         stat_cache_entry *sce = NULL;
51760                         int ifd;
51761 -                       
51762 +
51763                         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
51764                                 log_error_write(srv, __FILE__, __LINE__, "sb",
51765                                                 strerror(errno), c->file.name);
51766                                 return -1;
51767                         }
51768 -                                       
51769 +
51770                         offset = c->file.start + c->offset;
51771                         toSend = c->file.length - c->offset;
51772 -                       
51773 +
51774                         if (offset > sce->st.st_size) {
51775                                 log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
51776 -                               
51777 +
51778                                 return -1;
51779                         }
51780  
51781                         if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
51782                                 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
51783 -                               
51784 +
51785                                 return -1;
51786                         }
51787  
51788 @@ -170,44 +90,43 @@
51789                         fvec.sfv_flag = 0;
51790                         fvec.sfv_off = offset;
51791                         fvec.sfv_len = toSend;
51792 -                       
51793 +
51794                         /* Solaris sendfilev() */
51795                         if (-1 == (r = sendfilev(fd, &fvec, 1, &written))) {
51796                                 if (errno != EAGAIN) {
51797                                         log_error_write(srv, __FILE__, __LINE__, "ssd", "sendfile: ", strerror(errno), errno);
51798 -                                       
51799 +
51800                                         close(ifd);
51801 -                                       return -1;
51802 +                                       return NETWORK_STATUS_FATAL_ERROR;
51803                                 }
51804 -                               
51805 +
51806                                 r = 0;
51807                         }
51808 -                       
51809 +
51810                         close(ifd);
51811                         c->offset += written;
51812                         cq->bytes_out += written;
51813 -                       
51814 +
51815                         if (c->offset == c->file.length) {
51816                                 chunk_finished = 1;
51817                         }
51818 -                       
51819 +
51820                         break;
51821                 }
51822                 default:
51823 -                       
51824                         log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
51825 -                       
51826 -                       return -1;
51827 +
51828 +                       return NETWORK_STATUS_FATAL_ERROR;
51829                 }
51830 -               
51831 +
51832                 if (!chunk_finished) {
51833                         /* not finished yet */
51834 -                       
51835 +
51836                         break;
51837                 }
51838         }
51839  
51840 -       return chunks_written;
51841 +       return NETWORK_STATUS_SUCCESS;
51842  }
51843  
51844  #endif
51845 --- ../lighttpd-1.4.11/src/network_write.c      2005-10-22 12:27:56.000000000 +0300
51846 +++ lighttpd-1.5.0/src/network_write.c  2006-09-07 00:57:05.000000000 +0300
51847 @@ -1,11 +1,11 @@
51848  #include <sys/types.h>
51849  #include <sys/stat.h>
51850 -#include <sys/time.h>
51851 +
51852  #include <errno.h>
51853  #include <fcntl.h>
51854 -#include <unistd.h>
51855  #include <string.h>
51856  #include <stdlib.h>
51857 +#include <assert.h>
51858  
51859  #include "network.h"
51860  #include "fdevent.h"
51861 @@ -13,9 +13,12 @@
51862  #include "stat_cache.h"
51863  
51864  #include "sys-socket.h"
51865 +#include "sys-files.h"
51866  
51867  #include "network_backends.h"
51868  
51869 +#ifdef USE_WRITE
51870 +
51871  #ifdef HAVE_SYS_FILIO_H
51872  # include <sys/filio.h>
51873  #endif
51874 @@ -24,47 +27,100 @@
51875  #include <sys/resource.h>
51876  #endif
51877  
51878 -int network_write_chunkqueue_write(server *srv, connection *con, int fd, chunkqueue *cq) {
51879 +
51880 +/**
51881 +* fill the chunkqueue will all the data that we can get
51882 +*
51883 +* this might be optimized into a readv() which uses the chunks
51884 +* as vectors
51885 +*/
51886 +NETWORK_BACKEND_READ(read) {
51887 +       int toread;
51888 +       buffer *b;
51889 +       off_t r, start_bytes_in;
51890 +       off_t max_read = 256 * 1024;
51891 +
51892 +       /**
51893 +        * a EAGAIN is a successful read if we already read something to the chunkqueue
51894 +        */
51895 +       int read_something = 0;
51896 +
51897 +       start_bytes_in = cq->bytes_in;
51898 +       
51899 +       /* use a chunk-size of 16k */
51900 +       do {
51901 +               toread = 16384;
51902 +
51903 +               b = chunkqueue_get_append_buffer(cq);
51904 +
51905 +               buffer_prepare_copy(b, toread);
51906 +
51907 +               if (-1 == (r = read(sock->fd, b->ptr, toread))) {
51908 +                       switch (errno) {
51909 +                       case EAGAIN:
51910 +                               /* remove the last chunk from the chunkqueue */
51911 +                               chunkqueue_remove_empty_last_chunk(cq);
51912 +                               return read_something ? NETWORK_STATUS_SUCCESS : NETWORK_STATUS_WAIT_FOR_EVENT;
51913 +                       case ECONNRESET:
51914 +                               return NETWORK_STATUS_CONNECTION_CLOSE;
51915 +                       default:
51916 +                               ERROR("oops, read from fd=%d failed: %s (%d)", sock->fd, strerror(errno), errno );
51917 +
51918 +                               return NETWORK_STATUS_FATAL_ERROR;
51919 +                       }
51920 +               }
51921 +
51922 +               if (r == 0) {
51923 +                       chunkqueue_remove_empty_last_chunk(cq);
51924 +                       return read_something ? NETWORK_STATUS_SUCCESS : NETWORK_STATUS_CONNECTION_CLOSE;
51925 +               }
51926 +
51927 +               read_something = 1;
51928 +
51929 +               b->used = r;
51930 +               b->ptr[b->used++] = '\0';
51931 +               cq->bytes_in += r;
51932 +
51933 +               if (cq->bytes_in - start_bytes_in > max_read) break;
51934 +       } while (r == toread); 
51935 +
51936 +       return NETWORK_STATUS_SUCCESS;
51937 +}
51938 +
51939 +NETWORK_BACKEND_WRITE(write) {
51940         chunk *c;
51941         size_t chunks_written = 0;
51942 -       
51943 +
51944         for(c = cq->first; c; c = c->next) {
51945                 int chunk_finished = 0;
51946 -               
51947 +
51948                 switch(c->type) {
51949                 case MEM_CHUNK: {
51950                         char * offset;
51951                         size_t toSend;
51952                         ssize_t r;
51953 -                       
51954 +
51955                         if (c->mem->used == 0) {
51956                                 chunk_finished = 1;
51957                                 break;
51958                         }
51959 -                       
51960 +
51961                         offset = c->mem->ptr + c->offset;
51962                         toSend = c->mem->used - 1 - c->offset;
51963 -#ifdef __WIN32 
51964 -                       if ((r = send(fd, offset, toSend, 0)) < 0) {
51965 -                               log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed: ", strerror(errno), fd);
51966 -                               
51967 -                               return -1;
51968 -                       }
51969 -#else
51970 -                       if ((r = write(fd, offset, toSend)) < 0) {
51971 -                               log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed: ", strerror(errno), fd);
51972 -                               
51973 -                               return -1;
51974 +
51975 +                       if ((r = write(sock->fd, offset, toSend)) < 0) {
51976 +                               log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed: ", strerror(errno), sock->fd);
51977 +
51978 +                               return NETWORK_STATUS_FATAL_ERROR;
51979                         }
51980 -#endif
51981 -                       
51982 +
51983                         c->offset += r;
51984                         cq->bytes_out += r;
51985 -                       
51986 +
51987                         if (c->offset == (off_t)c->mem->used - 1) {
51988                                 chunk_finished = 1;
51989                         }
51990 -                       
51991 +
51992                         break;
51993                 }
51994                 case FILE_CHUNK: {
51995 @@ -76,93 +132,89 @@
51996                         size_t toSend;
51997                         stat_cache_entry *sce = NULL;
51998                         int ifd;
51999 -                       
52000 +
52001                         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
52002                                 log_error_write(srv, __FILE__, __LINE__, "sb",
52003                                                 strerror(errno), c->file.name);
52004 -                               return -1;
52005 +                               return NETWORK_STATUS_FATAL_ERROR;
52006                         }
52007 -                       
52008 +
52009                         offset = c->file.start + c->offset;
52010                         toSend = c->file.length - c->offset;
52011 -                       
52012 +
52013                         if (offset > sce->st.st_size) {
52014                                 log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
52015 -                               
52016 -                               return -1;
52017 +
52018 +                               return NETWORK_STATUS_FATAL_ERROR;
52019                         }
52020  
52021                         if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
52022                                 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
52023 -                               
52024 -                               return -1;
52025 +
52026 +                               return NETWORK_STATUS_FATAL_ERROR;
52027                         }
52028 -                       
52029 +
52030  #if defined USE_MMAP
52031                         if (MAP_FAILED == (p = mmap(0, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
52032                                 log_error_write(srv, __FILE__, __LINE__, "ss", "mmap failed: ", strerror(errno));
52033  
52034                                 close(ifd);
52035 -                               
52036 -                               return -1;
52037 +
52038 +                               return NETWORK_STATUS_FATAL_ERROR;
52039                         }
52040                         close(ifd);
52041  
52042 -                       if ((r = write(fd, p + offset, toSend)) <= 0) {
52043 +                       if ((r = write(sock->fd, p + offset, toSend)) <= 0) {
52044                                 log_error_write(srv, __FILE__, __LINE__, "ss", "write failed: ", strerror(errno));
52045                                 munmap(p, sce->st.st_size);
52046 -                               return -1;
52047 +                               return NETWORK_STATUS_FATAL_ERROR;
52048                         }
52049 -                       
52050 +
52051                         munmap(p, sce->st.st_size);
52052  #else
52053                         buffer_prepare_copy(srv->tmp_buf, toSend);
52054 -                       
52055 +
52056                         lseek(ifd, offset, SEEK_SET);
52057                         if (-1 == (toSend = read(ifd, srv->tmp_buf->ptr, toSend))) {
52058                                 log_error_write(srv, __FILE__, __LINE__, "ss", "read: ", strerror(errno));
52059                                 close(ifd);
52060 -                               
52061 -                               return -1;
52062 +
52063 +                               return NETWORK_STATUS_FATAL_ERROR;
52064                         }
52065                         close(ifd);
52066  
52067 -                       if (-1 == (r = send(fd, srv->tmp_buf->ptr, toSend, 0))) {
52068 +                       if (-1 == (r = send(sock->fd, srv->tmp_buf->ptr, toSend, 0))) {
52069                                 log_error_write(srv, __FILE__, __LINE__, "ss", "write: ", strerror(errno));
52070 -                               
52071 -                               return -1;
52072 +
52073 +                               return NETWORK_STATUS_FATAL_ERROR;
52074                         }
52075  #endif
52076                         c->offset += r;
52077                         cq->bytes_out += r;
52078 -                       
52079 +
52080                         if (c->offset == c->file.length) {
52081                                 chunk_finished = 1;
52082                         }
52083 -                       
52084 +
52085                         break;
52086                 }
52087                 default:
52088 -                       
52089 +
52090                         log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
52091 -                       
52092 -                       return -1;
52093 +
52094 +                       return NETWORK_STATUS_FATAL_ERROR;
52095                 }
52096 -               
52097 +
52098                 if (!chunk_finished) {
52099                         /* not finished yet */
52100 -                       
52101 +
52102                         break;
52103                 }
52104 -               
52105 +
52106                 chunks_written++;
52107         }
52108  
52109 -       return chunks_written;
52110 +       return NETWORK_STATUS_SUCCESS;
52111  }
52112  
52113 -#if 0
52114 -network_write_init(void) {
52115 -       p->write = network_write_write_chunkset;
52116 -}
52117  #endif
52118 --- ../lighttpd-1.4.11/src/network_writev.c     2006-02-15 01:02:36.000000000 +0200
52119 +++ lighttpd-1.5.0/src/network_writev.c 2006-07-18 13:03:40.000000000 +0300
52120 @@ -28,10 +28,10 @@
52121  
52122  #ifndef UIO_MAXIOV
52123  # if defined(__FreeBSD__) || defined(__APPLE__) || defined(__NetBSD__)
52124 -/* FreeBSD 4.7 defines it in sys/uio.h only if _KERNEL is specified */ 
52125 +/* FreeBSD 4.7 defines it in sys/uio.h only if _KERNEL is specified */
52126  #  define UIO_MAXIOV 1024
52127  # elif defined(__sgi)
52128 -/* IRIX 6.5 has sysconf(_SC_IOV_MAX) which might return 512 or bigger */ 
52129 +/* IRIX 6.5 has sysconf(_SC_IOV_MAX) which might return 512 or bigger */
52130  #  define UIO_MAXIOV 512
52131  # elif defined(__sun)
52132  /* Solaris (and SunOS?) defines IOV_MAX instead */
52133 @@ -51,105 +51,121 @@
52134  #define LOCAL_BUFFERING 1
52135  #endif
52136  
52137 -int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkqueue *cq) {
52138 -       chunk *c;
52139 +NETWORK_BACKEND_WRITE_CHUNK(writev_mem) {
52140 +       char * offset;
52141 +       size_t toSend;
52142 +       ssize_t r;
52143 +
52144 +       size_t num_chunks, i;
52145 +       struct iovec chunks[UIO_MAXIOV];
52146 +       chunk *tc; /* transfer chunks */
52147 +       size_t num_bytes = 0;
52148 +
52149 +       /* we can't send more then SSIZE_MAX bytes in one chunk */
52150 +
52151 +       /* build writev list
52152 +        *
52153 +        * 1. limit: num_chunks < UIO_MAXIOV
52154 +        * 2. limit: num_bytes < SSIZE_MAX
52155 +        */
52156 +       for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
52157 +
52158 +       for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
52159 +               if (tc->mem->used == 0) {
52160 +                       chunks[i].iov_base = tc->mem->ptr;
52161 +                       chunks[i].iov_len  = 0;
52162 +               } else {
52163 +                       offset = tc->mem->ptr + tc->offset;
52164 +                       toSend = tc->mem->used - 1 - tc->offset;
52165 +
52166 +                       chunks[i].iov_base = offset;
52167 +
52168 +                       /* protect the return value of writev() */
52169 +                       if (toSend > SSIZE_MAX ||
52170 +                           num_bytes + toSend > SSIZE_MAX) {
52171 +                               chunks[i].iov_len = SSIZE_MAX - num_bytes;
52172 +
52173 +                               num_chunks = i + 1;
52174 +                               break;
52175 +                       } else {
52176 +                               chunks[i].iov_len = toSend;
52177 +                       }
52178 +
52179 +                       num_bytes += toSend;
52180 +               }
52181 +       }
52182 +
52183 +       if ((r = writev(sock->fd, chunks, num_chunks)) < 0) {
52184 +               switch (errno) {
52185 +               case EAGAIN:
52186 +                       return NETWORK_STATUS_WAIT_FOR_EVENT;
52187 +               case EINTR:
52188 +                       return NETWORK_STATUS_INTERRUPTED;
52189 +               case EPIPE:
52190 +               case ECONNRESET:
52191 +                       return NETWORK_STATUS_CONNECTION_CLOSE;
52192 +               default:
52193 +                       log_error_write(srv, __FILE__, __LINE__, "ssd",
52194 +                                       "writev failed:", strerror(errno), sock->fd);
52195 +
52196 +                       return NETWORK_STATUS_FATAL_ERROR;
52197 +               }
52198 +       }
52199 +
52200 +       cq->bytes_out += r;
52201 +
52202 +       /* check which chunks have been written */
52203 +
52204 +       for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
52205 +               if (r >= (ssize_t)chunks[i].iov_len) {
52206 +                       /* written */
52207 +                       r -= chunks[i].iov_len;
52208 +                       tc->offset += chunks[i].iov_len;
52209 +               } else {
52210 +                       /* partially written */
52211 +
52212 +                       tc->offset += r;
52213 +
52214 +                       return NETWORK_STATUS_WAIT_FOR_EVENT;
52215 +               }
52216 +       }
52217 +
52218 +       /* all chunks have been pushed out */
52219 +       return NETWORK_STATUS_SUCCESS;
52220 +}
52221 +
52222 +NETWORK_BACKEND_WRITE(writev) {
52223 +       chunk *c, *tc;
52224         size_t chunks_written = 0;
52225 -       
52226 +
52227         for(c = cq->first; c; c = c->next) {
52228                 int chunk_finished = 0;
52229 -               
52230 +               network_status_t ret;
52231 +
52232                 switch(c->type) {
52233 -               case MEM_CHUNK: {
52234 -                       char * offset;
52235 -                       size_t toSend;
52236 -                       ssize_t r;
52237 -                       
52238 -                       size_t num_chunks, i;
52239 -                       struct iovec chunks[UIO_MAXIOV];
52240 -                       chunk *tc;
52241 -                       size_t num_bytes = 0;
52242 -                       
52243 -                       /* we can't send more then SSIZE_MAX bytes in one chunk */
52244 -                       
52245 -                       /* build writev list 
52246 -                        * 
52247 -                        * 1. limit: num_chunks < UIO_MAXIOV
52248 -                        * 2. limit: num_bytes < SSIZE_MAX
52249 -                        */
52250 -                       for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
52251 -                       
52252 -                       for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
52253 -                               if (tc->mem->used == 0) {
52254 -                                       chunks[i].iov_base = tc->mem->ptr;
52255 -                                       chunks[i].iov_len  = 0;
52256 -                               } else {
52257 -                                       offset = tc->mem->ptr + tc->offset;
52258 -                                       toSend = tc->mem->used - 1 - tc->offset;
52259 -                               
52260 -                                       chunks[i].iov_base = offset;
52261 -                                       
52262 -                                       /* protect the return value of writev() */
52263 -                                       if (toSend > SSIZE_MAX ||
52264 -                                           num_bytes + toSend > SSIZE_MAX) {
52265 -                                               chunks[i].iov_len = SSIZE_MAX - num_bytes;
52266 -                                               
52267 -                                               num_chunks = i + 1;
52268 -                                               break;
52269 -                                       } else {
52270 -                                               chunks[i].iov_len = toSend;
52271 -                                       }
52272 -                                       
52273 -                                       num_bytes += toSend;
52274 -                               }
52275 -                       }
52276 -                       
52277 -                       if ((r = writev(fd, chunks, num_chunks)) < 0) {
52278 -                               switch (errno) {
52279 -                               case EAGAIN:
52280 -                               case EINTR:
52281 -                                       r = 0;
52282 -                                       break;
52283 -                               case EPIPE:
52284 -                               case ECONNRESET:
52285 -                                       return -2;
52286 -                               default:
52287 -                                       log_error_write(srv, __FILE__, __LINE__, "ssd", 
52288 -                                                       "writev failed:", strerror(errno), fd);
52289 -                               
52290 -                                       return -1;
52291 -                               }
52292 -                       }
52293 -                       
52294 -                       cq->bytes_out += r;
52295 +               case MEM_CHUNK:
52296 +                       ret = network_write_chunkqueue_writev_mem(srv, con, sock, cq, c);
52297  
52298 -                       /* check which chunks have been written */
52299 -                       
52300 -                       for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
52301 -                               if (r >= (ssize_t)chunks[i].iov_len) {
52302 -                                       /* written */
52303 -                                       r -= chunks[i].iov_len;
52304 -                                       tc->offset += chunks[i].iov_len;
52305 -                                       
52306 +                       /* check which chunks are finished now */
52307 +                       for (tc = c; tc; tc = tc->next) {
52308 +                               /* finished the chunk */
52309 +                               if (tc->offset == tc->mem->used - 1) {
52310 +                                       /* skip the first c->next as that will be done by the c = c->next in the other for()-loop */
52311                                         if (chunk_finished) {
52312 -                                               /* skip the chunks from further touches */
52313 -                                               chunks_written++;
52314                                                 c = c->next;
52315                                         } else {
52316 -                                               /* chunks_written + c = c->next is done in the for()*/
52317 -                                               chunk_finished++;
52318 +                                               chunk_finished = 1;
52319                                         }
52320                                 } else {
52321 -                                       /* partially written */
52322 -                                       
52323 -                                       tc->offset += r;
52324 -                                       chunk_finished = 0;
52325 -
52326                                         break;
52327                                 }
52328                         }
52329 -                       
52330 +
52331 +                       if (ret != NETWORK_STATUS_SUCCESS) {
52332 +                               return ret;
52333 +                       }
52334 +
52335                         break;
52336 -               }
52337                 case FILE_CHUNK: {
52338                         ssize_t r;
52339                         off_t abs_offset;
52340 @@ -159,26 +175,26 @@
52341  #define KByte * 1024
52342  #define MByte * 1024 KByte
52343  #define GByte * 1024 MByte
52344 -                       const off_t we_want_to_mmap = 512 KByte; 
52345 +                       const off_t we_want_to_mmap = 512 KByte;
52346                         char *start = NULL;
52347  
52348                         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
52349                                 log_error_write(srv, __FILE__, __LINE__, "sb",
52350                                                 strerror(errno), c->file.name);
52351 -                               return -1;
52352 +                               return NETWORK_STATUS_FATAL_ERROR;
52353                         }
52354  
52355                         abs_offset = c->file.start + c->offset;
52356 -                       
52357 +
52358                         if (abs_offset > sce->st.st_size) {
52359 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
52360 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
52361                                                 "file was shrinked:", c->file.name);
52362 -                               
52363 -                               return -1;
52364 +
52365 +                               return NETWORK_STATUS_FATAL_ERROR;
52366                         }
52367  
52368 -                       /* mmap the buffer 
52369 -                        * - first mmap 
52370 +                       /* mmap the buffer
52371 +                        * - first mmap
52372                          * - new mmap as the we are at the end of the last one */
52373                         if (c->file.mmap.start == MAP_FAILED ||
52374                             abs_offset == (off_t)(c->file.mmap.offset + c->file.mmap.length)) {
52375 @@ -188,7 +204,7 @@
52376                                  * adaptive mem-mapping
52377                                  *   the problem:
52378                                  *     we mmap() the whole file. If someone has alot large files and 32bit
52379 -                                *     machine the virtual address area will be unrun and we will have a failing 
52380 +                                *     machine the virtual address area will be unrun and we will have a failing
52381                                  *     mmap() call.
52382                                  *   solution:
52383                                  *     only mmap 16M in one chunk and move the window as soon as we have finished
52384 @@ -234,8 +250,8 @@
52385                                 if (-1 == c->file.fd) {  /* open the file if not already open */
52386                                         if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
52387                                                 log_error_write(srv, __FILE__, __LINE__, "sbs", "open failed for:", c->file.name, strerror(errno));
52388 -                               
52389 -                                               return -1;
52390 +
52391 +                                               return NETWORK_STATUS_FATAL_ERROR;
52392                                         }
52393  #ifdef FD_CLOEXEC
52394                                         fcntl(c->file.fd, F_SETFD, FD_CLOEXEC);
52395 @@ -245,10 +261,10 @@
52396                                 if (MAP_FAILED == (c->file.mmap.start = mmap(0, to_mmap, PROT_READ, MAP_SHARED, c->file.fd, c->file.mmap.offset))) {
52397                                         /* close it here, otherwise we'd have to set FD_CLOEXEC */
52398  
52399 -                                       log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed:", 
52400 +                                       log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed:",
52401                                                         strerror(errno), c->file.name, c->file.fd);
52402  
52403 -                                       return -1;
52404 +                                       return NETWORK_STATUS_FATAL_ERROR;
52405                                 }
52406  
52407                                 c->file.mmap.length = to_mmap;
52408 @@ -258,7 +274,7 @@
52409  #ifdef HAVE_MADVISE
52410                                 /* don't advise files < 64Kb */
52411                                 if (c->file.mmap.length > (64 KByte)) {
52412 -                                       /* darwin 7 is returning EINVAL all the time and I don't know how to 
52413 +                                       /* darwin 7 is returning EINVAL all the time and I don't know how to
52414                                          * detect this at runtime.i
52415                                          *
52416                                          * ignore the return value for now */
52417 @@ -274,12 +290,12 @@
52418                         toSend = (c->file.mmap.offset + c->file.mmap.length) - (abs_offset);
52419  
52420                         if (toSend < 0) {
52421 -                               log_error_write(srv, __FILE__, __LINE__, "soooo", 
52422 +                               log_error_write(srv, __FILE__, __LINE__, "soooo",
52423                                                 "toSend is negative:",
52424                                                 toSend,
52425                                                 c->file.mmap.length,
52426                                                 abs_offset,
52427 -                                               c->file.mmap.offset); 
52428 +                                               c->file.mmap.offset);
52429                                 assert(toSend < 0);
52430                         }
52431  
52432 @@ -289,7 +305,7 @@
52433                         start = c->file.mmap.start;
52434  #endif
52435  
52436 -                       if ((r = write(fd, start + (abs_offset - c->file.mmap.offset), toSend)) < 0) {
52437 +                       if ((r = write(sock->fd, start + (abs_offset - c->file.mmap.offset), toSend)) < 0) {
52438                                 switch (errno) {
52439                                 case EAGAIN:
52440                                 case EINTR:
52441 @@ -297,18 +313,18 @@
52442                                         break;
52443                                 case EPIPE:
52444                                 case ECONNRESET:
52445 -                                       return -2;
52446 +                                       return NETWORK_STATUS_CONNECTION_CLOSE;
52447                                 default:
52448 -                                       log_error_write(srv, __FILE__, __LINE__, "ssd", 
52449 -                                                       "write failed:", strerror(errno), fd);
52450 -                                       
52451 -                                       return -1;
52452 +                                       log_error_write(srv, __FILE__, __LINE__, "ssd",
52453 +                                                       "write failed:", strerror(errno), sock->fd);
52454 +
52455 +                                       return NETWORK_STATUS_FATAL_ERROR;
52456                                 }
52457                         }
52458 -                       
52459 +
52460                         c->offset += r;
52461                         cq->bytes_out += r;
52462 -                       
52463 +
52464                         if (c->offset == c->file.length) {
52465                                 chunk_finished = 1;
52466  
52467 @@ -318,26 +334,26 @@
52468                                         c->file.mmap.start = MAP_FAILED;
52469                                 }
52470                         }
52471 -                       
52472 +
52473                         break;
52474                 }
52475                 default:
52476 -                       
52477 +
52478                         log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
52479 -                       
52480 -                       return -1;
52481 +
52482 +                       return NETWORK_STATUS_FATAL_ERROR;
52483                 }
52484 -               
52485 +
52486                 if (!chunk_finished) {
52487                         /* not finished yet */
52488 -                       
52489 +
52490                         break;
52491                 }
52492 -               
52493 +
52494                 chunks_written++;
52495         }
52496  
52497 -       return chunks_written;
52498 +       return NETWORK_STATUS_SUCCESS;
52499  }
52500  
52501  #endif
52502 --- ../lighttpd-1.4.11/src/plugin.c     2006-02-08 14:00:54.000000000 +0200
52503 +++ lighttpd-1.5.0/src/plugin.c 2006-09-07 00:57:05.000000000 +0300
52504 @@ -13,69 +13,73 @@
52505  #include <valgrind/valgrind.h>
52506  #endif
52507  
52508 -#ifndef __WIN32
52509 +#ifndef _WIN32
52510  #include <dlfcn.h>
52511  #endif
52512  /*
52513 - * 
52514 + *
52515   * if you change this enum to add a new callback, be sure
52516   * - that PLUGIN_FUNC_SIZEOF is the last entry
52517   * - that you add PLUGIN_TO_SLOT twice:
52518 - *   1. as callback-dispatcher 
52519 + *   1. as callback-dispatcher
52520   *   2. in plugins_call_init()
52521 - * 
52522 + *
52523   */
52524  
52525  typedef struct {
52526         PLUGIN_DATA;
52527  } plugin_data;
52528  
52529 -typedef enum { 
52530 +typedef enum {
52531         PLUGIN_FUNC_UNSET,
52532 -               PLUGIN_FUNC_HANDLE_URI_CLEAN, 
52533 -               PLUGIN_FUNC_HANDLE_URI_RAW, 
52534 -               PLUGIN_FUNC_HANDLE_REQUEST_DONE,
52535 +               PLUGIN_FUNC_HANDLE_URI_CLEAN,
52536 +               PLUGIN_FUNC_HANDLE_URI_RAW,
52537 +               PLUGIN_FUNC_HANDLE_RESPONSE_DONE,
52538                 PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE,
52539                 PLUGIN_FUNC_HANDLE_TRIGGER,
52540                 PLUGIN_FUNC_HANDLE_SIGHUP,
52541 -               PLUGIN_FUNC_HANDLE_SUBREQUEST,
52542 -               PLUGIN_FUNC_HANDLE_SUBREQUEST_START,
52543 +               PLUGIN_FUNC_HANDLE_START_BACKEND,
52544 +               PLUGIN_FUNC_HANDLE_SEND_REQUEST_CONTENT,
52545                 PLUGIN_FUNC_HANDLE_JOBLIST,
52546                 PLUGIN_FUNC_HANDLE_DOCROOT,
52547                 PLUGIN_FUNC_HANDLE_PHYSICAL,
52548                 PLUGIN_FUNC_CONNECTION_RESET,
52549 -               PLUGIN_FUNC_INIT, 
52550 +               PLUGIN_FUNC_INIT,
52551                 PLUGIN_FUNC_CLEANUP,
52552                 PLUGIN_FUNC_SET_DEFAULTS,
52553 -               
52554 +
52555                 PLUGIN_FUNC_SIZEOF
52556  } plugin_t;
52557  
52558  static plugin *plugin_init(void) {
52559         plugin *p;
52560 -       
52561 +
52562         p = calloc(1, sizeof(*p));
52563 -       
52564 +
52565 +       p->required_plugins = array_init();
52566 +
52567         return p;
52568  }
52569  
52570  static void plugin_free(plugin *p) {
52571         int use_dlclose = 1;
52572         if (p->name) buffer_free(p->name);
52573 +
52574 +       array_free(p->required_plugins);
52575  #ifdef HAVE_VALGRIND_VALGRIND_H
52576         /*if (RUNNING_ON_VALGRIND) use_dlclose = 0;*/
52577  #endif
52578  
52579  #ifndef LIGHTTPD_STATIC
52580 -       if (use_dlclose && p->lib) {    
52581 -#ifdef __WIN32
52582 +       if (use_dlclose && p->lib) {
52583 +#ifdef _WIN32
52584                 FreeLibrary(p->lib);
52585  #else
52586                 dlclose(p->lib);
52587  #endif
52588         }
52589  #endif
52590 -               
52591 +
52592         free(p);
52593  }
52594  
52595 @@ -89,17 +93,17 @@
52596                 srv->plugins.size += 4;
52597                 srv->plugins.ptr   = realloc(srv->plugins.ptr, srv->plugins.size * sizeof(*ps));
52598         }
52599 -       
52600 +
52601         ps = srv->plugins.ptr;
52602         ps[srv->plugins.used++] = p;
52603 -       
52604 +
52605         return 0;
52606  }
52607  
52608  /**
52609 - * 
52610 - * 
52611 - * 
52612 + *
52613 + *
52614 + *
52615   */
52616  
52617  #ifdef LIGHTTPD_STATIC
52618 @@ -121,30 +125,35 @@
52619  #else
52620  int plugins_load(server *srv) {
52621         plugin *p;
52622 +#ifdef _WIN32
52623 +    FARPROC init;
52624 +#else
52625         int (*init)(plugin *pl);
52626 +#endif
52627 +
52628         const char *error;
52629 -       size_t i;
52630 -       
52631 +       size_t i, j, k;
52632 +
52633         for (i = 0; i < srv->srvconf.modules->used; i++) {
52634                 data_string *d = (data_string *)srv->srvconf.modules->data[i];
52635                 char *modules = d->value->ptr;
52636 -       
52637 +
52638                 buffer_copy_string_buffer(srv->tmp_buf, srv->srvconf.modules_dir);
52639  
52640                 buffer_append_string(srv->tmp_buf, "/");
52641                 buffer_append_string(srv->tmp_buf, modules);
52642 -#if defined(__WIN32) || defined(__CYGWIN__)
52643 +#if defined(_WIN32) || defined(__CYGWIN__)
52644                 buffer_append_string(srv->tmp_buf, ".dll");
52645  #else
52646                 buffer_append_string(srv->tmp_buf, ".so");
52647  #endif
52648 -       
52649 +
52650                 p = plugin_init();
52651 -#ifdef __WIN32
52652 +#ifdef _WIN32
52653                 if (NULL == (p->lib = LoadLibrary(srv->tmp_buf->ptr))) {
52654                         LPVOID lpMsgBuf;
52655                         FormatMessage(
52656 -                               FORMAT_MESSAGE_ALLOCATE_BUFFER | 
52657 +                               FORMAT_MESSAGE_ALLOCATE_BUFFER |
52658                                 FORMAT_MESSAGE_FROM_SYSTEM,
52659                                 NULL,
52660                                 GetLastError(),
52661 @@ -152,36 +161,36 @@
52662                                 (LPTSTR) &lpMsgBuf,
52663                                 0, NULL );
52664  
52665 -                       log_error_write(srv, __FILE__, __LINE__, "ssb", "LoadLibrary() failed", 
52666 +                       log_error_write(srv, __FILE__, __LINE__, "ssb", "LoadLibrary() failed",
52667                                         lpMsgBuf, srv->tmp_buf);
52668 -                       
52669 +
52670                         plugin_free(p);
52671 -                       
52672 +
52673                         return -1;
52674  
52675                 }
52676 -#else  
52677 +#else
52678                 if (NULL == (p->lib = dlopen(srv->tmp_buf->ptr, RTLD_LAZY))) {
52679 -                       log_error_write(srv, __FILE__, __LINE__, "sbs", "dlopen() failed for:", 
52680 +                       log_error_write(srv, __FILE__, __LINE__, "sbs", "dlopen() failed for:",
52681                                         srv->tmp_buf, dlerror());
52682 -                       
52683 +
52684                         plugin_free(p);
52685 -                       
52686 +
52687                         return -1;
52688                 }
52689 -               
52690 +
52691  #endif
52692                 buffer_reset(srv->tmp_buf);
52693                 buffer_copy_string(srv->tmp_buf, modules);
52694                 buffer_append_string(srv->tmp_buf, "_plugin_init");
52695  
52696 -#ifdef __WIN32
52697 +#ifdef _WIN32
52698                 init = GetProcAddress(p->lib, srv->tmp_buf->ptr);
52699  
52700                 if (init == NULL)  {
52701                         LPVOID lpMsgBuf;
52702                         FormatMessage(
52703 -                               FORMAT_MESSAGE_ALLOCATE_BUFFER | 
52704 +                               FORMAT_MESSAGE_ALLOCATE_BUFFER |
52705                                 FORMAT_MESSAGE_FROM_SYSTEM,
52706                                 NULL,
52707                                 GetLastError(),
52708 @@ -190,7 +199,7 @@
52709                                 0, NULL );
52710  
52711                         log_error_write(srv, __FILE__, __LINE__, "sbs", "getprocaddress failed:", srv->tmp_buf, lpMsgBuf);
52712 -                       
52713 +
52714                         plugin_free(p);
52715                         return -1;
52716                 }
52717 @@ -203,24 +212,43 @@
52718  #endif
52719                 if ((error = dlerror()) != NULL)  {
52720                         log_error_write(srv, __FILE__, __LINE__, "s", error);
52721 -                       
52722 +
52723                         plugin_free(p);
52724                         return -1;
52725                 }
52726 -       
52727 +
52728  #endif
52729                 if ((*init)(p)) {
52730                         log_error_write(srv, __FILE__, __LINE__, "ss", modules, "plugin init failed" );
52731 -                       
52732 +
52733                         plugin_free(p);
52734                         return -1;
52735                 }
52736  #if 0
52737                 log_error_write(srv, __FILE__, __LINE__, "ss", modules, "plugin loaded" );
52738  #endif
52739 +               /* check if the required plugin is loaded */
52740 +               for (k = 0; k < p->required_plugins->used; k++) {
52741 +                       data_string *req = (data_string *)p->required_plugins->data[k];
52742 +
52743 +                       for (j = 0; j < i; j++) {
52744 +                               data_string *mod = (data_string *)srv->srvconf.modules->data[j];
52745 +
52746 +                               if (buffer_is_equal(req->value, mod->value)) break;
52747 +                       }
52748 +
52749 +                       if (j == i) {
52750 +                               /* not found */
52751 +                               log_error_write(srv, __FILE__, __LINE__, "ssbs", modules, "failed to load. required plugin", req->value, "was not loaded" );
52752 +
52753 +                               plugin_free(p);
52754 +                       
52755 +                               return -1;
52756 +                       }
52757 +               }
52758                 plugins_register(srv, p);
52759         }
52760 -       
52761 +
52762         return 0;
52763  }
52764  #endif
52765 @@ -253,8 +281,8 @@
52766         }
52767  
52768  /**
52769 - * plugins that use 
52770 - * 
52771 + * plugins that use
52772 + *
52773   * - server *srv
52774   * - connection *con
52775   * - void *p_d (plugin_data *)
52776 @@ -262,13 +290,13 @@
52777  
52778  PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean)
52779  PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw)
52780 -PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done)
52781 -PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close)
52782 -PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST, handle_subrequest)
52783 -PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start)
52784 -PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_JOBLIST, handle_joblist)
52785  PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot)
52786  PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical)
52787 +PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_START_BACKEND, handle_start_backend)
52788 +PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SEND_REQUEST_CONTENT, handle_send_request_content)
52789 +PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close)
52790 +PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_RESPONSE_DONE, handle_response_done)
52791 +PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_JOBLIST, handle_joblist)
52792  PLUGIN_TO_SLOT(PLUGIN_FUNC_CONNECTION_RESET, connection_reset)
52793  
52794  #undef PLUGIN_TO_SLOT
52795 @@ -301,12 +329,12 @@
52796         }
52797  
52798  /**
52799 - * plugins that use 
52800 - * 
52801 + * plugins that use
52802 + *
52803   * - server *srv
52804   * - void *p_d (plugin_data *)
52805   */
52806 -                                                                       
52807 +
52808  PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger)
52809  PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup)
52810  PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup)
52811 @@ -314,18 +342,18 @@
52812  
52813  #undef PLUGIN_TO_SLOT
52814  
52815 -#if 0                                                                  
52816 +#if 0
52817  /**
52818 - * 
52819 + *
52820   * special handler
52821 - * 
52822 + *
52823   */
52824  handler_t plugins_call_handle_fdevent(server *srv, const fd_conn *fdc) {
52825         size_t i;
52826         plugin **ps;
52827 -       
52828 +
52829         ps = srv->plugins.ptr;
52830 -       
52831 +
52832         for (i = 0; i < srv->plugins.used; i++) {
52833                 plugin *p = ps[i];
52834                 if (p->handle_fdevent) {
52835 @@ -344,34 +372,34 @@
52836                         }
52837                 }
52838         }
52839 -       
52840 +
52841         return HANDLER_GO_ON;
52842  }
52843  #endif
52844  /**
52845 - * 
52846 + *
52847   * - call init function of all plugins to init the plugin-internals
52848   * - added each plugin that supports has callback to the corresponding slot
52849 - * 
52850 + *
52851   * - is only called once.
52852   */
52853  
52854  handler_t plugins_call_init(server *srv) {
52855         size_t i;
52856         plugin **ps;
52857 -       
52858 +
52859         ps = srv->plugins.ptr;
52860 -       
52861 +
52862         /* fill slots */
52863 -       
52864 +
52865         srv->plugin_slots = calloc(PLUGIN_FUNC_SIZEOF, sizeof(ps));
52866 -       
52867 +
52868         for (i = 0; i < srv->plugins.used; i++) {
52869                 size_t j;
52870                 /* check which calls are supported */
52871 -               
52872 +
52873                 plugin *p = ps[i];
52874 -               
52875 +
52876  #define PLUGIN_TO_SLOT(x, y) \
52877         if (p->y) { \
52878                 plugin **slot = ((plugin ***)(srv->plugin_slots))[x]; \
52879 @@ -384,37 +412,38 @@
52880                         slot[j] = p;\
52881                         break;\
52882                 }\
52883 -       } 
52884 -               
52885 -               
52886 -               PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean); 
52887 -               PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw); 
52888 -               PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done);
52889 -               PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close);
52890 -               PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger);
52891 -               PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup);
52892 -               PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST, handle_subrequest);
52893 -               PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start);
52894 -               PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_JOBLIST, handle_joblist);
52895 +       }
52896 +
52897 +
52898 +               PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean);
52899 +               PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw);
52900                 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot);
52901                 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical);
52902 +               PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_START_BACKEND, handle_start_backend);
52903 +               PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SEND_REQUEST_CONTENT, handle_send_request_content);
52904 +               PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_RESPONSE_DONE, handle_response_done);
52905 +               PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close);
52906 +
52907 +               PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_JOBLIST, handle_joblist);
52908                 PLUGIN_TO_SLOT(PLUGIN_FUNC_CONNECTION_RESET, connection_reset);
52909                 PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup);
52910                 PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults);
52911 +               PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger);
52912 +               PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup);
52913  #undef PLUGIN_TO_SLOT
52914 -               
52915 +
52916                 if (p->init) {
52917                         if (NULL == (p->data = p->init())) {
52918 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
52919 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
52920                                                 "plugin-init failed for module", p->name);
52921                                 return HANDLER_ERROR;
52922                         }
52923 -                       
52924 +
52925                         /* used for con->mode, DIRECT == 0, plugins above that */
52926                         ((plugin_data *)(p->data))->id = i + 1;
52927 -                       
52928 +
52929                         if (p->version != LIGHTTPD_VERSION_ID) {
52930 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
52931 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
52932                                                 "plugin-version doesn't match lighttpd-version for", p->name);
52933                                 return HANDLER_ERROR;
52934                         }
52935 @@ -422,29 +451,46 @@
52936                         p->data = NULL;
52937                 }
52938         }
52939 -       
52940 +
52941         return HANDLER_GO_ON;
52942  }
52943  
52944 +/**
52945 + * get the config-storage of the named plugin 
52946 + */
52947 +void *plugin_get_config(server *srv, const char *name) {
52948 +       size_t i;
52949 +
52950 +       for (i = 0; i < srv->plugins.used; i++) {
52951 +               plugin *p = ((plugin **)srv->plugins.ptr)[i];
52952 +
52953 +               if (buffer_is_equal_string(p->name, name, strlen(name))) {
52954 +                       return p->data;
52955 +               }
52956 +       }
52957 +
52958 +       return NULL;
52959 +}
52960 +
52961  void plugins_free(server *srv) {
52962         size_t i;
52963         plugins_call_cleanup(srv);
52964 -       
52965 +
52966         for (i = 0; i < srv->plugins.used; i++) {
52967                 plugin *p = ((plugin **)srv->plugins.ptr)[i];
52968 -               
52969 +
52970                 plugin_free(p);
52971         }
52972 -       
52973 +
52974         for (i = 0; srv->plugin_slots && i < PLUGIN_FUNC_SIZEOF; i++) {
52975                 plugin **slot = ((plugin ***)(srv->plugin_slots))[i];
52976 -               
52977 +
52978                 if (slot) free(slot);
52979         }
52980 -       
52981 +
52982         free(srv->plugin_slots);
52983         srv->plugin_slots = NULL;
52984 -       
52985 +
52986         free(srv->plugins.ptr);
52987         srv->plugins.ptr = NULL;
52988         srv->plugins.used = 0;
52989 --- ../lighttpd-1.4.11/src/plugin.h     2005-08-15 12:28:56.000000000 +0300
52990 +++ lighttpd-1.5.0/src/plugin.h 2006-09-07 00:57:05.000000000 +0300
52991 @@ -12,6 +12,12 @@
52992  
52993  #define INIT_FUNC(x) \
52994                 static void *x()
52995 +/*
52996 + * The PATCH_OPTION() macro is used in the patch_connection() functions
52997 + * of the modules to update the config object for the current request.
52998 + */
52999 +#define PATCH_OPTION(x) \
53000 +               p->conf.x = s->x
53001  
53002  #define FREE_FUNC          SERVER_FUNC
53003  #define TRIGGER_FUNC       SERVER_FUNC
53004 @@ -25,40 +31,45 @@
53005  #define URIHANDLER_FUNC    CONNECTION_FUNC
53006  
53007  #define PLUGIN_DATA        size_t id
53008 -                                                                                                                                               
53009 +
53010 +/**
53011 + * we have 4 states on the connection:
53012 + * - read-header
53013 + * - read-content
53014 + * - write-header
53015 + * - write-content
53016 + */
53017 +
53018  typedef struct {
53019         size_t version;
53020 -       
53021 +
53022         buffer *name; /* name of the plugin */
53023 -       
53024 +
53025         void *(* init)                       ();
53026         handler_t (* set_defaults)           (server *srv, void *p_d);
53027         handler_t (* cleanup)                (server *srv, void *p_d);
53028                                                                                            /* is called ... */
53029         handler_t (* handle_trigger)         (server *srv, void *p_d);                     /* once a second */
53030         handler_t (* handle_sighup)          (server *srv, void *p_d);                     /* at a signup */
53031 -       
53032 -       handler_t (* handle_uri_raw)         (server *srv, connection *con, void *p_d);    /* after uri_raw is set */
53033 -       handler_t (* handle_uri_clean)       (server *srv, connection *con, void *p_d);    /* after uri is set */
53034 -       handler_t (* handle_docroot)         (server *srv, connection *con, void *p_d);    /* getting the document-root */
53035 -       handler_t (* handle_physical)        (server *srv, connection *con, void *p_d);    /* mapping url to physical path */
53036 -       handler_t (* handle_request_done)    (server *srv, connection *con, void *p_d);    /* at the end of a request */
53037 -       handler_t (* handle_connection_close)(server *srv, connection *con, void *p_d);    /* at the end of a connection */
53038 -       handler_t (* handle_joblist)         (server *srv, connection *con, void *p_d);    /* after all events are handled */
53039 -       
53040 -       
53041 -       
53042 -       handler_t (* handle_subrequest_start)(server *srv, connection *con, void *p_d);   
53043 -       
53044 -                                                                                          /* when a handler for the request 
53045 -                                                                                           * has to be found
53046 -                                                                                           */
53047 -       handler_t (* handle_subrequest)      (server *srv, connection *con, void *p_d);    /* */
53048 -       handler_t (* connection_reset)       (server *srv, connection *con, void *p_d);    /* */
53049 +
53050 +       handler_t (* handle_uri_raw)         (server *srv, connection *con, void *p_d);    /* after uri_raw is set (mod_rewrite) */
53051 +       handler_t (* handle_uri_clean)       (server *srv, connection *con, void *p_d);    /* after uri is set (mod_access, mod_auth) */
53052 +       handler_t (* handle_docroot)         (server *srv, connection *con, void *p_d);    /* getting the document-root (e.g. mod_simple_vhost) */
53053 +       handler_t (* handle_physical)        (server *srv, connection *con, void *p_d);    /* mapping url to physical path (e.g. mod_alias, mod_proxy_core) */
53054 +       handler_t (* handle_start_backend)   (server *srv, connection *con, void *p_d);    /* file exists locally (e.g. mod_staticfile) */
53055 +       handler_t (* handle_send_request_content)(server *srv, connection *con, void *p_d);    /* a handler for the request content */
53056 +       handler_t (* handle_response_header) (server *srv, connection *con, void *p_d);    /* a handler for the request content */
53057 +       handler_t (* handle_response_done)   (server *srv, connection *con, void *p_d);    /* after the response is sent (e.g. mod_accesslog) */
53058 +       handler_t (* connection_reset)       (server *srv, connection *con, void *p_d);    /* end of a request-response cycle (mod_acceslog, mod_proxy_core) */
53059 +       handler_t (* handle_connection_close)(server *srv, connection *con, void *p_d);    /* at the end of a connection [remove-me ?] */
53060 +       handler_t (* handle_joblist)         (server *srv, connection *con, void *p_d);    /* after all events are handled [remove-me ?] */
53061 +
53062         void *data;
53063 -       
53064 +
53065         /* dlopen handle */
53066         void *lib;
53067 +
53068 +       array *required_plugins;
53069  } plugin;
53070  
53071  int plugins_load(server *srv);
53072 @@ -66,11 +77,12 @@
53073  
53074  handler_t plugins_call_handle_uri_raw(server *srv, connection *con);
53075  handler_t plugins_call_handle_uri_clean(server *srv, connection *con);
53076 -handler_t plugins_call_handle_subrequest_start(server *srv, connection *con);
53077 -handler_t plugins_call_handle_subrequest(server *srv, connection *con);
53078 -handler_t plugins_call_handle_request_done(server *srv, connection *con);
53079  handler_t plugins_call_handle_docroot(server *srv, connection *con);
53080  handler_t plugins_call_handle_physical(server *srv, connection *con);
53081 +handler_t plugins_call_handle_start_backend(server *srv, connection *con);
53082 +handler_t plugins_call_handle_send_request_content(server *srv, connection *con);
53083 +handler_t plugins_call_handle_response_header(server *srv, connection *con);
53084 +handler_t plugins_call_handle_response_done(server *srv, connection *con);
53085  handler_t plugins_call_handle_connection_close(server *srv, connection *con);
53086  handler_t plugins_call_handle_joblist(server *srv, connection *con);
53087  handler_t plugins_call_connection_reset(server *srv, connection *con);
53088 @@ -88,5 +100,8 @@
53089  int config_patch_connection(server *srv, connection *con, comp_key_t comp);
53090  int config_check_cond(server *srv, connection *con, data_config *dc);
53091  int config_append_cond_match_buffer(connection *con, data_config *dc, buffer *buf, int n);
53092 +int config_exec_pcre_keyvalue_buffer(connection *con, pcre_keyvalue_buffer *kvb, data_config *context, buffer *match_buf, buffer *result);
53093 +
53094 +void *plugin_get_config(server *srv, const char *name);
53095  
53096  #endif
53097 --- ../lighttpd-1.4.11/src/proc_open.c  2005-08-11 01:26:39.000000000 +0300
53098 +++ lighttpd-1.5.0/src/proc_open.c      2006-07-16 00:26:04.000000000 +0300
53099 @@ -13,13 +13,13 @@
53100  #endif
53101  
53102  
53103 -#ifdef WIN32
53104 +#ifdef _WIN32
53105  /* {{{ win32 stuff */
53106  # define SHELLENV "ComSpec"
53107  # define SECURITY_DC , SECURITY_ATTRIBUTES *security
53108  # define SECURITY_CC , security
53109  # define pipe(pair) (CreatePipe(&pair[0], &pair[1], security, 2048L) ? 0 : -1)
53110 -static inline HANDLE dup_handle(HANDLE src, BOOL inherit, BOOL closeorig)
53111 +static HANDLE dup_handle(HANDLE src, BOOL inherit, BOOL closeorig)
53112  {
53113         HANDLE copy, self = GetCurrentProcess();
53114  
53115 @@ -148,11 +148,14 @@
53116         STARTUPINFO si;
53117         BOOL procok;
53118         SECURITY_ATTRIBUTES security;
53119 -       const char *shell;
53120 +       const char *shell = NULL;
53121 +       const char *windir = NULL;
53122         buffer *cmdline;
53123  
53124 -       if (NULL == (shell = getenv(SHELLENV))) {
53125 -               fprintf(stderr, "env %s is required", SHELLENV);
53126 +       if (NULL == (shell = getenv(SHELLENV)) &&
53127 +                       NULL == (windir = getenv("SystemRoot")) &&
53128 +                       NULL == (windir = getenv("windir"))) {
53129 +               fprintf(stderr, "One of %s,%%SystemRoot,%%windir is required", SHELLENV);
53130                 return -1;
53131         }
53132  
53133 @@ -177,17 +180,23 @@
53134         memset(&pi, 0, sizeof(pi));
53135  
53136         cmdline = buffer_init();
53137 -       buffer_append_string(cmdline, shell);
53138 +       if (shell) {
53139 +               buffer_append_string(cmdline, shell);
53140 +       } else {
53141 +               buffer_append_string(cmdline, windir);
53142 +               buffer_append_string(cmdline, "\\system32\\cmd.exe");
53143 +       }
53144         buffer_append_string_len(cmdline, CONST_STR_LEN(" /c "));
53145         buffer_append_string(cmdline, command);
53146         procok = CreateProcess(NULL, cmdline->ptr, &security, &security, TRUE,
53147                         NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);
53148 -       buffer_free(cmdline);
53149  
53150         if (FALSE == procok) {
53151 -               fprintf(stderr, "failed to CreateProcess");
53152 +               fprintf(stderr, "failed to CreateProcess: %s", cmdline->ptr);
53153 +               buffer_free(cmdline);
53154                 return -1;
53155         }
53156 +       buffer_free(cmdline);
53157  
53158         proc->child = pi.hProcess;
53159         CloseHandle(pi.hThread);
53160 @@ -226,8 +235,7 @@
53161         const char *shell;
53162  
53163         if (NULL == (shell = getenv(SHELLENV))) {
53164 -               fprintf(stderr, "env %s is required", SHELLENV);
53165 -               return -1;
53166 +               shell = "/bin/sh";
53167         }
53168  
53169         if (proc_open_pipes(proc) != 0) {
53170 @@ -262,11 +270,11 @@
53171         }
53172  }
53173  /* }}} */
53174 -#endif /* WIN32 */
53175 +#endif /* _WIN32 */
53176  
53177  /* {{{ proc_read_fd_to_buffer */
53178  static void proc_read_fd_to_buffer(int fd, buffer *b) {
53179 -       ssize_t s;
53180 +       int s; /* win32 has not ssize_t */
53181  
53182         for (;;) {
53183                 buffer_prepare_append(b, 512);
53184 --- ../lighttpd-1.4.11/src/proc_open.h  2005-08-11 01:26:39.000000000 +0300
53185 +++ lighttpd-1.5.0/src/proc_open.h      2006-07-16 00:26:04.000000000 +0300
53186 @@ -1,7 +1,7 @@
53187  
53188  #include "buffer.h"
53189  
53190 -#ifdef WIN32
53191 +#ifdef _WIN32
53192  #include <windows.h>
53193  typedef HANDLE descriptor_t;
53194  typedef HANDLE proc_pid_t;
53195 --- ../lighttpd-1.4.11/src/request.c    2006-03-05 11:58:09.000000000 +0200
53196 +++ lighttpd-1.5.0/src/request.c        2006-09-07 00:57:05.000000000 +0300
53197 @@ -5,22 +5,23 @@
53198  #include <string.h>
53199  #include <stdio.h>
53200  #include <ctype.h>
53201 +#include <errno.h>
53202  
53203  #include "request.h"
53204  #include "keyvalue.h"
53205  #include "log.h"
53206 +#include "http_req.h"
53207  
53208 -static int request_check_hostname(server *srv, connection *con, buffer *host) {
53209 +#include "sys-strings.h"
53210 +
53211 +static int request_check_hostname(buffer *host) {
53212         enum { DOMAINLABEL, TOPLABEL } stage = TOPLABEL;
53213         size_t i;
53214         int label_len = 0;
53215         size_t host_len;
53216         char *colon;
53217 -       int is_ip = -1; /* -1 don't know yet, 0 no, 1 yes */ 
53218 +       int is_ip = -1; /* -1 don't know yet, 0 no, 1 yes */
53219         int level = 0;
53220 -       
53221 -       UNUSED(srv);
53222 -       UNUSED(con);
53223  
53224         /*
53225          *       hostport      = host [ ":" port ]
53226 @@ -32,17 +33,18 @@
53227          *       IPv6address   = "[" ... "]"
53228          *       port          = *digit
53229          */
53230 -       
53231 +
53232         /* no Host: */
53233 -       if (!host || host->used == 0) return 0;
53234 -       
53235 +       if (buffer_is_empty(host)) return 0;
53236 +       if (host->used < 1) return 0;
53237 +
53238         host_len = host->used - 1;
53239 -       
53240 +
53241         /* IPv6 adress */
53242         if (host->ptr[0] == '[') {
53243                 char *c = host->ptr + 1;
53244                 int colon_cnt = 0;
53245 -               
53246 +
53247                 /* check portnumber */
53248                 for (; *c && *c != ']'; c++) {
53249                         if (*c == ':') {
53250 @@ -53,12 +55,12 @@
53251                                 return -1;
53252                         }
53253                 }
53254 -               
53255 +
53256                 /* missing ] */
53257                 if (!*c) {
53258                         return -1;
53259                 }
53260 -               
53261 +
53262                 /* check port */
53263                 if (*(c+1) == ':') {
53264                         for (c += 2; *c; c++) {
53265 @@ -69,39 +71,39 @@
53266                 }
53267                 return 0;
53268         }
53269 -       
53270 +
53271         if (NULL != (colon = memchr(host->ptr, ':', host_len))) {
53272                 char *c = colon + 1;
53273 -               
53274 +
53275                 /* check portnumber */
53276                 for (; *c; c++) {
53277                         if (!light_isdigit(*c)) return -1;
53278                 }
53279 -               
53280 +
53281                 /* remove the port from the host-len */
53282                 host_len = colon - host->ptr;
53283         }
53284 -       
53285 +
53286         /* Host is empty */
53287         if (host_len == 0) return -1;
53288 -       
53289 +
53290         /* scan from the right and skip the \0 */
53291         for (i = host_len - 1; i + 1 > 0; i--) {
53292                 const char c = host->ptr[i];
53293  
53294                 switch (stage) {
53295 -               case TOPLABEL: 
53296 +               case TOPLABEL:
53297                         if (c == '.') {
53298                                 /* only switch stage, if this is not the last character */
53299                                 if (i != host_len - 1) {
53300                                         if (label_len == 0) {
53301                                                 return -1;
53302                                         }
53303 -                                       
53304 +
53305                                         /* check the first character at right of the dot */
53306                                         if (is_ip == 0) {
53307                                                 if (!light_isalpha(host->ptr[i+1])) {
53308 -                                                       return -1; 
53309 +                                                       return -1;
53310                                                 }
53311                                         } else if (!light_isdigit(host->ptr[i+1])) {
53312                                                 is_ip = 0;
53313 @@ -111,9 +113,9 @@
53314                                                 /* just digits */
53315                                                 is_ip = 1;
53316                                         }
53317 -                                               
53318 +
53319                                         stage = DOMAINLABEL;
53320 -                                       
53321 +
53322                                         label_len = 0;
53323                                         level++;
53324                                 } else if (i == 0) {
53325 @@ -135,7 +137,7 @@
53326                                 }
53327                                 label_len++;
53328                         }
53329 -                       
53330 +
53331                         break;
53332                 case DOMAINLABEL:
53333                         if (is_ip == 1) {
53334 @@ -143,7 +145,7 @@
53335                                         if (label_len == 0) {
53336                                                 return -1;
53337                                         }
53338 -                                       
53339 +
53340                                         label_len = 0;
53341                                         level++;
53342                                 } else if (!light_isdigit(c)) {
53343 @@ -156,12 +158,12 @@
53344                                         if (label_len == 0) {
53345                                                 return -1;
53346                                         }
53347 -                                       
53348 +
53349                                         /* c is either - or alphanum here */
53350                                         if ('-' == host->ptr[i+1]) {
53351                                                 return -1;
53352                                         }
53353 -                                       
53354 +
53355                                         label_len = 0;
53356                                         level++;
53357                                 } else if (i == 0) {
53358 @@ -176,20 +178,20 @@
53359                                         label_len++;
53360                                 }
53361                         }
53362 -                       
53363 +
53364                         break;
53365                 }
53366         }
53367 -       
53368 +
53369         /* a IP has to consist of 4 parts */
53370         if (is_ip == 1 && level != 3) {
53371                 return -1;
53372         }
53373 -       
53374 +
53375         if (label_len == 0) {
53376                 return -1;
53377         }
53378 -       
53379 +
53380         return 0;
53381  }
53382  
53383 @@ -201,53 +203,53 @@
53384         char *s;
53385         size_t i;
53386         int state = 0;
53387 -       /*  
53388 -        * parse 
53389 -        * 
53390 +       /*
53391 +        * parse
53392 +        *
53393          * val1, val2, val3, val4
53394 -        * 
53395 +        *
53396          * into a array (more or less a explode() incl. striping of whitespaces
53397          */
53398 -       
53399 +
53400         if (b->used == 0) return 0;
53401 -       
53402 +
53403         s = b->ptr;
53404 -       
53405 +
53406         for (i =0; i < b->used - 1; ) {
53407                 char *start = NULL, *end = NULL;
53408                 data_string *ds;
53409 -               
53410 +
53411                 switch (state) {
53412                 case 0: /* ws */
53413 -                       
53414 +
53415                         /* skip ws */
53416                         for (; (*s == ' ' || *s == '\t') && i < b->used - 1; i++, s++);
53417 -                       
53418 -                       
53419 +
53420 +
53421                         state = 1;
53422                         break;
53423                 case 1: /* value */
53424                         start = s;
53425 -                       
53426 +
53427                         for (; *s != ',' && i < b->used - 1; i++, s++);
53428                         end = s - 1;
53429 -                       
53430 +
53431                         for (; (*end == ' ' || *end == '\t') && end > start; end--);
53432 -                       
53433 +
53434                         if (NULL == (ds = (data_string *)array_get_unused_element(vals, TYPE_STRING))) {
53435                                 ds = data_string_init();
53436                         }
53437  
53438                         buffer_copy_string_len(ds->value, start, end-start+1);
53439                         array_insert_unique(vals, (data_unset *)ds);
53440 -                       
53441 +
53442                         if (*s == ',') {
53443                                 state = 0;
53444                                 i++;
53445                                 s++;
53446                         } else {
53447                                 /* end of string */
53448 -                               
53449 +
53450                                 state = 2;
53451                         }
53452                         break;
53453 @@ -263,747 +265,239 @@
53454         if (c <= 32) return 0;
53455         if (c == 127) return 0;
53456         if (c == 255) return 0;
53457 -       
53458 +
53459         return 1;
53460  }
53461  
53462 -int http_request_parse(server *srv, connection *con) {
53463 -       char *uri = NULL, *proto = NULL, *method = NULL, con_length_set;
53464 -       int is_key = 1, key_len = 0, is_ws_after_key = 0, in_folding;
53465 -       char *value = NULL, *key = NULL;
53466 -       
53467 -       enum { HTTP_CONNECTION_UNSET, HTTP_CONNECTION_KEEPALIVE, HTTP_CONNECTION_CLOSE } keep_alive_set = HTTP_CONNECTION_UNSET;
53468 -       
53469 -       int line = 0;
53470 -       
53471 -       int request_line_stage = 0;
53472 -       size_t i, first;
53473 -       
53474 -       int done = 0;
53475 -       
53476 -       data_string *ds = NULL;
53477 -       
53478 -       /* 
53479 -        * Request: "^(GET|POST|HEAD) ([^ ]+(\\?[^ ]+|)) (HTTP/1\\.[01])$" 
53480 -        * Option : "^([-a-zA-Z]+): (.+)$"                    
53481 -        * End    : "^$"
53482 -        */
53483 +int http_request_parse(server *srv, connection *con, http_req *req) {
53484 +       size_t i;
53485 +       enum { HTTP_CONNECTION_UNSET, HTTP_CONNECTION_CLOSE, HTTP_CONNECTION_KEEPALIVE } keep_alive_set = HTTP_CONNECTION_UNSET;
53486  
53487 -       if (con->conf.log_request_header) {
53488 -               log_error_write(srv, __FILE__, __LINE__, "sdsdSb", 
53489 -                               "fd:", con->fd, 
53490 -                               "request-len:", con->request.request->used, 
53491 -                               "\n", con->request.request);
53492 +       if (req->protocol == HTTP_VERSION_UNSET) {
53493 +               con->http_status = 505; /* Version not Supported */
53494 +               return 0;
53495         }
53496  
53497 -       if (con->request_count > 1 &&
53498 -           con->request.request->ptr[0] == '\r' &&
53499 -           con->request.request->ptr[1] == '\n') {
53500 -               /* we are in keep-alive and might get \r\n after a previous POST request.*/
53501 -               
53502 -               buffer_copy_string_len(con->parse_request, con->request.request->ptr + 2, con->request.request->used - 1 - 2);
53503 -       } else {
53504 -               /* fill the local request buffer */
53505 -               buffer_copy_string_buffer(con->parse_request, con->request.request);
53506 +       if (req->method == HTTP_METHOD_UNSET) {
53507 +               con->http_status = 405; /* Method not allowed */
53508 +               return 0;
53509         }
53510 -       
53511 -       keep_alive_set = 0;
53512 -       con_length_set = 0;
53513  
53514 -       /* parse the first line of the request
53515 -        *
53516 -        * should be:
53517 -        *
53518 -        * <method> <uri> <protocol>\r\n
53519 +       if (buffer_is_empty(req->uri_raw)) {
53520 +               con->http_status = 400;
53521 +               return 0;
53522 +       }
53523 +
53524 +       /* strip absolute URLs
53525          * */
53526 -       for (i = 0, first = 0; i < con->parse_request->used && line == 0; i++) {
53527 -               char *cur = con->parse_request->ptr + i;
53528 +
53529 +       buffer_copy_string_buffer(con->request.orig_uri, req->uri_raw);
53530 +       if (req->uri_raw->ptr[0] == '/') {
53531 +               buffer_copy_string_buffer(con->request.uri, req->uri_raw);
53532 +       } else if (req->uri_raw->ptr[0] == '*') {
53533 +               if (req->method != HTTP_METHOD_OPTIONS) {
53534 +                       con->http_status = 400;
53535 +                       return 0;
53536 +               }
53537 +               buffer_copy_string_buffer(con->request.uri, req->uri_raw);
53538 +       } else {
53539 +               /* GET http://www.example.org/foobar */
53540 +               char *sl;
53541 +
53542 +               if (0 != strncmp(BUF_STR(req->uri_raw), "http://", 7)) {
53543 +                       con->http_status = 400;
53544 +                       return 0;
53545 +               }
53546 +
53547 +               if (NULL == (sl = strchr(BUF_STR(req->uri_raw) + 7, '/'))) {
53548 +                       con->http_status = 400;
53549 +                       return 0;
53550 +               }
53551                 
53552 -               switch(*cur) {
53553 -               case '\r': 
53554 -                       if (con->parse_request->ptr[i+1] == '\n') {
53555 -                               http_method_t r;
53556 -                               char *nuri = NULL;
53557 -                               size_t j;
53558 -                               
53559 -                               /* \r\n -> \0\0 */
53560 -                               con->parse_request->ptr[i] = '\0';
53561 -                               con->parse_request->ptr[i+1] = '\0';
53562 -                               
53563 -                               buffer_copy_string_len(con->request.request_line, con->parse_request->ptr, i);
53564 -                               
53565 -                               if (request_line_stage != 2) {
53566 -                                       con->http_status = 400;
53567 -                                       con->response.keep_alive = 0;
53568 -                                       con->keep_alive = 0;
53569 -                                       
53570 -                                       if (srv->srvconf.log_request_header_on_error) {
53571 -                                               log_error_write(srv, __FILE__, __LINE__, "s", "incomplete request line -> 400");
53572 -                                               log_error_write(srv, __FILE__, __LINE__, "Sb",
53573 -                                                               "request-header:\n",
53574 -                                                               con->request.request);
53575 -                                       }
53576 -                                       return 0;
53577 -                               }
53578 -                               
53579 -                               proto = con->parse_request->ptr + first;
53580 -                               
53581 -                               *(uri - 1) = '\0';
53582 -                               *(proto - 1) = '\0';
53583 -                               
53584 -                               /* we got the first one :) */
53585 -                               if (-1 == (r = get_http_method_key(method))) {
53586 -                                       con->http_status = 501;
53587 -                                       con->response.keep_alive = 0;
53588 -                                       con->keep_alive = 0;
53589 -                                       
53590 -                                       if (srv->srvconf.log_request_header_on_error) {
53591 -                                               log_error_write(srv, __FILE__, __LINE__, "s", "unknown http-method -> 501");
53592 -                                               log_error_write(srv, __FILE__, __LINE__, "Sb",
53593 -                                                               "request-header:\n",
53594 -                                                               con->request.request);
53595 -                                       }
53596 -                               
53597 -                                       return 0;
53598 +               buffer_copy_string(con->request.uri, sl);
53599 +               buffer_copy_string_len(con->request.http_host, BUF_STR(req->uri_raw) + 7, sl - BUF_STR(req->uri_raw) - 7);
53600 +       }
53601 +
53602 +       con->request.http_method = req->method;
53603 +       con->request.http_version = req->protocol;
53604 +
53605 +       for (i = 0; i < req->headers->used; i++) {
53606 +               data_string *ds = (data_string *)req->headers->data[i];
53607 +               data_string *hdr;
53608 +               int cmp;
53609 +
53610 +               /* this list is sorted */
53611 +               if (0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Connection")))) {
53612 +                       array *vals;
53613 +                       size_t vi;
53614 +                       /* Connection: Keep-Alive, ... */
53615 +
53616 +                       vals = srv->split_vals;
53617 +
53618 +                       array_reset(vals);
53619 +                       http_request_split_value(vals, ds->value);
53620 +
53621 +                       for (vi = 0; vi < vals->used; vi++) {
53622 +                               data_string *dsv = (data_string *)vals->data[vi];
53623 +
53624 +                               if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("keep-alive"))) {
53625 +                                       keep_alive_set = HTTP_CONNECTION_KEEPALIVE;
53626 +
53627 +                                       break;
53628 +                               } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("close"))) {
53629 +                                       keep_alive_set = HTTP_CONNECTION_CLOSE;
53630 +
53631 +                                       break;
53632                                 }
53633 -                               
53634 -                               con->request.http_method = r;
53635 -                       
53636 -                               /* 
53637 -                                * RFC2616 says:
53638 -                                *
53639 -                                * HTTP-Version   = "HTTP" "/" 1*DIGIT "." 1*DIGIT
53640 -                                *
53641 -                                * */   
53642 -                               if (0 == strncmp(proto, "HTTP/", sizeof("HTTP/") - 1)) {
53643 -                                       char * major = proto + sizeof("HTTP/") - 1;
53644 -                                       char * minor = strchr(major, '.');
53645 -                                       char *err = NULL;
53646 -                                       int major_num = 0, minor_num = 0;
53647 -
53648 -                                       int invalid_version = 0;
53649 -
53650 -                                       if (NULL == minor || /* no dot */
53651 -                                           minor == major || /* no major */
53652 -                                           *(minor + 1) == '\0' /* no minor */) {
53653 -                                               invalid_version = 1;
53654 -                                       } else {
53655 -                                               *minor = '\0';
53656 -                                               major_num = strtol(major, &err, 10);
53657 +                       }
53658 +               } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Content-Length")))) {
53659 +                       char *err;
53660 +                       long long int r;
53661  
53662 -                                               if (*err != '\0') invalid_version = 1;
53663 +                       /* ignore the header, if it is a duplicate */
53664 +                       if (con->request.content_length != -1) continue;
53665  
53666 -                                               *minor++ = '.';
53667 -                                               minor_num = strtol(minor, &err, 10);
53668 +                       r = strtoll(ds->value->ptr, &err, 10);
53669  
53670 -                                               if (*err != '\0') invalid_version = 1;
53671 -                                       }
53672 +                       if (*err != '\0') {
53673 +                               TRACE("content-length is not a number: %s (Status: 400)", err);
53674  
53675 -                                       if (invalid_version) {
53676 -                                               con->http_status = 400;
53677 -                                               con->keep_alive = 0;
53678 -
53679 -                                               if (srv->srvconf.log_request_header_on_error) {
53680 -                                                       log_error_write(srv, __FILE__, __LINE__, "s", "unknown protocol -> 400");
53681 -                                                       log_error_write(srv, __FILE__, __LINE__, "Sb",
53682 -                                                                       "request-header:\n",
53683 -                                                                       con->request.request);
53684 -                                               }
53685 -                                               return 0;
53686 -                                       }
53687 +                               con->http_status = 400;
53688  
53689 -                                       if (major_num == 1 && minor_num == 1) {
53690 -                                               con->request.http_version = con->conf.allow_http11 ? HTTP_VERSION_1_1 : HTTP_VERSION_1_0;
53691 -                                       } else if (major_num == 1 && minor_num == 0) {
53692 -                                               con->request.http_version = HTTP_VERSION_1_0;
53693 -                                       } else { 
53694 -                                               con->http_status = 505;
53695 -
53696 -                                               if (srv->srvconf.log_request_header_on_error) {
53697 -                                                       log_error_write(srv, __FILE__, __LINE__, "s", "unknown HTTP version -> 505");
53698 -                                                       log_error_write(srv, __FILE__, __LINE__, "Sb",
53699 -                                                                       "request-header:\n",
53700 -                                                                       con->request.request);
53701 -                                               }
53702 -                                               return 0;
53703 -                                       }
53704 -                               } else {
53705 -                                       con->http_status = 400;
53706 -                                       con->keep_alive = 0;
53707 +                               return 0;
53708 +                       }
53709 +
53710 +                       if (r == LLONG_MIN ||
53711 +                           r == LLONG_MAX) {
53712 +                               if (errno == ERANGE) {
53713 +                                       con->http_status = 413;
53714  
53715 -                                       if (srv->srvconf.log_request_header_on_error) {
53716 -                                               log_error_write(srv, __FILE__, __LINE__, "s", "unknown protocol -> 400");
53717 -                                               log_error_write(srv, __FILE__, __LINE__, "Sb",
53718 -                                                               "request-header:\n",
53719 -                                                               con->request.request);
53720 -                                       }
53721                                         return 0;
53722                                 }
53723 -                               
53724 -                               if (0 == strncmp(uri, "http://", 7) &&
53725 -                                   NULL != (nuri = strchr(uri + 7, '/'))) {
53726 -                                       /* ignore the host-part */
53727 -                                       
53728 -                                       buffer_copy_string_len(con->request.uri, nuri, proto - nuri - 1);
53729 -                               } else {
53730 -                                       /* everything looks good so far */
53731 -                                       buffer_copy_string_len(con->request.uri, uri, proto - uri - 1);
53732 -                               }
53733 -                               
53734 -                               /* check uri for invalid characters */
53735 -                               for (j = 0; j < con->request.uri->used - 1; j++) {
53736 -                                       if (!request_uri_is_valid_char(con->request.uri->ptr[j])) {
53737 -                                               unsigned char buf[2];
53738 -                                               con->http_status = 400;
53739 -                                               con->keep_alive = 0;
53740 -                                               
53741 -                                               if (srv->srvconf.log_request_header_on_error) {
53742 -                                                       buf[0] = con->request.uri->ptr[j];
53743 -                                                       buf[1] = '\0';
53744 -                                       
53745 -                                                       if (con->request.uri->ptr[j] > 32 &&
53746 -                                                           con->request.uri->ptr[j] != 127) {  
53747 -                                                               /* the character is printable -> print it */
53748 -                                                               log_error_write(srv, __FILE__, __LINE__, "ss",
53749 -                                                                               "invalid character in URI -> 400",
53750 -                                                                               buf);
53751 -                                                       } else {
53752 -                                                               /* a control-character, print ascii-code */
53753 -                                                               log_error_write(srv, __FILE__, __LINE__, "sd",
53754 -                                                                               "invalid character in URI -> 400",
53755 -                                                                               con->request.uri->ptr[j]);
53756 -                                                       }
53757 -                                               
53758 -                                                       log_error_write(srv, __FILE__, __LINE__, "Sb",
53759 -                                                                       "request-header:\n",
53760 -                                                                       con->request.request);
53761 -                                               }
53762 -                                               
53763 -                                               return 0;
53764 -                                       }
53765 -                               }
53766 -                               
53767 -                               buffer_copy_string_buffer(con->request.orig_uri, con->request.uri);
53768 -                               
53769 -                               con->http_status = 0;
53770 -                               
53771 -                               i++;
53772 -                               line++;
53773 -                               first = i+1;
53774                         }
53775 -                       break;
53776 -               case ' ':
53777 -                       switch(request_line_stage) {
53778 -                       case 0: 
53779 -                               /* GET|POST|... */
53780 -                               method = con->parse_request->ptr + first; 
53781 -                               first = i + 1;
53782 -                               break;
53783 -                       case 1:
53784 -                               /* /foobar/... */
53785 -                               uri = con->parse_request->ptr + first; 
53786 -                               first = i + 1;
53787 -                               break;
53788 -                       default:
53789 -                               /* ERROR, one space to much */
53790 +
53791 +                       if (r < 0) {
53792                                 con->http_status = 400;
53793 -                               con->response.keep_alive = 0;
53794 -                               con->keep_alive = 0;
53795 -                               
53796 -                               if (srv->srvconf.log_request_header_on_error) {
53797 -                                       log_error_write(srv, __FILE__, __LINE__, "s", "overlong request line -> 400");
53798 -                                       log_error_write(srv, __FILE__, __LINE__, "Sb",
53799 -                                                       "request-header:\n",
53800 -                                                       con->request.request);
53801 -                               }
53802 +
53803                                 return 0;
53804                         }
53805 -                       
53806 -                       request_line_stage++;
53807 -                       break;
53808 -               }
53809 -       }
53810 -       
53811 -       in_folding = 0;
53812  
53813 -       if (con->request.uri->used == 1) {
53814 -               con->http_status = 400;
53815 -               con->response.keep_alive = 0;
53816 -               con->keep_alive = 0;
53817 +                       /* don't handle more the SSIZE_MAX bytes in content-length */
53818 +                       if (r > SSIZE_MAX) {
53819 +                               con->http_status = 413;
53820  
53821 -               log_error_write(srv, __FILE__, __LINE__, "s", "no uri specified -> 400");
53822 -               if (srv->srvconf.log_request_header_on_error) {
53823 -                       log_error_write(srv, __FILE__, __LINE__, "Sb",
53824 -                                                       "request-header:\n",
53825 -                                                       con->request.request);
53826 -               }
53827 -               return 0;
53828 -       }
53829 +                               ERROR("request-size too long: %s (Status: 413)", BUF_STR(ds->value));
53830  
53831 -       
53832 -       for (; i < con->parse_request->used && !done; i++) {
53833 -               char *cur = con->parse_request->ptr + i;
53834 -               
53835 -               if (is_key) {
53836 -                       size_t j;
53837 -                       int got_colon = 0;
53838 -                       
53839 -                       /**
53840 -                        * 1*<any CHAR except CTLs or separators>
53841 -                        * CTLs == 0-31 + 127
53842 -                        * 
53843 +                               return 0;
53844 +                       }
53845 +
53846 +                       con->request.content_length = r;
53847 +               } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Expect")))) {
53848 +                       /* HTTP 2616 8.2.3
53849 +                        * Expect: 100-continue
53850 +                        *
53851 +                        *   -> (10.1.1)  100 (read content, process request, send final status-code)
53852 +                        *   -> (10.4.18) 417 (close)
53853 +                        *
53854 +                        *
53855                          */
53856 -                       switch(*cur) {
53857 -                       case ':':
53858 -                               is_key = 0;
53859 -                               
53860 -                               value = cur + 1;
53861 -                               
53862 -                               if (is_ws_after_key == 0) {
53863 -                                       key_len = i - first;
53864 -                               }
53865 -                               is_ws_after_key = 0;
53866 -                                       
53867 -                               break;
53868 -                       case '(':
53869 -                       case ')':
53870 -                       case '<':
53871 -                       case '>':
53872 -                       case '@':
53873 -                       case ',':
53874 -                       case ';':
53875 -                       case '\\':
53876 -                       case '\"':
53877 -                       case '/':
53878 -                       case '[':
53879 -                       case ']':
53880 -                       case '?':
53881 -                       case '=':
53882 -                       case '{':
53883 -                       case '}':
53884 +
53885 +                       if (0 != buffer_caseless_compare(CONST_BUF_LEN(ds->value), CONST_STR_LEN("100-continue"))) {
53886 +                               /* we only support 100-continue */
53887 +                               con->http_status = 417;
53888 +                               return 0;
53889 +                       }
53890 +
53891 +                       if (con->request.http_version != HTTP_VERSION_1_1) {
53892 +                               /* only HTTP/1.1 clients can send us this header */
53893 +                               con->http_status = 417;
53894 +                               return 0;
53895 +                       }
53896 +               } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Host")))) {
53897 +                       if (request_check_hostname(ds->value)) {
53898 +                               TRACE("%s", "Host header is invalue (Status: 400)");
53899                                 con->http_status = 400;
53900                                 con->keep_alive = 0;
53901 -                               con->response.keep_alive = 0;
53902 -                               
53903 -                               log_error_write(srv, __FILE__, __LINE__, "sbsds", 
53904 -                                               "invalid character in key", con->request.request, cur, *cur, "-> 400");
53905 +
53906                                 return 0;
53907 -                       case ' ':
53908 -                       case '\t':
53909 -                               if (i == first) {
53910 -                                       is_key = 0;
53911 -                                       in_folding = 1;
53912 -                                       value = cur;
53913 -                                       
53914 -                                       break;
53915 -                               }
53916 -                               
53917 -                               
53918 -                               key_len = i - first;
53919 -                               
53920 -                               /* skip every thing up to the : */
53921 -                               for (j = 1; !got_colon; j++) {
53922 -                                       switch(con->parse_request->ptr[j + i]) {
53923 -                                       case ' ':
53924 -                                       case '\t':
53925 -                                               /* skip WS */
53926 -                                               continue;
53927 -                                       case ':':
53928 -                                               /* ok, done */
53929 -                                               
53930 -                                               i += j - 1;
53931 -                                               got_colon = 1;
53932 -                                               
53933 -                                               break;
53934 -                                       default:
53935 -                                               /* error */
53936 -                                               
53937 -                                               if (srv->srvconf.log_request_header_on_error) {
53938 -                                                       log_error_write(srv, __FILE__, __LINE__, "s", "WS character in key -> 400");
53939 -                                                       log_error_write(srv, __FILE__, __LINE__, "Sb",
53940 -                                                               "request-header:\n",
53941 -                                                               con->request.request);
53942 -                                               }
53943 -                                       
53944 -                                               con->http_status = 400;
53945 -                                               con->response.keep_alive = 0;
53946 -                                               con->keep_alive = 0;
53947 -                                               
53948 -                                               return 0;
53949 -                                       }
53950 -                               }
53951 -                               
53952 -                               break;
53953 -                       case '\r':
53954 -                               if (con->parse_request->ptr[i+1] == '\n' && i == first) {
53955 -                                       /* End of Header */
53956 -                                       con->parse_request->ptr[i] = '\0';
53957 -                                       con->parse_request->ptr[i+1] = '\0';
53958 -                                       
53959 -                                       i++;
53960 -                                       
53961 -                                       done = 1;
53962 -                                       
53963 -                                       break;
53964 -                               } else {
53965 -                                       if (srv->srvconf.log_request_header_on_error) {
53966 -                                               log_error_write(srv, __FILE__, __LINE__, "s", "CR without LF -> 400");
53967 -                                               log_error_write(srv, __FILE__, __LINE__, "Sb",
53968 -                                                       "request-header:\n",
53969 -                                                       con->request.request);
53970 -                                       }
53971 -                                       
53972 -                                       con->http_status = 400;
53973 -                                       con->keep_alive = 0;
53974 -                                       con->response.keep_alive = 0;
53975 -                                       return 0;
53976 -                               }
53977 -                               /* fall thru */
53978 -                       case 0: /* illegal characters (faster than a if () :) */
53979 -                       case 1:
53980 -                       case 2:
53981 -                       case 3:
53982 -                       case 4:
53983 -                       case 5:
53984 -                       case 6:
53985 -                       case 7:
53986 -                       case 8:
53987 -                       case 10:
53988 -                       case 11:
53989 -                       case 12:
53990 -                       case 14:
53991 -                       case 15:
53992 -                       case 16:
53993 -                       case 17:
53994 -                       case 18:
53995 -                       case 19:
53996 -                       case 20:
53997 -                       case 21:
53998 -                       case 22:
53999 -                       case 23:
54000 -                       case 24:
54001 -                       case 25:
54002 -                       case 26:
54003 -                       case 27:
54004 -                       case 28:
54005 -                       case 29:
54006 -                       case 30:
54007 -                       case 31:
54008 -                       case 127:
54009 +                       }
54010 +
54011 +                       if (!buffer_is_empty(con->request.http_host)) {
54012 +                               TRACE("%s", "Host header is duplicate (Status: 400)");
54013                                 con->http_status = 400;
54014 -                               con->keep_alive = 0;
54015 -                               con->response.keep_alive = 0;
54016 -                               
54017 -                               if (srv->srvconf.log_request_header_on_error) {
54018 -                                       log_error_write(srv, __FILE__, __LINE__, "sbsds", 
54019 -                                               "CTL character in key", con->request.request, cur, *cur, "-> 400");
54020  
54021 -                                       log_error_write(srv, __FILE__, __LINE__, "Sb",
54022 -                                               "request-header:\n",
54023 -                                               con->request.request);
54024 -                               }
54025 -                               
54026                                 return 0;
54027 -                       default:
54028 -                               /* ok */
54029 -                               break;
54030                         }
54031 -               } else {
54032 -                       switch(*cur) {
54033 -                       case '\r': 
54034 -                               if (con->parse_request->ptr[i+1] == '\n') {
54035 -                                       /* End of Headerline */
54036 -                                       con->parse_request->ptr[i] = '\0';
54037 -                                       con->parse_request->ptr[i+1] = '\0';
54038 -                                       
54039 -                                       if (in_folding) {
54040 -                                               if (!ds) {
54041 -                                                       /* 400 */
54042 -                                       
54043 -                                                       if (srv->srvconf.log_request_header_on_error) {
54044 -                                                               log_error_write(srv, __FILE__, __LINE__, "s", "WS at the start of first line -> 400");
54045 -                                                       
54046 -                                                               log_error_write(srv, __FILE__, __LINE__, "Sb",
54047 -                                                                       "request-header:\n",
54048 -                                                                       con->request.request);
54049 -                                                       }
54050 -
54051 -                                       
54052 -                                                       con->http_status = 400;
54053 -                                                       con->keep_alive = 0;
54054 -                                                       con->response.keep_alive = 0;
54055 -                                                       return 0;
54056 -                                               }
54057 -                                               buffer_append_string(ds->value, value);
54058 -                                       } else {
54059 -                                               int s_len;
54060 -                                               key = con->parse_request->ptr + first;
54061 -                                       
54062 -                                               s_len = cur - value;
54063 -                                               
54064 -                                               if (s_len > 0) {
54065 -                                                       int cmp = 0;
54066 -                                                       if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
54067 -                                                               ds = data_string_init();
54068 -                                                       }
54069 -                                                       buffer_copy_string_len(ds->key, key, key_len);
54070 -                                                       buffer_copy_string_len(ds->value, value, s_len);
54071 -                                                       
54072 -                                                       /* retreive values 
54073 -                                                        * 
54074 -                                                        * 
54075 -                                                        * the list of options is sorted to simplify the search
54076 -                                                        */
54077 -                                                       
54078 -                                                       if (0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Connection")))) {
54079 -                                                               array *vals;
54080 -                                                               size_t vi;
54081 -                                                               
54082 -                                                               /* split on , */
54083 -                                                               
54084 -                                                               vals = srv->split_vals;
54085 -
54086 -                                                               array_reset(vals);
54087 -                                                               
54088 -                                                               http_request_split_value(vals, ds->value);
54089 -                                                               
54090 -                                                               for (vi = 0; vi < vals->used; vi++) {
54091 -                                                                       data_string *dsv = (data_string *)vals->data[vi];
54092 -                                                                       
54093 -                                                                       if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("keep-alive"))) {
54094 -                                                                               keep_alive_set = HTTP_CONNECTION_KEEPALIVE;
54095 -                                                                               
54096 -                                                                               break;
54097 -                                                                       } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("close"))) {
54098 -                                                                               keep_alive_set = HTTP_CONNECTION_CLOSE;
54099 -                                                                               
54100 -                                                                               break;
54101 -                                                                       }
54102 -                                                               }
54103 -                                                               
54104 -                                                       } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Content-Length")))) {
54105 -                                                               char *err;
54106 -                                                               unsigned long int r;
54107 -                                                               size_t j;
54108 -                                                               
54109 -                                                               if (con_length_set) {
54110 -                                                                       con->http_status = 400;
54111 -                                                                       con->keep_alive = 0;
54112 -                                                                       
54113 -                                                                       if (srv->srvconf.log_request_header_on_error) {
54114 -                                                                               log_error_write(srv, __FILE__, __LINE__, "s", 
54115 -                                                                                               "duplicate Content-Length-header -> 400");
54116 -                                                                               log_error_write(srv, __FILE__, __LINE__, "Sb",
54117 -                                                                                               "request-header:\n",
54118 -                                                                                               con->request.request);
54119 -                                                                       }
54120 -                                                                       return 0;
54121 -                                                               }
54122 -                                                               
54123 -                                                               if (ds->value->used == 0) SEGFAULT();
54124 -                                                               
54125 -                                                               for (j = 0; j < ds->value->used - 1; j++) {
54126 -                                                                       char c = ds->value->ptr[j];
54127 -                                                                       if (!isdigit((unsigned char)c)) {
54128 -                                                                               log_error_write(srv, __FILE__, __LINE__, "sbs", 
54129 -                                                                                               "content-length broken:", ds->value, "-> 400");
54130 -                                                                               
54131 -                                                                               con->http_status = 400;
54132 -                                                                               con->keep_alive = 0;
54133 -                                                                               
54134 -                                                                               array_insert_unique(con->request.headers, (data_unset *)ds);
54135 -                                                                               return 0;
54136 -                                                                       }
54137 -                                                               }
54138 -                                                               
54139 -                                                               r = strtoul(ds->value->ptr, &err, 10);
54140 -                                                               
54141 -                                                               if (*err == '\0') {
54142 -                                                                       con_length_set = 1;
54143 -                                                                       con->request.content_length = r;
54144 -                                                               } else {
54145 -                                                                       log_error_write(srv, __FILE__, __LINE__, "sbs", 
54146 -                                                                                       "content-length broken:", ds->value, "-> 400");
54147 -                                                                       
54148 -                                                                       con->http_status = 400;
54149 -                                                                       con->keep_alive = 0;
54150 -                                                                       
54151 -                                                                       array_insert_unique(con->request.headers, (data_unset *)ds);
54152 -                                                                       return 0;
54153 -                                                               }
54154 -                                                       } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Content-Type")))) {
54155 -                                                               /* if dup, only the first one will survive */
54156 -                                                               if (!con->request.http_content_type) {
54157 -                                                                       con->request.http_content_type = ds->value->ptr;
54158 -                                                               } else {
54159 -                                                                       con->http_status = 400;
54160 -                                                                       con->keep_alive = 0;
54161 -                                                                       
54162 -                                                                       if (srv->srvconf.log_request_header_on_error) {
54163 -                                                                               log_error_write(srv, __FILE__, __LINE__, "s", 
54164 -                                                                                               "duplicate Content-Type-header -> 400");
54165 -                                                                               log_error_write(srv, __FILE__, __LINE__, "Sb",
54166 -                                                                                               "request-header:\n",
54167 -                                                                                               con->request.request);
54168 -                                                                       }
54169 -                                                                       return 0;
54170 -                                                               }
54171 -                                                       } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Expect")))) {
54172 -                                                               /* HTTP 2616 8.2.3 
54173 -                                                                * Expect: 100-continue
54174 -                                                                * 
54175 -                                                                *   -> (10.1.1)  100 (read content, process request, send final status-code)
54176 -                                                                *   -> (10.4.18) 417 (close)
54177 -                                                                * 
54178 -                                                                * (not handled at all yet, we always send 417 here)
54179 -                                                                *
54180 -                                                                * What has to be added ?
54181 -                                                                * 1. handling of chunked request body
54182 -                                                                * 2. out-of-order sending from the HTTP/1.1 100 Continue
54183 -                                                                *    header
54184 -                                                                *
54185 -                                                                */
54186 -                                                               
54187 -                                                               con->http_status = 417;
54188 -                                                               con->keep_alive = 0;
54189 -                                                               
54190 -                                                               array_insert_unique(con->request.headers, (data_unset *)ds);
54191 -                                                               return 0;
54192 -                                                       } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Host")))) {
54193 -                                                               if (!con->request.http_host) {
54194 -                                                                       con->request.http_host = ds->value;
54195 -                                                               } else {
54196 -                                                                       con->http_status = 400;
54197 -                                                                       con->keep_alive = 0;
54198 -                                                                       
54199 -                                                                       if (srv->srvconf.log_request_header_on_error) {
54200 -                                                                               log_error_write(srv, __FILE__, __LINE__, "s", 
54201 -                                                                                               "duplicate Host-header -> 400");
54202 -                                                                               log_error_write(srv, __FILE__, __LINE__, "Sb",
54203 -                                                                                               "request-header:\n",
54204 -                                                                                               con->request.request);
54205 -                                                                       }
54206 -                                                                       return 0;
54207 -                                                               }
54208 -                                                       } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-Modified-Since")))) {
54209 -                                                               /* Proxies sometimes send dup headers
54210 -                                                                * if they are the same we ignore the second
54211 -                                                                * if not, we raise an error */
54212 -                                                               if (!con->request.http_if_modified_since) {
54213 -                                                                       con->request.http_if_modified_since = ds->value->ptr;
54214 -                                                               } else if (0 == strcasecmp(con->request.http_if_modified_since,
54215 -                                                                                       ds->value->ptr)) {
54216 -                                                                       /* ignore it if they are the same */
54217 -                                                               } else {
54218 -                                                                       con->http_status = 400;
54219 -                                                                       con->keep_alive = 0;
54220 -                                                                       
54221 -                                                                       if (srv->srvconf.log_request_header_on_error) {
54222 -                                                                               log_error_write(srv, __FILE__, __LINE__, "s", 
54223 -                                                                                               "duplicate If-Modified-Since header -> 400");
54224 -                                                                               log_error_write(srv, __FILE__, __LINE__, "Sb",
54225 -                                                                                               "request-header:\n",
54226 -                                                                                               con->request.request);
54227 -                                                                       }
54228 -                                                                       return 0;
54229 -                                                               }
54230 -                                                       } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-None-Match")))) {
54231 -                                                               /* if dup, only the first one will survive */
54232 -                                                               if (!con->request.http_if_none_match) {
54233 -                                                                       con->request.http_if_none_match = ds->value->ptr;
54234 -                                                               } else {
54235 -                                                                       con->http_status = 400;
54236 -                                                                       con->keep_alive = 0;
54237 -                                                                       
54238 -                                                                       if (srv->srvconf.log_request_header_on_error) {
54239 -                                                                               log_error_write(srv, __FILE__, __LINE__, "s", 
54240 -                                                                                               "duplicate If-None-Match-header -> 400");
54241 -                                                                               log_error_write(srv, __FILE__, __LINE__, "Sb",
54242 -                                                                                               "request-header:\n",
54243 -                                                                                               con->request.request);
54244 -                                                                       }
54245 -                                                                       return 0;
54246 -                                                               }
54247 -                                                       } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Range")))) {
54248 -                                                               if (!con->request.http_range) {
54249 -                                                                       /* bytes=.*-.* */
54250 -                                                               
54251 -                                                                       if (0 == strncasecmp(ds->value->ptr, "bytes=", 6) &&
54252 -                                                                           NULL != strchr(ds->value->ptr+6, '-')) {
54253 -                                                                               
54254 -                                                                               /* if dup, only the first one will survive */
54255 -                                                                               con->request.http_range = ds->value->ptr + 6;
54256 -                                                                       }
54257 -                                                               } else {
54258 -                                                                       con->http_status = 400;
54259 -                                                                       con->keep_alive = 0;
54260 -                                                                       
54261 -                                                                       if (srv->srvconf.log_request_header_on_error) {
54262 -                                                                               log_error_write(srv, __FILE__, __LINE__, "s", 
54263 -                                                                                               "duplicate Range-header -> 400");
54264 -                                                                               log_error_write(srv, __FILE__, __LINE__, "Sb",
54265 -                                                                                               "request-header:\n",
54266 -                                                                                               con->request.request);
54267 -                                                                       }
54268 -                                                                       return 0;
54269 -                                                               }
54270 -                                                       }
54271 -                                                       
54272 -                                                       array_insert_unique(con->request.headers, (data_unset *)ds);
54273 -                                               } else {
54274 -                                                       /* empty header-fields are not allowed by HTTP-RFC, we just ignore them */
54275 -                                               }
54276 -                                       }
54277 -                                       
54278 -                                       i++;
54279 -                                       first = i+1;
54280 -                                       is_key = 1;
54281 -                                       value = 0;
54282 -                                       key_len = 0;
54283 -                                       in_folding = 0;
54284 -                               } else {
54285 -                                       if (srv->srvconf.log_request_header_on_error) {
54286 -                                               log_error_write(srv, __FILE__, __LINE__, "sbs", 
54287 -                                                               "CR without LF", con->request.request, "-> 400");
54288 -                                       }
54289 -                                       
54290 +
54291 +                       buffer_copy_string_buffer(con->request.http_host, ds->value);
54292 +               } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-Modified-Since")))) {
54293 +                       data_string *old;
54294 +                       
54295 +                       if (NULL != (old = (data_string *)array_get_element(con->request.headers, "If-Modified-Since"))) {
54296 +                               if (0 != buffer_caseless_compare(CONST_BUF_LEN(old->value), CONST_BUF_LEN(ds->value))) {
54297 +                                       /* duplicate header and different timestamps */
54298                                         con->http_status = 400;
54299 -                                       con->keep_alive = 0;
54300 -                                       con->response.keep_alive = 0;
54301 +
54302 +                                       TRACE("%s", "If-Modified-Since is duplicate (Status: 400)");
54303 +
54304 +                                       return 0;
54305 +                               }
54306 +                       }
54307 +               } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-None-Match")))) {
54308 +                       data_string *old;
54309 +                       /* if dup, only the first one will survive */
54310 +                       if (NULL != (old = (data_string *)array_get_element(con->request.headers, "If-None-Match"))) {
54311 +                               if (0 != buffer_caseless_compare(CONST_BUF_LEN(old->value), CONST_BUF_LEN(ds->value))) {
54312 +                                       /* duplicate header and different timestamps */
54313 +                                       con->http_status = 400;
54314 +
54315 +                                       TRACE("%s", "If-None-Match is duplicate (Status: 400)");
54316 +
54317                                         return 0;
54318                                 }
54319 -                               break;
54320 -                       case ' ':
54321 -                       case '\t':
54322 -                               /* strip leading WS */
54323 -                               if (value == cur) value = cur+1;
54324 -                       default:
54325 -                               break;
54326 +                       }
54327 +               } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Range")))) {
54328 +                       if (NULL != array_get_element(con->request.headers, "Range")) {
54329 +                               /* duplicate Range header */
54330 +
54331 +                               TRACE("%s", "Range: header is duplicate (Status: 400)");
54332 +
54333 +                               con->http_status = 400;
54334 +                               con->keep_alive = 0;
54335 +                       
54336 +                               return 0;
54337                         }
54338                 }
54339 +
54340 +               hdr = data_string_init();
54341 +
54342 +               buffer_copy_string_buffer(hdr->key, ds->key);
54343 +               buffer_copy_string_buffer(hdr->value, ds->value);
54344 +
54345 +               array_insert_unique(con->request.headers, (data_unset *)hdr);
54346         }
54347 -       
54348 +
54349 +
54350         con->header_len = i;
54351 -       
54352 +
54353         /* do some post-processing */
54354  
54355         if (con->request.http_version == HTTP_VERSION_1_1) {
54356                 if (keep_alive_set != HTTP_CONNECTION_CLOSE) {
54357                         /* no Connection-Header sent */
54358 -                       
54359 +
54360                         /* HTTP/1.1 -> keep-alive default TRUE */
54361                         con->keep_alive = 1;
54362                 } else {
54363                         con->keep_alive = 0;
54364                 }
54365 -               
54366 +
54367                 /* RFC 2616, 14.23 */
54368 -               if (con->request.http_host == NULL ||
54369 -                   buffer_is_empty(con->request.http_host)) {
54370 +               if (buffer_is_empty(con->request.http_host)) {
54371                         con->http_status = 400;
54372                         con->response.keep_alive = 0;
54373                         con->keep_alive = 0;
54374 -                       
54375 +
54376                         if (srv->srvconf.log_request_header_on_error) {
54377                                 log_error_write(srv, __FILE__, __LINE__, "s", "HTTP/1.1 but Host missing -> 400");
54378                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
54379 @@ -1015,40 +509,21 @@
54380         } else {
54381                 if (keep_alive_set == HTTP_CONNECTION_KEEPALIVE) {
54382                         /* no Connection-Header sent */
54383 -                       
54384 +
54385                         /* HTTP/1.0 -> keep-alive default FALSE  */
54386                         con->keep_alive = 1;
54387                 } else {
54388                         con->keep_alive = 0;
54389                 }
54390         }
54391 -       
54392 -       /* check hostname field if it is set */
54393 -       if (NULL != con->request.http_host &&
54394 -           0 != request_check_hostname(srv, con, con->request.http_host)) {
54395 -               
54396 -               if (srv->srvconf.log_request_header_on_error) {
54397 -                       log_error_write(srv, __FILE__, __LINE__, "s",
54398 -                                       "Invalid Hostname -> 400");
54399 -                       log_error_write(srv, __FILE__, __LINE__, "Sb",
54400 -                                       "request-header:\n",
54401 -                                       con->request.request);
54402 -               }
54403 -
54404 -               con->http_status = 400;
54405 -               con->response.keep_alive = 0;
54406 -               con->keep_alive = 0;
54407 -               
54408 -               return 0;
54409 -       }
54410  
54411         switch(con->request.http_method) {
54412         case HTTP_METHOD_GET:
54413         case HTTP_METHOD_HEAD:
54414                 /* content-length is forbidden for those */
54415 -               if (con_length_set && con->request.content_length != 0) {
54416 +               if (con->request.content_length != -1) {
54417                         /* content-length is missing */
54418 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
54419 +                       log_error_write(srv, __FILE__, __LINE__, "s",
54420                                         "GET/HEAD with content-length -> 400");
54421  
54422                         con->keep_alive = 0;
54423 @@ -1058,9 +533,9 @@
54424                 break;
54425         case HTTP_METHOD_POST:
54426                 /* content-length is required for them */
54427 -               if (!con_length_set) {
54428 +               if (con->request.content_length == -1) {
54429                         /* content-length is missing */
54430 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
54431 +                       log_error_write(srv, __FILE__, __LINE__, "s",
54432                                         "POST-request, but content-length missing -> 411");
54433  
54434                         con->keep_alive = 0;
54435 @@ -1073,52 +548,27 @@
54436                 /* the may have a content-length */
54437                 break;
54438         }
54439 -                       
54440 -       
54441 -       /* check if we have read post data */
54442 -       if (con_length_set) {
54443 -               /* don't handle more the SSIZE_MAX bytes in content-length */
54444 -               if (con->request.content_length > SSIZE_MAX) {
54445 -                       con->http_status = 413; 
54446 -                       con->keep_alive = 0;
54447  
54448 -                       log_error_write(srv, __FILE__, __LINE__, "sds", 
54449 -                                       "request-size too long:", con->request.content_length, "-> 413");
54450 -                       return 0;
54451 -               }
54452  
54453 +       /* check if we have read post data */
54454 +       if (con->request.content_length != -1) {
54455                 /* divide by 1024 as srvconf.max_request_size is in kBytes */
54456                 if (srv->srvconf.max_request_size != 0 &&
54457                     (con->request.content_length >> 10) > srv->srvconf.max_request_size) {
54458 -                       /* the request body itself is larger then 
54459 +                       /* the request body itself is larger then
54460                          * our our max_request_size
54461                          */
54462 -               
54463 +
54464                         con->http_status = 413;
54465                         con->keep_alive = 0;
54466 -               
54467 -                       log_error_write(srv, __FILE__, __LINE__, "sds", 
54468 +
54469 +                       log_error_write(srv, __FILE__, __LINE__, "sds",
54470                                         "request-size too long:", con->request.content_length, "-> 413");
54471                         return 0;
54472                 }
54473 -               
54474 -               
54475 -               /* we have content */
54476 -               if (con->request.content_length != 0) {
54477 -                       return 1;
54478 -               }
54479         }
54480 -       
54481 +
54482         return 0;
54483  }
54484  
54485 -int http_request_header_finished(server *srv, connection *con) {
54486 -       UNUSED(srv);
54487  
54488 -       if (con->request.request->used < 5) return 0;
54489 -       
54490 -       if (0 == memcmp(con->request.request->ptr + con->request.request->used - 5, "\r\n\r\n", 4)) return 1;
54491 -       if (NULL != strstr(con->request.request->ptr, "\r\n\r\n")) return 1;
54492 -       
54493 -       return 0;
54494 -}
54495 --- ../lighttpd-1.4.11/src/request.h    2005-08-11 01:26:40.000000000 +0300
54496 +++ lighttpd-1.5.0/src/request.h        2006-09-07 00:57:05.000000000 +0300
54497 @@ -1,9 +1,9 @@
54498  #ifndef _REQUEST_H_
54499  #define _REQUEST_H_
54500  
54501 -#include "server.h"
54502 +#include "base.h"
54503 +#include "http_req.h"
54504  
54505 -int http_request_parse(server *srv, connection *con);
54506 -int http_request_header_finished(server *srv, connection *con);
54507 +int http_request_parse(server *srv, connection *con, http_req *req);
54508  
54509  #endif
54510 --- ../lighttpd-1.4.11/src/response.c   2006-03-04 16:41:39.000000000 +0200
54511 +++ lighttpd-1.5.0/src/response.c       2006-09-07 00:57:05.000000000 +0300
54512 @@ -7,7 +7,6 @@
54513  #include <stdlib.h>
54514  #include <string.h>
54515  #include <time.h>
54516 -#include <unistd.h>
54517  #include <ctype.h>
54518  #include <assert.h>
54519  
54520 @@ -24,15 +23,17 @@
54521  #include "plugin.h"
54522  
54523  #include "sys-socket.h"
54524 +#include "sys-files.h"
54525 +#include "sys-strings.h"
54526  
54527 -int http_response_write_header(server *srv, connection *con) {
54528 +int http_response_write_header(server *srv, connection *con, chunkqueue *raw) {
54529         buffer *b;
54530         size_t i;
54531         int have_date = 0;
54532         int have_server = 0;
54533 -       
54534 -       b = chunkqueue_get_prepend_buffer(con->write_queue);
54535 -       
54536 +
54537 +       b = chunkqueue_get_prepend_buffer(raw);
54538 +
54539         if (con->request.http_version == HTTP_VERSION_1_1) {
54540                 BUFFER_COPY_STRING_CONST(b, "HTTP/1.1 ");
54541         } else {
54542 @@ -41,25 +42,26 @@
54543         buffer_append_long(b, con->http_status);
54544         BUFFER_APPEND_STRING_CONST(b, " ");
54545         buffer_append_string(b, get_http_status_name(con->http_status));
54546 -       
54547 +
54548         if (con->request.http_version != HTTP_VERSION_1_1 || con->keep_alive == 0) {
54549                 BUFFER_APPEND_STRING_CONST(b, "\r\nConnection: ");
54550                 buffer_append_string(b, con->keep_alive ? "keep-alive" : "close");
54551         }
54552 -       
54553 +
54554         if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
54555                 BUFFER_APPEND_STRING_CONST(b, "\r\nTransfer-Encoding: chunked");
54556         }
54557 -       
54558 -       
54559 +
54560 +
54561         /* add all headers */
54562         for (i = 0; i < con->response.headers->used; i++) {
54563                 data_string *ds;
54564 -               
54565 +
54566                 ds = (data_string *)con->response.headers->data[i];
54567 -               
54568 +
54569                 if (ds->value->used && ds->key->used &&
54570 -                   0 != strncmp(ds->key->ptr, "X-LIGHTTPD-", sizeof("X-LIGHTTPD-") - 1)) {
54571 +                   0 != strncmp(ds->key->ptr, "X-LIGHTTPD-", sizeof("X-LIGHTTPD-") - 1) &&
54572 +                   0 != strcasecmp(ds->key->ptr, "X-Sendfile")) {
54573                         if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Date"))) have_date = 1;
54574                         if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Server"))) have_server = 1;
54575  
54576 @@ -68,28 +70,28 @@
54577                         BUFFER_APPEND_STRING_CONST(b, ": ");
54578                         buffer_append_string_buffer(b, ds->value);
54579  #if 0
54580 -                       log_error_write(srv, __FILE__, __LINE__, "bb", 
54581 +                       log_error_write(srv, __FILE__, __LINE__, "bb",
54582                                         ds->key, ds->value);
54583  #endif
54584                 }
54585         }
54586 -       
54587 +
54588         if (!have_date) {
54589                 /* HTTP/1.1 requires a Date: header */
54590                 BUFFER_APPEND_STRING_CONST(b, "\r\nDate: ");
54591 -       
54592 +
54593                 /* cache the generated timestamp */
54594                 if (srv->cur_ts != srv->last_generated_date_ts) {
54595                         buffer_prepare_copy(srv->ts_date_str, 255);
54596 -               
54597 -                       strftime(srv->ts_date_str->ptr, srv->ts_date_str->size - 1, 
54598 +
54599 +                       strftime(srv->ts_date_str->ptr, srv->ts_date_str->size - 1,
54600                                  "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(srv->cur_ts)));
54601 -                        
54602 +
54603                         srv->ts_date_str->used = strlen(srv->ts_date_str->ptr) + 1;
54604 -               
54605 +
54606                         srv->last_generated_date_ts = srv->cur_ts;
54607                 }
54608 -       
54609 +
54610                 buffer_append_string_buffer(b, srv->ts_date_str);
54611         }
54612  
54613 @@ -101,88 +103,85 @@
54614                         buffer_append_string_buffer(b, con->conf.server_tag);
54615                 }
54616         }
54617 -       
54618 +
54619         BUFFER_APPEND_STRING_CONST(b, "\r\n\r\n");
54620 -       
54621 -       
54622 +
54623 +
54624         con->bytes_header = b->used - 1;
54625 -       
54626 +
54627         if (con->conf.log_response_header) {
54628                 log_error_write(srv, __FILE__, __LINE__, "sSb", "Response-Header:", "\n", b);
54629         }
54630 -       
54631 +
54632         return 0;
54633  }
54634  
54635  
54636  
54637 -handler_t http_response_prepare(server *srv, connection *con) {
54638 +handler_t handle_get_backend(server *srv, connection *con) {
54639         handler_t r;
54640 -       
54641 -       /* looks like someone has already done a decision */
54642 -       if (con->mode == DIRECT && 
54643 +
54644 +       /* looks like someone has already made a decision */
54645 +       if (con->mode == DIRECT &&
54646             (con->http_status != 0 && con->http_status != 200)) {
54647                 /* remove a packets in the queue */
54648 -               if (con->file_finished == 0) {
54649 -                       chunkqueue_reset(con->write_queue);
54650 -               }
54651 -               
54652 +
54653                 return HANDLER_FINISHED;
54654         }
54655 -       
54656 +
54657         /* no decision yet, build conf->filename */
54658         if (con->mode == DIRECT && con->physical.path->used == 0) {
54659                 char *qstr;
54660  
54661 -               /* we only come here when we have the parse the full request again
54662 -                * 
54663 -                * a HANDLER_COMEBACK from mod_rewrite and mod_fastcgi might be a 
54664 +               /* we only come here when we have to parse the full request again
54665 +                *
54666 +                * a HANDLER_COMEBACK from mod_rewrite and mod_fastcgi might be a
54667                  * problem here as mod_setenv might get called multiple times
54668                  *
54669                  * fastcgi-auth might lead to a COMEBACK too
54670                  * fastcgi again dead server too
54671                  *
54672                  * mod_compress might add headers twice too
54673 -                * 
54674 +                *
54675                  *  */
54676 -               
54677 +
54678                 if (con->conf.log_condition_handling) {
54679                         log_error_write(srv, __FILE__, __LINE__,  "s",  "run condition");
54680                 }
54681                 config_patch_connection(srv, con, COMP_SERVER_SOCKET); /* SERVERsocket */
54682 -               
54683 +
54684                 /**
54685                  * prepare strings
54686 -                * 
54687 -                * - uri.path_raw 
54688 +                *
54689 +                * - uri.path_raw
54690                  * - uri.path (secure)
54691                  * - uri.query
54692 -                * 
54693 +                *
54694                  */
54695 -               
54696 -               /** 
54697 +
54698 +               /**
54699                  * Name according to RFC 2396
54700 -                * 
54701 +                *
54702                  * - scheme
54703                  * - authority
54704                  * - path
54705                  * - query
54706 -                * 
54707 +                *
54708                  * (scheme)://(authority)(path)?(query)
54709 -                * 
54710 -                * 
54711 +                *
54712 +                *
54713                  */
54714 -       
54715 +
54716                 buffer_copy_string(con->uri.scheme, con->conf.is_ssl ? "https" : "http");
54717                 buffer_copy_string_buffer(con->uri.authority, con->request.http_host);
54718                 buffer_to_lower(con->uri.authority);
54719 -               
54720 +
54721                 config_patch_connection(srv, con, COMP_HTTP_HOST);      /* Host:        */
54722                 config_patch_connection(srv, con, COMP_HTTP_REMOTEIP);  /* Client-IP */
54723                 config_patch_connection(srv, con, COMP_HTTP_REFERER);   /* Referer:     */
54724                 config_patch_connection(srv, con, COMP_HTTP_USERAGENT); /* User-Agent:  */
54725                 config_patch_connection(srv, con, COMP_HTTP_COOKIE);    /* Cookie:  */
54726 -               
54727 +
54728                 /** extract query string from request.uri */
54729                 if (NULL != (qstr = strchr(con->request.uri->ptr, '?'))) {
54730                         buffer_copy_string    (con->uri.query, qstr + 1);
54731 @@ -200,22 +199,22 @@
54732                         log_error_write(srv, __FILE__, __LINE__,  "sb", "URI-path     : ", con->uri.path_raw);
54733                         log_error_write(srv, __FILE__, __LINE__,  "sb", "URI-query    : ", con->uri.query);
54734                 }
54735 -               
54736 +
54737                 /* disable keep-alive if requested */
54738 -               
54739 +
54740                 if (con->request_count > con->conf.max_keep_alive_requests) {
54741                         con->keep_alive = 0;
54742                 }
54743 -               
54744 -               
54745 +
54746 +
54747                 /**
54748 -                *  
54749 -                * call plugins 
54750 -                * 
54751 +                *
54752 +                * call plugins
54753 +                *
54754                  * - based on the raw URL
54755 -                * 
54756 +                *
54757                  */
54758 -               
54759 +
54760                 switch(r = plugins_call_handle_uri_raw(srv, con)) {
54761                 case HANDLER_GO_ON:
54762                         break;
54763 @@ -229,14 +228,14 @@
54764                         break;
54765                 }
54766  
54767 -               /* build filename 
54768 +               /* build filename
54769                  *
54770                  * - decode url-encodings  (e.g. %20 -> ' ')
54771                  * - remove path-modifiers (e.g. /../)
54772                  */
54773 -               
54774 -               
54775 -               
54776 +
54777 +
54778 +
54779                 if (con->request.http_method == HTTP_METHOD_OPTIONS &&
54780                     con->uri.path_raw->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') {
54781                         /* OPTIONS * ... */
54782 @@ -253,15 +252,21 @@
54783                 }
54784  
54785                 /**
54786 -                *  
54787 -                * call plugins 
54788 -                * 
54789 +                *
54790 +                * call plugins
54791 +                *
54792                  * - based on the clean URL
54793 -                * 
54794 +                *
54795                  */
54796 -               
54797 +
54798                 config_patch_connection(srv, con, COMP_HTTP_URL); /* HTTPurl */
54799 -               
54800 +               config_patch_connection(srv, con, COMP_HTTP_QUERYSTRING); /* HTTPqs */
54801 +
54802 +               /* do we have to downgrade to 1.0 ? */
54803 +               if (!con->conf.allow_http11) {
54804 +                       con->request.http_version = HTTP_VERSION_1_0;
54805 +               }
54806 +
54807                 switch(r = plugins_call_handle_uri_clean(srv, con)) {
54808                 case HANDLER_GO_ON:
54809                         break;
54810 @@ -274,60 +279,62 @@
54811                         log_error_write(srv, __FILE__, __LINE__, "");
54812                         break;
54813                 }
54814 -               
54815 +
54816                 if (con->request.http_method == HTTP_METHOD_OPTIONS &&
54817                     con->uri.path->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') {
54818 -                       /* option requests are handled directly without checking of the path */
54819 -               
54820 +                       /* option requests are handled directly without checking the path */
54821 +
54822                         response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST"));
54823  
54824                         con->http_status = 200;
54825 -                       con->file_finished = 1;
54826 +                       /* no more content to send */
54827 +                       con->send->is_closed = 1;
54828  
54829                         return HANDLER_FINISHED;
54830                 }
54831  
54832                 /***
54833 -                * 
54834 -                * border 
54835 -                * 
54836 +                *
54837 +                * border
54838 +                *
54839                  * logical filename (URI) becomes a physical filename here
54840 -                * 
54841 -                * 
54842 -                * 
54843 +                *
54844 +                *
54845 +                *
54846                  */
54847 -               
54848 -               
54849 -               
54850 -               
54851 +
54852 +
54853 +
54854 +
54855                 /* 1. stat()
54856                  * ... ISREG() -> ok, go on
54857                  * ... ISDIR() -> index-file -> redirect
54858 -                * 
54859 -                * 2. pathinfo() 
54860 +                *
54861 +                * 2. pathinfo()
54862                  * ... ISREG()
54863 -                * 
54864 +                *
54865                  * 3. -> 404
54866 -                * 
54867 +                *
54868                  */
54869 -               
54870 +
54871                 /*
54872                  * SEARCH DOCUMENT ROOT
54873                  */
54874 -               
54875 +
54876                 /* set a default */
54877 -               
54878 +
54879                 buffer_copy_string_buffer(con->physical.doc_root, con->conf.document_root);
54880                 buffer_copy_string_buffer(con->physical.rel_path, con->uri.path);
54881 -               
54882 -#if defined(__WIN32) || defined(__CYGWIN__)
54883 -               /* strip dots from the end and spaces
54884 +
54885 +               filename_unix2local(con->physical.rel_path);
54886 +#if defined(_WIN32) || defined(__CYGWIN__)
54887 +               /* strip dots and spaces from the end
54888                  *
54889                  * windows/dos handle those filenames as the same file
54890                  *
54891                  * foo == foo. == foo..... == "foo...   " == "foo..  ./"
54892                  *
54893 -                * This will affect in some cases PATHINFO
54894 +                * This will affect PATHINFO in some cases
54895                  *
54896                  * on native windows we could prepend the filename with \\?\ to circumvent
54897                  * this behaviour. I have no idea how to push this through cygwin
54898 @@ -377,36 +384,41 @@
54899                         log_error_write(srv, __FILE__, __LINE__, "");
54900                         break;
54901                 }
54902 -               
54903 -               /* MacOS X and Windows can't distiguish between upper and lower-case 
54904 -                * 
54905 -                * convert to lower-case
54906 +
54907 +               /* The default Mac OS X and Windows filesystems can't distiguish between
54908 +                * upper- and lowercase, so convert to lowercase
54909                  */
54910                 if (con->conf.force_lowercase_filenames) {
54911                         buffer_to_lower(con->physical.rel_path);
54912                 }
54913  
54914 -               /* the docroot plugins might set the servername, if they don't we take http-host */
54915 +               /* the docroot plugins might set the servername; if they don't we take http-host */
54916                 if (buffer_is_empty(con->server_name)) {
54917                         buffer_copy_string_buffer(con->server_name, con->uri.authority);
54918                 }
54919 -               
54920 -               /** 
54921 -                * create physical filename 
54922 +
54923 +               /**
54924 +                * create physical filename
54925                  * -> physical.path = docroot + rel_path
54926 -                * 
54927 +                *
54928                  */
54929 -               
54930 +
54931                 buffer_copy_string_buffer(con->physical.path, con->physical.doc_root);
54932 -               BUFFER_APPEND_SLASH(con->physical.path);
54933 +               PATHNAME_APPEND_SLASH(con->physical.path);
54934                 buffer_copy_string_buffer(con->physical.basedir, con->physical.path);
54935                 if (con->physical.rel_path->used &&
54936 -                   con->physical.rel_path->ptr[0] == '/') {
54937 +                   con->physical.rel_path->ptr[0] == DIR_SEPERATOR) {
54938                         buffer_append_string_len(con->physical.path, con->physical.rel_path->ptr + 1, con->physical.rel_path->used - 2);
54939                 } else {
54940                         buffer_append_string_buffer(con->physical.path, con->physical.rel_path);
54941                 }
54942  
54943 +               /* win32: directories can't have a trailing slash */
54944 +               if (con->physical.path->ptr[con->physical.path->used - 2] == DIR_SEPERATOR) {
54945 +                       con->physical.path->ptr[con->physical.path->used - 2] = '\0';
54946 +                       con->physical.path->used--;
54947 +               }
54948 +
54949                 if (con->conf.log_request_handling) {
54950                         log_error_write(srv, __FILE__, __LINE__,  "s",  "-- after doc_root");
54951                         log_error_write(srv, __FILE__, __LINE__,  "sb", "Doc-Root     :", con->physical.doc_root);
54952 @@ -426,7 +438,7 @@
54953                         log_error_write(srv, __FILE__, __LINE__, "");
54954                         break;
54955                 }
54956 -               
54957 +
54958                 if (con->conf.log_request_handling) {
54959                         log_error_write(srv, __FILE__, __LINE__,  "s",  "-- logical -> physical");
54960                         log_error_write(srv, __FILE__, __LINE__,  "sb", "Doc-Root     :", con->physical.doc_root);
54961 @@ -434,41 +446,60 @@
54962                         log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
54963                 }
54964         }
54965 -       
54966 -       /* 
54967 -        * Noone catched away the file from normal path of execution yet (like mod_access)
54968 +
54969 +       /*
54970 +        * No one took the file away from the normal path of execution yet (like mod_access)
54971 +        *
54972 +        * we don't have a backend yet, try to resolve the physical path and go on
54973          * 
54974 -        * Go on and check of the file exists at all
54975          */
54976 -       
54977 +
54978         if (con->mode == DIRECT) {
54979                 char *slash = NULL;
54980                 char *pathinfo = NULL;
54981                 int found = 0;
54982                 stat_cache_entry *sce = NULL;
54983 -               
54984 +
54985                 if (con->conf.log_request_handling) {
54986                         log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling physical path");
54987                         log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
54988                 }
54989 -               
54990 +
54991                 if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
54992                         /* file exists */
54993 -                       
54994 +
54995                         if (con->conf.log_request_handling) {
54996                                 log_error_write(srv, __FILE__, __LINE__,  "s",  "-- file found");
54997                                 log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
54998                         }
54999 -                       
55000 +
55001 +#ifdef HAVE_LSTAT
55002 +                       if ((sce->is_symlink != 0) && !con->conf.follow_symlink) {
55003 +                               con->http_status = 403;
55004 +
55005 +                               if (con->conf.log_request_handling) {
55006 +                                       log_error_write(srv, __FILE__, __LINE__,  "s",  "-- access denied due symlink restriction");
55007 +                                       log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
55008 +                               }
55009 +
55010 +                               buffer_reset(con->physical.path);
55011 +                               return HANDLER_FINISHED;
55012 +                       };
55013 +#endif
55014 +
55015                         if (S_ISDIR(sce->st.st_mode)) {
55016 -                               if (con->physical.path->ptr[con->physical.path->used - 2] != '/') {
55017 +                               if (con->uri.path->ptr[con->uri.path->used - 2] != '/') {
55018                                         /* redirect to .../ */
55019 -                                       
55020 +
55021                                         http_response_redirect_to_directory(srv, con);
55022 -                                       
55023 +
55024                                         return HANDLER_FINISHED;
55025                                 }
55026 +#ifdef HAVE_LSTAT
55027 +                       } else if (!S_ISREG(sce->st.st_mode) && !sce->is_symlink) {
55028 +#else
55029                         } else if (!S_ISREG(sce->st.st_mode)) {
55030 +#endif
55031                                 /* any special handling of non-reg files ?*/
55032  
55033  
55034 @@ -477,12 +508,12 @@
55035                         switch (errno) {
55036                         case EACCES:
55037                                 con->http_status = 403;
55038 -       
55039 +
55040                                 if (con->conf.log_request_handling) {
55041                                         log_error_write(srv, __FILE__, __LINE__,  "s",  "-- access denied");
55042                                         log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
55043                                 }
55044 -                       
55045 +
55046                                 buffer_reset(con->physical.path);
55047                                 return HANDLER_FINISHED;
55048                         case ENOENT:
55049 @@ -499,77 +530,77 @@
55050                                 /* PATH_INFO ! :) */
55051                                 break;
55052                         default:
55053 -                               /* we have no idea what happend. let's tell the user so. */
55054 +                               /* we have no idea what happened, so tell the user. */
55055                                 con->http_status = 500;
55056                                 buffer_reset(con->physical.path);
55057 -                               
55058 +
55059                                 log_error_write(srv, __FILE__, __LINE__, "ssbsb",
55060                                                 "file not found ... or so: ", strerror(errno),
55061                                                 con->uri.path,
55062                                                 "->", con->physical.path);
55063 -                               
55064 +
55065                                 return HANDLER_FINISHED;
55066                         }
55067 -                       
55068 +
55069                         /* not found, perhaps PATHINFO */
55070 -                       
55071 +
55072                         buffer_copy_string_buffer(srv->tmp_buf, con->physical.path);
55073 -                       
55074 +
55075                         do {
55076                                 struct stat st;
55077 -                               
55078 +
55079                                 if (slash) {
55080                                         buffer_copy_string_len(con->physical.path, srv->tmp_buf->ptr, slash - srv->tmp_buf->ptr);
55081                                 } else {
55082                                         buffer_copy_string_buffer(con->physical.path, srv->tmp_buf);
55083                                 }
55084 -                               
55085 +
55086                                 if (0 == stat(con->physical.path->ptr, &(st)) &&
55087                                     S_ISREG(st.st_mode)) {
55088                                         found = 1;
55089                                         break;
55090                                 }
55091 -                               
55092 +
55093                                 if (pathinfo != NULL) {
55094                                         *pathinfo = '\0';
55095                                 }
55096                                 slash = strrchr(srv->tmp_buf->ptr, '/');
55097 -                               
55098 +
55099                                 if (pathinfo != NULL) {
55100                                         /* restore '/' */
55101                                         *pathinfo = '/';
55102                                 }
55103 -                               
55104 +
55105                                 if (slash) pathinfo = slash;
55106                         } while ((found == 0) && (slash != NULL) && (slash - srv->tmp_buf->ptr > con->physical.basedir->used - 2));
55107 -                       
55108 +
55109                         if (found == 0) {
55110 -                               /* no it really doesn't exists */
55111 +                               /* no, it really doesn't exists */
55112                                 con->http_status = 404;
55113 -                               
55114 +
55115                                 if (con->conf.log_file_not_found) {
55116                                         log_error_write(srv, __FILE__, __LINE__, "sbsb",
55117                                                         "file not found:", con->uri.path,
55118                                                         "->", con->physical.path);
55119                                 }
55120 -                               
55121 +
55122                                 buffer_reset(con->physical.path);
55123 -                               
55124 +
55125                                 return HANDLER_FINISHED;
55126                         }
55127 -                       
55128 +
55129                         /* we have a PATHINFO */
55130                         if (pathinfo) {
55131                                 buffer_copy_string(con->request.pathinfo, pathinfo);
55132 -                               
55133 +
55134                                 /*
55135                                  * shorten uri.path
55136                                  */
55137 -                               
55138 +
55139                                 con->uri.path->used -= strlen(pathinfo);
55140                                 con->uri.path->ptr[con->uri.path->used - 1] = '\0';
55141                         }
55142 -                       
55143 +
55144                         if (con->conf.log_request_handling) {
55145                                 log_error_write(srv, __FILE__, __LINE__,  "s",  "-- after pathinfo check");
55146                                 log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
55147 @@ -577,50 +608,37 @@
55148                                 log_error_write(srv, __FILE__, __LINE__,  "sb", "Pathinfo     :", con->request.pathinfo);
55149                         }
55150                 }
55151 -               
55152 +
55153                 if (con->conf.log_request_handling) {
55154                         log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling subrequest");
55155                         log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
55156                 }
55157 -               
55158 +
55159                 /* call the handlers */
55160 -               switch(r = plugins_call_handle_subrequest_start(srv, con)) {
55161 +               switch(r = plugins_call_handle_start_backend(srv, con)) {
55162                 case HANDLER_GO_ON:
55163 -                       /* request was not handled */
55164 -                       break;
55165                 case HANDLER_FINISHED:
55166 +                       /* if we are still here, no one wanted the file; status 403 is ok I think */
55167 +
55168                 default:
55169                         if (con->conf.log_request_handling) {
55170                                 log_error_write(srv, __FILE__, __LINE__,  "s",  "-- subrequest finished");
55171                         }
55172 -                       
55173 -                       /* something strange happend */
55174 +
55175 +                       /* something strange happened */
55176                         return r;
55177                 }
55178 -               
55179 -               /* if we are still here, no one wanted the file, status 403 is ok I think */
55180 -               
55181 -               if (con->mode == DIRECT) {
55182 -                       con->http_status = 403;
55183 -                       
55184 -                       return HANDLER_FINISHED;
55185 -               }
55186 -               
55187         }
55188 -       
55189 -       switch(r = plugins_call_handle_subrequest(srv, con)) {
55190 -       case HANDLER_GO_ON:
55191 -               /* request was not handled, looks like we are done */
55192 +
55193 +       if (con->mode == DIRECT) {
55194 +               con->http_status = 403;
55195 +
55196 +               TRACE("%s", "aaaaaaah, sending 403");
55197 +
55198                 return HANDLER_FINISHED;
55199 -       case HANDLER_FINISHED:
55200 -               /* request is finished */
55201 -       default:
55202 -               /* something strange happend */
55203 -               return r;
55204 -       }
55205 -       
55206 -       /* can't happen */
55207 -       return HANDLER_COMEBACK;
55208 +       } else {
55209 +               return HANDLER_GO_ON;
55210 +       }
55211  }
55212  
55213  
55214 --- ../lighttpd-1.4.11/src/response.h   2005-08-31 16:25:50.000000000 +0300
55215 +++ lighttpd-1.5.0/src/response.h       2006-09-07 00:57:05.000000000 +0300
55216 @@ -6,12 +6,12 @@
55217  #include "server.h"
55218  
55219  int http_response_parse(server *srv, connection *con);
55220 -int http_response_write_header(server *srv, connection *con);
55221 +int http_response_write_header(server *srv, connection *con, chunkqueue *cq);
55222  
55223  int response_header_insert(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen);
55224  int response_header_overwrite(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen);
55225  
55226 -handler_t http_response_prepare(server *srv, connection *con);
55227 +handler_t handle_get_backend(server *srv, connection *con);
55228  int http_response_redirect_to_directory(server *srv, connection *con);
55229  int http_response_handle_cachable(server *srv, connection *con, buffer * mtime);
55230  
55231 --- ../lighttpd-1.4.11/src/server.c     2006-03-04 19:12:17.000000000 +0200
55232 +++ lighttpd-1.5.0/src/server.c 2006-09-07 00:57:05.000000000 +0300
55233 @@ -1,11 +1,9 @@
55234  #include <sys/types.h>
55235 -#include <sys/time.h>
55236  #include <sys/stat.h>
55237  
55238  #include <string.h>
55239  #include <errno.h>
55240  #include <fcntl.h>
55241 -#include <unistd.h>
55242  #include <stdlib.h>
55243  #include <time.h>
55244  #include <signal.h>
55245 @@ -22,16 +20,21 @@
55246  #include "response.h"
55247  #include "request.h"
55248  #include "chunk.h"
55249 -#include "http_chunk.h"
55250  #include "fdevent.h"
55251  #include "connections.h"
55252  #include "stat_cache.h"
55253  #include "plugin.h"
55254  #include "joblist.h"
55255  #include "network_backends.h"
55256 -
55257 +#include "status_counter.h"
55258 +#ifdef _WIN32
55259 +/* use local getopt implementation */
55260 +# undef HAVE_GETOPT_H
55261 +#endif
55262  #ifdef HAVE_GETOPT_H
55263  #include <getopt.h>
55264 +#else
55265 +#include "getopt.h"
55266  #endif
55267  
55268  #ifdef HAVE_VALGRIND_VALGRIND_H
55269 @@ -60,8 +63,17 @@
55270  /* #define USE_ALARM */
55271  #endif
55272  
55273 +#ifdef _WIN32
55274 +#undef HAVE_SIGNAL
55275 +#endif
55276 +
55277 +#include "sys-files.h"
55278 +#include "sys-process.h"
55279 +#include "sys-socket.h"
55280 +
55281  static volatile sig_atomic_t srv_shutdown = 0;
55282  static volatile sig_atomic_t graceful_shutdown = 0;
55283 +static volatile sig_atomic_t graceful_restart = 0;
55284  static volatile sig_atomic_t handle_sig_alarm = 1;
55285  static volatile sig_atomic_t handle_sig_hup = 0;
55286  
55287 @@ -72,9 +84,9 @@
55288  
55289         switch (sig) {
55290         case SIGTERM: srv_shutdown = 1; break;
55291 -       case SIGINT: 
55292 +       case SIGINT:
55293              if (graceful_shutdown) srv_shutdown = 1;
55294 -            else graceful_shutdown = 1; 
55295 +            else graceful_shutdown = 1;
55296  
55297              break;
55298         case SIGALRM: handle_sig_alarm = 1; break;
55299 @@ -86,9 +98,9 @@
55300  static void signal_handler(int sig) {
55301         switch (sig) {
55302         case SIGTERM: srv_shutdown = 1; break;
55303 -       case SIGINT: 
55304 +       case SIGINT:
55305              if (graceful_shutdown) srv_shutdown = 1;
55306 -            else graceful_shutdown = 1; 
55307 +            else graceful_shutdown = 1;
55308  
55309              break;
55310         case SIGALRM: handle_sig_alarm = 1; break;
55311 @@ -110,35 +122,35 @@
55312         signal(SIGTSTP, SIG_IGN);
55313  #endif
55314         if (0 != fork()) exit(0);
55315 -       
55316 +
55317         if (-1 == setsid()) exit(0);
55318  
55319         signal(SIGHUP, SIG_IGN);
55320  
55321         if (0 != fork()) exit(0);
55322 -       
55323 +
55324         if (0 != chdir("/")) exit(0);
55325  }
55326  #endif
55327  
55328  static server *server_init(void) {
55329         int i;
55330 -       
55331 +
55332         server *srv = calloc(1, sizeof(*srv));
55333         assert(srv);
55334 +    srv->max_fds = 1024;
55335  #define CLEAN(x) \
55336         srv->x = buffer_init();
55337 -       
55338 +
55339         CLEAN(response_header);
55340         CLEAN(parse_full_path);
55341         CLEAN(ts_debug_str);
55342         CLEAN(ts_date_str);
55343 -       CLEAN(errorlog_buf);
55344         CLEAN(response_range);
55345         CLEAN(tmp_buf);
55346         srv->empty_string = buffer_init_string("");
55347         CLEAN(cond_check_buf);
55348 -       
55349 +
55350         CLEAN(srvconf.errorlog_file);
55351         CLEAN(srvconf.groupname);
55352         CLEAN(srvconf.username);
55353 @@ -146,68 +158,62 @@
55354         CLEAN(srvconf.bindhost);
55355         CLEAN(srvconf.event_handler);
55356         CLEAN(srvconf.pid_file);
55357 -       
55358 +
55359         CLEAN(tmp_chunk_len);
55360  #undef CLEAN
55361 -       
55362 +
55363  #define CLEAN(x) \
55364         srv->x = array_init();
55365 -       
55366 +
55367         CLEAN(config_context);
55368         CLEAN(config_touched);
55369 -       CLEAN(status);
55370  #undef CLEAN
55371 -       
55372 +
55373         for (i = 0; i < FILE_CACHE_MAX; i++) {
55374                 srv->mtime_cache[i].str = buffer_init();
55375         }
55376 -       
55377 +
55378         srv->cur_ts = time(NULL);
55379         srv->startup_ts = srv->cur_ts;
55380 -       
55381 +
55382         srv->conns = calloc(1, sizeof(*srv->conns));
55383         assert(srv->conns);
55384 -       
55385 +
55386         srv->joblist = calloc(1, sizeof(*srv->joblist));
55387         assert(srv->joblist);
55388 -       
55389 +
55390         srv->fdwaitqueue = calloc(1, sizeof(*srv->fdwaitqueue));
55391         assert(srv->fdwaitqueue);
55392 -       
55393 +
55394         srv->srvconf.modules = array_init();
55395         srv->srvconf.modules_dir = buffer_init_string(LIBRARY_DIR);
55396         srv->srvconf.network_backend = buffer_init();
55397         srv->srvconf.upload_tempdirs = array_init();
55398 -       
55399 -       /* use syslog */
55400 -       srv->errorlog_fd = -1;
55401 -       srv->errorlog_mode = ERRORLOG_STDERR;
55402  
55403         srv->split_vals = array_init();
55404 -       
55405 +
55406         return srv;
55407  }
55408  
55409  static void server_free(server *srv) {
55410         size_t i;
55411 -       
55412 +
55413         for (i = 0; i < FILE_CACHE_MAX; i++) {
55414                 buffer_free(srv->mtime_cache[i].str);
55415         }
55416 -       
55417 +
55418  #define CLEAN(x) \
55419         buffer_free(srv->x);
55420 -       
55421 +
55422         CLEAN(response_header);
55423         CLEAN(parse_full_path);
55424         CLEAN(ts_debug_str);
55425         CLEAN(ts_date_str);
55426 -       CLEAN(errorlog_buf);
55427         CLEAN(response_range);
55428         CLEAN(tmp_buf);
55429         CLEAN(empty_string);
55430         CLEAN(cond_check_buf);
55431 -       
55432 +
55433         CLEAN(srvconf.errorlog_file);
55434         CLEAN(srvconf.groupname);
55435         CLEAN(srvconf.username);
55436 @@ -217,7 +223,7 @@
55437         CLEAN(srvconf.pid_file);
55438         CLEAN(srvconf.modules_dir);
55439         CLEAN(srvconf.network_backend);
55440 -       
55441 +
55442         CLEAN(tmp_chunk_len);
55443  #undef CLEAN
55444  
55445 @@ -225,15 +231,15 @@
55446         fdevent_unregister(srv->ev, srv->fd);
55447  #endif
55448         fdevent_free(srv->ev);
55449 -       
55450 +
55451         free(srv->conns);
55452 -       
55453 +
55454         if (srv->config_storage) {
55455                 for (i = 0; i < srv->config_context->used; i++) {
55456                         specific_config *s = srv->config_storage[i];
55457  
55458                         if (!s) continue;
55459 -                       
55460 +
55461                         buffer_free(s->document_root);
55462                         buffer_free(s->server_name);
55463                         buffer_free(s->server_tag);
55464 @@ -242,32 +248,31 @@
55465                         buffer_free(s->error_handler);
55466                         buffer_free(s->errorfile_prefix);
55467                         array_free(s->mimetypes);
55468 -                       
55469 +
55470                         free(s);
55471                 }
55472                 free(srv->config_storage);
55473                 srv->config_storage = NULL;
55474         }
55475 -       
55476 +
55477  #define CLEAN(x) \
55478         array_free(srv->x);
55479 -       
55480 +
55481         CLEAN(config_context);
55482         CLEAN(config_touched);
55483 -       CLEAN(status);
55484         CLEAN(srvconf.upload_tempdirs);
55485  #undef CLEAN
55486 -       
55487 +
55488         joblist_free(srv, srv->joblist);
55489         fdwaitqueue_free(srv, srv->fdwaitqueue);
55490 -       
55491 +
55492         if (srv->stat_cache) {
55493                 stat_cache_free(srv->stat_cache);
55494         }
55495  
55496         array_free(srv->srvconf.modules);
55497         array_free(srv->split_vals);
55498 -       
55499 +
55500         free(srv);
55501  }
55502  
55503 @@ -281,14 +286,12 @@
55504  " - a light and fast webserver\n" \
55505  "Build-Date: " __DATE__ " " __TIME__ "\n";
55506  ;
55507 -#undef TEXT_SSL        
55508 +#undef TEXT_SSL
55509         write(STDOUT_FILENO, b, strlen(b));
55510  }
55511  
55512  static void show_features (void) {
55513 -  show_version();
55514 -  printf("\nEvent Handlers:\n\n%s",
55515 -
55516 +  const char *s = ""
55517  #ifdef USE_SELECT
55518        "\t+ select (generic)\n"
55519  #else
55520 @@ -355,11 +358,6 @@
55521  #else
55522        "\t- crypt support\n"
55523  #endif
55524 -#ifdef USE_PAM
55525 -      "\t+ PAM support\n"
55526 -#else
55527 -      "\t- PAM support\n"
55528 -#endif
55529  #ifdef USE_OPENSSL
55530        "\t+ SSL Support\n"
55531  #else
55532 @@ -371,9 +369,9 @@
55533        "\t- PCRE support\n"
55534  #endif
55535  #ifdef HAVE_MYSQL
55536 -      "\t+ mySQL support\n"
55537 +      "\t+ MySQL support\n"
55538  #else
55539 -      "\t- mySQL support\n"
55540 +      "\t- MySQL support\n"
55541  #endif
55542  #if defined(HAVE_LDAP_H) && defined(HAVE_LBER_H) && defined(HAVE_LIBLDAP) && defined(HAVE_LIBLBER)
55543        "\t+ LDAP support\n"
55544 @@ -410,8 +408,11 @@
55545  #else
55546        "\t- GDBM support\n"
55547  #endif
55548 -      "\n"
55549 -      );
55550 +      "\n";
55551 +
55552 +  show_version();
55553 +
55554 +  printf("\nEvent Handlers:\n\n%s", s);
55555  }
55556  
55557  static void show_help (void) {
55558 @@ -433,197 +434,570 @@
55559  " -h         show this help\n" \
55560  "\n"
55561  ;
55562 -#undef TEXT_SSL        
55563 +#undef TEXT_SSL
55564  #undef TEXT_IPV6
55565         write(STDOUT_FILENO, b, strlen(b));
55566  }
55567  
55568 -int main (int argc, char **argv) {
55569 -       server *srv = NULL;
55570 -       int print_config = 0;
55571 -       int test_config = 0;
55572 -       int i_am_root;
55573 -       int o;
55574 -       int num_childs = 0;
55575 -       int pid_fd = -1, fd;
55576 -       size_t i;
55577 -#ifdef HAVE_SIGACTION
55578 -       struct sigaction act;
55579 -#endif
55580 -#ifdef HAVE_GETRLIMIT
55581 -       struct rlimit rlim;
55582 -#endif
55583 -       
55584 -#ifdef USE_ALARM
55585 -       struct itimerval interval;
55586 -       
55587 -       interval.it_interval.tv_sec = 1;
55588 -       interval.it_interval.tv_usec = 0;
55589 -       interval.it_value.tv_sec = 1;
55590 -       interval.it_value.tv_usec = 0;
55591 -#endif
55592 -       
55593 -       
55594 -       /* for nice %b handling in strfime() */
55595 -       setlocale(LC_TIME, "C");
55596 -       
55597 -       if (NULL == (srv = server_init())) {
55598 -               fprintf(stderr, "did this really happen?\n");
55599 -               return -1;
55600 -       }
55601 -       
55602 -       /* init structs done */
55603 -       
55604 -       srv->srvconf.port = 0;
55605 -#ifdef HAVE_GETUID
55606 -       i_am_root = (getuid() == 0);
55607 -#else
55608 -       i_am_root = 0;
55609 -#endif
55610 -       srv->srvconf.dont_daemonize = 0;
55611 -       
55612 -       while(-1 != (o = getopt(argc, argv, "f:m:hvVDpt"))) {
55613 -               switch(o) {
55614 -               case 'f': 
55615 -                       if (config_read(srv, optarg)) { 
55616 -                               server_free(srv);
55617 -                               return -1;
55618 -                       }
55619 -                       break;
55620 -               case 'm':
55621 -                       buffer_copy_string(srv->srvconf.modules_dir, optarg);
55622 -                       break;
55623 -               case 'p': print_config = 1; break;
55624 -               case 't': test_config = 1; break;
55625 -               case 'D': srv->srvconf.dont_daemonize = 1; break;
55626 -               case 'v': show_version(); return 0;
55627 -               case 'V': show_features(); return 0;          
55628 -               case 'h': show_help(); return 0;
55629 -               default: 
55630 -                       show_help();
55631 -                       server_free(srv);
55632 -                       return -1;
55633 -               }
55634 -       }
55635 -       
55636 -       if (!srv->config_storage) {
55637 -               log_error_write(srv, __FILE__, __LINE__, "s",
55638 -                               "No configuration available. Try using -f option.");
55639 -               
55640 -               server_free(srv);
55641 -               return -1;
55642 -       }
55643 -       
55644 -       if (print_config) {
55645 -               data_unset *dc = srv->config_context->data[0];
55646 -               if (dc) {
55647 -                       dc->print(dc, 0);
55648 -                       fprintf(stderr, "\n");
55649 -               } else {
55650 -                       /* shouldn't happend */
55651 -                       fprintf(stderr, "global config not found\n");
55652 -               }
55653 -       }
55654 +int lighty_mainloop(server *srv) {
55655 +       fdevent_revents *revents = fdevent_revents_init();
55656  
55657 -       if (test_config) {
55658 -               printf("Syntax OK\n");
55659 -       }
55660 +       /* main-loop */
55661 +       while (!srv_shutdown) {
55662 +               int n;
55663 +               size_t ndx;
55664 +               time_t min_ts;
55665  
55666 -       if (test_config || print_config) {
55667 -               server_free(srv);
55668 -               return 0;
55669 -       }
55670 -       
55671 -       /* close stdin and stdout, as they are not needed */
55672 -       /* move stdin to /dev/null */
55673 -       if (-1 != (fd = open("/dev/null", O_RDONLY))) {
55674 -               close(STDIN_FILENO);
55675 -               dup2(fd, STDIN_FILENO);
55676 -               close(fd);
55677 -       }
55678 -       
55679 -       /* move stdout to /dev/null */
55680 -       if (-1 != (fd = open("/dev/null", O_WRONLY))) {
55681 -               close(STDOUT_FILENO);
55682 -               dup2(fd, STDOUT_FILENO);
55683 -               close(fd);
55684 -       }
55685 -       
55686 -       if (0 != config_set_defaults(srv)) {
55687 -               log_error_write(srv, __FILE__, __LINE__, "s", 
55688 -                               "setting default values failed");
55689 -               server_free(srv);
55690 -               return -1;
55691 -       }
55692 -       
55693 -       /* UID handling */
55694 -#ifdef HAVE_GETUID
55695 -       if (!i_am_root && (geteuid() == 0 || getegid() == 0)) {
55696 -               /* we are setuid-root */
55697 -               
55698 -               log_error_write(srv, __FILE__, __LINE__, "s", 
55699 -                               "Are you nuts ? Don't apply a SUID bit to this binary");
55700 -               
55701 -               server_free(srv);
55702 -               return -1;
55703 -       }
55704 -#endif
55705 -       
55706 -       /* check document-root */
55707 -       if (srv->config_storage[0]->document_root->used <= 1) {
55708 -               log_error_write(srv, __FILE__, __LINE__, "s", 
55709 -                               "document-root is not set\n");
55710 -               
55711 -               server_free(srv);
55712 -               
55713 -               return -1;
55714 -       }
55715 -       
55716 -       if (plugins_load(srv)) {
55717 -               log_error_write(srv, __FILE__, __LINE__, "s",
55718 -                               "loading plugins finally failed");
55719 -               
55720 -               plugins_free(srv);
55721 -               server_free(srv);
55722 -               
55723 -               return -1;
55724 -       }
55725 -       
55726 -       /* open pid file BEFORE chroot */
55727 -       if (srv->srvconf.pid_file->used) {
55728 -               if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
55729 -                       struct stat st;
55730 -                       if (errno != EEXIST) {
55731 -                               log_error_write(srv, __FILE__, __LINE__, "sbs",
55732 -                                       "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
55733 -                               return -1;
55734 -                       }
55735 -                       
55736 -                       if (0 != stat(srv->srvconf.pid_file->ptr, &st)) {
55737 -                               log_error_write(srv, __FILE__, __LINE__, "sbs",
55738 -                                               "stating existing pid-file failed:", srv->srvconf.pid_file, strerror(errno));
55739 +               if (handle_sig_hup) {
55740 +                       handler_t r;
55741 +
55742 +                       /* reset notification */
55743 +                       handle_sig_hup = 0;
55744 +
55745 +#if 0
55746 +                               pid_t pid;
55747 +
55748 +                       /* send the old process into a graceful-shutdown and start a
55749 +                        * new process right away
55750 +                        *
55751 +                        * BUGS:
55752 +                        * - if webserver is running on port < 1024 (e.g. 80, 433)
55753 +                        *   we don't have the permissions to bind to that port anymore
55754 +                        *
55755 +                        *
55756 +                        *  */
55757 +                       if (0 == (pid = fork())) {
55758 +                               execve(argv[0], argv, envp);
55759 +
55760 +                               exit(-1);
55761 +                       } else if (pid == -1) {
55762 +
55763 +                       } else {
55764 +                               /* parent */
55765 +
55766 +                               graceful_shutdown = 1; /* shutdown without killing running connections */
55767 +                               graceful_restart = 1;  /* don't delete pid file */
55768                         }
55769 -                       
55770 -                       if (!S_ISREG(st.st_mode)) {
55771 -                               log_error_write(srv, __FILE__, __LINE__, "sb",
55772 -                                               "pid-file exists and isn't regular file:", srv->srvconf.pid_file);
55773 -                               return -1;
55774 +#else
55775 +                       /* cycle logfiles */
55776 +
55777 +                       switch(r = plugins_call_handle_sighup(srv)) {
55778 +                       case HANDLER_GO_ON:
55779 +                               break;
55780 +                       default:
55781 +                               log_error_write(srv, __FILE__, __LINE__, "sd", "sighup-handler return with an error", r);
55782 +                               break;
55783                         }
55784 -                       
55785 -                       if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
55786 -                               log_error_write(srv, __FILE__, __LINE__, "sbs",
55787 -                                               "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
55788 +
55789 +                       if (-1 == log_error_cycle()) {
55790 +                               log_error_write(srv, __FILE__, __LINE__, "s", "cycling errorlog failed, dying");
55791 +
55792                                 return -1;
55793                         }
55794 +#endif
55795                 }
55796 +
55797 +               if (handle_sig_alarm) {
55798 +                       /* a new second */
55799 +
55800 +#ifdef USE_ALARM
55801 +                       /* reset notification */
55802 +                       handle_sig_alarm = 0;
55803 +#endif
55804 +
55805 +                       /* get current time */
55806 +                       min_ts = time(NULL);
55807 +
55808 +                       if (min_ts != srv->cur_ts) {
55809 +                               int cs = 0;
55810 +                               connections *conns = srv->conns;
55811 +                               handler_t r;
55812 +
55813 +                               switch(r = plugins_call_handle_trigger(srv)) {
55814 +                               case HANDLER_GO_ON:
55815 +                                       break;
55816 +                               case HANDLER_ERROR:
55817 +                                       log_error_write(srv, __FILE__, __LINE__, "s", "one of the triggers failed");
55818 +                                       break;
55819 +                               default:
55820 +                                       log_error_write(srv, __FILE__, __LINE__, "d", r);
55821 +                                       break;
55822 +                               }
55823 +
55824 +                               /* trigger waitpid */
55825 +                               srv->cur_ts = min_ts;
55826 +
55827 +                               /* cleanup stat-cache */
55828 +                               stat_cache_trigger_cleanup(srv);
55829 +                               /**
55830 +                                * check all connections for timeouts
55831 +                                *
55832 +                                */
55833 +                               for (ndx = 0; ndx < conns->used; ndx++) {
55834 +                                       int changed = 0;
55835 +                                       connection *con;
55836 +                                       int t_diff;
55837 +
55838 +                                       con = conns->ptr[ndx];
55839 +
55840 +                                       switch (con->state) {
55841 +                                       case CON_STATE_READ_REQUEST_HEADER:
55842 +                                       case CON_STATE_READ_REQUEST_CONTENT: 
55843 +                                               if (con->recv->is_closed) break; /* everything is read, no need to fear a timeout */
55844 +                                               
55845 +                                               if (con->request_count == 1) {
55846 +                                                       if (srv->cur_ts - con->read_idle_ts > con->conf.max_read_idle) {
55847 +                                                               /* time - out */
55848 +#if 0
55849 +                                                               log_error_write(srv, __FILE__, __LINE__, "sd",
55850 +                                                                               "connection closed - read-timeout:", con->fd);
55851 +#endif
55852 +                                                               TRACE("%s", "(timeout)");
55853 +                                                               connection_set_state(srv, con, CON_STATE_ERROR);
55854 +                                                               changed = 1;
55855 +                                                       }
55856 +                                               } else {
55857 +                                                       if (srv->cur_ts - con->read_idle_ts > con->conf.max_keep_alive_idle) {
55858 +                                                               /* time - out */
55859 +#if 0
55860 +                                                               log_error_write(srv, __FILE__, __LINE__, "sd",
55861 +                                                                               "connection closed - read-timeout:", con->fd);
55862 +#endif
55863 +                                                               TRACE("%s", "(timeout)");
55864 +                                                               connection_set_state(srv, con, CON_STATE_ERROR);
55865 +                                                               changed = 1;
55866 +                                                       }
55867 +                                               }
55868 +                                               break;
55869 +                                       case CON_STATE_WRITE_RESPONSE_HEADER:
55870 +                                       case CON_STATE_WRITE_RESPONSE_CONTENT:
55871 +                                       
55872 +
55873 +                                               if (con->write_request_ts != 0 &&
55874 +                                                   srv->cur_ts - con->write_request_ts > con->conf.max_write_idle) {
55875 +                                                       /* time - out */
55876 +#if 1
55877 +                                                       log_error_write(srv, __FILE__, __LINE__, "sbsosds",
55878 +                                                                       "NOTE: a request for",
55879 +                                                                       con->request.uri,
55880 +                                                                       "timed out after writing",
55881 +                                                                       con->bytes_written,
55882 +                                                                       "bytes. We waited",
55883 +                                                                       (int)con->conf.max_write_idle,
55884 +                                                                       "seconds. If this a problem increase server.max-write-idle");
55885 +#endif
55886 +                                                               TRACE("%s", "(timeout)");
55887 +                                                       connection_set_state(srv, con, CON_STATE_ERROR);
55888 +                                                       changed = 1;
55889 +                                               }
55890 +                                               break;
55891 +                                       default:
55892 +                                               /* the other ones are uninteresting */
55893 +                                               break;
55894 +                                       }
55895 +                                       /* we don't like div by zero */
55896 +                                       if (0 == (t_diff = srv->cur_ts - con->connection_start)) t_diff = 1;
55897 +
55898 +                                       if (con->traffic_limit_reached &&
55899 +                                           (con->conf.kbytes_per_second == 0 ||
55900 +                                            ((con->bytes_written / t_diff) < con->conf.kbytes_per_second * 1024))) {
55901 +                                               /* enable connection again */
55902 +                                               con->traffic_limit_reached = 0;
55903 +
55904 +                                               changed = 1;
55905 +                                       }
55906 +
55907 +                                       if (changed) {
55908 +                                               connection_state_machine(srv, con);
55909 +                                       }
55910 +                                       con->bytes_written_cur_second = 0;
55911 +                                       *(con->conf.global_bytes_per_second_cnt_ptr) = 0;
55912 +
55913 +#if 0
55914 +                                       if (cs == 0) {
55915 +                                               fprintf(stderr, "connection-state: ");
55916 +                                               cs = 1;
55917 +                                       }
55918 +
55919 +                                       fprintf(stderr, "c[%d,%d]: %s ",
55920 +                                               con->fd,
55921 +                                               con->fcgi.fd,
55922 +                                               connection_get_state(con->state));
55923 +#endif
55924 +                               }
55925 +
55926 +                               if (cs == 1) fprintf(stderr, "\n");
55927 +                       }
55928 +               }
55929 +
55930 +               if (srv->sockets_disabled) {
55931 +                       /* our server sockets are disabled, why ? */
55932 +
55933 +                       if ((srv->cur_fds + srv->want_fds < srv->max_fds * 0.8) && /* we have enough unused fds */
55934 +                           (srv->conns->used < srv->max_conns * 0.9) &&
55935 +                           (0 == graceful_shutdown)) {
55936 +                               size_t i;
55937 +
55938 +                               for (i = 0; i < srv->srv_sockets.used; i++) {
55939 +                                       server_socket *srv_socket = srv->srv_sockets.ptr[i];
55940 +                                       fdevent_event_add(srv->ev, srv_socket->sock, FDEVENT_IN);
55941 +                               }
55942 +
55943 +                               log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets enabled again");
55944 +
55945 +                               srv->sockets_disabled = 0;
55946 +                       }
55947 +               } else {
55948 +                       if ((srv->cur_fds + srv->want_fds > srv->max_fds * 0.9) || /* out of fds */
55949 +                           (srv->conns->used > srv->max_conns) || /* out of connections */
55950 +                           (graceful_shutdown)) { /* graceful_shutdown */
55951 +                               size_t i;
55952 +
55953 +                               /* disable server-fds */
55954 +
55955 +                               for (i = 0; i < srv->srv_sockets.used; i++) {
55956 +                                       server_socket *srv_socket = srv->srv_sockets.ptr[i];
55957 +                                       fdevent_event_del(srv->ev, srv_socket->sock);
55958 +
55959 +                                       if (graceful_shutdown) {
55960 +                                               /* we don't want this socket anymore,
55961 +                                                *
55962 +                                                * closing it right away will make it possible for
55963 +                                                * the next lighttpd to take over (graceful restart)
55964 +                                                *  */
55965 +
55966 +                                               fdevent_unregister(srv->ev, srv_socket->sock);
55967 +                                               closesocket(srv_socket->sock->fd);
55968 +                                               srv_socket->sock->fd = -1;
55969 +
55970 +                                               /* network_close() will cleanup after us */
55971 +                                       }
55972 +                               }
55973 +
55974 +                               if (graceful_shutdown) {
55975 +                                       log_error_write(srv, __FILE__, __LINE__, "s", "[note] graceful shutdown started");
55976 +                               } else if (srv->conns->used > srv->max_conns) {
55977 +                                       log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, connection limit reached");
55978 +                               } else {
55979 +                                       log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, out-of-fds");
55980 +                               }
55981 +
55982 +                               srv->sockets_disabled = 1;
55983 +                       }
55984 +               }
55985 +
55986 +               if (graceful_shutdown && srv->conns->used == 0) {
55987 +                       /* we are in graceful shutdown phase and all connections are closed
55988 +                        * we are ready to terminate without harming anyone */
55989 +                       srv_shutdown = 1;
55990 +               }
55991 +
55992 +               /* we still have some fds to share */
55993 +               if (srv->want_fds) {
55994 +                       /* check the fdwaitqueue for waiting fds */
55995 +                       int free_fds = srv->max_fds - srv->cur_fds - 16;
55996 +                       connection *con;
55997 +
55998 +                       for (; free_fds > 0 && NULL != (con = fdwaitqueue_unshift(srv, srv->fdwaitqueue)); free_fds--) {
55999 +                               connection_state_machine(srv, con);
56000 +
56001 +                               srv->want_fds--;
56002 +                       }
56003 +               }
56004 +
56005 +               if ((n = fdevent_poll(srv->ev, 1000)) > 0) {
56006 +                       /* n is the number of events */
56007 +                       size_t i;
56008 +                       fdevent_get_revents(srv->ev, n, revents);
56009 +
56010 +                       /* handle client connections first
56011 +                        * 
56012 +                        * this is a bit of a hack, but we have to make sure than we handle 
56013 +                        * close-events before the connection is reused for a keep-alive 
56014 +                        * request
56015 +                        *
56016 +                        * this is mostly an issue for mod_proxy_core, but you never know
56017 +                        *
56018 +                        */
56019 +
56020 +                       for (i = 0; i < revents->used; i++) {
56021 +                               fdevent_revent *revent = revents->ptr[i];
56022 +                               handler_t r;
56023 +
56024 +                               /* skip server-fds */
56025 +                               if (revent->handler == network_server_handle_fdevent) continue;
56026 +
56027 +                               switch (r = (*(revent->handler))(srv, revent->context, revent->revents)) {
56028 +                               case HANDLER_FINISHED:
56029 +                               case HANDLER_GO_ON:
56030 +                               case HANDLER_WAIT_FOR_EVENT:
56031 +                               case HANDLER_WAIT_FOR_FD:
56032 +                                       break;
56033 +                               case HANDLER_ERROR:
56034 +                                       /* should never happen */
56035 +                                       SEGFAULT();
56036 +                                       break;
56037 +                               default:
56038 +                                       log_error_write(srv, __FILE__, __LINE__, "d", r);
56039 +                                       break;
56040 +                               }
56041 +                       } 
56042 +
56043 +                       for (i = 0; i < revents->used; i++) {
56044 +                               fdevent_revent *revent = revents->ptr[i];
56045 +                               handler_t r;
56046 +
56047 +                               /* server fds only */
56048 +                               if (revent->handler != network_server_handle_fdevent) continue;
56049 +
56050 +                               switch (r = (*(revent->handler))(srv, revent->context, revent->revents)) {
56051 +                               case HANDLER_FINISHED:
56052 +                               case HANDLER_GO_ON:
56053 +                               case HANDLER_WAIT_FOR_EVENT:
56054 +                               case HANDLER_WAIT_FOR_FD:
56055 +                                       break;
56056 +                               case HANDLER_ERROR:
56057 +                                       /* should never happen */
56058 +                                       SEGFAULT();
56059 +                                       break;
56060 +                               default:
56061 +                                       log_error_write(srv, __FILE__, __LINE__, "d", r);
56062 +                                       break;
56063 +                               }
56064 +                       } 
56065 +
56066 +               } else if (n < 0 && errno != EINTR) {
56067 +                       log_error_write(srv, __FILE__, __LINE__, "ss",
56068 +                                       "fdevent_poll failed:",
56069 +                                       strerror(errno));
56070 +               }
56071 +
56072 +               for (ndx = 0; ndx < srv->joblist->used; ndx++) {
56073 +                       connection *con = srv->joblist->ptr[ndx];
56074 +                       handler_t r;
56075 +
56076 +                       connection_state_machine(srv, con);
56077 +
56078 +                       switch(r = plugins_call_handle_joblist(srv, con)) {
56079 +                       case HANDLER_FINISHED:
56080 +                       case HANDLER_GO_ON:
56081 +                               break;
56082 +                       default:
56083 +                               log_error_write(srv, __FILE__, __LINE__, "d", r);
56084 +                               break;
56085 +                       }
56086 +
56087 +                       con->in_joblist = 0;
56088 +               }
56089 +
56090 +               srv->joblist->used = 0;
56091 +       }
56092 +
56093 +       fdevent_revents_free(revents);
56094 +
56095 +       return 0;
56096 +}
56097 +
56098 +
56099 +int main (int argc, char **argv, char **envp) {
56100 +       server *srv = NULL;
56101 +       int print_config = 0;
56102 +       int test_config = 0;
56103 +       int i_am_root;
56104 +       int o;
56105 +       int num_childs = 0;
56106 +       int pid_fd = -1, fd;
56107 +       size_t i;
56108 +#ifdef _WIN32
56109 +       char *optarg = NULL;
56110 +#endif
56111 +
56112 +#ifdef HAVE_SIGACTION
56113 +       struct sigaction act;
56114 +#endif
56115 +#ifdef HAVE_GETRLIMIT
56116 +       struct rlimit rlim;
56117 +#endif
56118 +
56119 +#ifdef USE_ALARM
56120 +       struct itimerval interval;
56121 +
56122 +       interval.it_interval.tv_sec = 1;
56123 +       interval.it_interval.tv_usec = 0;
56124 +       interval.it_value.tv_sec = 1;
56125 +       interval.it_value.tv_usec = 0;
56126 +#endif
56127 +
56128 +       log_init();
56129 +       status_counter_init();
56130 +
56131 +       /* for nice %b handling in strfime() */
56132 +       setlocale(LC_TIME, "C");
56133 +       
56134 +       if (NULL == (srv = server_init())) {
56135 +               fprintf(stderr, "did this really happen?\n");
56136 +               return -1;
56137 +       }
56138 +
56139 +       /* init structs done */
56140 +
56141 +       srv->srvconf.port = 0;
56142 +#ifdef HAVE_GETUID
56143 +       i_am_root = (getuid() == 0);
56144 +#else
56145 +       i_am_root = 0;
56146 +#endif
56147 +       srv->srvconf.dont_daemonize = 0;
56148 +
56149 +       while(-1 != (o = getopt(argc, argv, "f:m:hvVDpt"))) {
56150 +               switch(o) {
56151 +               case 'f':
56152 +#ifdef _WIN32
56153 +                       /* evil HACK for windows, optarg is not set */
56154 +                       optarg = argv[optind-1];
56155 +#endif
56156 +                       if (config_read(srv, optarg)) {
56157 +                               server_free(srv);
56158 +                               return -1;
56159 +                       }
56160 +
56161 +                       break;
56162 +               case 'm':
56163 +                       buffer_copy_string(srv->srvconf.modules_dir, optarg);
56164 +                       break;
56165 +               case 'p': print_config = 1; break;
56166 +               case 't': test_config = 1; break;
56167 +               case 'D': srv->srvconf.dont_daemonize = 1; break;
56168 +               case 'v': show_version(); return 0;
56169 +               case 'V': show_features(); return 0;
56170 +               case 'h': show_help(); return 0;
56171 +               default:
56172 +                       show_help();
56173 +                       server_free(srv);
56174 +                       return -1;
56175 +               }
56176 +       }
56177 +
56178 +       if (!srv->config_storage) {
56179 +               log_error_write(srv, __FILE__, __LINE__, "s",
56180 +                               "No configuration available. Try using -f option.");
56181 +
56182 +               server_free(srv);
56183 +               return -1;
56184 +       }
56185 +
56186 +       if (print_config) {
56187 +               data_unset *dc = srv->config_context->data[0];
56188 +               if (dc) {
56189 +                       dc->print(dc, 0);
56190 +                       fprintf(stderr, "\n");
56191 +               } else {
56192 +                       /* shouldn't happend */
56193 +                       fprintf(stderr, "global config not found\n");
56194 +               }
56195 +       }
56196 +
56197 +       if (test_config) {
56198 +               printf("Syntax OK\n");
56199 +       }
56200 +
56201 +       if (test_config || print_config) {
56202 +               server_free(srv);
56203 +               return 0;
56204         }
56205  
56206 +       /* close stdin and stdout, as they are not needed */
56207 +       /* move stdin to /dev/null */
56208 +       if (-1 != (fd = open("/dev/null", O_RDONLY))) {
56209 +               close(STDIN_FILENO);
56210 +               dup2(fd, STDIN_FILENO);
56211 +               close(fd);
56212 +       }
56213 +
56214 +       /* move stdout to /dev/null */
56215 +       if (-1 != (fd = open("/dev/null", O_WRONLY))) {
56216 +               close(STDOUT_FILENO);
56217 +               dup2(fd, STDOUT_FILENO);
56218 +               close(fd);
56219 +       }
56220 +
56221 +       if (0 != config_set_defaults(srv)) {
56222 +               log_error_write(srv, __FILE__, __LINE__, "s",
56223 +                               "setting default values failed");
56224 +               server_free(srv);
56225 +               return -1;
56226 +       }
56227 +
56228 +       /* UID handling */
56229 +#ifdef HAVE_GETUID
56230 +       if (!i_am_root && (geteuid() == 0 || getegid() == 0)) {
56231 +               /* we are setuid-root */
56232 +
56233 +               log_error_write(srv, __FILE__, __LINE__, "s",
56234 +                               "Are you nuts ? Don't apply a SUID bit to this binary");
56235 +
56236 +               server_free(srv);
56237 +               return -1;
56238 +       }
56239 +#endif
56240 +
56241 +       /* check document-root */
56242 +       if (srv->config_storage[0]->document_root->used <= 1) {
56243 +               log_error_write(srv, __FILE__, __LINE__, "s",
56244 +                               "document-root is not set\n");
56245 +
56246 +               server_free(srv);
56247 +
56248 +               return -1;
56249 +       }
56250 +
56251 +       if (plugins_load(srv)) {
56252 +               log_error_write(srv, __FILE__, __LINE__, "s",
56253 +                               "loading plugins finally failed");
56254 +
56255 +               plugins_free(srv);
56256 +               server_free(srv);
56257 +
56258 +               return -1;
56259 +       }
56260 +
56261 +#ifndef _WIN32
56262 +       /* open pid file BEFORE chroot */
56263 +       if (srv->srvconf.pid_file->used) {
56264 +               if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
56265 +                       struct stat st;
56266 +                       if (errno != EEXIST) {
56267 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
56268 +                                       "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
56269 +                               return -1;
56270 +                       }
56271 +
56272 +                       if (0 != stat(srv->srvconf.pid_file->ptr, &st)) {
56273 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
56274 +                                               "stating existing pid-file failed:", srv->srvconf.pid_file, strerror(errno));
56275 +                       }
56276 +
56277 +                       if (!S_ISREG(st.st_mode)) {
56278 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
56279 +                                               "pid-file exists and isn't regular file:", srv->srvconf.pid_file);
56280 +                               return -1;
56281 +                       }
56282 +
56283 +                       if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
56284 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
56285 +                                               "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
56286 +                               return -1;
56287 +                       }
56288 +               }
56289 +       }
56290 +#endif
56291         if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
56292                 /* select limits itself
56293                  *
56294                  * as it is a hard limit and will lead to a segfault we add some safety
56295                  * */
56296 -               srv->max_fds = FD_SETSIZE - 200;
56297 +        fprintf(stderr, "%s.%d: max parallel connections: %d\r\n", __FILE__, __LINE__, FD_SETSIZE);
56298 +               srv->max_fds = FD_SETSIZE - 4;
56299         } else {
56300                 srv->max_fds = 4096;
56301         }
56302 @@ -636,7 +1010,7 @@
56303  #ifdef HAVE_VALGRIND_VALGRIND_H
56304                 if (RUNNING_ON_VALGRIND) use_rlimit = 0;
56305  #endif
56306 -               
56307 +
56308  #ifdef HAVE_GETRLIMIT
56309                 if (0 != getrlimit(RLIMIT_NOFILE, &rlim)) {
56310                         log_error_write(srv, __FILE__, __LINE__,
56311 @@ -644,13 +1018,13 @@
56312                                         strerror(errno));
56313                         return -1;
56314                 }
56315 -               
56316 +
56317                 if (use_rlimit && srv->srvconf.max_fds) {
56318                         /* set rlimits */
56319 -                       
56320 +
56321                         rlim.rlim_cur = srv->srvconf.max_fds;
56322                         rlim.rlim_max = srv->srvconf.max_fds;
56323 -                       
56324 +
56325                         if (0 != setrlimit(RLIMIT_NOFILE, &rlim)) {
56326                                 log_error_write(srv, __FILE__, __LINE__,
56327                                                 "ss", "couldn't set 'max filedescriptors'",
56328 @@ -659,7 +1033,7 @@
56329                         }
56330                 }
56331  
56332 -               /* #372: solaris need some fds extra for devpoll */     
56333 +               /* #372: solaris need some fds extra for devpoll */
56334                 if (rlim.rlim_cur > 10) rlim.rlim_cur -= 10;
56335  
56336                 if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
56337 @@ -677,33 +1051,33 @@
56338                 if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
56339                         /* don't raise the limit above FD_SET_SIZE */
56340                         if (srv->max_fds > FD_SETSIZE - 200) {
56341 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
56342 +                               log_error_write(srv, __FILE__, __LINE__, "sd",
56343                                                 "can't raise max filedescriptors above",  FD_SETSIZE - 200,
56344                                                 "if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds.");
56345                                 return -1;
56346                         }
56347                 }
56348  
56349 -               
56350 +
56351  #ifdef HAVE_PWD_H
56352                 /* set user and group */
56353                 if (srv->srvconf.username->used) {
56354                         if (NULL == (pwd = getpwnam(srv->srvconf.username->ptr))) {
56355 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
56356 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
56357                                                 "can't find username", srv->srvconf.username);
56358                                 return -1;
56359                         }
56360 -                       
56361 +
56362                         if (pwd->pw_uid == 0) {
56363                                 log_error_write(srv, __FILE__, __LINE__, "s",
56364                                                 "I will not set uid to 0\n");
56365                                 return -1;
56366                         }
56367                 }
56368 -               
56369 +
56370                 if (srv->srvconf.groupname->used) {
56371                         if (NULL == (grp = getgrnam(srv->srvconf.groupname->ptr))) {
56372 -                               log_error_write(srv, __FILE__, __LINE__, "sb", 
56373 +                               log_error_write(srv, __FILE__, __LINE__, "sb",
56374                                         "can't find groupname", srv->srvconf.groupname);
56375                                 return -1;
56376                         }
56377 @@ -713,15 +1087,15 @@
56378                                 return -1;
56379                         }
56380                 }
56381 -#endif         
56382 +#endif
56383                 /* we need root-perms for port < 1024 */
56384                 if (0 != network_init(srv)) {
56385                         plugins_free(srv);
56386                         server_free(srv);
56387 -                       
56388 +
56389                         return -1;
56390                 }
56391 -#ifdef HAVE_CHROOT     
56392 +#ifdef HAVE_CHROOT
56393                 if (srv->srvconf.changeroot->used) {
56394                         tzset();
56395  
56396 @@ -761,7 +1135,7 @@
56397                 }
56398  
56399                 if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
56400 -                       srv->max_fds = rlim.rlim_cur < FD_SETSIZE - 200 ? rlim.rlim_cur : FD_SETSIZE - 200;
56401 +                       srv->max_fds = rlim.rlim_cur < FD_SETSIZE - 4 ? rlim.rlim_cur : FD_SETSIZE - 4;
56402                 } else {
56403                         srv->max_fds = rlim.rlim_cur;
56404                 }
56405 @@ -775,18 +1149,18 @@
56406  #endif
56407                 if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
56408                         /* don't raise the limit above FD_SET_SIZE */
56409 -                       if (srv->max_fds > FD_SETSIZE - 200) {
56410 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
56411 -                                               "can't raise max filedescriptors above",  FD_SETSIZE - 200,
56412 +                       if (srv->max_fds > FD_SETSIZE - 4) {
56413 +                               log_error_write(srv, __FILE__, __LINE__, "sd",
56414 +                                               "can't raise max filedescriptors above",  FD_SETSIZE - 4,
56415                                                 "if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds.");
56416                                 return -1;
56417                         }
56418                 }
56419 -               
56420 +
56421                 if (0 != network_init(srv)) {
56422                         plugins_free(srv);
56423                         server_free(srv);
56424 -                       
56425 +
56426                         return -1;
56427                 }
56428         }
56429 @@ -802,25 +1176,27 @@
56430                 /* or use the default */
56431                 srv->max_conns = srv->max_fds;
56432         }
56433 -       
56434 +
56435         if (HANDLER_GO_ON != plugins_call_init(srv)) {
56436                 log_error_write(srv, __FILE__, __LINE__, "s", "Initialization of plugins failed. Going down.");
56437 -               
56438 +
56439                 plugins_free(srv);
56440                 network_close(srv);
56441                 server_free(srv);
56442 -               
56443 +
56444                 return -1;
56445         }
56446  
56447 -#ifdef HAVE_FORK       
56448 +#ifdef HAVE_FORK
56449         /* network is up, let's deamonize ourself */
56450         if (srv->srvconf.dont_daemonize == 0) daemonize();
56451  #endif
56452  
56453 +#ifdef HAVE_PWD_H
56454         srv->gid = getgid();
56455         srv->uid = getuid();
56456 -       
56457 +#endif
56458 +
56459         /* write pid file */
56460         if (pid_fd != -1) {
56461                 buffer_copy_long(srv->tmp_buf, getpid());
56462 @@ -829,17 +1205,17 @@
56463                 close(pid_fd);
56464                 pid_fd = -1;
56465         }
56466 -       
56467 +
56468         if (HANDLER_GO_ON != plugins_call_set_defaults(srv)) {
56469                 log_error_write(srv, __FILE__, __LINE__, "s", "Configuration of plugins failed. Going down.");
56470 -               
56471 +
56472                 plugins_free(srv);
56473                 network_close(srv);
56474                 server_free(srv);
56475 -               
56476 +
56477                 return -1;
56478         }
56479 -       
56480 +
56481         /* dump unused config-keys */
56482         for (i = 0; i < srv->config_context->used; i++) {
56483                 array *config = ((data_config *)srv->config_context->data[i])->value;
56484 @@ -847,43 +1223,49 @@
56485  
56486                 for (j = 0; config && j < config->used; j++) {
56487                         data_unset *du = config->data[j];
56488 -                       
56489 +
56490                         /* all var.* is known as user defined variable */
56491                         if (strncmp(du->key->ptr, "var.", sizeof("var.") - 1) == 0) {
56492                                 continue;
56493                         }
56494  
56495                         if (NULL == array_get_element(srv->config_touched, du->key->ptr)) {
56496 -                               log_error_write(srv, __FILE__, __LINE__, "sbs", 
56497 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
56498                                                 "WARNING: unknown config-key:",
56499                                                 du->key,
56500                                                 "(ignored)");
56501                         }
56502                 }
56503         }
56504 -       
56505 -       if (srv->config_deprecated) {
56506 +
56507 +       if (srv->config_unsupported) {
56508                 log_error_write(srv, __FILE__, __LINE__, "s", 
56509 +                               "Configuration contains unsupported keys. Going down.");
56510 +       }
56511 +
56512 +       if (srv->config_deprecated) {
56513 +               log_error_write(srv, __FILE__, __LINE__, "s",
56514                                 "Configuration contains deprecated keys. Going down.");
56515 -               
56516 +       }
56517 +
56518 +       if (srv->config_unsupported || srv->config_deprecated) {
56519                 plugins_free(srv);
56520                 network_close(srv);
56521                 server_free(srv);
56522 -               
56523 +
56524                 return -1;
56525         }
56526 -       
56527 -       if (-1 == log_error_open(srv)) {
56528 -               log_error_write(srv, __FILE__, __LINE__, "s", 
56529 +
56530 +       if (-1 == log_error_open(srv->srvconf.errorlog_file, srv->srvconf.errorlog_use_syslog)) {
56531 +               log_error_write(srv, __FILE__, __LINE__, "s",
56532                                 "opening errorlog failed, dying");
56533 -               
56534 +
56535                 plugins_free(srv);
56536                 network_close(srv);
56537                 server_free(srv);
56538                 return -1;
56539         }
56540 -       
56541 -       
56542 +
56543  #ifdef HAVE_SIGACTION
56544         memset(&act, 0, sizeof(act));
56545         act.sa_handler = SIG_IGN;
56546 @@ -903,7 +1285,7 @@
56547         sigaction(SIGHUP,  &act, NULL);
56548         sigaction(SIGALRM, &act, NULL);
56549         sigaction(SIGCHLD, &act, NULL);
56550 -       
56551 +
56552  #elif defined(HAVE_SIGNAL)
56553         /* ignore the SIGPIPE from sendfile() */
56554         signal(SIGPIPE, SIG_IGN);
56555 @@ -914,20 +1296,20 @@
56556         signal(SIGCHLD,  signal_handler);
56557         signal(SIGINT,  signal_handler);
56558  #endif
56559 -       
56560 +
56561  #ifdef USE_ALARM
56562         signal(SIGALRM, signal_handler);
56563 -       
56564 +
56565         /* setup periodic timer (1 second) */
56566         if (setitimer(ITIMER_REAL, &interval, NULL)) {
56567                 log_error_write(srv, __FILE__, __LINE__, "s", "setting timer failed");
56568                 return -1;
56569         }
56570 -       
56571 +
56572         getitimer(ITIMER_REAL, &interval);
56573  #endif
56574  
56575 -#ifdef HAVE_FORK       
56576 +#ifdef HAVE_FORK
56577         /* start watcher and workers */
56578         num_childs = srv->srvconf.max_worker;
56579         if (num_childs > 0) {
56580 @@ -957,13 +1339,13 @@
56581         }
56582  #endif
56583  
56584 -       if (NULL == (srv->ev = fdevent_init(srv->max_fds + 1, srv->event_handler))) {
56585 +       if (NULL == (srv->ev = fdevent_init(/*srv->max_fds + 1*/ 4096, srv->event_handler))) {
56586                 log_error_write(srv, __FILE__, __LINE__,
56587                                 "s", "fdevent_init failed");
56588                 return -1;
56589         }
56590 -       /* 
56591 -        * kqueue() is called here, select resets its internals, 
56592 +       /*
56593 +        * kqueue() is called here, select resets its internals,
56594          * all server sockets get their handlers
56595          *
56596          * */
56597 @@ -971,7 +1353,7 @@
56598                 plugins_free(srv);
56599                 network_close(srv);
56600                 server_free(srv);
56601 -               
56602 +
56603                 return -1;
56604         }
56605  
56606 @@ -986,17 +1368,17 @@
56607         /* setup FAM */
56608         if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM) {
56609                 if (0 != FAMOpen2(srv->stat_cache->fam, "lighttpd")) {
56610 -                       log_error_write(srv, __FILE__, __LINE__, "s", 
56611 +                       log_error_write(srv, __FILE__, __LINE__, "s",
56612                                          "could not open a fam connection, dieing.");
56613                         return -1;
56614                 }
56615  #ifdef HAVE_FAMNOEXISTS
56616                 FAMNoExists(srv->stat_cache->fam);
56617  #endif
56618 +               srv->stat_cache->sock->fd = FAMCONNECTION_GETFD(srv->stat_cache->fam);
56619  
56620 -               srv->stat_cache->fam_fcce_ndx = -1;
56621 -               fdevent_register(srv->ev, FAMCONNECTION_GETFD(srv->stat_cache->fam), stat_cache_handle_fdevent, NULL);
56622 -               fdevent_event_add(srv->ev, &(srv->stat_cache->fam_fcce_ndx), FAMCONNECTION_GETFD(srv->stat_cache->fam), FDEVENT_IN);
56623 +               fdevent_register(srv->ev, srv->stat_cache->sock, stat_cache_handle_fdevent, NULL);
56624 +               fdevent_event_add(srv->ev, srv->stat_cache->sock, FDEVENT_IN);
56625         }
56626  #endif
56627  
56628 @@ -1007,330 +1389,36 @@
56629  
56630         for (i = 0; i < srv->srv_sockets.used; i++) {
56631                 server_socket *srv_socket = srv->srv_sockets.ptr[i];
56632 -               if (-1 == fdevent_fcntl_set(srv->ev, srv_socket->fd)) {
56633 +               if (-1 == fdevent_fcntl_set(srv->ev, srv_socket->sock)) {
56634                         log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed:", strerror(errno));
56635                         return -1;
56636                 }
56637         }
56638  
56639 -       /* main-loop */
56640 -       while (!srv_shutdown) {
56641 -               int n;
56642 -               size_t ndx;
56643 -               time_t min_ts;
56644 -               
56645 -               if (handle_sig_hup) {
56646 -                       handler_t r;
56647 -                       
56648 -                       /* reset notification */
56649 -                       handle_sig_hup = 0;
56650 -                       
56651 -                       
56652 -                       /* cycle logfiles */
56653 -                       
56654 -                       switch(r = plugins_call_handle_sighup(srv)) {
56655 -                       case HANDLER_GO_ON:
56656 -                               break;
56657 -                       default:
56658 -                               log_error_write(srv, __FILE__, __LINE__, "sd", "sighup-handler return with an error", r);
56659 -                               break;
56660 -                       }
56661 -                       
56662 -                       if (-1 == log_error_cycle(srv)) {
56663 -                               log_error_write(srv, __FILE__, __LINE__, "s", "cycling errorlog failed, dying");
56664 -                               
56665 -                               return -1;
56666 -                       }
56667 -               }
56668 -               
56669 -               if (handle_sig_alarm) {
56670 -                       /* a new second */
56671 -                       
56672 -#ifdef USE_ALARM
56673 -                       /* reset notification */
56674 -                       handle_sig_alarm = 0;
56675 -#endif
56676 -                       
56677 -                       /* get current time */
56678 -                       min_ts = time(NULL);
56679 -                       
56680 -                       if (min_ts != srv->cur_ts) {
56681 -                               int cs = 0;
56682 -                               connections *conns = srv->conns;
56683 -                               handler_t r;
56684 -                               
56685 -                               switch(r = plugins_call_handle_trigger(srv)) {
56686 -                               case HANDLER_GO_ON:
56687 -                                       break;
56688 -                               case HANDLER_ERROR:
56689 -                                       log_error_write(srv, __FILE__, __LINE__, "s", "one of the triggers failed");
56690 -                                       break;
56691 -                               default:
56692 -                                       log_error_write(srv, __FILE__, __LINE__, "d", r);
56693 -                                       break;
56694 -                               }
56695 -                               
56696 -                               /* trigger waitpid */
56697 -                               srv->cur_ts = min_ts;
56698 -                       
56699 -                               /* cleanup stat-cache */        
56700 -                               stat_cache_trigger_cleanup(srv);
56701 -                               /**
56702 -                                * check all connections for timeouts 
56703 -                                * 
56704 -                                */
56705 -                               for (ndx = 0; ndx < conns->used; ndx++) {
56706 -                                       int changed = 0;
56707 -                                       connection *con;
56708 -                                       int t_diff;
56709 -                                       
56710 -                                       con = conns->ptr[ndx];
56711 -
56712 -                                       if (con->state == CON_STATE_READ ||
56713 -                                           con->state == CON_STATE_READ_POST) {
56714 -                                               if (con->request_count == 1) {
56715 -                                                       if (srv->cur_ts - con->read_idle_ts > con->conf.max_read_idle) {
56716 -                                                               /* time - out */
56717 -#if 0
56718 -                                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
56719 -                                                                               "connection closed - read-timeout:", con->fd);
56720 -#endif
56721 -                                                               connection_set_state(srv, con, CON_STATE_ERROR);
56722 -                                                               changed = 1;
56723 -                                                       }
56724 -                                               } else {
56725 -                                                       if (srv->cur_ts - con->read_idle_ts > con->conf.max_keep_alive_idle) {
56726 -                                                               /* time - out */
56727 -#if 0
56728 -                                                               log_error_write(srv, __FILE__, __LINE__, "sd", 
56729 -                                                                               "connection closed - read-timeout:", con->fd);
56730 -#endif
56731 -                                                               connection_set_state(srv, con, CON_STATE_ERROR);
56732 -                                                               changed = 1;
56733 -                                                       }
56734 -                                               }
56735 -                                       }
56736 -                                       
56737 -                                       if ((con->state == CON_STATE_WRITE) &&
56738 -                                           (con->write_request_ts != 0)) { 
56739 -#if 0
56740 -                                               if (srv->cur_ts - con->write_request_ts > 60) {
56741 -                                                       log_error_write(srv, __FILE__, __LINE__, "sdd", 
56742 -                                                                       "connection closed - pre-write-request-timeout:", con->fd, srv->cur_ts - con->write_request_ts);
56743 -                                               }
56744 -#endif
56745 -                                               
56746 -                                               if (srv->cur_ts - con->write_request_ts > con->conf.max_write_idle) {
56747 -                                                       /* time - out */
56748 -#if 1
56749 -                                                       log_error_write(srv, __FILE__, __LINE__, "sbsosds", 
56750 -                                                                       "NOTE: a request for",
56751 -                                                                       con->request.uri,
56752 -                                                                       "timed out after writing",
56753 -                                                                       con->bytes_written,
56754 -                                                                       "bytes. We waited",
56755 -                                                                       (int)con->conf.max_write_idle,
56756 -                                                                       "seconds. If this a problem increase server.max-write-idle");
56757 -#endif
56758 -                                                       connection_set_state(srv, con, CON_STATE_ERROR);
56759 -                                                       changed = 1;
56760 -                                               }
56761 -                                       }
56762 -                                       /* we don't like div by zero */
56763 -                                       if (0 == (t_diff = srv->cur_ts - con->connection_start)) t_diff = 1;
56764 -       
56765 -                                       if (con->traffic_limit_reached && 
56766 -                                           (con->conf.kbytes_per_second == 0 || 
56767 -                                            ((con->bytes_written / t_diff) < con->conf.kbytes_per_second * 1024))) {
56768 -                                               /* enable connection again */
56769 -                                               con->traffic_limit_reached = 0;
56770 -                                               
56771 -                                               changed = 1;
56772 -                                       }
56773 -                                       
56774 -                                       if (changed) {
56775 -                                               connection_state_machine(srv, con);
56776 -                                       }
56777 -                                       con->bytes_written_cur_second = 0;
56778 -                                       *(con->conf.global_bytes_per_second_cnt_ptr) = 0;
56779 -                                       
56780 -#if 0
56781 -                                       if (cs == 0) {
56782 -                                               fprintf(stderr, "connection-state: ");
56783 -                                               cs = 1;
56784 -                                       }
56785 -                                       
56786 -                                       fprintf(stderr, "c[%d,%d]: %s ",
56787 -                                               con->fd,
56788 -                                               con->fcgi.fd,
56789 -                                               connection_get_state(con->state));
56790 -#endif
56791 -                               }
56792 -                               
56793 -                               if (cs == 1) fprintf(stderr, "\n");
56794 -                       }
56795 -               }
56796 -
56797 -               if (srv->sockets_disabled) {
56798 -                       /* our server sockets are disabled, why ? */
56799 -
56800 -                       if ((srv->cur_fds + srv->want_fds < srv->max_fds * 0.8) && /* we have enough unused fds */
56801 -                           (srv->conns->used < srv->max_conns * 0.9) &&
56802 -                           (0 == graceful_shutdown)) {
56803 -                               for (i = 0; i < srv->srv_sockets.used; i++) {
56804 -                                       server_socket *srv_socket = srv->srv_sockets.ptr[i];
56805 -                                       fdevent_event_add(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN);
56806 -                               }
56807 -                       
56808 -                               log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets enabled again");
56809 -                       
56810 -                               srv->sockets_disabled = 0;
56811 -                       }
56812 -               } else {
56813 -                       if ((srv->cur_fds + srv->want_fds > srv->max_fds * 0.9) || /* out of fds */
56814 -                           (srv->conns->used > srv->max_conns) || /* out of connections */
56815 -                           (graceful_shutdown)) { /* graceful_shutdown */ 
56816 -
56817 -                               /* disable server-fds */
56818 -                       
56819 -                               for (i = 0; i < srv->srv_sockets.used; i++) {
56820 -                                       server_socket *srv_socket = srv->srv_sockets.ptr[i];
56821 -                                       fdevent_event_del(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd);
56822 -
56823 -                                       if (graceful_shutdown) {
56824 -                                               /* we don't want this socket anymore,
56825 -                                                *
56826 -                                                * closing it right away will make it possible for
56827 -                                                * the next lighttpd to take over (graceful restart)
56828 -                                                *  */
56829 -
56830 -                                               fdevent_unregister(srv->ev, srv_socket->fd);
56831 -                                               close(srv_socket->fd);
56832 -                                               srv_socket->fd = -1;
56833 -
56834 -                                               /* network_close() will cleanup after us */
56835 -                                       }
56836 -                               }
56837 -               
56838 -                               if (graceful_shutdown) {
56839 -                                       log_error_write(srv, __FILE__, __LINE__, "s", "[note] graceful shutdown started");
56840 -                               } else if (srv->conns->used > srv->max_conns) {
56841 -                                       log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, connection limit reached");
56842 -                               } else {
56843 -                                       log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, out-of-fds");
56844 -                               }
56845 -                       
56846 -                               srv->sockets_disabled = 1;
56847 -                       }
56848 -               }
56849 +       lighty_mainloop(srv);
56850  
56851 -               if (graceful_shutdown && srv->conns->used == 0) {
56852 -                       /* we are in graceful shutdown phase and all connections are closed
56853 -                        * we are ready to terminate without harming anyone */
56854 -                       srv_shutdown = 1;
56855 -               }
56856 -               
56857 -               /* we still have some fds to share */
56858 -               if (srv->want_fds) { 
56859 -                       /* check the fdwaitqueue for waiting fds */
56860 -                       int free_fds = srv->max_fds - srv->cur_fds - 16;
56861 -                       connection *con;
56862 -                       
56863 -                       for (; free_fds > 0 && NULL != (con = fdwaitqueue_unshift(srv, srv->fdwaitqueue)); free_fds--) {
56864 -                               connection_state_machine(srv, con);
56865 -                               
56866 -                               srv->want_fds--;
56867 -                       }
56868 -               }
56869 +       status_counter_free();
56870  
56871 -               if ((n = fdevent_poll(srv->ev, 1000)) > 0) {
56872 -                       /* n is the number of events */
56873 -                       int revents;
56874 -                       int fd_ndx;
56875 -#if 0
56876 -                       if (n > 0) {
56877 -                               log_error_write(srv, __FILE__, __LINE__, "sd", 
56878 -                                               "polls:", n);
56879 -                       }
56880 -#endif                 
56881 -                       fd_ndx = -1;
56882 -                       do {
56883 -                               fdevent_handler handler;
56884 -                               void *context;
56885 -                               handler_t r;
56886 -                               
56887 -                               fd_ndx  = fdevent_event_next_fdndx (srv->ev, fd_ndx);
56888 -                               revents = fdevent_event_get_revent (srv->ev, fd_ndx);
56889 -                               fd      = fdevent_event_get_fd     (srv->ev, fd_ndx);
56890 -                               handler = fdevent_get_handler(srv->ev, fd);
56891 -                               context = fdevent_get_context(srv->ev, fd);
56892 -                               
56893 -                               /* connection_handle_fdevent needs a joblist_append */
56894 -#if 0
56895 -                               log_error_write(srv, __FILE__, __LINE__, "sdd", 
56896 -                                               "event for", fd, revents);
56897 -#endif                         
56898 -                               switch (r = (*handler)(srv, context, revents)) {
56899 -                               case HANDLER_FINISHED:
56900 -                               case HANDLER_GO_ON:
56901 -                               case HANDLER_WAIT_FOR_EVENT:
56902 -                               case HANDLER_WAIT_FOR_FD:
56903 -                                       break;
56904 -                               case HANDLER_ERROR:
56905 -                                       /* should never happen */
56906 -                                       SEGFAULT();
56907 -                                       break;
56908 -                               default:
56909 -                                       log_error_write(srv, __FILE__, __LINE__, "d", r);
56910 -                                       break;
56911 -                               }
56912 -                       } while (--n > 0);
56913 -               } else if (n < 0 && errno != EINTR) {
56914 -                       log_error_write(srv, __FILE__, __LINE__, "ss", 
56915 -                                       "fdevent_poll failed:", 
56916 -                                       strerror(errno));
56917 -               }
56918 -               
56919 -               for (ndx = 0; ndx < srv->joblist->used; ndx++) {
56920 -                       connection *con = srv->joblist->ptr[ndx];
56921 -                       handler_t r;
56922 -                       
56923 -                       connection_state_machine(srv, con);
56924 -                       
56925 -                       switch(r = plugins_call_handle_joblist(srv, con)) {
56926 -                       case HANDLER_FINISHED:
56927 -                       case HANDLER_GO_ON:
56928 -                               break;
56929 -                       default:
56930 -                               log_error_write(srv, __FILE__, __LINE__, "d", r);
56931 -                               break;
56932 -                       }
56933 -                       
56934 -                       con->in_joblist = 0;
56935 -               }
56936 -               
56937 -               srv->joblist->used = 0;
56938 -       }
56939 -       
56940 -       if (srv->srvconf.pid_file->used &&
56941 +       if (0 == graceful_restart &&
56942 +           srv->srvconf.pid_file->used &&
56943             srv->srvconf.changeroot->used == 0) {
56944                 if (0 != unlink(srv->srvconf.pid_file->ptr)) {
56945                         if (errno != EACCES && errno != EPERM) {
56946 -                               log_error_write(srv, __FILE__, __LINE__, "sbds", 
56947 -                                               "unlink failed for:", 
56948 +                               log_error_write(srv, __FILE__, __LINE__, "sbds",
56949 +                                               "unlink failed for:",
56950                                                 srv->srvconf.pid_file,
56951                                                 errno,
56952                                                 strerror(errno));
56953                         }
56954                 }
56955         }
56956 -       
56957 +
56958         /* clean-up */
56959 -       log_error_close(srv);
56960         network_close(srv);
56961         connections_free(srv);
56962         plugins_free(srv);
56963         server_free(srv);
56964 -       
56965 +       log_free();
56966 +
56967         return 0;
56968  }
56969 --- ../lighttpd-1.4.11/src/settings.h   2005-08-11 01:26:41.000000000 +0300
56970 +++ lighttpd-1.5.0/src/settings.h       2006-07-16 00:26:04.000000000 +0300
56971 @@ -9,24 +9,24 @@
56972  /**
56973   * max size of a buffer which will just be reset
56974   * to ->used = 0 instead of really freeing the buffer
56975 - * 
56976 + *
56977   * 64kB (no real reason, just a guess)
56978   */
56979  #define BUFFER_MAX_REUSE_SIZE  (4 * 1024)
56980  
56981  /**
56982   * max size of the HTTP request header
56983 - * 
56984 + *
56985   * 32k should be enough for everything (just a guess)
56986 - * 
56987 + *
56988   */
56989  #define MAX_HTTP_REQUEST_HEADER  (32 * 1024)
56990  
56991 -typedef enum { HANDLER_UNSET, 
56992 -               HANDLER_GO_ON, 
56993 +typedef enum { HANDLER_UNSET,
56994 +               HANDLER_GO_ON,
56995                 HANDLER_FINISHED,
56996 -               HANDLER_COMEBACK, 
56997 -               HANDLER_WAIT_FOR_EVENT, 
56998 +               HANDLER_COMEBACK,
56999 +               HANDLER_WAIT_FOR_EVENT,
57000                 HANDLER_ERROR,
57001                 HANDLER_WAIT_FOR_FD
57002  } handler_t;
57003 --- ../lighttpd-1.4.11/src/spawn-fcgi.c 2006-03-07 14:18:10.000000000 +0200
57004 +++ lighttpd-1.5.0/src/spawn-fcgi.c     2006-07-16 00:26:04.000000000 +0300
57005 @@ -1,19 +1,16 @@
57006  #include <sys/types.h>
57007 -#include <sys/time.h>
57008  #include <sys/stat.h>
57009  
57010  #include <stdlib.h>
57011  #include <string.h>
57012  #include <errno.h>
57013  #include <stdio.h>
57014 -#include <unistd.h>
57015  #include <fcntl.h>
57016 -
57017 +#include <time.h>
57018  #ifdef HAVE_CONFIG_H
57019  #include "config.h"
57020  #endif
57021  
57022 -
57023  #ifdef HAVE_PWD_H
57024  #include <grp.h>
57025  #include <pwd.h>
57026 @@ -30,6 +27,7 @@
57027  #endif
57028  
57029  #include "sys-socket.h"
57030 +#include "sys-files.h"
57031  
57032  #ifdef HAVE_SYS_WAIT_H
57033  #include <sys/wait.h>
57034 @@ -45,28 +43,28 @@
57035         int fcgi_fd;
57036         int socket_type, status;
57037         struct timeval tv = { 0, 100 * 1000 };
57038 -       
57039 +
57040         struct sockaddr_un fcgi_addr_un;
57041         struct sockaddr_in fcgi_addr_in;
57042         struct sockaddr *fcgi_addr;
57043 -       
57044 +
57045         socklen_t servlen;
57046 -       
57047 +
57048         if (child_count < 2) {
57049                 child_count = 5;
57050         }
57051 -       
57052 +
57053         if (child_count > 256) {
57054                 child_count = 256;
57055         }
57056 -       
57057 -       
57058 +
57059 +
57060         if (unixsocket) {
57061                 memset(&fcgi_addr, 0, sizeof(fcgi_addr));
57062 -               
57063 +
57064                 fcgi_addr_un.sun_family = AF_UNIX;
57065                 strcpy(fcgi_addr_un.sun_path, unixsocket);
57066 -               
57067 +
57068  #ifdef SUN_LEN
57069                 servlen = SUN_LEN(&fcgi_addr_un);
57070  #else
57071 @@ -84,50 +82,50 @@
57072                  }
57073                 fcgi_addr_in.sin_port = htons(port);
57074                 servlen = sizeof(fcgi_addr_in);
57075 -               
57076 +
57077                 socket_type = AF_INET;
57078                 fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
57079         }
57080 -       
57081 +
57082         if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
57083 -               fprintf(stderr, "%s.%d\n", 
57084 +               fprintf(stderr, "%s.%d\n",
57085                         __FILE__, __LINE__);
57086                 return -1;
57087         }
57088 -       
57089 +
57090         if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
57091                 /* server is not up, spawn in  */
57092                 pid_t child;
57093                 int val;
57094 -               
57095 +
57096                 if (unixsocket) unlink(unixsocket);
57097 -               
57098 +
57099                 close(fcgi_fd);
57100 -               
57101 +
57102                 /* reopen socket */
57103                 if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
57104 -                       fprintf(stderr, "%s.%d\n", 
57105 +                       fprintf(stderr, "%s.%d\n",
57106                                 __FILE__, __LINE__);
57107                         return -1;
57108                 }
57109  
57110                 val = 1;
57111                 if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
57112 -                       fprintf(stderr, "%s.%d\n", 
57113 +                       fprintf(stderr, "%s.%d\n",
57114                                 __FILE__, __LINE__);
57115                         return -1;
57116                 }
57117  
57118                 /* create socket */
57119                 if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) {
57120 -                       fprintf(stderr, "%s.%d: bind failed: %s\n", 
57121 +                       fprintf(stderr, "%s.%d: bind failed: %s\n",
57122                                 __FILE__, __LINE__,
57123                                 strerror(errno));
57124                         return -1;
57125                 }
57126 -               
57127 +
57128                 if (-1 == listen(fcgi_fd, 1024)) {
57129 -                       fprintf(stderr, "%s.%d: fd = -1\n", 
57130 +                       fprintf(stderr, "%s.%d: fd = -1\n",
57131                                 __FILE__, __LINE__);
57132                         return -1;
57133                 }
57134 @@ -137,42 +135,45 @@
57135                 } else {
57136                         child = 0;
57137                 }
57138 -               
57139 +
57140                 switch (child) {
57141                 case 0: {
57142                         char cgi_childs[64];
57143                         char *b;
57144 -                       
57145 +
57146                         int i = 0;
57147 -                       
57148 +
57149 +                       /* loose control terminal */
57150 +                       setsid();
57151 +
57152                         /* is save as we limit to 256 childs */
57153                         sprintf(cgi_childs, "PHP_FCGI_CHILDREN=%d", child_count);
57154 -                       
57155 +
57156                         if(fcgi_fd != FCGI_LISTENSOCK_FILENO) {
57157                                 close(FCGI_LISTENSOCK_FILENO);
57158                                 dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO);
57159                                 close(fcgi_fd);
57160                         }
57161 -                       
57162 +
57163                         /* we don't need the client socket */
57164                         for (i = 3; i < 256; i++) {
57165                                 close(i);
57166                         }
57167 -                       
57168 +
57169                         /* create environment */
57170 -                       
57171 +
57172                         putenv(cgi_childs);
57173 -                       
57174 +
57175                         /* fork and replace shell */
57176                         b = malloc(strlen("exec ") + strlen(appPath) + 1);
57177                         strcpy(b, "exec ");
57178                         strcat(b, appPath);
57179 -                       
57180 +
57181                         /* exec the cgi */
57182                         execl("/bin/sh", "sh", "-c", b, NULL);
57183 -                       
57184 +
57185                         exit(errno);
57186 -                       
57187 +
57188                         break;
57189                 }
57190                 case -1:
57191 @@ -180,47 +181,47 @@
57192                         break;
57193                 default:
57194                         /* father */
57195 -                       
57196 +
57197                         /* wait */
57198                         select(0, NULL, NULL, NULL, &tv);
57199 -                       
57200 +
57201                         switch (waitpid(child, &status, WNOHANG)) {
57202                         case 0:
57203 -                               fprintf(stderr, "%s.%d: child spawned successfully: PID: %d\n", 
57204 +                               fprintf(stderr, "%s.%d: child spawned successfully: PID: %d\n",
57205                                         __FILE__, __LINE__,
57206                                         child);
57207 -                               
57208 +
57209                                 /* write pid file */
57210                                 if (pid_fd != -1) {
57211                                         /* assume a 32bit pid_t */
57212                                         char pidbuf[12];
57213 -                                       
57214 +
57215                                         snprintf(pidbuf, sizeof(pidbuf) - 1, "%d", child);
57216 -                                       
57217 +
57218                                         write(pid_fd, pidbuf, strlen(pidbuf));
57219                                         close(pid_fd);
57220                                         pid_fd = -1;
57221                                 }
57222 -                               
57223 +
57224                                 break;
57225                         case -1:
57226                                 break;
57227                         default:
57228                                 if (WIFEXITED(status)) {
57229 -                                       fprintf(stderr, "%s.%d: child exited with: %d, %s\n", 
57230 +                                       fprintf(stderr, "%s.%d: child exited with: %d, %s\n",
57231                                                 __FILE__, __LINE__,
57232                                                 WEXITSTATUS(status), strerror(WEXITSTATUS(status)));
57233                                 } else if (WIFSIGNALED(status)) {
57234 -                                       fprintf(stderr, "%s.%d: child signaled: %d\n", 
57235 +                                       fprintf(stderr, "%s.%d: child signaled: %d\n",
57236                                                 __FILE__, __LINE__,
57237                                                 WTERMSIG(status));
57238                                 } else {
57239 -                                       fprintf(stderr, "%s.%d: child died somehow: %d\n", 
57240 +                                       fprintf(stderr, "%s.%d: child died somehow: %d\n",
57241                                                 __FILE__, __LINE__,
57242                                                 status);
57243                                 }
57244                         }
57245 -                               
57246 +
57247                         break;
57248                 }
57249         } else {
57250 @@ -228,16 +229,16 @@
57251                         __FILE__, __LINE__);
57252                 return -1;
57253         }
57254 -       
57255 +
57256         close(fcgi_fd);
57257 -       
57258 +
57259         return 0;
57260  }
57261  
57262  
57263  void show_version () {
57264         char *b = "spawn-fcgi" "-" PACKAGE_VERSION \
57265 -" - spawns fastcgi processes\n" 
57266 +" - spawns fastcgi processes\n"
57267  ;
57268         write(1, b, strlen(b));
57269  }
57270 @@ -265,7 +266,7 @@
57271  
57272  
57273  int main(int argc, char **argv) {
57274 -       char *fcgi_app = NULL, *changeroot = NULL, *username = NULL, 
57275 +       char *fcgi_app = NULL, *changeroot = NULL, *username = NULL,
57276                 *groupname = NULL, *unixsocket = NULL, *pid_file = NULL,
57277                  *addr = NULL;
57278         unsigned short port = 0;
57279 @@ -273,9 +274,9 @@
57280         int i_am_root, o;
57281         int pid_fd = -1;
57282         int nofork = 0;
57283 -       
57284 +
57285         i_am_root = (getuid() == 0);
57286 -       
57287 +
57288         while(-1 != (o = getopt(argc, argv, "c:f:g:hna:p:u:vC:s:P:"))) {
57289                 switch(o) {
57290                 case 'f': fcgi_app = optarg; break;
57291 @@ -290,137 +291,137 @@
57292                 case 'P': pid_file = optarg; /* PID file */ break;
57293                 case 'v': show_version(); return 0;
57294                 case 'h': show_help(); return 0;
57295 -               default: 
57296 +               default:
57297                         show_help();
57298                         return -1;
57299                 }
57300         }
57301 -       
57302 +
57303         if (fcgi_app == NULL || (port == 0 && unixsocket == NULL)) {
57304                 show_help();
57305                 return -1;
57306         }
57307 -           
57308 +
57309         if (unixsocket && port) {
57310 -               fprintf(stderr, "%s.%d: %s\n", 
57311 +               fprintf(stderr, "%s.%d: %s\n",
57312                         __FILE__, __LINE__,
57313                         "either a unix domain socket or a tcp-port, but not both\n");
57314 -               
57315 +
57316                 return -1;
57317         }
57318 -       
57319 +
57320         if (unixsocket && strlen(unixsocket) > UNIX_PATH_MAX - 1) {
57321 -               fprintf(stderr, "%s.%d: %s\n", 
57322 +               fprintf(stderr, "%s.%d: %s\n",
57323                         __FILE__, __LINE__,
57324                         "path of the unix socket is too long\n");
57325 -               
57326 +
57327                 return -1;
57328         }
57329  
57330         /* UID handling */
57331         if (!i_am_root && (geteuid() == 0 || getegid() == 0)) {
57332                 /* we are setuid-root */
57333 -               
57334 -               fprintf(stderr, "%s.%d: %s\n", 
57335 +
57336 +               fprintf(stderr, "%s.%d: %s\n",
57337                         __FILE__, __LINE__,
57338                         "Are you nuts ? Don't apply a SUID bit to this binary\n");
57339 -               
57340 +
57341                 return -1;
57342         }
57343 -       
57344 -       if (pid_file && 
57345 +
57346 +       if (pid_file &&
57347             (-1 == (pid_fd = open(pid_file, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)))) {
57348                 struct stat st;
57349                 if (errno != EEXIST) {
57350 -                       fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n", 
57351 +                       fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n",
57352                                 __FILE__, __LINE__,
57353                                 pid_file, strerror(errno));
57354 -                       
57355 +
57356                         return -1;
57357                 }
57358 -               
57359 +
57360                 /* ok, file exists */
57361 -               
57362 +
57363                 if (0 != stat(pid_file, &st)) {
57364 -                       fprintf(stderr, "%s.%d: stating pid-file '%s' failed: %s\n", 
57365 +                       fprintf(stderr, "%s.%d: stating pid-file '%s' failed: %s\n",
57366                                 __FILE__, __LINE__,
57367                                 pid_file, strerror(errno));
57368 -                       
57369 +
57370                         return -1;
57371                 }
57372 -               
57373 +
57374                 /* is it a regular file ? */
57375 -               
57376 +
57377                 if (!S_ISREG(st.st_mode)) {
57378 -                       fprintf(stderr, "%s.%d: pid-file exists and isn't regular file: '%s'\n", 
57379 +                       fprintf(stderr, "%s.%d: pid-file exists and isn't regular file: '%s'\n",
57380                                 __FILE__, __LINE__,
57381                                 pid_file);
57382 -                       
57383 +
57384                         return -1;
57385                 }
57386 -               
57387 +
57388                 if (-1 == (pid_fd = open(pid_file, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
57389 -                       fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n", 
57390 +                       fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n",
57391                                 __FILE__, __LINE__,
57392                                 pid_file, strerror(errno));
57393 -                       
57394 +
57395                         return -1;
57396                 }
57397         }
57398 -       
57399 +
57400         if (i_am_root) {
57401                 struct group *grp = NULL;
57402                 struct passwd *pwd = NULL;
57403 -               
57404 +
57405                 /* set user and group */
57406 -               
57407 +
57408                 if (username) {
57409                         if (NULL == (pwd = getpwnam(username))) {
57410 -                               fprintf(stderr, "%s.%d: %s, %s\n", 
57411 +                               fprintf(stderr, "%s.%d: %s, %s\n",
57412                                         __FILE__, __LINE__,
57413                                         "can't find username", username);
57414                                 return -1;
57415                         }
57416 -                       
57417 +
57418                         if (pwd->pw_uid == 0) {
57419 -                               fprintf(stderr, "%s.%d: %s\n", 
57420 +                               fprintf(stderr, "%s.%d: %s\n",
57421                                         __FILE__, __LINE__,
57422                                         "I will not set uid to 0\n");
57423                                 return -1;
57424                         }
57425                 }
57426 -               
57427 +
57428                 if (groupname) {
57429                         if (NULL == (grp = getgrnam(groupname))) {
57430 -                               fprintf(stderr, "%s.%d: %s %s\n", 
57431 +                               fprintf(stderr, "%s.%d: %s %s\n",
57432                                         __FILE__, __LINE__,
57433 -                                       "can't find groupname", 
57434 +                                       "can't find groupname",
57435                                         groupname);
57436                                 return -1;
57437                         }
57438                         if (grp->gr_gid == 0) {
57439 -                               fprintf(stderr, "%s.%d: %s\n", 
57440 +                               fprintf(stderr, "%s.%d: %s\n",
57441                                         __FILE__, __LINE__,
57442                                         "I will not set gid to 0\n");
57443                                 return -1;
57444                         }
57445                 }
57446 -               
57447 +
57448                 if (changeroot) {
57449                         if (-1 == chroot(changeroot)) {
57450 -                               fprintf(stderr, "%s.%d: %s %s\n", 
57451 +                               fprintf(stderr, "%s.%d: %s %s\n",
57452                                         __FILE__, __LINE__,
57453                                         "chroot failed: ", strerror(errno));
57454                                 return -1;
57455                         }
57456                         if (-1 == chdir("/")) {
57457 -                               fprintf(stderr, "%s.%d: %s %s\n", 
57458 +                               fprintf(stderr, "%s.%d: %s %s\n",
57459                                         __FILE__, __LINE__,
57460                                         "chdir failed: ", strerror(errno));
57461                                 return -1;
57462                         }
57463                 }
57464 -               
57465 +
57466                 /* drop root privs */
57467                 if (groupname) {
57468                         setgid(grp->gr_gid);
57469 @@ -428,7 +429,7 @@
57470                 }
57471                 if (username) setuid(pwd->pw_uid);
57472         }
57473 -       
57474 +
57475         return fcgi_spawn_connection(fcgi_app, addr, port, unixsocket, child_count, pid_fd, nofork);
57476  }
57477  #else
57478 --- ../lighttpd-1.4.11/src/splaytree.c  2005-09-12 21:51:28.000000000 +0300
57479 +++ lighttpd-1.5.0/src/splaytree.c      2006-07-16 00:26:03.000000000 +0300
57480 @@ -56,19 +56,19 @@
57481  
57482  #define node_size splaytree_size
57483  
57484 -/* Splay using the key i (which may or may not be in the tree.) 
57485 - * The starting root is t, and the tree used is defined by rat 
57486 +/* Splay using the key i (which may or may not be in the tree.)
57487 + * The starting root is t, and the tree used is defined by rat
57488   * size fields are maintained */
57489  splay_tree * splaytree_splay (splay_tree *t, int i) {
57490      splay_tree N, *l, *r, *y;
57491      int comp, root_size, l_size, r_size;
57492 -    
57493 +
57494      if (t == NULL) return t;
57495      N.left = N.right = NULL;
57496      l = r = &N;
57497      root_size = node_size(t);
57498      l_size = r_size = 0;
57499
57500 +
57501      for (;;) {
57502          comp = compare(i, t->key);
57503          if (comp < 0) {
57504 @@ -120,7 +120,7 @@
57505          y->size = r_size;
57506          r_size -= 1+node_size(y->right);
57507      }
57508
57509 +
57510      l->right = t->left;                                /* assemble */
57511      r->left = t->right;
57512      t->left = N.right;
57513 --- ../lighttpd-1.4.11/src/splaytree.h  2005-09-12 21:51:13.000000000 +0300
57514 +++ lighttpd-1.5.0/src/splaytree.h      2006-07-16 00:26:03.000000000 +0300
57515 @@ -19,6 +19,6 @@
57516  /* This macro returns the size of a node.  Unlike "x->size",     */
57517  /* it works even if x=NULL.  The test could be avoided by using  */
57518  /* a special version of NULL which was a real node with size 0.  */
57519
57520 +
57521  
57522  #endif
57523 --- ../lighttpd-1.4.11/src/stat_cache.c 2005-11-22 15:23:51.000000000 +0200
57524 +++ lighttpd-1.5.0/src/stat_cache.c     2006-09-07 00:57:05.000000000 +0300
57525 @@ -6,7 +6,6 @@
57526  #include <stdlib.h>
57527  #include <string.h>
57528  #include <errno.h>
57529 -#include <unistd.h>
57530  #include <stdio.h>
57531  #include <fcntl.h>
57532  #include <assert.h>
57533 @@ -25,19 +24,8 @@
57534  #endif
57535  
57536  #include "sys-mmap.h"
57537 -
57538 -/* NetBSD 1.3.x needs it */
57539 -#ifndef MAP_FAILED
57540 -# define MAP_FAILED -1
57541 -#endif
57542 -
57543 -#ifndef O_LARGEFILE
57544 -# define O_LARGEFILE 0
57545 -#endif
57546 -
57547 -#ifndef HAVE_LSTAT
57548 -#define lstat stat
57549 -#endif
57550 +#include "sys-files.h"
57551 +#include "sys-strings.h"
57552  
57553  #if 0
57554  /* enables debug code for testing if all nodes in the stat-cache as accessable */
57555 @@ -52,8 +40,8 @@
57556   *
57557   * if we get a change-event from FAM, we increment the version in the FAM->dir mapping
57558   *
57559 - * if the stat()-cache is queried we check if the version id for the directory is the 
57560 - * same and return immediatly. 
57561 + * if the stat()-cache is queried we check if the version id for the directory is the
57562 + * same and return immediatly.
57563   *
57564   *
57565   * What we need:
57566 @@ -62,17 +50,17 @@
57567   * - for each FAMRequest we have to find the version in the directory cache (index as userdata)
57568   *
57569   * stat <<-> directory <-> FAMRequest
57570 - * 
57571 - * if file is deleted, directory is dirty, file is rechecked ... 
57572 + *
57573 + * if file is deleted, directory is dirty, file is rechecked ...
57574   * if directory is deleted, directory mapping is removed
57575 - *  
57576 + *
57577   * */
57578  
57579  #ifdef HAVE_FAM_H
57580  typedef struct {
57581         FAMRequest *req;
57582         FAMConnection *fc;
57583 -       
57584 +
57585         buffer *name;
57586  
57587         int version;
57588 @@ -83,16 +71,16 @@
57589   * - we need a hash
57590   * - the hash-key is used as sorting criteria for a tree
57591   * - a splay-tree is used as we can use the caching effect of it
57592 - */ 
57593 + */
57594  
57595  /* we want to cleanup the stat-cache every few seconds, let's say 10
57596   *
57597   * - remove entries which are outdated since 30s
57598   * - remove entries which are fresh but havn't been used since 60s
57599   * - if we don't have a stat-cache entry for a directory, release it from the monitor
57600 - */ 
57601 + */
57602  
57603 -#ifdef DEBUG_STAT_CACHE        
57604 +#ifdef DEBUG_STAT_CACHE
57605  typedef struct {
57606         int *ptr;
57607  
57608 @@ -105,15 +93,16 @@
57609  
57610  stat_cache *stat_cache_init(void) {
57611         stat_cache *fc = NULL;
57612 -       
57613 +
57614         fc = calloc(1, sizeof(*fc));
57615 -       
57616 +
57617         fc->dir_name = buffer_init();
57618  #ifdef HAVE_FAM_H
57619         fc->fam = calloc(1, sizeof(*fc->fam));
57620 +       fc->sock = iosocket_init();
57621  #endif
57622  
57623 -#ifdef DEBUG_STAT_CACHE        
57624 +#ifdef DEBUG_STAT_CACHE
57625         ctrl.size = 0;
57626  #endif
57627  
57628 @@ -122,24 +111,24 @@
57629  
57630  static stat_cache_entry * stat_cache_entry_init(void) {
57631         stat_cache_entry *sce = NULL;
57632 -       
57633 +
57634         sce = calloc(1, sizeof(*sce));
57635 -       
57636 +
57637         sce->name = buffer_init();
57638         sce->etag = buffer_init();
57639         sce->content_type = buffer_init();
57640 -       
57641 +
57642         return sce;
57643  }
57644  
57645  static void stat_cache_entry_free(void *data) {
57646         stat_cache_entry *sce = data;
57647         if (!sce) return;
57648 -       
57649 +
57650         buffer_free(sce->etag);
57651         buffer_free(sce->name);
57652         buffer_free(sce->content_type);
57653 -       
57654 +
57655         free(sce);
57656  }
57657  
57658 @@ -148,22 +137,22 @@
57659         fam_dir_entry *fam_dir = NULL;
57660  
57661         fam_dir = calloc(1, sizeof(*fam_dir));
57662 -       
57663 +
57664         fam_dir->name = buffer_init();
57665 -       
57666 +
57667         return fam_dir;
57668  }
57669  
57670  static void fam_dir_entry_free(void *data) {
57671         fam_dir_entry *fam_dir = data;
57672 -       
57673 +
57674         if (!fam_dir) return;
57675 -       
57676 +
57677         FAMCancelMonitor(fam_dir->fc, fam_dir->req);
57678 -       
57679 +
57680         buffer_free(fam_dir->name);
57681         free(fam_dir->req);
57682 -       
57683 +
57684         free(fam_dir);
57685  }
57686  #endif
57687 @@ -174,7 +163,7 @@
57688                 splay_tree *node = sc->files;
57689  
57690                 osize = sc->files->size;
57691 -                       
57692 +
57693                 stat_cache_entry_free(node->data);
57694                 sc->files = splaytree_delete(sc->files, node->key);
57695  
57696 @@ -187,12 +176,12 @@
57697         while (sc->dirs) {
57698                 int osize;
57699                 splay_tree *node = sc->dirs;
57700 -               
57701 +
57702                 osize = sc->dirs->size;
57703  
57704                 fam_dir_entry_free(node->data);
57705                 sc->dirs = splaytree_delete(sc->dirs, node->key);
57706 -               
57707 +
57708                 if (osize == 1) {
57709                         assert(NULL == sc->dirs);
57710                 } else {
57711 @@ -202,6 +191,7 @@
57712  
57713         if (sc->fam) {
57714                 FAMClose(sc->fam);
57715 +               iosocket_free(sc->sock);
57716                 free(sc->fam);
57717         }
57718  #endif
57719 @@ -212,7 +202,7 @@
57720  static int stat_cache_attr_get(buffer *buf, char *name) {
57721         int attrlen;
57722         int ret;
57723 -       
57724 +
57725         attrlen = 1024;
57726         buffer_prepare_copy(buf, attrlen);
57727         attrlen--;
57728 @@ -251,15 +241,15 @@
57729             sc->fam) {
57730  
57731                 events = FAMPending(sc->fam);
57732 -       
57733 +
57734                 for (i = 0; i < events; i++) {
57735                         FAMEvent fe;
57736                         fam_dir_entry *fam_dir;
57737                         splay_tree *node;
57738                         int ndx;
57739 -               
57740 +
57741                         FAMNextEvent(sc->fam, &fe);
57742 -       
57743 +
57744                         /* handle event */
57745  
57746                         switch(fe.code) {
57747 @@ -280,7 +270,7 @@
57748  
57749                                 sc->dirs = splaytree_splay(sc->dirs, ndx);
57750                                 node = sc->dirs;
57751 -                       
57752 +
57753                                 if (node && (node->key == ndx)) {
57754                                         int osize = splaytree_size(sc->dirs);
57755  
57756 @@ -298,17 +288,15 @@
57757  
57758         if (revent & FDEVENT_HUP) {
57759                 /* fam closed the connection */
57760 -               srv->stat_cache->fam_fcce_ndx = -1;
57761 -
57762 -               fdevent_event_del(srv->ev, &(sc->fam_fcce_ndx), FAMCONNECTION_GETFD(sc->fam));
57763 -               fdevent_unregister(srv->ev, FAMCONNECTION_GETFD(sc->fam));
57764 +               fdevent_event_del(srv->ev, sc->sock);
57765 +               fdevent_unregister(srv->ev, sc->sock);
57766  
57767                 FAMClose(sc->fam);
57768                 free(sc->fam);
57769  
57770                 sc->fam = NULL;
57771         }
57772 -       
57773 +
57774         return HANDLER_GO_ON;
57775  }
57776  
57777 @@ -328,11 +316,25 @@
57778  }
57779  #endif
57780  
57781 +#ifdef HAVE_LSTAT
57782 +static int stat_cache_lstat(server *srv, char *dname, struct stat *lst) {
57783 +       if (lstat(dname, lst) == 0) {
57784 +               return S_ISLNK(lst->st_mode) ? 0 : 1;
57785 +       }
57786 +       else {
57787 +               log_error_write(srv, __FILE__, __LINE__, "sss",
57788 +                               "lstat failed for:",
57789 +                               dname, strerror(errno));
57790 +       };
57791 +       return -1;
57792 +}
57793 +#endif
57794 +
57795  /***
57796   *
57797   *
57798   *
57799 - * returns: 
57800 + * returns:
57801   *  - HANDLER_FINISHED on cache-miss (don't forget to reopen the file)
57802   *  - HANDLER_ERROR on stat() failed -> see errno for problem
57803   */
57804 @@ -348,16 +350,16 @@
57805         struct stat st;
57806         size_t k;
57807         int fd;
57808 -#ifdef DEBUG_STAT_CACHE        
57809 +#ifdef DEBUG_STAT_CACHE
57810         size_t i;
57811  #endif
57812  
57813         int file_ndx;
57814         splay_tree *file_node = NULL;
57815  
57816 -       *ret_sce = NULL; 
57817 +       *ret_sce = NULL;
57818  
57819 -       /* 
57820 +       /*
57821          * check if the directory for this file has changed
57822          */
57823  
57824 @@ -366,23 +368,23 @@
57825         file_ndx = hashme(name);
57826         sc->files = splaytree_splay(sc->files, file_ndx);
57827  
57828 -#ifdef DEBUG_STAT_CACHE        
57829 +#ifdef DEBUG_STAT_CACHE
57830         for (i = 0; i < ctrl.used; i++) {
57831                 if (ctrl.ptr[i] == file_ndx) break;
57832         }
57833  #endif
57834  
57835         if (sc->files && (sc->files->key == file_ndx)) {
57836 -#ifdef DEBUG_STAT_CACHE        
57837 +#ifdef DEBUG_STAT_CACHE
57838                 /* it was in the cache */
57839                 assert(i < ctrl.used);
57840  #endif
57841 -               
57842 -               /* we have seen this file already and 
57843 +
57844 +               /* we have seen this file already and
57845                  * don't stat() it again in the same second */
57846  
57847                 file_node = sc->files;
57848 -               
57849 +
57850                 sce = file_node->data;
57851  
57852                 /* check if the name is the same, we might have a collision */
57853 @@ -390,7 +392,7 @@
57854                 if (buffer_is_equal(name, sce->name)) {
57855                         if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_SIMPLE) {
57856                                 if (sce->stat_ts == srv->cur_ts) {
57857 -                                       *ret_sce = sce; 
57858 +                                       *ret_sce = sce;
57859                                         return HANDLER_GO_ON;
57860                                 }
57861                         }
57862 @@ -400,15 +402,15 @@
57863                          * file_node is used by the FAM check below to see if we know this file
57864                          * and if we can save a stat().
57865                          *
57866 -                        * BUT, the sce is not reset here as the entry into the cache is ok, we 
57867 +                        * BUT, the sce is not reset here as the entry into the cache is ok, we
57868                          * it is just not pointing to our requested file.
57869 -                        * 
57870 +                        *
57871                          *  */
57872  
57873                         file_node = NULL;
57874                 }
57875         } else {
57876 -#ifdef DEBUG_STAT_CACHE        
57877 +#ifdef DEBUG_STAT_CACHE
57878                 if (i != ctrl.used) {
57879                         fprintf(stderr, "%s.%d: %08x was already inserted but not found in cache, %s\n", __FILE__, __LINE__, file_ndx, name->ptr);
57880                 }
57881 @@ -424,23 +426,23 @@
57882                 }
57883  
57884                 dir_ndx = hashme(sc->dir_name);
57885 -               
57886 +
57887                 sc->dirs = splaytree_splay(sc->dirs, dir_ndx);
57888 -               
57889 +
57890                 if (sc->dirs && (sc->dirs->key == dir_ndx)) {
57891                         dir_node = sc->dirs;
57892                 }
57893 -               
57894 +
57895                 if (dir_node && file_node) {
57896                         /* we found a file */
57897 -                       
57898 +
57899                         sce = file_node->data;
57900                         fam_dir = dir_node->data;
57901 -                       
57902 +
57903                         if (fam_dir->version == sce->dir_version) {
57904                                 /* the stat()-cache entry is still ok */
57905 -                               
57906 -                               *ret_sce = sce; 
57907 +
57908 +                               *ret_sce = sce;
57909                                 return HANDLER_GO_ON;
57910                         }
57911                 }
57912 @@ -448,12 +450,11 @@
57913  #endif
57914  
57915         /*
57916 -        * *lol* 
57917 +        * *lol*
57918          * - open() + fstat() on a named-pipe results in a (intended) hang.
57919 -        * - stat() if regualar file + open() to see if we can read from it is better
57920 +        * - stat() if regular file + open() to see if we can read from it is better
57921          *
57922          * */
57923 -
57924         if (-1 == stat(name->ptr, &st)) {
57925                 return HANDLER_ERROR;
57926         }
57927 @@ -469,16 +470,16 @@
57928  
57929         if (NULL == sce) {
57930                 int osize = 0;
57931 -                      
57932 +
57933                 if (sc->files) {
57934                         osize = sc->files->size;
57935                 }
57936  
57937                 sce = stat_cache_entry_init();
57938                 buffer_copy_string_buffer(sce->name, name);
57939 -               
57940 -               sc->files = splaytree_insert(sc->files, file_ndx, sce); 
57941 -#ifdef DEBUG_STAT_CACHE        
57942 +
57943 +               sc->files = splaytree_insert(sc->files, file_ndx, sce);
57944 +#ifdef DEBUG_STAT_CACHE
57945                 if (ctrl.size == 0) {
57946                         ctrl.size = 16;
57947                         ctrl.used = 0;
57948 @@ -499,29 +500,70 @@
57949         sce->st = st;
57950         sce->stat_ts = srv->cur_ts;
57951  
57952 -       /* catch the obvious symlinks 
57953 +       /* catch the obvious symlinks
57954          *
57955          * this is not a secure check as we still have a race-condition between
57956 -        * the stat() and the open. We can only solve this by 
57957 +        * the stat() and the open. We can only solve this by
57958          * 1. open() the file
57959          * 2. fstat() the fd
57960          *
57961          * and keeping the file open for the rest of the time. But this can
57962          * only be done at network level.
57963 -        * 
57964 -        * */
57965 -       if (S_ISLNK(st.st_mode) && !con->conf.follow_symlink) {
57966 -               return HANDLER_ERROR;
57967 -       }
57968 +        *
57969 +        * per default it is not a symlink
57970 +        **/
57971 +#ifdef HAVE_LSTAT
57972 +       sce->is_symlink = 0;
57973 +       struct stat lst;
57974 +       if (stat_cache_lstat(srv, name->ptr, &lst)  == 0) {
57975 +#ifdef DEBUG_STAT_CACHE
57976 +                       log_error_write(srv, __FILE__, __LINE__, "sb",
57977 +                                       "found symlink", name);
57978 +#endif
57979 +                       sce->is_symlink = 1;
57980 +               }
57981  
57982 -       if (S_ISREG(st.st_mode)) {      
57983 +       /*
57984 +        * we assume "/" can not be symlink, so
57985 +        * skip the symlink stuff if our path is /
57986 +        **/
57987 +       else if ((name->used > 2)) {
57988 +               char *dname, *s_cur;
57989 +
57990 +               dname = strndup(name->ptr, name->used);
57991 +               while ((s_cur = strrchr(dname,'/'))) {
57992 +                       *s_cur = '\0';
57993 +                       if (dname == s_cur) {
57994 +#ifdef DEBUG_STAT_CACHE
57995 +                               log_error_write(srv, __FILE__, __LINE__, "s", "reached /");
57996 +#endif
57997 +                               break;
57998 +                       }
57999 +#ifdef DEBUG_STAT_CACHE
58000 +                       log_error_write(srv, __FILE__, __LINE__, "sss",
58001 +                                       "checking if", dname, "is a symlink");
58002 +#endif
58003 +                       if (stat_cache_lstat(srv, dname, &lst)  == 0) {
58004 +                               sce->is_symlink = 1;
58005 +#ifdef DEBUG_STAT_CACHE
58006 +                               log_error_write(srv, __FILE__, __LINE__, "ss",
58007 +                                               "found symlink", dname);
58008 +#endif
58009 +                               break;
58010 +                       };
58011 +               };
58012 +               free(dname);
58013 +       };
58014 +#endif
58015 +
58016 +       if (S_ISREG(st.st_mode)) {
58017                 /* determine mimetype */
58018                 buffer_reset(sce->content_type);
58019 -               
58020 +
58021                 for (k = 0; k < con->conf.mimetypes->used; k++) {
58022                         data_string *ds = (data_string *)con->conf.mimetypes->data[k];
58023                         buffer *type = ds->key;
58024 -               
58025 +
58026                         if (type->used == 0) continue;
58027  
58028                         /* check if the right side is the same */
58029 @@ -538,8 +580,10 @@
58030                         stat_cache_attr_get(sce->content_type, name->ptr);
58031                 }
58032  #endif
58033 +       } else if (S_ISDIR(st.st_mode)) {
58034 +               etag_create(sce->etag, &(sce->st));
58035         }
58036 -               
58037 +
58038  #ifdef HAVE_FAM_H
58039         if (sc->fam &&
58040             (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM)) {
58041 @@ -549,19 +593,19 @@
58042                         fam_dir->fc = sc->fam;
58043  
58044                         buffer_copy_string_buffer(fam_dir->name, sc->dir_name);
58045 -                       
58046 +
58047                         fam_dir->version = 1;
58048 -                       
58049 +
58050                         fam_dir->req = calloc(1, sizeof(FAMRequest));
58051 -                       
58052 -                       if (0 != FAMMonitorDirectory(sc->fam, fam_dir->name->ptr, 
58053 +
58054 +                       if (0 != FAMMonitorDirectory(sc->fam, fam_dir->name->ptr,
58055                                                      fam_dir->req, fam_dir)) {
58056 -                               
58057 -                               log_error_write(srv, __FILE__, __LINE__, "sbs", 
58058 -                                               "monitoring dir failed:", 
58059 -                                               fam_dir->name, 
58060 +
58061 +                               log_error_write(srv, __FILE__, __LINE__, "sbs",
58062 +                                               "monitoring dir failed:",
58063 +                                               fam_dir->name,
58064                                                 FamErrlist[FAMErrno]);
58065 -                               
58066 +
58067                                 fam_dir_entry_free(fam_dir);
58068                         } else {
58069                                 int osize = 0;
58070 @@ -570,7 +614,7 @@
58071                                         osize = sc->dirs->size;
58072                                 }
58073  
58074 -                               sc->dirs = splaytree_insert(sc->dirs, dir_ndx, fam_dir); 
58075 +                               sc->dirs = splaytree_insert(sc->dirs, dir_ndx, fam_dir);
58076                                 assert(sc->dirs);
58077                                 assert(sc->dirs->data == fam_dir);
58078                                 assert(osize == (sc->dirs->size - 1));
58079 @@ -578,9 +622,9 @@
58080                 } else {
58081                         fam_dir = dir_node->data;
58082                 }
58083 -               
58084 +
58085                 /* bind the fam_fc to the stat() cache entry */
58086 -                       
58087 +
58088                 if (fam_dir) {
58089                         sce->dir_version = fam_dir->version;
58090                         sce->dir_ndx     = dir_ndx;
58091 @@ -594,11 +638,11 @@
58092  }
58093  
58094  /**
58095 - * remove stat() from cache which havn't been stat()ed for 
58096 + * remove stat() from cache which havn't been stat()ed for
58097   * more than 10 seconds
58098 - * 
58099   *
58100 - * walk though the stat-cache, collect the ids which are too old 
58101 + *
58102 + * walk though the stat-cache, collect the ids which are too old
58103   * and remove them in a second loop
58104   */
58105  
58106 @@ -639,9 +683,9 @@
58107                 sc->files = splaytree_splay(sc->files, ndx);
58108  
58109                 node = sc->files;
58110 -               
58111 +
58112                 if (node && (node->key == ndx)) {
58113 -#ifdef DEBUG_STAT_CACHE        
58114 +#ifdef DEBUG_STAT_CACHE
58115                         size_t j;
58116                         int osize = splaytree_size(sc->files);
58117                         stat_cache_entry *sce = node->data;
58118 @@ -649,7 +693,7 @@
58119                         stat_cache_entry_free(node->data);
58120                         sc->files = splaytree_delete(sc->files, ndx);
58121  
58122 -#ifdef DEBUG_STAT_CACHE        
58123 +#ifdef DEBUG_STAT_CACHE
58124                         for (j = 0; j < ctrl.used; j++) {
58125                                 if (ctrl.ptr[j] == ndx) {
58126                                         ctrl.ptr[j] = ctrl.ptr[--ctrl.used];
58127 --- ../lighttpd-1.4.11/src/status_counter.c     1970-01-01 03:00:00.000000000 +0300
58128 +++ lighttpd-1.5.0/src/status_counter.c 2006-07-19 20:02:55.000000000 +0300
58129 @@ -0,0 +1,75 @@
58130 +#include <stdlib.h>
58131 +
58132 +#include "status_counter.h"
58133 +/**
58134 + * The status array can carry all the status information you want
58135 + * the key to the array is <module-prefix>.<name>
58136 + * and the values are counters
58137 + *
58138 + * example:
58139 + *   fastcgi.backends        = 10
58140 + *   fastcgi.active-backends = 6
58141 + *   fastcgi.backend.<key>.load = 24
58142 + *   fastcgi.backend.<key>....
58143 + *
58144 + *   fastcgi.backend.<key>.disconnects = ...
58145 + */
58146 +
58147 +static array *counters = NULL;
58148 +
58149 +void status_counter_init(void) {
58150 +       counters = array_init();
58151 +}
58152 +void status_counter_free(void) {
58153 +       array_free(counters);
58154 +}
58155 +
58156 +array *status_counter_get_array(void) {
58157 +       return counters;
58158 +}
58159 +
58160 +data_integer *status_counter_get_counter(const char *s, size_t len) {
58161 +       data_integer *di;
58162 +       array *status = status_counter_get_array();
58163 +
58164 +       if (NULL == (di = (data_integer *)array_get_element(status, s))) {
58165 +               /* not found, create it */
58166 +
58167 +               if (NULL == (di = (data_integer *)array_get_unused_element(status, TYPE_INTEGER))) {
58168 +                       di = data_integer_init();
58169 +               }
58170 +               buffer_copy_string_len(di->key, s, len);
58171 +               di->value = 0;
58172 +
58173 +               array_insert_unique(status, (data_unset *)di);
58174 +       }
58175 +       return di;
58176 +}
58177 +
58178 +/* dummies of the statistic framework functions
58179 + * they will be moved to a statistics.c later */
58180 +int status_counter_inc(const char *s, size_t len) {
58181 +       data_integer *di = status_counter_get_counter(s, len);
58182 +
58183 +       di->value++;
58184 +
58185 +       return 0;
58186 +}
58187 +
58188 +int status_counter_dec(const char *s, size_t len) {
58189 +       data_integer *di = status_counter_get_counter(s, len);
58190 +
58191 +       if (di->value > 0) di->value--;
58192 +
58193 +       return 0;
58194 +}
58195 +
58196 +int status_counter_set(const char *s, size_t len, int val) {
58197 +       data_integer *di = status_counter_get_counter(s, len);
58198 +
58199 +       di->value = val;
58200 +
58201 +       return 0;
58202 +}
58203 +
58204 +
58205 --- ../lighttpd-1.4.11/src/status_counter.h     1970-01-01 03:00:00.000000000 +0300
58206 +++ lighttpd-1.5.0/src/status_counter.h 2006-07-19 20:02:55.000000000 +0300
58207 @@ -0,0 +1,16 @@
58208 +#ifndef _STATUS_COUNTER_H_
58209 +#define _STATUS_COUNTER_H_
58210 +
58211 +#include <sys/types.h>
58212 +
58213 +#include "array.h"
58214 +
58215 +void status_counter_init(void);
58216 +void status_counter_free(void);
58217 +array *status_counter_get_array(void);
58218 +data_integer *status_counter_get_counter(const char *s, size_t len);
58219 +int status_counter_inc(const char *s, size_t len);
58220 +int status_counter_dec(const char *s, size_t len);
58221 +int status_counter_set(const char *s, size_t len, int val);
58222 +
58223 +#endif 
58224 --- ../lighttpd-1.4.11/src/stream.c     2005-09-23 21:50:15.000000000 +0300
58225 +++ lighttpd-1.5.0/src/stream.c 2006-07-16 00:26:04.000000000 +0300
58226 @@ -1,7 +1,6 @@
58227  #include <sys/types.h>
58228  #include <sys/stat.h>
58229  
58230 -#include <unistd.h> 
58231  #include <fcntl.h>
58232  
58233  #include "stream.h"
58234 @@ -10,6 +9,7 @@
58235  #endif
58236  
58237  #include "sys-mmap.h"
58238 +#include "sys-files.h"
58239  
58240  #ifndef O_BINARY
58241  # define O_BINARY 0
58242 @@ -19,39 +19,39 @@
58243         struct stat st;
58244  #ifdef HAVE_MMAP
58245         int fd;
58246 -#elif defined __WIN32
58247 +#elif defined _WIN32
58248         HANDLE *fh, *mh;
58249         void *p;
58250  #endif
58251  
58252         f->start = NULL;
58253 -       
58254 +
58255         if (-1 == stat(fn->ptr, &st)) {
58256                 return -1;
58257         }
58258 -       
58259 +
58260         f->size = st.st_size;
58261  
58262  #ifdef HAVE_MMAP
58263         if (-1 == (fd = open(fn->ptr, O_RDONLY | O_BINARY))) {
58264                 return -1;
58265         }
58266 -       
58267 +
58268         f->start = mmap(0, f->size, PROT_READ, MAP_SHARED, fd, 0);
58269 -       
58270 +
58271         close(fd);
58272 -       
58273 +
58274         if (MAP_FAILED == f->start) {
58275                 return -1;
58276         }
58277  
58278 -#elif defined __WIN32
58279 -       fh = CreateFile(fn->ptr, 
58280 -                       GENERIC_READ, 
58281 -                       FILE_SHARE_READ, 
58282 -                       NULL, 
58283 -                       OPEN_EXISTING, 
58284 -                       FILE_ATTRIBUTE_READONLY, 
58285 +#elif defined _WIN32
58286 +       fh = CreateFile(fn->ptr,
58287 +                       GENERIC_READ,
58288 +                       FILE_SHARE_READ,
58289 +                       NULL,
58290 +                       OPEN_EXISTING,
58291 +                       FILE_ATTRIBUTE_READONLY,
58292                         NULL);
58293  
58294         if (!fh) return -1;
58295 @@ -66,7 +66,7 @@
58296         if (!mh) {
58297                 LPVOID lpMsgBuf;
58298                 FormatMessage(
58299 -                       FORMAT_MESSAGE_ALLOCATE_BUFFER | 
58300 +                       FORMAT_MESSAGE_ALLOCATE_BUFFER |
58301                         FORMAT_MESSAGE_FROM_SYSTEM,
58302                         NULL,
58303                         GetLastError(),
58304 @@ -76,7 +76,7 @@
58305  
58306                 return -1;
58307         }
58308 -       
58309 +
58310         p = MapViewOfFile(mh,
58311                         FILE_MAP_READ,
58312                         0,
58313 @@ -87,9 +87,9 @@
58314  
58315         f->start = p;
58316  #else
58317 -# error no mmap found  
58318 +# error no mmap found
58319  #endif
58320 -       
58321 +
58322         return 0;
58323  }
58324  
58325 --- ../lighttpd-1.4.11/src/sys-files.h  1970-01-01 03:00:00.000000000 +0300
58326 +++ lighttpd-1.5.0/src/sys-files.h      2006-07-16 00:26:04.000000000 +0300
58327 @@ -0,0 +1,67 @@
58328 +#ifndef _SYS_FILES_H_
58329 +#define _SYS_FILES_H_
58330 +
58331 +#define DIR_SEPERATOR_UNIX '/'
58332 +#define DIR_SEPERATOR_WIN '\\'
58333 +
58334 +#ifdef _WIN32
58335 +#include <windows.h>
58336 +#include <io.h>     /* open */
58337 +#include <direct.h> /* chdir */
58338 +
58339 +#include "buffer.h"
58340 +
58341 +#define DIR_SEPERATOR DIR_SEPERATOR_WIN
58342 +
58343 +#define __S_ISTYPE(mode, mask)  (((mode) & _S_IFMT) == (mask))
58344 +
58345 +#define S_ISDIR(mode)    __S_ISTYPE((mode), _S_IFDIR)
58346 +#define S_ISCHR(mode)    __S_ISTYPE((mode), _S_IFCHR)
58347 +#define S_ISBLK(mode)    __S_ISTYPE((mode), _S_IFBLK)
58348 +#define S_ISREG(mode)    __S_ISTYPE((mode), _S_IFREG)
58349 +/* we don't support symlinks */
58350 +#define S_ISLNK(mode)    0
58351 +
58352 +#define lstat stat
58353 +#define mkstemp mktemp
58354 +#define mkdir(x, y) mkdir(x)
58355 +
58356 +struct dirent {
58357 +    const char *d_name;
58358 +};
58359 +
58360 +typedef struct {
58361 +    HANDLE h;
58362 +    WIN32_FIND_DATA finddata;
58363 +    struct dirent dent;
58364 +} DIR;
58365 +
58366 +DIR *opendir(const char *dn);
58367 +struct dirent *readdir(DIR *d);
58368 +void closedir(DIR *d);
58369 +
58370 +buffer *filename_unix2local(buffer *b);
58371 +buffer *pathname_unix2local(buffer *b);
58372 +
58373 +#else
58374 +#include <unistd.h>
58375 +#include <dirent.h>
58376 +
58377 +#define DIR_SEPERATOR DIR_SEPERATOR_UNIX
58378 +
58379 +#define filename_unix2local(x) (x)
58380 +#define pathname_unix2local(x) (x)
58381 +#endif
58382 +
58383 +#define PATHNAME_APPEND_SLASH(x) \
58384 +       if (x->used > 1 && x->ptr[x->used - 2] != DIR_SEPERATOR) { \
58385 +        char sl[2] = { DIR_SEPERATOR, 0 }; \
58386 +        BUFFER_APPEND_STRING_CONST(x, sl); \
58387 +    }
58388 +
58389 +#ifndef O_LARGEFILE
58390 +# define O_LARGEFILE 0
58391 +#endif
58392 +
58393 +#endif
58394 +
58395 --- ../lighttpd-1.4.11/src/sys-mmap.h   2005-08-11 01:26:34.000000000 +0300
58396 +++ lighttpd-1.5.0/src/sys-mmap.h       2006-07-16 00:26:04.000000000 +0300
58397 @@ -1,7 +1,7 @@
58398  #ifndef WIN32_MMAP_H
58399  #define WIN32_MMAP_H
58400  
58401 -#ifdef __WIN32
58402 +#ifdef _WIN32
58403  
58404  #define MAP_FAILED -1
58405  #define PROT_SHARED 0
58406 --- ../lighttpd-1.4.11/src/sys-process.h        1970-01-01 03:00:00.000000000 +0300
58407 +++ lighttpd-1.5.0/src/sys-process.h    2006-07-16 00:26:04.000000000 +0300
58408 @@ -0,0 +1,17 @@
58409 +#ifndef _SYS_PROCESS_H_
58410 +#define _SYS_PROCESS_H_
58411 +
58412 +#ifdef _WIN32
58413 +#include <process.h>
58414 +#define pid_t int
58415 +/* win32 has no fork() */
58416 +#define kill(x, y)
58417 +#define getpid() 0
58418 +
58419 +#else
58420 +#include <sys/wait.h>
58421 +#include <unistd.h>
58422 +#endif
58423 +
58424 +#endif
58425 +
58426 --- ../lighttpd-1.4.11/src/sys-socket.h 2005-08-11 01:26:39.000000000 +0300
58427 +++ lighttpd-1.5.0/src/sys-socket.h     2006-09-07 00:57:05.000000000 +0300
58428 @@ -1,16 +1,32 @@
58429  #ifndef WIN32_SOCKET_H
58430  #define WIN32_SOCKET_H
58431  
58432 -#ifdef __WIN32
58433 +#ifdef HAVE_CONFIG_H
58434 +#include "config.h"
58435 +#endif
58436 +
58437 +#ifdef _WIN32
58438  
58439  #include <winsock2.h>
58440  
58441  #define ECONNRESET WSAECONNRESET
58442  #define EINPROGRESS WSAEINPROGRESS
58443  #define EALREADY WSAEALREADY
58444 +#define ENOTCONN WSAENOTCONN
58445 +#define EWOULDBLOCK WSAEWOULDBLOCK
58446  #define ioctl ioctlsocket
58447  #define hstrerror(x) ""
58448 +#define STDIN_FILENO 0
58449 +#define STDOUT_FILENO 1
58450 +#define STDERR_FILENO 2
58451 +#define ssize_t int
58452 +
58453 +int inet_aton(const char *cp, struct in_addr *inp);
58454 +#define HAVE_INET_ADDR
58455 +#undef HAVE_INET_ATON
58456 +
58457  #else
58458 +#include <sys/types.h> /* required by netinet/tcp.h on FreeBSD */
58459  #include <sys/socket.h>
58460  #include <sys/ioctl.h>
58461  #include <netinet/in.h>
58462 @@ -18,7 +34,32 @@
58463  #include <sys/un.h>
58464  #include <arpa/inet.h>
58465  
58466 +#ifndef SUN_LEN
58467 +#define SUN_LEN(su) \
58468 +        (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
58469 +#endif
58470 +
58471 +#define closesocket(x) close(x)
58472 +
58473  #include <netdb.h>
58474 +#endif /* !_WIN32 */
58475 +
58476 +#ifdef HAVE_INET_NTOP
58477 +/* only define it if it isn't defined yet */
58478 +#ifndef HAVE_IPV6
58479 +#define HAVE_IPV6
58480 +#endif
58481 +#endif
58482 +
58483 +typedef union {
58484 +#ifdef HAVE_IPV6
58485 +       struct sockaddr_in6 ipv6;
58486 +#endif
58487 +       struct sockaddr_in ipv4;
58488 +#ifdef HAVE_SYS_UN_H
58489 +       struct sockaddr_un un;
58490  #endif
58491 +       struct sockaddr plain;
58492 +} sock_addr;
58493  
58494  #endif
58495 --- ../lighttpd-1.4.11/src/sys-strings.h        1970-01-01 03:00:00.000000000 +0300
58496 +++ lighttpd-1.5.0/src/sys-strings.h    2006-07-16 00:26:03.000000000 +0300
58497 @@ -0,0 +1,11 @@
58498 +#ifndef _SYS_STRINGS_H_
58499 +#define _SYS_STRINGS_H_
58500 +
58501 +#ifdef _WIN32
58502 +#define strcasecmp stricmp
58503 +#define strncasecmp strnicmp
58504 +#define strtoll(p, e, b) _strtoi64(p, e, b)
58505 +#endif
58506 +
58507 +#endif
58508 +
58509 --- ../lighttpd-1.4.11/tests/LightyTest.pm      2006-01-14 20:32:31.000000000 +0200
58510 +++ lighttpd-1.5.0/tests/LightyTest.pm  2006-09-07 00:57:05.000000000 +0300
58511 @@ -87,14 +87,16 @@
58512         # pre-process configfile if necessary
58513         #
58514  
58515 -       unlink($self->{TESTDIR}."/tmp/cfg.file");
58516 -       system("cat ".$self->{SRCDIR}."/".$self->{CONFIGFILE}.' | perl -pe "s#\@SRCDIR\@#'.$self->{BASEDIR}.'/tests/#" > '.$self->{TESTDIR}.'/tmp/cfg.file');
58517 +       $ENV{'SRCDIR'} = $self->{BASEDIR}.'/tests';
58518 +       $ENV{'PORT'} = $self->{PORT};
58519  
58520         unlink($self->{LIGHTTPD_PIDFILE});
58521 -       if (1) {
58522 -               system($self->{LIGHTTPD_PATH}." -f ".$self->{TESTDIR}."/tmp/cfg.file -m ".$self->{MODULES_PATH});
58523 +       if (defined $ENV{"TRACEME"} && $ENV{"TRACEME"} eq 'strace') {
58524 +               system("strace -tt -s 512 -o strace ".$self->{LIGHTTPD_PATH}." -D -f ".$self->{SRCDIR}."/".$self->{CONFIGFILE}." -m ".$self->{MODULES_PATH}." &");
58525 +       } elsif (defined $ENV{"TRACEME"} && $ENV{"TRACEME"} eq 'valgrind') {
58526 +               system("valgrind --tool=memcheck --show-reachable=yes --leak-check=yes --log-file=valgrind ".$self->{LIGHTTPD_PATH}." -D -f ".$self->{SRCDIR}."/".$self->{CONFIGFILE}." -m ".$self->{MODULES_PATH}." &");
58527         } else {
58528 -               system("valgrind --tool=memcheck --show-reachable=yes --leak-check=yes --logfile=foo ".$self->{LIGHTTPD_PATH}." -D -f ".$self->{TESTDIR}."/tmp/cfg.file -m ".$self->{MODULES_PATH}." &");
58529 +               system($self->{LIGHTTPD_PATH}." -f ".$self->{SRCDIR}."/".$self->{CONFIGFILE}." -m ".$self->{MODULES_PATH});
58530         }
58531  
58532         select(undef, undef, undef, 0.1);
58533 @@ -184,7 +186,7 @@
58534                                         (my $h = $1) =~ tr/[A-Z]/[a-z]/;
58535  
58536                                         if (defined $resp_hdr{$h}) {
58537 -                                               diag(sprintf("header %s is duplicated: %s and %s\n",
58538 +                                               diag(sprintf("header '%s' is duplicated: '%s' and '%s'\n",
58539                                                              $h, $resp_hdr{$h}, $2));
58540                                         } else {
58541                                                 $resp_hdr{$h} = $2;
58542 @@ -196,6 +198,9 @@
58543                         }
58544                 }
58545  
58546 +               $t->{etag} = $resp_hdr{'etag'};
58547 +               $t->{date} = $resp_hdr{'date'};
58548 +
58549                 # check length
58550                 if (defined $resp_hdr{"content-length"}) {
58551                         $resp_body = substr($lines, 0, $resp_hdr{"content-length"});
58552 --- ../lighttpd-1.4.11/tests/Makefile.am        2005-09-16 15:48:40.000000000 +0300
58553 +++ lighttpd-1.5.0/tests/Makefile.am    2006-07-16 00:26:05.000000000 +0300
58554 @@ -39,10 +39,18 @@
58555        mod-redirect.t \
58556        mod-userdir.t \
58557        mod-rewrite.t \
58558 +      mod-proxy.t \
58559        request.t \
58560        mod-ssi.t \
58561        LightyTest.pm \
58562 -      mod-setenv.t 
58563 +      mod-setenv.t \
58564 +      lowercase.t \
58565 +      lowercase.conf \
58566 +      proxy.conf \
58567 +      cachable.t \
58568 +      default.conf \
58569 +      proxy-backend-1.conf \
58570 +      proxy-backend-2.conf 
58571  
58572  
58573  TESTS_ENVIRONMENT=$(srcdir)/wrapper.sh $(srcdir) $(top_builddir) 
58574 --- ../lighttpd-1.4.11/tests/bug-06.conf        2005-08-27 17:44:19.000000000 +0300
58575 +++ lighttpd-1.5.0/tests/bug-06.conf    2006-07-16 00:26:04.000000000 +0300
58576 @@ -1,5 +1,5 @@
58577 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
58578 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
58579 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
58580 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
58581  
58582  ## bind to port (default: 80)
58583  server.port                 = 2048
58584 @@ -8,7 +8,7 @@
58585  
58586  ## bind to localhost (default: all interfaces)
58587  server.bind                = "localhost"
58588 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
58589 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
58590  server.name                = "www.example.org"
58591  server.tag                 = "Apache 1.3.29"
58592  
58593 @@ -59,7 +59,7 @@
58594  ######################## MODULE CONFIG ############################
58595  
58596  
58597 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
58598 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
58599  
58600  mimetype.assign             = ( ".png"  => "image/png", 
58601                                  ".jpg"  => "image/jpeg",
58602 @@ -77,7 +77,7 @@
58603                                 ".c"    => "text/plain",
58604                                 ".conf" => "text/plain" )
58605  
58606 -compress.cache-dir          = "@SRCDIR@/tmp/lighttpd/cache/compress/"
58607 +compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
58608  compress.filetype           = ("text/plain", "text/html")
58609  
58610  setenv.add-environment      = ( "TRAC_ENV" => "foo")
58611 @@ -90,7 +90,7 @@
58612                                     "host" => "127.0.0.1",
58613                                     "port" => 1026,
58614  #                                  "mode" => "authorizer",
58615 -#                                  "docroot" => "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/",
58616 +#                                  "docroot" => env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/",
58617                                   )
58618                                 )
58619                               )
58620 @@ -106,7 +106,7 @@
58621  ssl.pemfile                 = "server.pem"
58622  
58623  auth.backend                = "plain"
58624 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
58625 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
58626  auth.backend.plain.groupfile = "lighttpd.group"
58627  
58628  auth.backend.ldap.hostname  = "localhost"
58629 @@ -149,15 +149,15 @@
58630  status.config-url           = "/server-config"
58631  
58632  simple-vhost.document-root  = "pages"
58633 -simple-vhost.server-root    = "@SRCDIR@/tmp/lighttpd/servers/"
58634 +simple-vhost.server-root    = env.SRCDIR + "/tmp/lighttpd/servers/"
58635  simple-vhost.default-host   = "www.example.org"
58636  
58637  $HTTP["host"] == "vvv.example.org" {
58638 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
58639 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
58640  }
58641  
58642  $HTTP["host"] == "zzz.example.org" {
58643 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
58644 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
58645    server.name = "zzz.example.org"
58646  }
58647  
58648 --- ../lighttpd-1.4.11/tests/bug-12.conf        2005-08-27 17:44:19.000000000 +0300
58649 +++ lighttpd-1.5.0/tests/bug-12.conf    2006-07-16 00:26:04.000000000 +0300
58650 @@ -1,5 +1,5 @@
58651 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
58652 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
58653 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
58654 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
58655  
58656  ## bind to port (default: 80)
58657  server.port                 = 2048
58658 @@ -8,7 +8,7 @@
58659  
58660  ## bind to localhost (default: all interfaces)
58661  server.bind                = "localhost"
58662 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
58663 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
58664  server.name                = "www.example.org"
58665  server.tag                 = "Apache 1.3.29"
58666  
58667 @@ -61,7 +61,7 @@
58668  ######################## MODULE CONFIG ############################
58669  
58670  
58671 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
58672 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
58673  
58674  mimetype.assign             = ( ".png"  => "image/png", 
58675                                  ".jpg"  => "image/jpeg",
58676 @@ -79,7 +79,7 @@
58677                                 ".c"    => "text/plain",
58678                                 ".conf" => "text/plain" )
58679  
58680 -compress.cache-dir          = "@SRCDIR@/tmp/lighttpd/cache/compress/"
58681 +compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
58682  compress.filetype           = ("text/plain", "text/html")
58683  
58684  setenv.add-environment      = ( "TRAC_ENV" => "foo")
58685 @@ -92,7 +92,7 @@
58686                                     "host" => "127.0.0.1",
58687                                     "port" => 1026,
58688  #                                  "mode" => "authorizer",
58689 -#                                  "docroot" => "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/",
58690 +#                                  "docroot" => env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/",
58691                                   )
58692                                 )
58693                               )
58694 @@ -108,7 +108,7 @@
58695  ssl.pemfile                 = "server.pem"
58696  
58697  auth.backend                = "plain"
58698 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
58699 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
58700  auth.backend.plain.groupfile = "lighttpd.group"
58701  
58702  auth.backend.ldap.hostname  = "localhost"
58703 @@ -151,15 +151,15 @@
58704  status.config-url           = "/server-config"
58705  
58706  simple-vhost.document-root  = "pages"
58707 -simple-vhost.server-root    = "@SRCDIR@/tmp/lighttpd/servers/"
58708 +simple-vhost.server-root    = env.SRCDIR + "/tmp/lighttpd/servers/"
58709  simple-vhost.default-host   = "www.example.org"
58710  
58711  $HTTP["host"] == "vvv.example.org" {
58712 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
58713 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
58714  }
58715  
58716  $HTTP["host"] == "zzz.example.org" {
58717 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
58718 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
58719    server.name = "zzz.example.org"
58720  }
58721  
58722 --- ../lighttpd-1.4.11/tests/cachable.t 1970-01-01 03:00:00.000000000 +0300
58723 +++ lighttpd-1.5.0/tests/cachable.t     2006-07-18 13:03:40.000000000 +0300
58724 @@ -0,0 +1,112 @@
58725 +#!/usr/bin/env perl
58726 +BEGIN {
58727 +    # add current source dir to the include-path
58728 +    # we need this for make distcheck
58729 +   (my $srcdir = $0) =~ s#/[^/]+$#/#;
58730 +   unshift @INC, $srcdir;
58731 +}
58732 +
58733 +use strict;
58734 +use IO::Socket;
58735 +use Test::More tests => 12;
58736 +use LightyTest;
58737 +
58738 +my $tf = LightyTest->new();
58739 +my $t;
58740 +
58741 +$tf->{CONFIGFILE} = 'lighttpd.conf';
58742 +    
58743 +ok($tf->start_proc == 0, "Starting lighttpd") or die();
58744 +
58745 +## check if If-Modified-Since, If-None-Match works
58746 +
58747 +$t->{REQUEST}  = ( <<EOF
58748 +GET / HTTP/1.0
58749 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT
58750 +EOF
58751 + );
58752 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
58753 +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-Modified-Since');
58754 +
58755 +$t->{REQUEST}  = ( <<EOF
58756 +GET / HTTP/1.0
58757 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT; foo
58758 +EOF
58759 + );
58760 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '+Last-Modified' => ''} ];
58761 +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-Modified-Since, comment');
58762 +
58763 +my $now = $t->{date};
58764 +
58765 +$t->{REQUEST}  = ( <<EOF
58766 +GET / HTTP/1.0
58767 +If-Modified-Since: $now
58768 +EOF
58769 + );
58770 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
58771 +ok($tf->handle_http($t) == 0, 'Conditional GET - new If-Modified-Since');
58772 +
58773 +$t->{REQUEST}  = ( <<EOF
58774 +GET / HTTP/1.0
58775 +If-Modified-Since: $now; foo
58776 +EOF
58777 + );
58778 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
58779 +ok($tf->handle_http($t) == 0, 'Conditional GET - new If-Modified-Since, comment');
58780 +
58781 +$t->{REQUEST}  = ( <<EOF
58782 +GET / HTTP/1.0
58783 +If-None-Match: foo
58784 +EOF
58785 + );
58786 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '+ETag' => ''} ];
58787 +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-None-Match');
58788 +
58789 +my $etag = $t->{etag};
58790 +
58791 +$t->{REQUEST}  = ( <<EOF
58792 +GET / HTTP/1.0
58793 +If-None-Match: $etag
58794 +EOF
58795 + );
58796 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
58797 +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-None-Match');
58798 +
58799 +$t->{REQUEST}  = ( <<EOF
58800 +GET / HTTP/1.0
58801 +If-None-Match: $etag
58802 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT; foo
58803 +EOF
58804 + );
58805 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
58806 +ok($tf->handle_http($t) == 0, 'Conditional GET - ETag + old Last-Modified');
58807 +
58808 +$t->{REQUEST}  = ( <<EOF
58809 +GET / HTTP/1.0
58810 +If-None-Match: $etag
58811 +If-Modified-Since: $now; foo
58812 +EOF
58813 + );
58814 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
58815 +ok($tf->handle_http($t) == 0, 'Conditional GET - ETag, Last-Modified + comment');
58816 +
58817 +$t->{REQUEST}  = ( <<EOF
58818 +GET / HTTP/1.0
58819 +If-None-Match: Foo
58820 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT; foo
58821 +EOF
58822 + );
58823 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
58824 +ok($tf->handle_http($t) == 0, 'Conditional GET - old ETAG + old Last-Modified');
58825 +
58826 +$t->{REQUEST}  = ( <<EOF
58827 +GET / HTTP/1.0
58828 +If-None-Match: $etag
58829 +If-Modified-Since: $now foo
58830 +EOF
58831 + );
58832 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 412 } ];
58833 +ok($tf->handle_http($t) == 0, 'Conditional GET - ETag + Last-Modified + overlong timestamp');
58834 +
58835 +ok($tf->stop_proc == 0, "Stopping lighttpd");
58836 +
58837 --- ../lighttpd-1.4.11/tests/condition.conf     2005-08-27 17:44:19.000000000 +0300
58838 +++ lighttpd-1.5.0/tests/condition.conf 2006-07-16 00:26:05.000000000 +0300
58839 @@ -2,15 +2,15 @@
58840  debug.log-request-handling = "enable"
58841  debug.log-condition-handling = "enable"
58842  
58843 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
58844 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
58845 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
58846 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
58847  
58848  ## bind to port (default: 80)
58849  server.port                 = 2048
58850  
58851  ## bind to localhost (default: all interfaces)
58852  server.bind                = "localhost"
58853 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
58854 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
58855  server.name                = "www.example.org"
58856  server.tag                 = "Apache 1.3.29"
58857  
58858 @@ -22,25 +22,25 @@
58859  ######################## MODULE CONFIG ############################
58860  
58861  
58862 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
58863 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
58864  
58865  mimetype.assign             = ( ".html" => "text/html" )
58866  
58867  url.redirect = ("^" => "/default")
58868  
58869  $HTTP["host"] == "www.example.org" {
58870 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
58871 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
58872    server.name = "www.example.org"
58873    url.redirect = ("^" => "/match_1")
58874  }
58875  else $HTTP["host"] == "test1.example.org" {
58876 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
58877 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
58878    server.name = "test1.example.org"
58879    url.redirect = ("^" => "/match_2")
58880  }
58881  # comments
58882  else $HTTP["host"] == "test2.example.org" {
58883 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
58884 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
58885    server.name = "test2.example.org"
58886    url.redirect = ("^" => "/match_3")
58887  }
58888 @@ -48,7 +48,7 @@
58889          # comments
58890  
58891  else $HTTP["host"] == "test3.example.org" {
58892 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
58893 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
58894    server.name = "test3.example.org"
58895    url.redirect = ("^" => "/match_4")
58896  
58897 --- ../lighttpd-1.4.11/tests/core-keepalive.t   2005-11-17 15:54:19.000000000 +0200
58898 +++ lighttpd-1.5.0/tests/core-keepalive.t       2006-07-16 00:26:05.000000000 +0300
58899 @@ -40,7 +40,7 @@
58900  
58901  GET /12345.txt HTTP/1.0
58902  Host: 123.example.org
58903 -Connection: keep-alive
58904 +Connection: close
58905  EOF
58906   );
58907  $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } , { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
58908 --- ../lighttpd-1.4.11/tests/core.t     2006-03-04 19:08:22.000000000 +0200
58909 +++ lighttpd-1.5.0/tests/core.t 2006-09-07 00:57:05.000000000 +0300
58910 @@ -44,21 +44,21 @@
58911  GET / HTTP/.01
58912  EOF
58913   );
58914 -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ];
58915 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 505 } ];
58916  ok($tf->handle_http($t) == 0, 'missing major version');
58917  
58918  $t->{REQUEST}  = ( <<EOF
58919  GET / HTTP/01.
58920  EOF
58921   );
58922 -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ];
58923 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 505 } ];
58924  ok($tf->handle_http($t) == 0, 'missing minor version');
58925  
58926  $t->{REQUEST}  = ( <<EOF
58927  GET / HTTP/a.b
58928  EOF
58929   );
58930 -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ];
58931 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 505 } ];
58932  ok($tf->handle_http($t) == 0, 'strings as version');
58933  
58934  $t->{REQUEST}  = ( <<EOF
58935 --- ../lighttpd-1.4.11/tests/default.conf       1970-01-01 03:00:00.000000000 +0300
58936 +++ lighttpd-1.5.0/tests/default.conf   2006-07-16 00:26:05.000000000 +0300
58937 @@ -0,0 +1,111 @@
58938 +server.name                = "www.example.org"
58939 +
58940 +## bind to port (default: 80)
58941 +server.port                 = env.PORT
58942 +
58943 +
58944 +server.dir-listing          = "enable"
58945 +
58946 +#server.event-handler        = "linux-sysepoll"
58947 +#server.event-handler        = "linux-rtsig"
58948 +
58949 +server.modules              = ( 
58950 +                               "mod_rewrite",
58951 +                               "mod_setenv",
58952 +                               "mod_access", 
58953 +                               "mod_auth",
58954 +                               "mod_status", 
58955 +                               "mod_expire",
58956 +                               "mod_simple_vhost",
58957 +                               "mod_redirect", 
58958 +                               "mod_secdownload",
58959 +                               "mod_ssi",
58960 +                               "mod_fastcgi",
58961 +                               "mod_proxy",
58962 +                               "mod_cgi",
58963 +                               "mod_compress",
58964 +                               "mod_userdir",
58965 +                               "mod_accesslog" ) 
58966 +
58967 +server.indexfiles           = ( "index.php", "index.html", 
58968 +                                "index.htm", "default.htm" )
58969 +
58970 +ssi.extension = ( ".shtml" )
58971 +
58972 +######################## MODULE CONFIG ############################
58973 +
58974 +
58975 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
58976 +server.errorlog             = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
58977 +
58978 +mimetype.assign             = ( ".png"  => "image/png", 
58979 +                                ".jpg"  => "image/jpeg",
58980 +                                ".jpeg" => "image/jpeg",
58981 +                                ".gif"  => "image/gif",
58982 +                                ".html" => "text/html",
58983 +                                ".htm"  => "text/html",
58984 +                                ".pdf"  => "application/pdf",
58985 +                                ".swf"  => "application/x-shockwave-flash",
58986 +                                ".spl"  => "application/futuresplash",
58987 +                                ".txt"  => "text/plain",
58988 +                                ".tar.gz" =>   "application/x-tgz",
58989 +                                ".tgz"  => "application/x-tgz",
58990 +                                ".gz"   => "application/x-gzip",
58991 +                               ".c"    => "text/plain",
58992 +                               ".conf" => "text/plain" )
58993 +
58994 +compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
58995 +compress.filetype           = ("text/plain", "text/html")
58996 +
58997 +setenv.add-environment      = ( "TRAC_ENV" => "tracenv", "SETENV" => "setenv")
58998 +
58999 +cgi.assign                  = ( ".pl"  => "/usr/bin/perl",
59000 +                                ".cgi" => "/usr/bin/perl",
59001 +                               ".py"  => "/usr/bin/python" )
59002 +                       
59003 +userdir.include-user = ( "jan" )
59004 +userdir.path = "/"
59005 +
59006 +ssl.engine                  = "disable"
59007 +ssl.pemfile                 = "server.pem"
59008 +
59009 +auth.backend                = "plain"
59010 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
59011 +auth.backend.htpasswd.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.htpasswd"
59012 +auth.backend.plain.groupfile = "lighttpd.group"
59013 +
59014 +auth.backend.ldap.hostname  = "localhost"
59015 +auth.backend.ldap.base-dn   = "dc=my-domain,dc=com"
59016 +auth.backend.ldap.filter    = "(uid=$)"
59017 +
59018 +auth.require                = ( "/server-status" => 
59019 +                                ( 
59020 +                                 "method"  => "digest",
59021 +                                 "realm"   => "download archiv",
59022 +                                 "require" => "valid-user"
59023 +                               ),
59024 +                               "/auth.php" => 
59025 +                                ( 
59026 +                                 "method"  => "basic",
59027 +                                 "realm"   => "download archiv",
59028 +                                 "require" => "user=jan"
59029 +                               ),
59030 +                               "/server-config" => 
59031 +                                ( 
59032 +                                 "method"  => "basic",
59033 +                                 "realm"   => "download archiv",
59034 +                                 "require" => "valid-user"
59035 +                               )
59036 +                              )
59037 +
59038 +url.access-deny             = ( "~", ".inc")
59039 +
59040 +url.redirect                = ( "^/redirect/$" => "http://localhost:2048/" )
59041 +
59042 +url.rewrite                = ( "^/rewrite/foo($|\?.+)" => "/indexfile/rewrite.php$1",
59043 +                               "^/rewrite/bar(?:$|\?(.+))" => "/indexfile/rewrite.php?bar&$1" )
59044 +
59045 +#### status module
59046 +status.status-url           = "/server-status"
59047 +status.config-url           = "/server-config"
59048 +
59049 --- ../lighttpd-1.4.11/tests/docroot/www/dummydir/.svn/entries  2006-03-09 19:21:49.000000000 +0200
59050 +++ lighttpd-1.5.0/tests/docroot/www/dummydir/.svn/entries      2006-09-07 00:57:05.000000000 +0300
59051 @@ -9,5 +9,6 @@
59052     last-author="jan"
59053     kind="dir"
59054     uuid="152afb58-edef-0310-8abb-c4023f1b3aa9"
59055 -   revision="1040"/>
59056 +   repos="svn://svn.lighttpd.net/lighttpd"
59057 +   revision="1277"/>
59058  </wc-entries>
59059 --- ../lighttpd-1.4.11/tests/fastcgi-10.conf    2005-08-31 23:36:34.000000000 +0300
59060 +++ lighttpd-1.5.0/tests/fastcgi-10.conf        2006-07-16 00:26:04.000000000 +0300
59061 @@ -1,12 +1,12 @@
59062 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
59063 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
59064 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59065 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
59066  
59067  ## bind to port (default: 80)
59068  server.port                 = 2048
59069  
59070  ## bind to localhost (default: all interfaces)
59071  server.bind                = "localhost"
59072 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
59073 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
59074  server.name                = "www.example.org"
59075  server.tag                 = "Apache 1.3.29"
59076  
59077 @@ -44,7 +44,7 @@
59078  ######################## MODULE CONFIG ############################
59079  
59080  
59081 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
59082 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
59083  
59084  mimetype.assign             = ( ".png"  => "image/png", 
59085                                  ".jpg"  => "image/jpeg",
59086 @@ -62,7 +62,7 @@
59087                                 ".c"    => "text/plain",
59088                                 ".conf" => "text/plain" )
59089  
59090 -compress.cache-dir          = "@SRCDIR@/tmp/lighttpd/cache/compress/"
59091 +compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
59092  compress.filetype           = ("text/plain", "text/html")
59093  
59094  fastcgi.debug               = 0
59095 @@ -85,7 +85,7 @@
59096  ssl.pemfile                 = "server.pem"
59097  
59098  auth.backend                = "plain"
59099 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
59100 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
59101  auth.backend.plain.groupfile = "lighttpd.group"
59102  
59103  auth.backend.ldap.hostname  = "localhost"
59104 @@ -128,11 +128,11 @@
59105  status.config-url           = "/server-config"
59106  
59107  $HTTP["host"] == "vvv.example.org" {
59108 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
59109 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59110  }
59111  
59112  $HTTP["host"] == "zzz.example.org" {
59113 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
59114 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59115    server.name = "zzz.example.org"
59116  }
59117  
59118 --- ../lighttpd-1.4.11/tests/fastcgi-13.conf    2006-01-03 12:38:17.000000000 +0200
59119 +++ lighttpd-1.5.0/tests/fastcgi-13.conf        2006-07-18 13:03:40.000000000 +0300
59120 @@ -1,5 +1,5 @@
59121 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
59122 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
59123 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59124 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
59125  
59126  debug.log-request-header   = "enable"
59127  debug.log-response-header  = "enable"
59128 @@ -10,7 +10,7 @@
59129  
59130  ## bind to localhost (default: all interfaces)
59131  server.bind                = "localhost"
59132 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
59133 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
59134  server.name                = "www.example.org"
59135  server.tag                 = "Apache 1.3.29"
59136  
59137 @@ -59,7 +59,7 @@
59138  ######################## MODULE CONFIG ############################
59139  
59140  
59141 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
59142 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
59143  
59144  mimetype.assign             = ( ".png"  => "image/png", 
59145                                  ".jpg"  => "image/jpeg",
59146 @@ -77,7 +77,7 @@
59147                                 ".c"    => "text/plain",
59148                                 ".conf" => "text/plain" )
59149  
59150 -compress.cache-dir          = "@SRCDIR@/tmp/lighttpd/cache/compress/"
59151 +compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
59152  compress.filetype           = ("text/plain", "text/html")
59153  
59154  fastcgi.debug               = 0
59155 @@ -85,7 +85,7 @@
59156                                    "grisu" => ( 
59157                                     "host" => "127.0.0.1",
59158                                     "port" => 1048,
59159 -                                   "bin-path" => "/home/jan/Documents/php-5.1.0/sapi/cgi/php -c /usr/local/lib/php.ini",
59160 +                                   "bin-path" => "/home/jan/Documents/php-5.1.4/sapi/cgi/php -c /usr/local/lib/php.ini",
59161                                     "bin-copy-environment" => ( "PATH", "SHELL", "USER" ),
59162                                   )
59163                                 )
59164 @@ -102,7 +102,7 @@
59165  ssl.pemfile                 = "server.pem"
59166  
59167  auth.backend                = "plain"
59168 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
59169 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
59170  auth.backend.plain.groupfile = "lighttpd.group"
59171  
59172  auth.backend.ldap.hostname  = "localhost"
59173 @@ -145,11 +145,11 @@
59174  status.config-url           = "/server-config"
59175  
59176  $HTTP["host"] == "vvv.example.org" {
59177 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
59178 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59179  }
59180  
59181  $HTTP["host"] == "zzz.example.org" {
59182 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
59183 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59184    server.name = "zzz.example.org"
59185  }
59186  
59187 --- ../lighttpd-1.4.11/tests/fastcgi-auth.conf  2005-08-27 17:44:19.000000000 +0300
59188 +++ lighttpd-1.5.0/tests/fastcgi-auth.conf      2006-07-16 00:26:05.000000000 +0300
59189 @@ -1,5 +1,5 @@
59190 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
59191 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
59192 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59193 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
59194  
59195  debug.log-request-header   = "enable"
59196  debug.log-response-header  = "enable"
59197 @@ -12,7 +12,7 @@
59198  
59199  ## bind to localhost (default: all interfaces)
59200  server.bind                = "localhost"
59201 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
59202 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
59203  server.name                = "www.example.org"
59204  server.tag                 = "Apache 1.3.29"
59205  
59206 @@ -61,7 +61,7 @@
59207  ######################## MODULE CONFIG ############################
59208  
59209  
59210 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
59211 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
59212  
59213  mimetype.assign             = ( ".png"  => "image/png", 
59214                                  ".jpg"  => "image/jpeg",
59215 @@ -79,7 +79,7 @@
59216                                 ".c"    => "text/plain",
59217                                 ".conf" => "text/plain" )
59218  
59219 -compress.cache-dir          = "@SRCDIR@/tmp/lighttpd/cache/compress/"
59220 +compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
59221  compress.filetype           = ("text/plain", "text/html")
59222  
59223  fastcgi.debug               = 0
59224 @@ -87,9 +87,9 @@
59225                                    "grisu" => ( 
59226                                     "host" => "127.0.0.1",
59227                                     "port" => 20000,
59228 -                                   "bin-path" => "@SRCDIR@/fcgi-auth",
59229 +                                   "bin-path" => env.SRCDIR + "/fcgi-auth",
59230                                      "mode" => "authorizer",
59231 -                                    "docroot" => "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/",
59232 +                                    "docroot" => env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/",
59233                                     
59234                                   )
59235                                 )
59236 @@ -106,7 +106,7 @@
59237  ssl.pemfile                 = "server.pem"
59238  
59239  auth.backend                = "plain"
59240 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
59241 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
59242  auth.backend.plain.groupfile = "lighttpd.group"
59243  
59244  auth.backend.ldap.hostname  = "localhost"
59245 @@ -149,11 +149,11 @@
59246  status.config-url           = "/server-config"
59247  
59248  $HTTP["host"] == "vvv.example.org" {
59249 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
59250 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59251  }
59252  
59253  $HTTP["host"] == "zzz.example.org" {
59254 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
59255 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59256    server.name = "zzz.example.org"
59257  }
59258  
59259 --- ../lighttpd-1.4.11/tests/fastcgi-responder.conf     2005-08-27 17:44:19.000000000 +0300
59260 +++ lighttpd-1.5.0/tests/fastcgi-responder.conf 2006-07-16 00:26:05.000000000 +0300
59261 @@ -1,5 +1,5 @@
59262 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
59263 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
59264 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59265 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
59266  
59267  #debug.log-request-header   = "enable"
59268  #debug.log-response-header  = "enable"
59269 @@ -15,7 +15,7 @@
59270  
59271  ## bind to localhost (default: all interfaces)
59272  server.bind                = "localhost"
59273 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
59274 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
59275  server.name                = "www.example.org"
59276  server.tag                 = "Apache 1.3.29"
59277  
59278 @@ -64,7 +64,7 @@
59279  ######################## MODULE CONFIG ############################
59280  
59281  
59282 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
59283 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
59284  
59285  mimetype.assign             = ( ".png"  => "image/png", 
59286                                  ".jpg"  => "image/jpeg",
59287 @@ -82,7 +82,7 @@
59288                                 ".c"    => "text/plain",
59289                                 ".conf" => "text/plain" )
59290  
59291 -compress.cache-dir          = "@SRCDIR@/tmp/lighttpd/cache/compress/"
59292 +compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
59293  compress.filetype           = ("text/plain", "text/html")
59294  
59295  fastcgi.debug               = 0
59296 @@ -90,10 +90,11 @@
59297                                    "grisu" => ( 
59298                                     "host" => "127.0.0.1",
59299                                     "port" => 10000,
59300 -                                   "bin-path" => "@SRCDIR@/fcgi-responder",
59301 +                                   "bin-path" => env.SRCDIR + "/fcgi-responder",
59302                                     "check-local" => "disable",
59303                                     "max-procs" => 1,
59304 -                                   "min-procs" => 1
59305 +                                   "min-procs" => 1,
59306 +                                   "allow-x-send-file" => "enable",
59307                                   )
59308                                 )
59309                               )
59310 @@ -109,7 +110,7 @@
59311  ssl.pemfile                 = "server.pem"
59312  
59313  auth.backend                = "plain"
59314 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
59315 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
59316  auth.backend.plain.groupfile = "lighttpd.group"
59317  
59318  auth.backend.ldap.hostname  = "localhost"
59319 @@ -152,11 +153,11 @@
59320  status.config-url           = "/server-config"
59321  
59322  $HTTP["host"] == "vvv.example.org" {
59323 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
59324 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59325  }
59326  
59327  $HTTP["host"] == "zzz.example.org" {
59328 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
59329 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59330    server.name = "zzz.example.org"
59331  }
59332  
59333 --- ../lighttpd-1.4.11/tests/fcgi-responder.c   2005-08-11 01:26:55.000000000 +0300
59334 +++ lighttpd-1.5.0/tests/fcgi-responder.c       2006-07-16 00:26:05.000000000 +0300
59335 @@ -6,11 +6,17 @@
59336  int main () {
59337         int num_requests = 2;
59338         
59339 -       while (num_requests > 0 &&
59340 -              FCGI_Accept() >= 0) {
59341 -               char* p;
59342 -               
59343 -               if (NULL != (p = getenv("QUERY_STRING"))) {
59344 +       while (num_requests > 0 && FCGI_Accept() >= 0) {
59345 +               char* p = NULL;
59346 +               char* doc_root = NULL;
59347 +               char fname[4096];
59348 +               char* pfname = (char *)fname;
59349 +
59350 +               doc_root = getenv("DOCUMENT_ROOT");
59351 +               p = getenv("QUERY_STRING");
59352 +
59353 +               if (NULL != p && NULL != doc_root) {
59354 +                       snprintf(pfname, sizeof(fname), "%s/phpinfo.php", doc_root);
59355                         if (0 == strcmp(p, "lf")) {
59356                                 printf("Status: 200 OK\n\n");
59357                         } else if (0 == strcmp(p, "crlf")) {
59358 @@ -23,6 +29,18 @@
59359                                 printf("Status: 200 OK\r\n");
59360                                 fflush(stdout);
59361                                 printf("\r\n");
59362 +                       } else if (0 == strcmp(p,"x-lighttpd-send-file")) {
59363 +                               printf("Status: 200 OK\r\n");
59364 +                               printf("X-LIGHTTPD-send-file: %s\r\n", pfname);
59365 +                               printf("\r\n");
59366 +                       } else if (0 == strcmp(p,"xsendfile")) {
59367 +                               printf("Status: 200 OK\r\n");
59368 +                               printf("X-Sendfile: %s\r\n", pfname);
59369 +                               printf("\r\n");
59370 +                       } else if (0 == strcmp(p,"xsendfile-mixed-case")) {
59371 +                               printf("Status: 200 OK\r\n");
59372 +                               printf("X-SeNdFiLe: %s\r\n", pfname);
59373 +                               printf("\r\n");
59374                         } else if (0 == strcmp(p, "die-at-end")) {
59375                                 printf("Status: 200 OK\r\n\r\n");
59376                                 num_requests--;
59377 --- ../lighttpd-1.4.11/tests/lighttpd.conf      2006-03-09 15:26:58.000000000 +0200
59378 +++ lighttpd-1.5.0/tests/lighttpd.conf  2006-09-07 00:57:05.000000000 +0300
59379 @@ -1,80 +1,20 @@
59380 -debug.log-request-handling = "enable"
59381 -debug.log-condition-handling = "enable"
59382 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
59383 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
59384 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59385 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
59386 +server.tag = "Apache 1.3.29"
59387  
59388 +debug.log-request-handling = "enable"
59389 +debug.log-response-header = "enable"
59390  ## 64 Mbyte ... nice limit
59391  server.max-request-size = 65000
59392  
59393 -## bind to port (default: 80)
59394 -server.port                 = 2048
59395 +include "default.conf"
59396  
59397 -## bind to localhost (default: all interfaces)
59398 -server.bind                = "localhost"
59399 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
59400 -server.name                = "www.example.org"
59401 -server.tag                 = "Apache 1.3.29"
59402 -
59403 -server.dir-listing          = "enable"
59404 -
59405 -#server.event-handler        = "linux-sysepoll"
59406 -#server.event-handler        = "linux-rtsig"
59407 -
59408 -#server.modules.path         = ""
59409 -server.modules              = ( 
59410 -                               "mod_rewrite",
59411 -                               "mod_setenv",
59412 -                               "mod_secdownload",
59413 -                               "mod_access", 
59414 -                               "mod_auth",
59415 -#                              "mod_httptls",
59416 -                               "mod_status", 
59417 -                               "mod_expire",
59418 -                               "mod_simple_vhost",
59419 -                               "mod_redirect", 
59420 -#                              "mod_evhost",
59421 -#                              "mod_localizer",
59422 -                               "mod_fastcgi",
59423 -                               "mod_cgi",
59424 -                               "mod_compress",
59425 -                               "mod_userdir",
59426 -                               "mod_ssi",
59427 -                               "mod_accesslog" ) 
59428 -
59429 -server.indexfiles           = ( "index.php", "index.html", 
59430 -                                "index.htm", "default.htm" )
59431 -
59432 -
59433 -######################## MODULE CONFIG ############################
59434 -
59435 -ssi.extension = ( ".shtml" )
59436 -
59437 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
59438 -
59439 -mimetype.assign             = ( ".png"  => "image/png", 
59440 -                                ".jpg"  => "image/jpeg",
59441 -                                ".jpeg" => "image/jpeg",
59442 -                                ".gif"  => "image/gif",
59443 -                                ".html" => "text/html",
59444 -                                ".htm"  => "text/html",
59445 -                                ".pdf"  => "application/pdf",
59446 -                                ".swf"  => "application/x-shockwave-flash",
59447 -                                ".spl"  => "application/futuresplash",
59448 -                                ".txt"  => "text/plain",
59449 -                                ".tar.gz" =>   "application/x-tgz",
59450 -                                ".tgz"  => "application/x-tgz",
59451 -                                ".gz"   => "application/x-gzip",
59452 -                               ".c"    => "text/plain",
59453 -                               ".conf" => "text/plain" )
59454 +setenv.add-request-header   = ( "FOO" => "foo")
59455 +setenv.add-response-header  = ( "BAR" => "foo")
59456  
59457  $HTTP["host"] == "cache.example.org" {
59458 -  compress.cache-dir          = "@SRCDIR@/tmp/lighttpd/cache/compress/"
59459 +  compress.cache-dir          = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
59460  }
59461 -compress.filetype           = ("text/plain", "text/html")
59462 -
59463 -setenv.add-environment      = ( "TRAC_ENV" => "tracenv", "SETENV" => "setenv")
59464 -setenv.add-request-header   = ( "FOO" => "foo")
59465 -setenv.add-response-header  = ( "BAR" => "foo")
59466  
59467  $HTTP["url"] =~ "\.pdf$" {
59468    server.range-requests = "disable"
59469 @@ -85,76 +25,43 @@
59470                                 "/prefix.fcgi" => ( ( "host" => "127.0.0.1", "port" => 1026, "check-local" => "disable", "broken-scriptfilename" => "enable" ) )
59471                               )
59472                 
59473 -
59474 -cgi.assign                  = ( ".pl"  => "/usr/bin/perl",
59475 -                                ".cgi" => "/usr/bin/perl",
59476 -                               ".py"  => "/usr/bin/python" )
59477 -                       
59478 -userdir.include-user = ( "jan" )
59479 -userdir.path = "/"
59480 -
59481 -ssl.engine                  = "disable"
59482 -ssl.pemfile                 = "server.pem"
59483 -
59484  $HTTP["host"] == "auth-htpasswd.example.org" {
59485         auth.backend                = "htpasswd"
59486  }
59487  
59488 -auth.backend                = "plain"
59489 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
59490 -
59491 -auth.backend.htpasswd.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.htpasswd"
59492 -
59493 -
59494 -auth.require                = ( "/server-status" => 
59495 -                                ( 
59496 -                                 "method"  => "digest",
59497 -                                 "realm"   => "download archiv",
59498 -                                 "require" => "group=www|user=jan|host=192.168.2.10"
59499 -                               ),
59500 -                               "/server-config" => 
59501 -                                ( 
59502 -                                 "method"  => "basic",
59503 -                                 "realm"   => "download archiv",
59504 -                                 "require" => "valid-user"
59505 -                               )
59506 -                              )
59507 -
59508 -url.access-deny             = ( "~", ".inc")
59509 -
59510 -url.rewrite                = ( "^/rewrite/foo($|\?.+)" => "/indexfile/rewrite.php$1",
59511 -                               "^/rewrite/bar(?:$|\?(.+))" => "/indexfile/rewrite.php?bar&$1" )
59512 -
59513 -expire.url                  = ( "/expire/access" => "access 2 hours", 
59514 -                               "/expire/modification" => "access plus 1 seconds 2 minutes")
59515 -
59516 -#cache.cache-dir             = "/home/weigon/wwwroot/cache/"
59517 -
59518 -#### status module
59519 -status.status-url           = "/server-status"
59520 -status.config-url           = "/server-config"
59521 -
59522  $HTTP["host"] == "vvv.example.org" {
59523 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
59524 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59525    secdownload.secret          = "verysecret"
59526 -  secdownload.document-root   = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
59527 +  secdownload.document-root   = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59528    secdownload.uri-prefix      = "/sec/"
59529    secdownload.timeout         = 120
59530  }
59531  
59532  $HTTP["host"] == "zzz.example.org" {
59533 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
59534 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59535    server.name = "zzz.example.org"
59536  }
59537  
59538 +$HTTP["host"] == "symlink.example.org" {
59539 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59540 +  server.name = "symlink.example.org"
59541 +  server.follow-symlink = "enable"
59542 +}
59543 +
59544 +$HTTP["host"] == "nosymlink.example.org" {
59545 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59546 +  server.name = "symlink.example.org"
59547 +  server.follow-symlink = "disable"
59548 +}
59549 +
59550  $HTTP["host"] == "no-simple.example.org" {
59551 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/123.example.org/pages/"
59552 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/123.example.org/pages/"
59553    server.name = "zzz.example.org"
59554  }
59555  
59556  $HTTP["host"] !~ "(no-simple\.example\.org)" {
59557    simple-vhost.document-root  = "pages"
59558 -  simple-vhost.server-root    = "@SRCDIR@/tmp/lighttpd/servers/"
59559 +  simple-vhost.server-root    = env.SRCDIR + "/tmp/lighttpd/servers/"
59560    simple-vhost.default-host   = "www.example.org"
59561  }
59562  
59563 --- ../lighttpd-1.4.11/tests/lowercase.conf     1970-01-01 03:00:00.000000000 +0300
59564 +++ lighttpd-1.5.0/tests/lowercase.conf 2006-07-16 00:26:05.000000000 +0300
59565 @@ -0,0 +1,80 @@
59566 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
59567 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
59568 +
59569 +## bind to port (default: 80)
59570 +server.port                 = 2048
59571 +
59572 +## bind to localhost (default: all interfaces)
59573 +server.bind                = "localhost"
59574 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
59575 +
59576 +server.force-lowercase-filenames = "enable"
59577 +
59578 +server.dir-listing          = "enable"
59579 +
59580 +server.modules              = ( 
59581 +                               "mod_rewrite",
59582 +                               "mod_setenv",
59583 +                               "mod_secdownload",
59584 +                               "mod_access", 
59585 +                               "mod_auth",
59586 +                               "mod_status", 
59587 +                               "mod_expire",
59588 +                               "mod_redirect", 
59589 +                               "mod_fastcgi",
59590 +                               "mod_cgi" ) 
59591 +
59592 +server.indexfiles           = ( "index.php", "index.html", 
59593 +                                "index.htm", "default.htm" )
59594 +
59595 +
59596 +######################## MODULE CONFIG ############################
59597 +
59598 +mimetype.assign             = ( ".png"  => "image/png", 
59599 +                                ".jpg"  => "image/jpeg",
59600 +                                ".jpeg" => "image/jpeg",
59601 +                                ".gif"  => "image/gif",
59602 +                                ".html" => "text/html",
59603 +                                ".htm"  => "text/html",
59604 +                                ".pdf"  => "application/pdf",
59605 +                                ".swf"  => "application/x-shockwave-flash",
59606 +                                ".spl"  => "application/futuresplash",
59607 +                                ".txt"  => "text/plain",
59608 +                                ".tar.gz" =>   "application/x-tgz",
59609 +                                ".tgz"  => "application/x-tgz",
59610 +                                ".gz"   => "application/x-gzip",
59611 +                               ".c"    => "text/plain",
59612 +                               ".conf" => "text/plain" )
59613 +
59614 +fastcgi.debug               = 0
59615 +fastcgi.server              = ( ".php" =>        ( ( "host" => "127.0.0.1", "port" => 1026, "broken-scriptfilename" => "enable" ) ),
59616 +                               "/prefix.fcgi" => ( ( "host" => "127.0.0.1", "port" => 1026, "check-local" => "disable", "broken-scriptfilename" => "enable" ) )
59617 +                             )
59618 +               
59619 +
59620 +cgi.assign                  = ( ".pl"  => "/usr/bin/perl",
59621 +                                ".cgi" => "/usr/bin/perl",
59622 +                               ".py"  => "/usr/bin/python" )
59623 +                       
59624 +auth.backend                = "plain"
59625 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
59626 +
59627 +auth.backend.htpasswd.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.htpasswd"
59628 +
59629 +$HTTP["host"] == "lowercase-auth" {
59630 +  auth.require             = ( "/image.jpg" => 
59631 +                                ( 
59632 +                                 "method"  => "digest",
59633 +                                 "realm"   => "download archiv",
59634 +                                 "require" => "valid-user"
59635 +                               )
59636 +                              )
59637 +}
59638 +
59639 +$HTTP["host"] == "lowercase-deny" {
59640 +  url.access-deny             = ( ".jpg")
59641 +}
59642 +
59643 +$HTTP["host"] == "lowercase-exclude" {
59644 +  static-file.exclude-extensions = ( ".jpg" )
59645 +}
59646 --- ../lighttpd-1.4.11/tests/lowercase.t        1970-01-01 03:00:00.000000000 +0300
59647 +++ lighttpd-1.5.0/tests/lowercase.t    2006-07-16 00:26:05.000000000 +0300
59648 @@ -0,0 +1,94 @@
59649 +#!/usr/bin/env perl
59650 +BEGIN {
59651 +    # add current source dir to the include-path
59652 +    # we need this for make distcheck
59653 +   (my $srcdir = $0) =~ s#/[^/]+$#/#;
59654 +   unshift @INC, $srcdir;
59655 +}
59656 +
59657 +use strict;
59658 +use IO::Socket;
59659 +use Test::More tests => 10;
59660 +use LightyTest;
59661 +
59662 +my $tf = LightyTest->new();
59663 +my $t;
59664 +
59665 +$tf->{CONFIGFILE} = 'lowercase.conf';
59666 +    
59667 +ok($tf->start_proc == 0, "Starting lighttpd") or die();
59668 +
59669 +## check if lower-casing works
59670 +
59671 +$t->{REQUEST}  = ( <<EOF
59672 +GET /image.JPG HTTP/1.0
59673 +EOF
59674 + );
59675 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
59676 +ok($tf->handle_http($t) == 0, 'uppercase access');
59677 +
59678 +$t->{REQUEST}  = ( <<EOF
59679 +GET /image.jpg HTTP/1.0
59680 +EOF
59681 + );
59682 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
59683 +ok($tf->handle_http($t) == 0, 'lowercase access');
59684 +
59685 +## check that mod-auth works
59686 +
59687 +$t->{REQUEST}  = ( <<EOF
59688 +GET /image.JPG HTTP/1.0
59689 +Host: lowercase-auth
59690 +EOF
59691 + );
59692 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 401 } ];
59693 +ok($tf->handle_http($t) == 0, 'uppercase access');
59694 +
59695 +$t->{REQUEST}  = ( <<EOF
59696 +GET /image.jpg HTTP/1.0
59697 +Host: lowercase-auth
59698 +EOF
59699 + );
59700 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 401 } ];
59701 +ok($tf->handle_http($t) == 0, 'lowercase access');
59702 +
59703 +
59704 +## check that mod-staticfile exclude works
59705 +$t->{REQUEST}  = ( <<EOF
59706 +GET /image.JPG HTTP/1.0
59707 +Host: lowercase-exclude
59708 +EOF
59709 + );
59710 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
59711 +ok($tf->handle_http($t) == 0, 'upper case access to staticfile.exclude-extension');
59712 +
59713 +$t->{REQUEST}  = ( <<EOF
59714 +GET /image.jpg HTTP/1.0
59715 +Host: lowercase-exclude
59716 +EOF
59717 + );
59718 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
59719 +ok($tf->handle_http($t) == 0, 'lowercase access');
59720 +
59721 +
59722 +## check that mod-access exclude works
59723 +$t->{REQUEST}  = ( <<EOF
59724 +GET /image.JPG HTTP/1.0
59725 +Host: lowercase-deny
59726 +EOF
59727 + );
59728 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
59729 +ok($tf->handle_http($t) == 0, 'uppercase access to url.access-deny protected location');
59730 +
59731 +$t->{REQUEST}  = ( <<EOF
59732 +GET /image.jpg HTTP/1.0
59733 +Host: lowercase-deny
59734 +EOF
59735 + );
59736 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
59737 +ok($tf->handle_http($t) == 0, 'lowercase access');
59738 +
59739 +
59740 +
59741 +ok($tf->stop_proc == 0, "Stopping lighttpd");
59742 +
59743 --- ../lighttpd-1.4.11/tests/mod-cgi.t  2005-09-01 14:43:05.000000000 +0300
59744 +++ lighttpd-1.5.0/tests/mod-cgi.t      2006-07-18 13:03:40.000000000 +0300
59745 @@ -43,7 +43,7 @@
59746  GET /nph-status.pl HTTP/1.0
59747  EOF
59748   );
59749 -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
59750 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 502 } ];
59751  ok($tf->handle_http($t) == 0, 'NPH + perl, Bug #14');
59752  
59753  $t->{REQUEST} = ( <<EOF
59754 --- ../lighttpd-1.4.11/tests/mod-fastcgi.t      2006-03-09 15:30:45.000000000 +0200
59755 +++ lighttpd-1.5.0/tests/mod-fastcgi.t  2006-07-18 13:03:40.000000000 +0300
59756 @@ -7,7 +7,7 @@
59757  }
59758  
59759  use strict;
59760 -use Test::More tests => 47;
59761 +use Test::More tests => 49;
59762  use LightyTest;
59763  
59764  my $tf = LightyTest->new();
59765 @@ -15,7 +15,7 @@
59766  my $t;
59767  
59768  SKIP: {
59769 -       skip "no PHP running on port 1026", 30 unless $tf->listening_on(1026);
59770 +       skip "no PHP running on port 1026", 29 unless $tf->listening_on(1026);
59771  
59772         ok($tf->start_proc == 0, "Starting lighttpd") or die();
59773  
59774 @@ -223,7 +223,7 @@
59775  }
59776  
59777  SKIP: {
59778 -       skip "no php found", 4 unless -x "/home/jan/Documents/php-5.1.0/sapi/cgi/php"; 
59779 +       skip "no php found", 4 unless -x "/home/jan/Documents/php-5.1.4/sapi/cgi/php";
59780         $tf->{CONFIGFILE} = 'fastcgi-13.conf';
59781         ok($tf->start_proc == 0, "Starting lighttpd with $tf->{CONFIGFILE}") or die();
59782         $t->{REQUEST}  = ( <<EOF
59783 @@ -285,6 +285,34 @@
59784         $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => 'test123' } ];
59785         ok($tf->handle_http($t) == 0, 'line-ending \r\n + \r\n');
59786  
59787 +    # X-LIGHTTPD-send-file
59788 +       $t->{REQUEST}  = ( <<EOF
59789 +GET /index.fcgi?x-lighttpd-send-file HTTP/1.0
59790 +Host: www.example.org
59791 +EOF
59792 + );
59793 +       $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '<?php phpinfo(); ?>
59794 +' } ];
59795 +       ok($tf->handle_http($t) == 0, 'X-LIGHTTPD-send-file');
59796 +    # X-Sendfile
59797 +       $t->{REQUEST}  = ( <<EOF
59798 +GET /index.fcgi?xsendfile HTTP/1.0
59799 +Host: www.example.org
59800 +EOF
59801 + );
59802 +       $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '<?php phpinfo(); ?>
59803 +' } ];
59804 +       ok($tf->handle_http($t) == 0, 'X-Sendfile');
59805 +
59806 +       $t->{REQUEST}  = ( <<EOF
59807 +GET /index.fcgi?xsendfile-mixed-case HTTP/1.0
59808 +Host: www.example.org
59809 +EOF
59810 + );
59811 +       $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '<?php phpinfo(); ?>
59812 +' } ];
59813 +       ok($tf->handle_http($t) == 0, 'X-SeNdFiLe in mixed case');
59814 +
59815         $t->{REQUEST}  = ( <<EOF
59816  GET /index.fcgi?die-at-end HTTP/1.0
59817  Host: www.example.org
59818 --- ../lighttpd-1.4.11/tests/mod-proxy.t        1970-01-01 03:00:00.000000000 +0300
59819 +++ lighttpd-1.5.0/tests/mod-proxy.t    2006-07-18 13:03:40.000000000 +0300
59820 @@ -0,0 +1,175 @@
59821 +#!/usr/bin/env perl
59822 +BEGIN {
59823 +    # add current source dir to the include-path
59824 +    # we need this for make distcheck
59825 +   (my $srcdir = $0) =~ s#/[^/]+$#/#;
59826 +   unshift @INC, $srcdir;
59827 +}
59828 +
59829 +use strict;
59830 +use IO::Socket;
59831 +use Test::More tests => 21;
59832 +use LightyTest;
59833 +
59834 +my $tf_proxy = LightyTest->new();
59835 +my $tf_backend1 = LightyTest->new();
59836 +my $tf_backend2 = LightyTest->new();
59837 +
59838 +my $t;
59839 +
59840 +## we need two procs
59841 +## 1. the real webserver
59842 +## 2. the proxy server
59843 +
59844 +SKIP: {
59845 +  skip "disabled for now", 21;
59846 +$tf_proxy->{PORT} = 2048;
59847 +$tf_proxy->{CONFIGFILE} = 'proxy.conf';
59848 +$tf_proxy->{LIGHTTPD_PIDFILE} = $tf_proxy->{SRCDIR}.'/tmp/lighttpd/lighttpd-proxy.pid';
59849 +
59850 +$tf_backend1->{PORT} = 2050;
59851 +$tf_backend1->{CONFIGFILE} = 'proxy-backend-1.conf';
59852 +$tf_backend1->{LIGHTTPD_PIDFILE} = $tf_backend1->{SRCDIR}.'/tmp/lighttpd/lighttpd-backend-1.pid';
59853 +
59854 +$tf_backend2->{PORT} = 2051;
59855 +$tf_backend2->{CONFIGFILE} = 'proxy-backend-2.conf';
59856 +$tf_backend2->{LIGHTTPD_PIDFILE} = $tf_backend2->{SRCDIR}.'/tmp/lighttpd/lighttpd-backend-2.pid';
59857 +
59858 +
59859 +ok($tf_backend1->start_proc == 0, "Starting lighttpd") or die();
59860 +
59861 +ok($tf_proxy->start_proc == 0, "Starting lighttpd as proxy") or die();
59862 +
59863 +sleep(1);
59864 +
59865 +$t->{REQUEST}  = ( <<EOF
59866 +GET /index.html HTTP/1.0
59867 +Host: www.example.org
59868 +EOF
59869 + );
59870 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
59871 +ok($tf_proxy->handle_http($t) == 0, 'valid request');
59872 +
59873 +$t->{REQUEST}  = ( <<EOF
59874 +GET /index.html HTTP/1.0
59875 +Host: www.example.org
59876 +EOF
59877 + );
59878 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'Server' => 'proxy-backend-1' } ];
59879 +ok($tf_proxy->handle_http($t) == 0, 'drop Server from real server');
59880 +
59881 +$t->{REQUEST}  = ( <<EOF
59882 +GET /balance-rr/foo HTTP/1.0
59883 +Host: www.example.org
59884 +EOF
59885 + );
59886 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
59887 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - one backend');
59888 +
59889 +$t->{REQUEST}  = ( <<EOF
59890 +GET /balance-rr/foo HTTP/1.0
59891 +Host: www.example.org
59892 +EOF
59893 + );
59894 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
59895 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - one host down, failover');
59896 +
59897 +$t->{REQUEST}  = ( <<EOF
59898 +GET /balance-fair/foo HTTP/1.0
59899 +Host: www.example.org
59900 +EOF
59901 + );
59902 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
59903 +ok($tf_proxy->handle_http($t) == 0, 'balance fair - one backend');
59904 +
59905 +## backend 2 starting 
59906 +ok($tf_backend2->start_proc == 0, "Starting second proxy backend") or die();
59907 +
59908 +$t->{REQUEST}  = ( <<EOF
59909 +GET /balance-rr/foo HTTP/1.0
59910 +Host: www.example.org
59911 +EOF
59912 + );
59913 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
59914 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - lb, backend 1');
59915 +
59916 +$t->{REQUEST}  = ( <<EOF
59917 +GET /balance-rr/foo HTTP/1.0
59918 +Host: www.example.org
59919 +EOF
59920 + );
59921 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
59922 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - lb, backend 2');
59923 +
59924 +$t->{REQUEST}  = ( <<EOF
59925 +GET /balance-hash/foo HTTP/1.0
59926 +Host: www.example.org
59927 +EOF
59928 + );
59929 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
59930 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - lb, backend 1');
59931 +
59932 +$t->{REQUEST}  = ( <<EOF
59933 +GET /balance-hash/foo HTTP/1.0
59934 +Host: www.example.org
59935 +EOF
59936 + );
59937 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
59938 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - lb, backend 1 - same URL');
59939 +
59940 +$t->{REQUEST}  = ( <<EOF
59941 +GET /balance-hash/bar HTTP/1.0
59942 +Host: www.example.org
59943 +EOF
59944 + );
59945 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
59946 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - lb, backend 2');
59947 +
59948 +$t->{REQUEST}  = ( <<EOF
59949 +GET /balance-hash/bar HTTP/1.0
59950 +Host: www.example.org
59951 +EOF
59952 + );
59953 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
59954 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - lb, backend 2 - same URL');
59955 +
59956 +## backend 1 stopping, failover 
59957 +ok($tf_backend1->stop_proc == 0, "Stopping backend 1");
59958 +
59959 +$t->{REQUEST}  = ( <<EOF
59960 +GET /balance-hash/foo HTTP/1.0
59961 +Host: www.example.org
59962 +EOF
59963 + );
59964 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
59965 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - failover to backend 2');
59966 +
59967 +$t->{REQUEST}  = ( <<EOF
59968 +GET /balance-hash/bar HTTP/1.0
59969 +Host: www.example.org
59970 +EOF
59971 + );
59972 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
59973 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - failover to backend 2 - same URL');
59974 +
59975 +$t->{REQUEST}  = ( <<EOF
59976 +GET /balance-rr/foo HTTP/1.0
59977 +Host: www.example.org
59978 +EOF
59979 + );
59980 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
59981 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - failover to backend 2');
59982 +
59983 +$t->{REQUEST}  = ( <<EOF
59984 +GET /balance-fair/foo HTTP/1.0
59985 +Host: www.example.org
59986 +EOF
59987 + );
59988 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
59989 +ok($tf_proxy->handle_http($t) == 0, 'balance fair - failover to backend 2');
59990 +
59991 +
59992 +ok($tf_backend2->stop_proc == 0, "Stopping lighttpd");
59993 +
59994 +ok($tf_proxy->stop_proc == 0, "Stopping lighttpd proxy");
59995 +}
59996 --- ../lighttpd-1.4.11/tests/proxy-backend-1.conf       1970-01-01 03:00:00.000000000 +0300
59997 +++ lighttpd-1.5.0/tests/proxy-backend-1.conf   2006-07-16 00:26:05.000000000 +0300
59998 @@ -0,0 +1,7 @@
59999 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
60000 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd-backend-1.pid"
60001 +
60002 +include "default.conf"
60003 +
60004 +
60005 +server.tag = "proxy-backend-1"
60006 --- ../lighttpd-1.4.11/tests/proxy-backend-2.conf       1970-01-01 03:00:00.000000000 +0300
60007 +++ lighttpd-1.5.0/tests/proxy-backend-2.conf   2006-07-16 00:26:04.000000000 +0300
60008 @@ -0,0 +1,7 @@
60009 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
60010 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd-backend-2.pid"
60011 +
60012 +include "default.conf"
60013 +
60014 +
60015 +server.tag = "proxy-backend-2"
60016 --- ../lighttpd-1.4.11/tests/proxy.conf 1970-01-01 03:00:00.000000000 +0300
60017 +++ lighttpd-1.5.0/tests/proxy.conf     2006-07-16 00:26:05.000000000 +0300
60018 @@ -0,0 +1,26 @@
60019 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
60020 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd-proxy.pid"
60021 +server.tag = "proxy"
60022 +
60023 +include "default.conf"
60024 +
60025 +## 127.0.0.1 and 127.0.0.2 are the same host
60026 +proxy.server              = ( 
60027 +  "" => (( "host" => "127.0.0.1",
60028 +          "port" => 2050 ),
60029 +         ( "host" => "127.0.0.2",
60030 +           "port" => 2051 )
60031 +  ))
60032 +               
60033 +$HTTP["url"] =~ "^/balance-rr/" {
60034 +  proxy.balance = "round-robin"
60035 +}
60036 +
60037 +$HTTP["url"] =~ "^/balance-hash/" {
60038 +  proxy.balance = "hash"
60039 +}
60040 +
60041 +$HTTP["url"] =~ "^/balance-fair/" {
60042 +  proxy.balance = "fair"
60043 +}
60044 +
60045 --- ../lighttpd-1.4.11/tests/request.t  2006-03-04 16:37:20.000000000 +0200
60046 +++ lighttpd-1.5.0/tests/request.t      2006-09-07 00:57:05.000000000 +0300
60047 @@ -96,12 +96,16 @@
60048  ok($tf->handle_http($t) == 0, 'HEAD request, file-not-found, query-string');
60049  
60050  $t->{REQUEST}  = ( <<EOF
60051 -GET / HTTP/1.1
60052 +POST / HTTP/1.1
60053  Connection: close
60054 +Content-Length: 4
60055 +Host: www.example.org
60056  Expect: 100-continue
60057 +
60058 +1234
60059  EOF
60060   );
60061 -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 417, '-HTTP-Content' => ''} ];
60062 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 100} ];
60063  ok($tf->handle_http($t) == 0, 'Continue, Expect');
60064  
60065  ## ranges
60066 --- ../lighttpd-1.4.11/tests/var-include.conf   2005-08-27 17:44:19.000000000 +0300
60067 +++ lighttpd-1.5.0/tests/var-include.conf       2006-07-16 00:26:05.000000000 +0300
60068 @@ -2,15 +2,15 @@
60069  debug.log-request-handling = "enable"
60070  debug.log-condition-handling = "enable"
60071  
60072 -server.document-root         = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
60073 -server.pid-file              = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
60074 +server.document-root         = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
60075 +server.pid-file              = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
60076  
60077  ## bind to port (default: 80)
60078  server.port                 = 2048
60079  
60080  ## bind to localhost (default: all interfaces)
60081  server.bind                = "localhost"
60082 -server.errorlog            = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
60083 +server.errorlog            = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
60084  server.name                = "www.example.org"
60085  server.tag                 = "Apache 1.3.29"
60086  
60087 @@ -21,19 +21,19 @@
60088  ######################## MODULE CONFIG ############################
60089  
60090  
60091 -accesslog.filename          = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
60092 +accesslog.filename          = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
60093  
60094  mimetype.assign             = ( ".html" => "text/html" )
60095  
60096  url.redirect = ("^" => "/default")
60097  
60098  $HTTP["host"] == "www.example.org" {
60099 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
60100 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
60101    server.name = "www.example.org"
60102    url.redirect = ("^" => "/redirect")
60103  }
60104  $HTTP["host"] == "test.example.org" {
60105 -  server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
60106 +  server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
60107    server.name = "test.example.org"
60108    var.myvar = "good"
60109    var.one = 1
This page took 5.273044 seconds and 4 git commands to generate.