xref: /PHP-5.5/sapi/thttpd/thttpd_patch (revision f4983c0d)
1diff -ur thttpd-2.21b/Makefile.in thttpd-2.21b-cool/Makefile.in
2--- thttpd-2.21b/Makefile.in	Thu Mar 29 20:36:21 2001
3+++ thttpd-2.21b-cool/Makefile.in	Sat Sep 20 14:43:20 2003
4@@ -46,13 +46,15 @@
5
6 # You shouldn't need to edit anything below here.
7
8+include php_makefile
9+
10 CC =		@CC@
11 CCOPT =		@V_CCOPT@
12 DEFS =		@DEFS@
13-INCLS =		-I.
14+INCLS =		-I. $(PHP_CFLAGS)
15 CFLAGS =	$(CCOPT) $(DEFS) $(INCLS)
16-LDFLAGS =	@LDFLAGS@
17-LIBS =		@LIBS@
18+LDFLAGS =	@LDFLAGS@ $(PHP_LDFLAGS)
19+LIBS =		@LIBS@ $(PHP_LIBS)
20 NETLIBS =	@V_NETLIBS@
21 INSTALL =	@INSTALL@
22
23@@ -62,7 +64,7 @@
24 	@rm -f $@
25 	$(CC) $(CFLAGS) -c $*.c
26
27-SRC =		thttpd.c libhttpd.c fdwatch.c mmc.c timers.c match.c tdate_parse.c syslog.c
28+SRC =		thttpd.c libhttpd.c fdwatch.c mmc.c timers.c match.c tdate_parse.c syslog.c php_thttpd.c
29
30 OBJ =		$(SRC:.c=.o) @LIBOBJS@
31
32@@ -77,7 +79,7 @@
33 all:		this subdirs
34 this:		$(ALL)
35
36-thttpd: $(OBJ)
37+thttpd: $(OBJ) libphp5.a
38 	@rm -f $@
39 	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJ) $(LIBS) $(NETLIBS)
40
41diff -ur thttpd-2.21b/config.h thttpd-2.21b-cool/config.h
42--- thttpd-2.21b/config.h	Mon Apr  9 23:57:36 2001
43+++ thttpd-2.21b-cool/config.h	Sat Sep 20 14:43:20 2003
44@@ -82,6 +82,11 @@
45 */
46 #define IDLE_READ_TIMELIMIT 60
47
48+/* CONFIGURE: How many seconds to allow for reading the subsequent requests
49+** on a keep-alive connection.  Should be simiar to LINGER_TIME
50+*/
51+#define IDLE_KEEPALIVE_TIMELIMIT 2
52+
53 /* CONFIGURE: How many seconds before an idle connection gets closed.
54 */
55 #define IDLE_SEND_TIMELIMIT 300
56@@ -316,7 +321,7 @@
57 /* CONFIGURE: A list of index filenames to check.  The files are searched
58 ** for in this order.
59 */
60-#define INDEX_NAMES "index.html", "index.htm", "Default.htm", "index.cgi"
61+#define INDEX_NAMES "index.php", "index.html", "index.htm", "Default.htm", "index.cgi"
62
63 /* CONFIGURE: If this is defined then thttpd will automatically generate
64 ** index pages for directories that don't have an explicit index file.
65diff -ur thttpd-2.21b/configure thttpd-2.21b-cool/configure
66--- thttpd-2.21b/configure	Sat Apr 21 02:07:14 2001
67+++ thttpd-2.21b-cool/configure	Sat Sep 20 14:43:20 2003
68@@ -1021,7 +1021,7 @@
69 fi
70 echo "$ac_t""$CPP" 1>&6
71
72-for ac_hdr in fcntl.h grp.h memory.h paths.h poll.h sys/poll.h sys/event.h osreldate.h
73+for ac_hdr in fcntl.h grp.h memory.h paths.h poll.h sys/poll.h sys/event.h osreldate.h netinet/tcp.h
74 do
75 ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
76 echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
77diff -ur thttpd-2.21b/configure.in thttpd-2.21b-cool/configure.in
78--- thttpd-2.21b/configure.in	Sat Apr 21 02:06:23 2001
79+++ thttpd-2.21b-cool/configure.in	Sat Sep 20 14:43:20 2003
80@@ -64,7 +64,7 @@
81 	AC_MSG_RESULT(no)
82 fi
83
84-AC_CHECK_HEADERS(fcntl.h grp.h memory.h paths.h poll.h sys/poll.h sys/event.h osreldate.h)
85+AC_CHECK_HEADERS(fcntl.h grp.h memory.h paths.h poll.h sys/poll.h sys/event.h osreldate.h netinet/tcp.h)
86 AC_HEADER_TIME
87 AC_HEADER_DIRENT
88
89diff -ur thttpd-2.21b/fdwatch.c thttpd-2.21b-cool/fdwatch.c
90--- thttpd-2.21b/fdwatch.c	Fri Apr 13 07:36:08 2001
91+++ thttpd-2.21b-cool/fdwatch.c	Sat Sep 20 14:43:20 2003
92@@ -419,6 +419,7 @@
93     if ( pollfds == (struct pollfd*) 0 || poll_fdidx == (int*) 0 ||
94 	 poll_rfdidx == (int*) 0 )
95 	return -1;
96+	memset(pollfds, 0, sizeof(struct pollfd) * nfiles);
97     return 0;
98     }
99
100@@ -460,7 +461,7 @@
101
102     ridx = 0;
103     for ( i = 0; i < npollfds; ++i )
104-	if ( pollfds[i].revents & ( POLLIN | POLLOUT ) )
105+	if ( pollfds[i].revents & ( POLLIN | POLLOUT | POLLERR | POLLHUP | POLLNVAL ) )
106 	    poll_rfdidx[ridx++] = pollfds[i].fd;
107
108     return r;
109@@ -472,8 +473,8 @@
110     {
111     switch ( fd_rw[fd] )
112 	{
113-	case FDW_READ: return pollfds[poll_fdidx[fd]].revents & POLLIN;
114-	case FDW_WRITE: return pollfds[poll_fdidx[fd]].revents & POLLOUT;
115+	case FDW_READ: return pollfds[poll_fdidx[fd]].revents & ( POLLIN | POLLERR | POLLHUP | POLLNVAL );
116+	case FDW_WRITE: return pollfds[poll_fdidx[fd]].revents & (  POLLOUT | POLLERR | POLLHUP | POLLNVAL );
117 	default: return 0;
118 	}
119     }
120diff -ur thttpd-2.21b/libhttpd.c thttpd-2.21b-cool/libhttpd.c
121--- thttpd-2.21b/libhttpd.c	Tue Apr 24 00:42:40 2001
122+++ thttpd-2.21b-cool/libhttpd.c	Sat Sep 20 14:43:29 2003
123@@ -56,6 +56,10 @@
124 #include <unistd.h>
125 #include <stdarg.h>
126
127+#ifdef HAVE_NETINET_TCP_H
128+#include <netinet/tcp.h>
129+#endif
130+
131 #ifdef HAVE_OSRELDATE_H
132 #include <osreldate.h>
133 #endif /* HAVE_OSRELDATE_H */
134@@ -85,6 +89,12 @@
135 #include "match.h"
136 #include "tdate_parse.h"
137
138+#include "php_thttpd.h"
139+
140+#ifdef __CYGWIN__
141+# define timezone _timezone
142+#endif
143+
144 #ifndef STDIN_FILENO
145 #define STDIN_FILENO 0
146 #endif
147@@ -111,7 +121,7 @@
148 static int initialize_listen_socket( httpd_sockaddr* saP );
149 static void unlisten( httpd_server* hs );
150 static void add_response( httpd_conn* hc, char* str );
151-static void send_mime( httpd_conn* hc, int status, char* title, char* encodings, char* extraheads, char* type, int length, time_t mod );
152+static void send_mime( httpd_conn* hc, int status, char* title, char* encodings, char* extraheads, char* type, int length, time_t mod, const char *, size_t );
153 static void send_response( httpd_conn* hc, int status, char* title, char* extraheads, char* form, char* arg );
154 static void send_response_tail( httpd_conn* hc );
155 static void defang( char* str, char* dfstr, int dfsize );
156@@ -242,6 +252,10 @@
157 	free( (void*) hs->cwd );
158     if ( hs->cgi_pattern != (char*) 0 )
159 	free( (void*) hs->cgi_pattern );
160+    if ( hs->php_pattern != (char*) 0 )
161+	free( (void*) hs->php_pattern );
162+    if ( hs->phps_pattern != (char*) 0 )
163+	free( (void*) hs->phps_pattern );
164     if ( hs->charset != (char*) 0 )
165 	free( (void*) hs->charset );
166     if ( hs->url_pattern != (char*) 0 )
167@@ -249,6 +263,7 @@
168     if ( hs->local_pattern != (char*) 0 )
169 	free( (void*) hs->local_pattern );
170     free( (void*) hs );
171+    thttpd_php_shutdown();
172     }
173
174
175@@ -257,7 +272,8 @@
176     char* hostname, httpd_sockaddr* sa4P, httpd_sockaddr* sa6P, int port,
177     char* cgi_pattern, char* charset, char* cwd, int no_log, FILE* logfp,
178     int no_symlink, int vhost, int global_passwd, char* url_pattern,
179-    char* local_pattern, int no_empty_referers )
180+    char* local_pattern, int no_empty_referers, char* php_pattern,
181+    char* phps_pattern )
182     {
183     httpd_server* hs;
184     static char ghnbuf[256];
185@@ -312,6 +328,8 @@
186 	}
187
188     hs->port = port;
189+    hs->php_pattern = strdup(php_pattern);
190+    hs->phps_pattern = strdup(phps_pattern);
191     if ( cgi_pattern == (char*) 0 )
192 	hs->cgi_pattern = (char*) 0;
193     else
194@@ -329,7 +347,7 @@
195 	while ( ( cp = strstr( hs->cgi_pattern, "|/" ) ) != (char*) 0 )
196 	    (void) strcpy( cp + 1, cp + 2 );
197 	}
198-    hs->charset = strdup( charset );
199+	hs->charset = strdup( charset );
200     hs->cwd = strdup( cwd );
201     if ( hs->cwd == (char*) 0 )
202 	{
203@@ -385,6 +403,8 @@
204 	return (httpd_server*) 0;
205 	}
206
207+    thttpd_php_init();
208+
209     /* Done initializing. */
210     if ( hs->binding_hostname == (char*) 0 )
211 	syslog( LOG_INFO, "%.80s starting on port %d", SERVER_SOFTWARE, hs->port );
212@@ -418,6 +438,11 @@
213 	}
214     (void) fcntl( listen_fd, F_SETFD, 1 );
215
216+#if defined(TCP_DEFER_ACCEPT) && defined(SOL_TCP)
217+	on = 30; /* give clients 30s to send first data packet */
218+	setsockopt(listen_fd, SOL_TCP, TCP_DEFER_ACCEPT, &on, sizeof(on));
219+#endif
220+
221     /* Allow reuse of local addresses. */
222     on = 1;
223     if ( setsockopt(
224@@ -582,6 +607,9 @@
225     /* And send it, if necessary. */
226     if ( hc->responselen > 0 )
227 	{
228+/*
229+printf("**RESPONSE [%d]** len = %d\n%*.*s\n", hc->conn_fd, hc->responselen, hc->responselen, hc->responselen, hc->response);
230+*/
231 	(void) write( hc->conn_fd, hc->response, hc->responselen );
232 	hc->responselen = 0;
233 	}
234@@ -619,18 +647,22 @@
235 	}
236     }
237
238+extern time_t httpd_time_now;
239+extern char httpd_now_buf[];
240+
241+#define SMART_STR_USE_REALLOC
242+
243+#include "ext/standard/php_smart_str.h"
244
245 static void
246-send_mime( httpd_conn* hc, int status, char* title, char* encodings, char* extraheads, char* type, int length, time_t mod )
247+send_mime( httpd_conn* hc, int status, char* title, char* encodings, char* extraheads, char* type, int length, time_t mod, const char *last_modified, size_t last_modified_len)
248     {
249-    time_t now;
250     const char* rfc1123fmt = "%a, %d %b %Y %H:%M:%S GMT";
251-    char nowbuf[100];
252     char modbuf[100];
253-    char fixed_type[500];
254-    char buf[1000];
255     int partial_content;
256-
257+	smart_str s = {0};
258+	int type_len;
259+
260     hc->status = status;
261     hc->bytes_to_send = length;
262     if ( hc->mime_flag )
263@@ -649,41 +681,89 @@
264 	else
265 	    partial_content = 0;
266
267-	now = time( (time_t*) 0 );
268 	if ( mod == (time_t) 0 )
269-	    mod = now;
270-	(void) strftime( nowbuf, sizeof(nowbuf), rfc1123fmt, gmtime( &now ) );
271-	(void) strftime( modbuf, sizeof(modbuf), rfc1123fmt, gmtime( &mod ) );
272-	(void) my_snprintf(
273-	    fixed_type, sizeof(fixed_type), type, hc->hs->charset );
274-	(void) my_snprintf( buf, sizeof(buf),
275-	    "%.20s %d %s\r\nServer: %s\r\nContent-Type: %s\r\nDate: %s\r\nLast-Modified: %s\r\nAccept-Ranges: bytes\r\nConnection: close\r\n",
276-	    hc->protocol, status, title, EXPOSED_SERVER_SOFTWARE, fixed_type,
277-	    nowbuf, modbuf );
278-	add_response( hc, buf );
279+	    mod = httpd_time_now;
280+
281+	if (last_modified == 0) {
282+		(void) strftime( modbuf, sizeof(modbuf), rfc1123fmt, gmtime( &mod ) );
283+		last_modified = modbuf;
284+		last_modified_len = strlen(modbuf);
285+	}
286+
287+	type_len = strlen(type);
288+
289+	if (hc->response) {
290+		s.c = hc->response;
291+		s.len = 0;
292+		s.a = hc->maxresponse;
293+		hc->response = 0;
294+		hc->maxresponse = 0;
295+	}
296+
297+	smart_str_appends(&s, "HTTP/1.1 ");
298+	smart_str_append_long(&s, status);
299+	smart_str_appends(&s, " HTTP\r\nServer: " EXPOSED_SERVER_SOFTWARE "\r\n"
300+			"Content-Type: ");
301+
302+	if (type[type_len-2] == '%' && type[type_len-1] == 's') {
303+		smart_str_appendl(&s, type, type_len - 2);
304+		smart_str_appends(&s, hc->hs->charset);
305+	} else {
306+		smart_str_appendl(&s, type, type_len);
307+	}
308+
309+
310+	smart_str_appends(&s, "\r\nDate: ");
311+	smart_str_appends(&s, httpd_now_buf);
312+	smart_str_appends(&s, "\r\nLast-Modified: ");
313+	smart_str_appendl(&s, last_modified, last_modified_len);
314+	smart_str_appends(&s, "\r\nAccept-Ranges: bytes\r\n");
315+
316 	if ( encodings[0] != '\0' )
317 	    {
318-	    (void) my_snprintf( buf, sizeof(buf),
319-		"Content-Encoding: %s\r\n", encodings );
320-	    add_response( hc, buf );
321+			smart_str_appends(&s, "Content-Encoding: ");
322+			smart_str_appends(&s, encodings);
323+			smart_str_appends(&s, "\r\n");
324 	    }
325 	if ( partial_content )
326 	    {
327-	    (void) my_snprintf( buf, sizeof(buf),
328-		"Content-Range: bytes %ld-%ld/%d\r\nContent-Length: %ld\r\n",
329-		(long) hc->init_byte_loc, (long) hc->end_byte_loc, length,
330-		(long) ( hc->end_byte_loc - hc->init_byte_loc + 1 ) );
331-	    add_response( hc, buf );
332+
333+			smart_str_appends(&s, "Content-Range: bytes ");
334+			smart_str_append_long(&s, hc->init_byte_loc);
335+			smart_str_appendc(&s, '-');
336+			smart_str_append_long(&s, hc->end_byte_loc);
337+			smart_str_appendc(&s, '/');
338+			smart_str_append_long(&s, length);
339+			smart_str_appends(&s, "\r\nContent-Length: ");
340+			smart_str_append_long(&s, hc->end_byte_loc - hc->init_byte_loc + 1);
341+			smart_str_appends(&s, "\r\n");
342+
343 	    }
344 	else if ( length >= 0 )
345 	    {
346-	    (void) my_snprintf( buf, sizeof(buf),
347-		"Content-Length: %d\r\n", length );
348-	    add_response( hc, buf );
349+			smart_str_appends(&s, "Content-Length: ");
350+			smart_str_append_long(&s, length);
351+			smart_str_appends(&s, "\r\n");
352 	    }
353+	else {
354+		hc->do_keep_alive = 0;
355+	}
356 	if ( extraheads[0] != '\0' )
357-	    add_response( hc, extraheads );
358-	add_response( hc, "\r\n" );
359+		smart_str_appends(&s, extraheads);
360+	if (hc->do_keep_alive) {
361+		smart_str_appends(&s, "Connection: keep-alive\r\n\r\n" );
362+	} else {
363+		smart_str_appends(&s, "Connection: close\r\n\r\n" );
364+	}
365+	smart_str_0(&s);
366+
367+	if (hc->response) {
368+		free(hc->response);
369+	}
370+	hc->response = s.c;
371+	hc->maxresponse = s.a;
372+	hc->responselen = s.len;
373+
374 	}
375     }
376
377@@ -725,7 +805,7 @@
378     {
379     char defanged_arg[1000], buf[2000];
380
381-    send_mime( hc, status, title, "", extraheads, "text/html", -1, 0 );
382+    send_mime( hc, status, title, "", extraheads, "text/html", -1, 0, 0, 0 );
383     (void) my_snprintf( buf, sizeof(buf),
384 	"<HTML><HEAD><TITLE>%d %s</TITLE></HEAD>\n<BODY BGCOLOR=\"#cc9999\"><H2>%d %s</H2>\n",
385 	status, title, status, title );
386@@ -764,7 +844,7 @@
387     char* cp2;
388
389     for ( cp1 = str, cp2 = dfstr;
390-	  *cp1 != '\0' && cp2 - dfstr < dfsize - 1;
391+	  *cp1 != '\0' && cp2 - dfstr < dfsize - 5;
392 	  ++cp1, ++cp2 )
393 	{
394 	switch ( *cp1 )
395@@ -834,7 +914,7 @@
396     fp = fopen( filename, "r" );
397     if ( fp == (FILE*) 0 )
398 	return 0;
399-    send_mime( hc, status, title, "", extraheads, "text/html", -1, 0 );
400+    send_mime( hc, status, title, "", extraheads, "text/html", -1, 0, 0, 0 );
401     for (;;)
402 	{
403 	r = fread( buf, 1, sizeof(buf) - 1, fp );
404@@ -1336,6 +1416,9 @@
405     if ( hc->tildemapped )
406 	return 1;
407
408+    if ( hc->hostname[0] == '.' || strchr( hc->hostname, '/' ) != (char*) 0 )
409+	return 0;
410+
411     /* Figure out the host directory. */
412 #ifdef VHOST_DIRLEVELS
413     httpd_realloc_str(
414@@ -1436,7 +1519,7 @@
415     restlen = strlen( path );
416     httpd_realloc_str( &rest, &maxrest, restlen );
417     (void) strcpy( rest, path );
418-    if ( rest[restlen - 1] == '/' )
419+    if ( restlen > 0 && rest[restlen - 1] == '/' )
420 	rest[--restlen] = '\0';         /* trim trailing slash */
421     if ( ! tildemapped )
422 	/* Remove any leading slashes. */
423@@ -1603,6 +1686,70 @@
424
425
426 int
427+httpd_request_reset(httpd_conn* hc, int preserve_read_buf )
428+{
429+	if (!preserve_read_buf) {
430+	    hc->read_idx = 0;
431+    	hc->checked_idx = 0;
432+	}
433+
434+		if (hc->read_buf_is_mmap) {
435+			hc->read_buf_is_mmap = 0;
436+			munmap(hc->read_buf, hc->read_size);
437+			hc->read_buf = NULL;
438+			hc->read_size = 0;
439+			httpd_realloc_str( &hc->read_buf, &hc->read_size, 500 );
440+		}
441+    hc->checked_state = CHST_FIRSTWORD;
442+    hc->method = METHOD_UNKNOWN;
443+    hc->status = 0;
444+    hc->bytes_to_send = 0;
445+    hc->bytes_sent = 0;
446+    hc->encodedurl = "";
447+    hc->decodedurl[0] = '\0';
448+    hc->protocol = "UNKNOWN";
449+    hc->origfilename[0] = '\0';
450+    hc->expnfilename[0] = '\0';
451+    hc->encodings[0] = '\0';
452+    hc->pathinfo[0] = '\0';
453+    hc->query[0] = '\0';
454+    hc->referer = "";
455+    hc->useragent = "";
456+    hc->accept[0] = '\0';
457+    hc->accepte[0] = '\0';
458+    hc->acceptl = "";
459+    hc->cookie = "";
460+    hc->contenttype = "";
461+    hc->reqhost[0] = '\0';
462+    hc->hdrhost = "";
463+    hc->hostdir[0] = '\0';
464+    hc->authorization = "";
465+    hc->remoteuser[0] = '\0';
466+    hc->response[0] = '\0';
467+#ifdef TILDE_MAP_2
468+    hc->altdir[0] = '\0';
469+#endif /* TILDE_MAP_2 */
470+    hc->responselen = 0;
471+    hc->if_modified_since = (time_t) -1;
472+    hc->range_if = (time_t) -1;
473+    hc->contentlength = -1;
474+    hc->type = "";
475+    hc->hostname = (char*) 0;
476+    hc->mime_flag = 1;
477+    hc->one_one = 0;
478+    hc->got_range = 0;
479+    hc->tildemapped = 0;
480+    hc->init_byte_loc = 0;
481+    hc->end_byte_loc = -1;
482+    hc->keep_alive = 0;
483+    hc->do_keep_alive = 0;
484+    hc->should_linger = 0;
485+    hc->file_address = (char*) 0;
486+    hc->read_body_into_mem = 0;
487+    return GC_OK;
488+}
489+
490+int
491 httpd_get_conn( httpd_server* hs, int listen_fd, httpd_conn* hc )
492     {
493     httpd_sockaddr sa;
494@@ -1612,6 +1759,7 @@
495 	{
496 	hc->read_size = 0;
497 	httpd_realloc_str( &hc->read_buf, &hc->read_size, 500 );
498+	hc->read_buf_is_mmap = 0;
499 	hc->maxdecodedurl =
500 	    hc->maxorigfilename = hc->maxexpnfilename = hc->maxencodings =
501 	    hc->maxpathinfo = hc->maxquery = hc->maxaccept =
502@@ -1631,12 +1779,19 @@
503 	httpd_realloc_str( &hc->reqhost, &hc->maxreqhost, 0 );
504 	httpd_realloc_str( &hc->hostdir, &hc->maxhostdir, 0 );
505 	httpd_realloc_str( &hc->remoteuser, &hc->maxremoteuser, 0 );
506-	httpd_realloc_str( &hc->response, &hc->maxresponse, 0 );
507+	httpd_realloc_str( &hc->response, &hc->maxresponse, 350 );
508 #ifdef TILDE_MAP_2
509 	httpd_realloc_str( &hc->altdir, &hc->maxaltdir, 0 );
510 #endif /* TILDE_MAP_2 */
511 	hc->initialized = 1;
512 	}
513+		if (hc->read_buf_is_mmap) {
514+			hc->read_buf_is_mmap = 0;
515+			munmap(hc->read_buf, hc->read_size);
516+			hc->read_buf = NULL;
517+			hc->read_size = 0;
518+			httpd_realloc_str( &hc->read_buf, &hc->read_size, 500 );
519+		}
520
521     /* Accept the new connection. */
522     sz = sizeof(sa);
523@@ -1657,53 +1812,12 @@
524     hc->hs = hs;
525     memset( &hc->client_addr, 0, sizeof(hc->client_addr) );
526     memcpy( &hc->client_addr, &sa, sockaddr_len( &sa ) );
527-    hc->read_idx = 0;
528-    hc->checked_idx = 0;
529-    hc->checked_state = CHST_FIRSTWORD;
530-    hc->method = METHOD_UNKNOWN;
531-    hc->status = 0;
532-    hc->bytes_to_send = 0;
533-    hc->bytes_sent = 0;
534-    hc->encodedurl = "";
535-    hc->decodedurl[0] = '\0';
536-    hc->protocol = "UNKNOWN";
537-    hc->origfilename[0] = '\0';
538-    hc->expnfilename[0] = '\0';
539-    hc->encodings[0] = '\0';
540-    hc->pathinfo[0] = '\0';
541-    hc->query[0] = '\0';
542-    hc->referer = "";
543-    hc->useragent = "";
544-    hc->accept[0] = '\0';
545-    hc->accepte[0] = '\0';
546-    hc->acceptl = "";
547-    hc->cookie = "";
548-    hc->contenttype = "";
549-    hc->reqhost[0] = '\0';
550-    hc->hdrhost = "";
551-    hc->hostdir[0] = '\0';
552-    hc->authorization = "";
553-    hc->remoteuser[0] = '\0';
554-    hc->response[0] = '\0';
555-#ifdef TILDE_MAP_2
556-    hc->altdir[0] = '\0';
557-#endif /* TILDE_MAP_2 */
558-    hc->responselen = 0;
559-    hc->if_modified_since = (time_t) -1;
560-    hc->range_if = (time_t) -1;
561-    hc->contentlength = -1;
562-    hc->type = "";
563-    hc->hostname = (char*) 0;
564-    hc->mime_flag = 1;
565-    hc->one_one = 0;
566-    hc->got_range = 0;
567-    hc->tildemapped = 0;
568-    hc->init_byte_loc = 0;
569-    hc->end_byte_loc = -1;
570-    hc->keep_alive = 0;
571-    hc->should_linger = 0;
572-    hc->file_address = (char*) 0;
573-    return GC_OK;
574+
575+/*
576+printf("doing httpd_get_con(%d)\n", hc->conn_fd);
577+*/
578+
579+    return httpd_request_reset(hc, 0);
580     }
581
582
583@@ -1720,6 +1834,9 @@
584     {
585     char c;
586
587+/*
588+printf("**REQUEST [%d]**\n%*.*s\n", hc->conn_fd, hc->read_idx, hc->read_idx, hc->read_buf);
589+*/
590     for ( ; hc->checked_idx < hc->read_idx; ++hc->checked_idx )
591 	{
592 	c = hc->read_buf[hc->checked_idx];
593@@ -1912,8 +2029,11 @@
594 	    eol = strpbrk( protocol, " \t\n\r" );
595 	    if ( eol != (char*) 0 )
596 		*eol = '\0';
597-	    if ( strcasecmp( protocol, "HTTP/1.0" ) != 0 )
598+	    if ( strcasecmp( protocol, "HTTP/1.0" ) != 0 ) {
599 		hc->one_one = 1;
600+		hc->keep_alive = 1;
601+		hc->do_keep_alive = 1;
602+		}
603 	    }
604 	}
605     /* Check for HTTP/1.1 absolute URL. */
606@@ -2129,6 +2249,7 @@
607 		cp = &buf[11];
608 		cp += strspn( cp, " \t" );
609 		if ( strcasecmp( cp, "keep-alive" ) == 0 )
610+		    hc->do_keep_alive = 1;
611 		    hc->keep_alive = 1;
612 		}
613 #ifdef LOG_UNKNOWN_HEADERS
614@@ -2168,6 +2289,9 @@
615 	    }
616 	}
617
618+/*
619+printf("one_one = %d   keep_alive = %d\n", hc->one_one, hc->keep_alive);
620+*/
621     if ( hc->one_one )
622 	{
623 	/* Check that HTTP/1.1 requests specify a host, as required. */
624@@ -2177,14 +2301,14 @@
625 	    return -1;
626 	    }
627
628-	/* If the client wants to do keep-alives, it might also be doing
629-	** pipelining.  There's no way for us to tell.  Since we don't
630-	** implement keep-alives yet, if we close such a connection there
631-	** might be unread pipelined requests waiting.  So, we have to
632-	** do a lingering close.
633+	/*
634+	**  Disable keep alive support for bad browsers,
635+	**    list taken from Apache 1.3.19
636 	*/
637-	if ( hc->keep_alive )
638-	    hc->should_linger = 1;
639+	if ( hc->do_keep_alive &&
640+	    ( strstr(hc->useragent, "Mozilla/2") != NULL ||
641+	      strstr(hc->useragent, "MSIE 4.0b2;") != NULL))
642+		hc->do_keep_alive = 0;
643 	}
644
645     /* Ok, the request has been parsed.  Now we resolve stuff that
646@@ -2349,15 +2473,24 @@
647
648
649 void
650-httpd_close_conn( httpd_conn* hc, struct timeval* nowP )
651-    {
652-    make_log_entry( hc, nowP );
653+httpd_complete_request( httpd_conn* hc, struct timeval* nowP)
654+{
655+	if (hc->method != METHOD_UNKNOWN)
656+		make_log_entry( hc, nowP );
657
658-    if ( hc->file_address != (char*) 0 )
659+	if ( hc->file_address == (char*) 1 )
660+    {
661+	thttpd_closed_conn(hc->conn_fd);
662+    } else if ( hc->file_address != (char*) 0 )
663 	{
664 	mmc_unmap( hc->file_address, &(hc->sb), nowP );
665 	hc->file_address = (char*) 0;
666 	}
667+	}
668+
669+void
670+httpd_close_conn( httpd_conn* hc, struct timeval* nowP )
671+{
672     if ( hc->conn_fd >= 0 )
673 	{
674 	(void) close( hc->conn_fd );
675@@ -2370,7 +2503,12 @@
676     {
677     if ( hc->initialized )
678 	{
679-	free( (void*) hc->read_buf );
680+
681+	if ( hc->read_buf_is_mmap ) {
682+	    munmap( hc->read_buf, hc->read_size );
683+	} else {
684+	    free( (void*) hc->read_buf );
685+	}
686 	free( (void*) hc->decodedurl );
687 	free( (void*) hc->origfilename );
688 	free( (void*) hc->expnfilename );
689@@ -2556,7 +2694,7 @@
690 	return -1;
691 	}
692
693-    send_mime( hc, 200, ok200title, "", "", "text/html", -1, hc->sb.st_mtime );
694+    send_mime( hc, 200, ok200title, "", "", "text/html", -1, hc->sb.st_mtime, 0, 0 );
695     if ( hc->method == METHOD_HEAD )
696 	closedir( dirp );
697     else if ( hc->method == METHOD_GET )
698@@ -3026,11 +3164,9 @@
699 post_post_garbage_hack( httpd_conn* hc )
700     {
701     char buf[2];
702-    int r;
703
704-    r = recv( hc->conn_fd, buf, sizeof(buf), MSG_PEEK );
705-    if ( r > 0 )
706-	(void) read( hc->conn_fd, buf, r );
707+	fcntl(hc->conn_fd, F_SETFL, O_NONBLOCK);
708+	(void) read( hc->conn_fd, buf, 2 );
709     }
710
711
712@@ -3313,6 +3449,11 @@
713     int r;
714     ClientData client_data;
715
716+    /*
717+    **  We are not going to leave the socket open after a CGI... too hard
718+    */
719+    hc->do_keep_alive = 0;
720+
721     if ( hc->method == METHOD_GET || hc->method == METHOD_POST )
722 	{
723 	httpd_clear_ndelay( hc->conn_fd );
724@@ -3369,6 +3510,7 @@
725     int expnlen, indxlen;
726     char* cp;
727     char* pi;
728+    int nocache = 0;
729
730     expnlen = strlen( hc->expnfilename );
731
732@@ -3561,6 +3703,16 @@
733 	 match( hc->hs->cgi_pattern, hc->expnfilename ) )
734 	return cgi( hc );
735
736+	if ( hc->hs->php_pattern != (char*) 0 &&
737+			match( hc->hs->php_pattern, hc->expnfilename)) {
738+		return thttpd_php_request( hc, 0 );
739+	}
740+
741+	if ( hc->hs->phps_pattern != (char*) 0 &&
742+			match( hc->hs->phps_pattern, hc->expnfilename)) {
743+		return thttpd_php_request( hc, 1 );
744+	}
745+
746     /* It's not CGI.  If it's executable or there's pathinfo, someone's
747     ** trying to either serve or run a non-CGI file as CGI.   Either case
748     ** is prohibited.
749@@ -3594,32 +3746,46 @@
750 	hc->end_byte_loc = hc->sb.st_size - 1;
751
752     figure_mime( hc );
753+    if ( strncmp(hc->decodedurl, "/nocache/", sizeof("/nocache/") - 1 ) == 0 )
754+	nocache = 1;
755
756     if ( hc->method == METHOD_HEAD )
757 	{
758 	send_mime(
759 	    hc, 200, ok200title, hc->encodings, "", hc->type, hc->sb.st_size,
760-	    hc->sb.st_mtime );
761+	    hc->sb.st_mtime, 0, 0 );
762 	}
763-    else if ( hc->if_modified_since != (time_t) -1 &&
764+    else if ( !nocache && hc->if_modified_since != (time_t) -1 &&
765 	 hc->if_modified_since >= hc->sb.st_mtime )
766 	{
767-	hc->method = METHOD_HEAD;
768 	send_mime(
769-	    hc, 304, err304title, hc->encodings, "", hc->type, hc->sb.st_size,
770-	    hc->sb.st_mtime );
771+	    hc, 304, err304title, hc->encodings, "", hc->type, -1,
772+	    hc->sb.st_mtime, 0, 0 );
773 	}
774     else
775 	{
776-	hc->file_address = mmc_map( hc->expnfilename, &(hc->sb), nowP );
777+	char *extraheads = "";
778+	char *lm;
779+	size_t lml;
780+
781+	if ( nocache )
782+	    {
783+	    extraheads = "Expires: Thu, 19 Nov 1981 08:52:00 GMT\r\n"
784+		"Cache-Control: no-store, no-cache, must-revalidate, "
785+		"post-check=0, pre-check=0\r\n"
786+		"Pragma: no-cache\r\n";
787+	    }
788+
789+	hc->file_address = mmc_map( hc->expnfilename, &(hc->sb), nowP, nocache, &lm, &lml );
790 	if ( hc->file_address == (char*) 0 )
791 	    {
792 	    httpd_send_err( hc, 500, err500title, "", err500form, hc->encodedurl );
793 	    return -1;
794 	    }
795+
796 	send_mime(
797-	    hc, 200, ok200title, hc->encodings, "", hc->type, hc->sb.st_size,
798-	    hc->sb.st_mtime );
799+	    hc, 200, ok200title, hc->encodings, extraheads, hc->type, hc->sb.st_size,
800+	    hc->sb.st_mtime, lm, lml );
801 	}
802
803     return 0;
804@@ -3638,6 +3804,9 @@
805     return r;
806     }
807
808+#define smart_str_append_const(a,b) smart_str_appendl(a,b,sizeof(b)-1)
809+
810+static smart_str bentries;
811
812 static void
813 make_log_entry( httpd_conn* hc, struct timeval* nowP )
814@@ -3648,88 +3817,62 @@
815
816     if ( hc->hs->no_log )
817 	return;
818-
819-    /* This is straight CERN Combined Log Format - the only tweak
820-    ** being that if we're using syslog() we leave out the date, because
821-    ** syslogd puts it in.  The included syslogtocern script turns the
822-    ** results into true CERN format.
823-    */
824-
825     /* Format remote user. */
826     if ( hc->remoteuser[0] != '\0' )
827-	ru = hc->remoteuser;
828+    ru = hc->remoteuser;
829     else
830-	ru = "-";
831+    ru = "-";
832     /* If we're vhosting, prepend the hostname to the url.  This is
833     ** a little weird, perhaps writing separate log files for
834     ** each vhost would make more sense.
835     */
836-    if ( hc->hs->vhost && ! hc->tildemapped )
837-	(void) my_snprintf( url, sizeof(url),
838-	    "/%.100s%.200s",
839-	    hc->hostname == (char*) 0 ? hc->hs->server_hostname : hc->hostname,
840-	    hc->encodedurl );
841-    else
842-	(void) my_snprintf( url, sizeof(url),
843-	    "%.200s", hc->encodedurl );
844-    /* Format the bytes. */
845-    if ( (long) hc->bytes_sent >= 0 )
846-	(void) my_snprintf( bytes, sizeof(bytes),
847-	    "%ld", (long) hc->bytes_sent );
848-    else
849-	(void) strcpy( bytes, "-" );
850
851     /* Logfile or syslog? */
852     if ( hc->hs->logfp != (FILE*) 0 )
853-	{
854-	time_t now;
855-	struct tm* t;
856-	const char* cernfmt_nozone = "%d/%b/%Y:%H:%M:%S";
857-	char date_nozone[100];
858-	int zone;
859-	char sign;
860-	char date[100];
861-
862-	/* Get the current time, if necessary. */
863-	if ( nowP != (struct timeval*) 0 )
864-	    now = nowP->tv_sec;
865-	else
866-	    now = time( (time_t*) 0 );
867-	/* Format the time, forcing a numeric timezone (some log analyzers
868-	** are stoooopid about this).
869-	*/
870-	t = localtime( &now );
871-	(void) strftime( date_nozone, sizeof(date_nozone), cernfmt_nozone, t );
872-#ifdef HAVE_TM_GMTOFF
873-	zone = t->tm_gmtoff / 60L;
874-#else
875-	zone = -timezone / 60L;
876-	/* Probably have to add something about daylight time here. */
877-#endif
878-	if ( zone >= 0 )
879-	    sign = '+';
880-	else
881-	    {
882-	    sign = '-';
883-	    zone = -zone;
884-	    }
885-	zone = ( zone / 60 ) * 100 + zone % 60;
886-	(void) my_snprintf( date, sizeof(date),
887-	    "%s %c%04d", date_nozone, sign, zone );
888-	/* And write the log entry. */
889-	(void) fprintf( hc->hs->logfp,
890-	    "%.80s - %.80s [%s] \"%.80s %.300s %.80s\" %d %s \"%.200s\" \"%.80s\"\n",
891-	    httpd_ntoa( &hc->client_addr ), ru, date,
892-	    httpd_method_str( hc->method ), url, hc->protocol,
893-	    hc->status, bytes, hc->referer, hc->useragent );
894-	(void) fflush( hc->hs->logfp );	/* don't need to flush every time */
895-	}
896-    else
897-	syslog( LOG_INFO,
898-	    "%.80s - %.80s \"%.80s %.200s %.80s\" %d %s \"%.200s\" \"%.80s\"",
899-	    httpd_ntoa( &hc->client_addr ), ru,
900-	    httpd_method_str( hc->method ), url, hc->protocol,
901-	    hc->status, bytes, hc->referer, hc->useragent );
902+    {
903+    /* XXXXXXX */
904+
905+    smart_str_appends(&bentries, httpd_ntoa(&hc->client_addr));
906+    smart_str_append_const(&bentries, " - ");
907+    smart_str_appends(&bentries, ru);
908+    smart_str_append_const(&bentries, " [");
909+    smart_str_appendl(&bentries, hc->hs->log_date, hc->hs->log_date_len);
910+    smart_str_append_const(&bentries, "] \"");
911+    smart_str_appends(&bentries, httpd_method_str(hc->method));
912+    smart_str_appendc(&bentries, ' ');
913+
914+    if (hc->hs->vhost && ! hc->tildemapped) {
915+        smart_str_appendc(&bentries, '/');
916+        if (hc->hostname)
917+            smart_str_appends(&bentries, hc->hostname);
918+        else
919+            smart_str_appends(&bentries, hc->hs->server_hostname);
920+    }
921+    smart_str_appends(&bentries, hc->encodedurl);
922+
923+    smart_str_appendc(&bentries, ' ');
924+    smart_str_appends(&bentries, hc->protocol);
925+    smart_str_append_const(&bentries, "\" ");
926+    smart_str_append_long(&bentries, hc->status);
927+    if (hc->bytes_sent >= 0) {
928+        smart_str_appendc(&bentries, ' ');
929+        smart_str_append_long(&bentries, hc->bytes_sent);
930+        smart_str_append_const(&bentries, " \"");
931+    } else {
932+        smart_str_append_const(&bentries, " - \"");
933+    }
934+    smart_str_appends(&bentries, hc->referer);
935+    smart_str_append_const(&bentries, "\" \"");
936+    smart_str_appends(&bentries, hc->useragent);
937+    smart_str_append_const(&bentries, "\"\n");
938+
939+    if (bentries.len > 16384) {
940+        int fd = fileno(hc->hs->logfp);
941+        write(fd, bentries.c, bentries.len);
942+        bentries.len = 0;
943+    }
944+    }
945+
946     }
947
948
949@@ -3840,7 +3983,24 @@
950     {
951 #ifdef HAVE_GETNAMEINFO
952     static char str[200];
953+	static smart_str httpd_ntoa_buf;
954+
955+	if (saP->sa_in.sin_family == AF_INET) {
956+        unsigned long n = ntohl(saP->sa_in.sin_addr.s_addr);
957
958+        httpd_ntoa_buf.len = 0;
959+        smart_str_append_long(&httpd_ntoa_buf, (n >> 24));
960+        smart_str_appendc(&httpd_ntoa_buf, '.');
961+        smart_str_append_long(&httpd_ntoa_buf, (n >> 16) & 255);
962+        smart_str_appendc(&httpd_ntoa_buf, '.');
963+        smart_str_append_long(&httpd_ntoa_buf, (n >> 8) & 255);
964+        smart_str_appendc(&httpd_ntoa_buf, '.');
965+        smart_str_append_long(&httpd_ntoa_buf, (n >> 0) & 255);
966+        smart_str_0(&httpd_ntoa_buf);
967+
968+        return httpd_ntoa_buf.c;
969+	}
970+
971     if ( getnameinfo( &saP->sa, sockaddr_len( saP ), str, sizeof(str), 0, 0, NI_NUMERICHOST ) != 0 )
972 	{
973 	str[0] = '?';
974diff -ur thttpd-2.21b/libhttpd.h thttpd-2.21b-cool/libhttpd.h
975--- thttpd-2.21b/libhttpd.h	Tue Apr 24 00:36:50 2001
976+++ thttpd-2.21b-cool/libhttpd.h	Sat Sep 20 14:43:20 2003
977@@ -69,6 +69,8 @@
978     char* server_hostname;
979     int port;
980     char* cgi_pattern;
981+    char* php_pattern;
982+    char* phps_pattern;
983     char* charset;
984     char* cwd;
985     int listen4_fd, listen6_fd;
986@@ -80,6 +82,8 @@
987     char* url_pattern;
988     char* local_pattern;
989     int no_empty_referers;
990+	size_t log_date_len;
991+	char log_date[100];
992     } httpd_server;
993
994 /* A connection. */
995@@ -88,6 +92,7 @@
996     httpd_server* hs;
997     httpd_sockaddr client_addr;
998     char* read_buf;
999+    char read_buf_is_mmap;
1000     int read_size, read_idx, checked_idx;
1001     int checked_state;
1002     int method;
1003@@ -132,11 +137,12 @@
1004     int got_range;
1005     int tildemapped;	/* this connection got tilde-mapped */
1006     off_t init_byte_loc, end_byte_loc;
1007-    int keep_alive;
1008+    int keep_alive, do_keep_alive;
1009     int should_linger;
1010     struct stat sb;
1011     int conn_fd;
1012     char* file_address;
1013+    char read_body_into_mem;
1014     } httpd_conn;
1015
1016 /* Methods. */
1017@@ -168,7 +174,8 @@
1018     char* hostname, httpd_sockaddr* sa4P, httpd_sockaddr* sa6P, int port,
1019     char* cgi_pattern, char* charset, char* cwd, int no_log, FILE* logfp,
1020     int no_symlink, int vhost, int global_passwd, char* url_pattern,
1021-    char* local_pattern, int no_empty_referers );
1022+    char* local_pattern, int no_empty_referers, char* php_pattern,
1023+    char* phps_pattern );
1024
1025 /* Change the log file. */
1026 extern void httpd_set_logfp( httpd_server* hs, FILE* logfp );
1027@@ -229,6 +236,8 @@
1028 ** If you don't have a current timeval handy just pass in 0.
1029 */
1030 extern void httpd_close_conn( httpd_conn* hc, struct timeval* nowP );
1031+void httpd_complete_request( httpd_conn* hc, struct timeval* nowP);
1032+int httpd_request_reset(httpd_conn* hc,int );
1033
1034 /* Call this to de-initialize a connection struct and *really* free the
1035 ** mallocced strings.
1036diff -ur thttpd-2.21b/mime_encodings.txt thttpd-2.21b-cool/mime_encodings.txt
1037--- thttpd-2.21b/mime_encodings.txt	Wed May 10 03:22:28 2000
1038+++ thttpd-2.21b-cool/mime_encodings.txt	Sat Sep 20 14:43:20 2003
1039@@ -3,6 +3,6 @@
1040 # A list of file extensions followed by the corresponding MIME encoding.
1041 # Extensions not found in the table proceed to the mime_types table.
1042
1043-Z	x-compress
1044-gz	x-gzip
1045+Z	compress
1046+gz	gzip
1047 uu	x-uuencode
1048diff -ur thttpd-2.21b/mime_types.txt thttpd-2.21b-cool/mime_types.txt
1049--- thttpd-2.21b/mime_types.txt	Sat Apr 14 04:53:30 2001
1050+++ thttpd-2.21b-cool/mime_types.txt	Sat Sep 20 14:43:20 2003
1051@@ -1,135 +1,138 @@
1052-# mime_types.txt
1053-#
1054-# A list of file extensions followed by the corresponding MIME type.
1055-# Extensions not found in the table are returned as text/plain.
1056-
1057-html	text/html; charset=%s
1058-htm	text/html; charset=%s
1059-txt	text/plain; charset=%s
1060-rtx	text/richtext
1061-etx	text/x-setext
1062-tsv	text/tab-separated-values
1063-css	text/css
1064-xml	text/xml
1065-dtd	text/xml
1066-
1067-gif	image/gif
1068-jpg	image/jpeg
1069-jpeg	image/jpeg
1070-jpe	image/jpeg
1071-jfif	image/jpeg
1072-tif	image/tiff
1073-tiff	image/tiff
1074-pbm	image/x-portable-bitmap
1075-pgm	image/x-portable-graymap
1076-ppm	image/x-portable-pixmap
1077-pnm	image/x-portable-anymap
1078-xbm	image/x-xbitmap
1079-xpm	image/x-xpixmap
1080-xwd	image/x-xwindowdump
1081-ief	image/ief
1082-png	image/png
1083-
1084-au	audio/basic
1085-snd	audio/basic
1086-aif	audio/x-aiff
1087-aiff	audio/x-aiff
1088-aifc	audio/x-aiff
1089-ra	audio/x-pn-realaudio
1090-ram	audio/x-pn-realaudio
1091-rm	audio/x-pn-realaudio
1092-rpm	audio/x-pn-realaudio-plugin
1093-wav	audio/wav
1094-mid	audio/midi
1095-midi	audio/midi
1096-kar	audio/midi
1097-mpga	audio/mpeg
1098-mp2	audio/mpeg
1099-mp3	audio/mpeg
1100-
1101-mpeg	video/mpeg
1102-mpg	video/mpeg
1103-mpe	video/mpeg
1104-qt	video/quicktime
1105-mov	video/quicktime
1106-avi	video/x-msvideo
1107-movie	video/x-sgi-movie
1108-mv	video/x-sgi-movie
1109-vx	video/x-rad-screenplay
1110-
1111-a	application/octet-stream
1112+ez	application/andrew-inset
1113+hqx	application/mac-binhex40
1114+cpt	application/mac-compactpro
1115+doc	application/msword
1116 bin	application/octet-stream
1117+dms	application/octet-stream
1118+lha	application/octet-stream
1119+lzh	application/octet-stream
1120 exe	application/octet-stream
1121-dump	application/octet-stream
1122-o	application/octet-stream
1123-class	application/java
1124-js	application/x-javascript
1125+class	application/octet-stream
1126+so	application/octet-stream
1127+dll	application/octet-stream
1128+oda	application/oda
1129+pdf	application/pdf
1130 ai	application/postscript
1131 eps	application/postscript
1132 ps	application/postscript
1133-dir	application/x-director
1134+smi	application/smil
1135+smil	application/smil
1136+mif	application/vnd.mif
1137+xls	application/vnd.ms-excel
1138+ppt	application/vnd.ms-powerpoint
1139+wbxml	application/vnd.wap.wbxml
1140+wmlc	application/vnd.wap.wmlc
1141+wmlsc	application/vnd.wap.wmlscriptc
1142+bcpio	application/x-bcpio
1143+vcd	application/x-cdlink
1144+pgn	application/x-chess-pgn
1145+cpio	application/x-cpio
1146+csh	application/x-csh
1147 dcr	application/x-director
1148+dir	application/x-director
1149 dxr	application/x-director
1150-fgd	application/x-director
1151-aam	application/x-authorware-map
1152-aas	application/x-authorware-seg
1153-aab	application/x-authorware-bin
1154-fh4	image/x-freehand
1155-fh7	image/x-freehand
1156-fh5	image/x-freehand
1157-fhc	image/x-freehand
1158-fh	image/x-freehand
1159-spl	application/futuresplash
1160-swf	application/x-shockwave-flash
1161 dvi	application/x-dvi
1162+spl	application/x-futuresplash
1163 gtar	application/x-gtar
1164 hdf	application/x-hdf
1165-hqx	application/mac-binhex40
1166-iv	application/x-inventor
1167+js	application/x-javascript
1168+skp	application/x-koan
1169+skd	application/x-koan
1170+skt	application/x-koan
1171+skm	application/x-koan
1172 latex	application/x-latex
1173-man	application/x-troff-man
1174-me	application/x-troff-me
1175-mif	application/x-mif
1176-ms	application/x-troff-ms
1177-oda	application/oda
1178-pdf	application/pdf
1179-rtf	application/rtf
1180-bcpio	application/x-bcpio
1181-cpio	application/x-cpio
1182-sv4cpio	application/x-sv4cpio
1183-sv4crc	application/x-sv4crc
1184-sh	application/x-shar
1185+nc	application/x-netcdf
1186+cdf	application/x-netcdf
1187+sh	application/x-sh
1188 shar	application/x-shar
1189+swf	application/x-shockwave-flash
1190 sit	application/x-stuffit
1191+sv4cpio	application/x-sv4cpio
1192+sv4crc	application/x-sv4crc
1193 tar	application/x-tar
1194+tcl	application/x-tcl
1195 tex	application/x-tex
1196-texi	application/x-texinfo
1197 texinfo	application/x-texinfo
1198+texi	application/x-texinfo
1199+t	application/x-troff
1200 tr	application/x-troff
1201 roff	application/x-troff
1202 man	application/x-troff-man
1203 me	application/x-troff-me
1204 ms	application/x-troff-ms
1205-zip	application/x-zip-compressed
1206-tsp	application/dsptype
1207-wsrc	application/x-wais-source
1208 ustar	application/x-ustar
1209-cdf	application/x-netcdf
1210-nc	application/x-netcdf
1211-doc	application/msword
1212-ppt	application/powerpoint
1213-
1214-crt	application/x-x509-ca-cert
1215-crl	application/x-pkcs7-crl
1216-
1217+src	application/x-wais-source
1218+xhtml	application/xhtml+xml
1219+xht	application/xhtml+xml
1220+zip	application/zip
1221+au	audio/basic
1222+snd	audio/basic
1223+mid	audio/midi
1224+midi	audio/midi
1225+kar	audio/midi
1226+mpga	audio/mpeg
1227+mp2	audio/mpeg
1228+mp3	audio/mpeg
1229+aif	audio/x-aiff
1230+aiff	audio/x-aiff
1231+aifc	audio/x-aiff
1232+m3u	audio/x-mpegurl
1233+ram	audio/x-pn-realaudio
1234+rm	audio/x-pn-realaudio
1235+rpm	audio/x-pn-realaudio-plugin
1236+ra	audio/x-realaudio
1237+wav	audio/x-wav
1238+pdb	chemical/x-pdb
1239+xyz	chemical/x-xyz
1240+bmp	image/bmp
1241+gif	image/gif
1242+ief	image/ief
1243+jpeg	image/jpeg
1244+jpg	image/jpeg
1245+jpe	image/jpeg
1246+png	image/png
1247+tiff	image/tiff
1248+tif	image/tiff
1249+djvu	image/vnd.djvu
1250+djv	image/vnd.djvu
1251+wbmp	image/vnd.wap.wbmp
1252+ras	image/x-cmu-raster
1253+pnm	image/x-portable-anymap
1254+pbm	image/x-portable-bitmap
1255+pgm	image/x-portable-graymap
1256+ppm	image/x-portable-pixmap
1257+rgb	image/x-rgb
1258+xbm	image/x-xbitmap
1259+xpm	image/x-xpixmap
1260+xwd	image/x-xwindowdump
1261+igs	model/iges
1262+iges	model/iges
1263+msh	model/mesh
1264+mesh	model/mesh
1265+silo	model/mesh
1266 wrl	model/vrml
1267 vrml	model/vrml
1268-mime	message/rfc822
1269-
1270-pac	application/x-ns-proxy-autoconfig
1271-
1272+css	text/css
1273+html	text/html; charset=%s
1274+htm	text/html; charset=%s
1275+asc	text/plain; charset=%s
1276+txt	text/plain; charset=%s
1277+rtx	text/richtext
1278+rtf	text/rtf
1279+sgml	text/sgml
1280+sgm	text/sgml
1281+tsv	text/tab-separated-values
1282 wml	text/vnd.wap.wml
1283-wmlc	application/vnd.wap.wmlc
1284 wmls	text/vnd.wap.wmlscript
1285-wmlsc	application/vnd.wap.wmlscriptc
1286-wbmp	image/vnd.wap.wbmp
1287+etx	text/x-setext
1288+xml	text/xml
1289+xsl	text/xml
1290+mpeg	video/mpeg
1291+mpg	video/mpeg
1292+mpe	video/mpeg
1293+qt	video/quicktime
1294+mov	video/quicktime
1295+mxu	video/vnd.mpegurl
1296+avi	video/x-msvideo
1297+movie	video/x-sgi-movie
1298+ice	x-conference/x-cooltalk
1299diff -ur thttpd-2.21b/mmc.c thttpd-2.21b-cool/mmc.c
1300--- thttpd-2.21b/mmc.c	Fri Apr 13 23:02:15 2001
1301+++ thttpd-2.21b-cool/mmc.c	Sat Sep 20 14:43:20 2003
1302@@ -70,6 +70,9 @@
1303     unsigned int hash;
1304     int hash_idx;
1305     struct MapStruct* next;
1306+    char nocache;
1307+	size_t last_modified_len;
1308+	char last_modified[100];
1309     } Map;
1310
1311
1312@@ -93,12 +96,13 @@
1313
1314
1315 void*
1316-mmc_map( char* filename, struct stat* sbP, struct timeval* nowP )
1317+mmc_map( char* filename, struct stat* sbP, struct timeval* nowP, int nocache, char **last_modified, size_t *last_modified_len )
1318     {
1319     time_t now;
1320     struct stat sb;
1321     Map* m;
1322     int fd;
1323+	const char* rfc1123fmt = "%a, %d %b %Y %H:%M:%S GMT";
1324
1325     /* Stat the file, if necessary. */
1326     if ( sbP != (struct stat*) 0 )
1327@@ -130,7 +134,7 @@
1328 	/* Yep.  Just return the existing map */
1329 	++m->refcount;
1330 	m->reftime = now;
1331-	return m->addr;
1332+	goto done;
1333 	}
1334
1335     /* Open the file. */
1336@@ -167,12 +171,13 @@
1337     m->ctime = sb.st_ctime;
1338     m->refcount = 1;
1339     m->reftime = now;
1340+    m->nocache = (char) nocache;
1341
1342     /* Avoid doing anything for zero-length files; some systems don't like
1343     ** to mmap them, other systems dislike mallocing zero bytes.
1344     */
1345     if ( m->size == 0 )
1346-	m->addr = (void*) 1;	/* arbitrary non-NULL address */
1347+	m->addr = (void*) 5;	/* arbitrary non-NULL address */
1348     else
1349 	{
1350 #ifdef HAVE_MMAP
1351@@ -223,6 +228,13 @@
1352     maps = m;
1353     ++map_count;
1354
1355+	strftime( m->last_modified, sizeof(m->last_modified), rfc1123fmt, gmtime( &sb.st_mtime ) );
1356+	m->last_modified_len = strlen(m->last_modified);
1357+
1358+done:
1359+	*last_modified = m->last_modified;
1360+	*last_modified_len = m->last_modified_len;
1361+
1362     /* And return the address. */
1363     return m->addr;
1364     }
1365@@ -231,27 +243,32 @@
1366 void
1367 mmc_unmap( void* addr, struct stat* sbP, struct timeval* nowP )
1368     {
1369-    Map* m = (Map*) 0;
1370+    Map* m = (Map*) 0, **mm = &maps;
1371
1372     /* Find the Map entry for this address.  First try a hash. */
1373     if ( sbP != (struct stat*) 0 )
1374 	{
1375 	m = find_hash( sbP->st_ino, sbP->st_dev, sbP->st_size, sbP->st_ctime );
1376-	if ( m != (Map*) 0 && m->addr != addr )
1377+	if ( m != (Map*) 0 && ( m->addr != addr || m->nocache == 1 ) )
1378 	    m = (Map*) 0;
1379 	}
1380     /* If that didn't work, try a full search. */
1381     if ( m == (Map*) 0 )
1382-	for ( m = maps; m != (Map*) 0; m = m->next )
1383+	for ( m = maps; m != (Map*) 0; m = m->next ) {
1384 	    if ( m->addr == addr )
1385 		break;
1386+		mm = &m->next;
1387+	}
1388     if ( m == (Map*) 0 )
1389 	syslog( LOG_ERR, "mmc_unmap failed to find entry!" );
1390     else if ( m->refcount <= 0 )
1391 	syslog( LOG_ERR, "mmc_unmap found zero or negative refcount!" );
1392     else
1393 	{
1394-	--m->refcount;
1395+	if ( --m->refcount == 0 && m->nocache == 1 ) {
1396+		really_unmap( mm );
1397+		return;
1398+	}
1399 	if ( nowP != (struct timeval*) 0 )
1400 	    m->reftime = nowP->tv_sec;
1401 	else
1402diff -ur thttpd-2.21b/mmc.h thttpd-2.21b-cool/mmc.h
1403--- thttpd-2.21b/mmc.h	Fri Apr 13 07:36:54 2001
1404+++ thttpd-2.21b-cool/mmc.h	Sat Sep 20 14:43:20 2003
1405@@ -31,8 +31,9 @@
1406 /* Returns an mmap()ed area for the given file, or (void*) 0 on errors.
1407 ** If you have a stat buffer on the file, pass it in, otherwise pass 0.
1408 ** Same for the current time.
1409+** Set nocache to 1, if this entry is supposed to be removed quickly.
1410 */
1411-extern void* mmc_map( char* filename, struct stat* sbP, struct timeval* nowP );
1412+extern void* mmc_map( char* filename, struct stat* sbP, struct timeval* nowP, int nocache, char **last_modified, size_t *last_modified_len );
1413
1414 /* Done with an mmap()ed area that was returned by mmc_map().
1415 ** If you have a stat buffer on the file, pass it in, otherwise pass 0.
1416diff -ur thttpd-2.21b/thttpd.c thttpd-2.21b-cool/thttpd.c
1417--- thttpd-2.21b/thttpd.c	Tue Apr 24 00:41:57 2001
1418+++ thttpd-2.21b-cool/thttpd.c	Sat Sep 20 14:43:20 2003
1419@@ -53,6 +53,10 @@
1420 #endif
1421 #include <unistd.h>
1422
1423+#include <sys/mman.h>
1424+
1425+#include <limits.h>
1426+
1427 #include "fdwatch.h"
1428 #include "libhttpd.h"
1429 #include "mmc.h"
1430@@ -66,6 +70,8 @@
1431 static char* dir;
1432 static int do_chroot, no_log, no_symlink, do_vhost, do_global_passwd;
1433 static char* cgi_pattern;
1434+static char* php_pattern;
1435+static char* phps_pattern;
1436 static char* url_pattern;
1437 static int no_empty_referers;
1438 static char* local_pattern;
1439@@ -95,10 +101,10 @@
1440     httpd_conn* hc;
1441     int tnums[MAXTHROTTLENUMS];         /* throttle indexes */
1442     int numtnums;
1443+    int keep_alive;
1444     long limit;
1445     time_t started_at;
1446-    Timer* idle_read_timer;
1447-    Timer* idle_send_timer;
1448+    time_t last_io;
1449     Timer* wakeup_timer;
1450     Timer* linger_timer;
1451     long wouldblock_delay;
1452@@ -106,17 +112,22 @@
1453     off_t bytes_sent;
1454     off_t bytes_to_send;
1455     } connecttab;
1456-static connecttab* connects;
1457+static connecttab* connects, **free_connects;
1458+static int next_free_connect;
1459 static int numconnects, maxconnects;
1460 static int httpd_conn_count;
1461
1462 /* The connection states. */
1463-#define CNST_FREE 0
1464-#define CNST_READING 1
1465-#define CNST_SENDING 2
1466-#define CNST_PAUSING 3
1467-#define CNST_LINGERING 4
1468-
1469+enum {
1470+	CNST_FREE = 0,
1471+	CNST_READING,
1472+	CNST_SENDING,
1473+	CNST_PAUSING,
1474+	CNST_LINGERING,
1475+	CNST_SENDING_RESP,
1476+	CNST_READING_BODY,
1477+	CNST_TOTAL_NR
1478+};
1479
1480 static httpd_server* hs = (httpd_server*) 0;
1481 int terminate = 0;
1482@@ -140,23 +151,32 @@
1483 static int handle_newconnect( struct timeval* tvP, int listen_fd );
1484 static void handle_read( connecttab* c, struct timeval* tvP );
1485 static void handle_send( connecttab* c, struct timeval* tvP );
1486+static void handle_send_resp( connecttab* c, struct timeval* tvP );
1487+static void handle_read_body( connecttab* c, struct timeval* tvP );
1488 static void handle_linger( connecttab* c, struct timeval* tvP );
1489 static int check_throttles( connecttab* c );
1490+static void timeout_conns( ClientData client_data, struct timeval* nowP );
1491 static void clear_throttles( connecttab* c, struct timeval* tvP );
1492 static void update_throttles( ClientData client_data, struct timeval* nowP );
1493-static void clear_connection( connecttab* c, struct timeval* tvP );
1494+static void clear_connection( connecttab* c, struct timeval* tvP, int );
1495 static void really_clear_connection( connecttab* c, struct timeval* tvP );
1496-static void idle_read_connection( ClientData client_data, struct timeval* nowP );
1497-static void idle_send_connection( ClientData client_data, struct timeval* nowP );
1498 static void wakeup_connection( ClientData client_data, struct timeval* nowP );
1499 static void linger_clear_connection( ClientData client_data, struct timeval* nowP );
1500 static void occasional( ClientData client_data, struct timeval* nowP );
1501+static void periodic_jobs( ClientData client_data, struct timeval* nowP );
1502 #ifdef STATS_TIME
1503 static void show_stats( ClientData client_data, struct timeval* nowP );
1504 #endif /* STATS_TIME */
1505 static void logstats( struct timeval* nowP );
1506 static void thttpd_logstats( long secs );
1507+static void boot_request(connecttab *c, struct timeval *tvP);
1508+
1509+typedef void (*handler_func)(connecttab*, struct timeval *);
1510+
1511+handler_func handler_array[CNST_TOTAL_NR] =
1512+{NULL, handle_read, handle_send, NULL, handle_linger, handle_send_resp, handle_read_body};
1513
1514+#define RUN_HANDLER(type, c) if (handler_array[type]) handler_array[type](c, &tv)
1515
1516 static void
1517 handle_term( int sig )
1518@@ -177,7 +197,7 @@
1519 	return;
1520
1521     /* Re-open the log file. */
1522-    if ( logfile != (char*) 0 )
1523+    if ( logfile != (char*) 0 && strcmp(logfile, "-") != 0)
1524 	{
1525 	logfp = fopen( logfile, "a" );
1526 	if ( logfp == (FILE*) 0 )
1527@@ -198,6 +218,8 @@
1528     }
1529
1530
1531+time_t httpd_time_now;
1532+
1533 static void
1534 handle_usr2( int sig )
1535     {
1536@@ -217,7 +239,6 @@
1537     int num_ready;
1538     int cnum, ridx;
1539     connecttab* c;
1540-    httpd_conn* hc;
1541     httpd_sockaddr sa4;
1542     httpd_sockaddr sa6;
1543     int gotv4, gotv6;
1544@@ -270,7 +291,9 @@
1545 	    no_log = 1;
1546 	    logfp = (FILE*) 0;
1547 	    }
1548-	else
1549+	else if (strcmp(logfile, "-") == 0) {
1550+		logfp = stdout;
1551+	} else
1552 	    {
1553 	    logfp = fopen( logfile, "a" );
1554 	    if ( logfp == (FILE*) 0 )
1555@@ -420,7 +443,8 @@
1556 	hostname,
1557 	gotv4 ? &sa4 : (httpd_sockaddr*) 0, gotv6 ? &sa6 : (httpd_sockaddr*) 0,
1558 	port, cgi_pattern, charset, cwd, no_log, logfp, no_symlink, do_vhost,
1559-	do_global_passwd, url_pattern, local_pattern, no_empty_referers );
1560+	do_global_passwd, url_pattern, local_pattern, no_empty_referers,
1561+	php_pattern, phps_pattern);
1562     if ( hs == (httpd_server*) 0 )
1563 	exit( 1 );
1564
1565@@ -430,6 +454,12 @@
1566 	syslog( LOG_CRIT, "tmr_create(occasional) failed" );
1567 	exit( 1 );
1568 	}
1569+
1570+	if (tmr_create(0, timeout_conns, JunkClientData, 30 * 1000, 1) == 0) {
1571+		syslog(LOG_CRIT, "tmr_create(timeout_conns) failed");
1572+		exit(1);
1573+	}
1574+
1575     if ( numthrottles > 0 )
1576 	{
1577 	/* Set up the throttles timer. */
1578@@ -439,6 +469,12 @@
1579 	    exit( 1 );
1580 	    }
1581 	}
1582+
1583+	if (tmr_create(0, periodic_jobs, JunkClientData, 2000, 1) == 0) {
1584+		syslog(LOG_CRIT, "tmr_create failed");
1585+		exit(1);
1586+	}
1587+
1588 #ifdef STATS_TIME
1589     /* Set up the stats timer. */
1590     if ( tmr_create( (struct timeval*) 0, show_stats, JunkClientData, STATS_TIME * 1000L, 1 ) == (Timer*) 0 )
1591@@ -454,12 +490,14 @@
1592     /* If we're root, try to become someone else. */
1593     if ( getuid() == 0 )
1594 	{
1595+#ifndef __CYGWIN__
1596 	/* Set aux groups to null. */
1597 	if ( setgroups( 0, (const gid_t*) 0 ) < 0 )
1598 	    {
1599 	    syslog( LOG_CRIT, "setgroups - %m" );
1600 	    exit( 1 );
1601 	    }
1602+#endif
1603 	/* Set primary group. */
1604 	if ( setgid( gid ) < 0 )
1605 	    {
1606@@ -495,13 +533,17 @@
1607 	}
1608     maxconnects -= SPARE_FDS;
1609     connects = NEW( connecttab, maxconnects );
1610+    free_connects = malloc(sizeof(connecttab *) * maxconnects);
1611+    next_free_connect = maxconnects;
1612     if ( connects == (connecttab*) 0 )
1613 	{
1614 	syslog( LOG_CRIT, "out of memory allocating a connecttab" );
1615 	exit( 1 );
1616 	}
1617+
1618     for ( cnum = 0; cnum < maxconnects; ++cnum )
1619 	{
1620+	free_connects[cnum] = &connects[maxconnects - cnum - 1];
1621 	connects[cnum].conn_state = CNST_FREE;
1622 	connects[cnum].hc = (httpd_conn*) 0;
1623 	}
1624@@ -518,6 +560,9 @@
1625
1626     /* Main loop. */
1627     (void) gettimeofday( &tv, (struct timezone*) 0 );
1628+    httpd_time_now = tv.tv_sec;
1629+	periodic_jobs(JunkClientData, &tv);
1630+
1631     while ( ( ! terminate ) || numconnects > 0 )
1632 	{
1633 	/* Do the fd watch. */
1634@@ -530,6 +575,7 @@
1635 	    exit( 1 );
1636 	    }
1637 	(void) gettimeofday( &tv, (struct timezone*) 0 );
1638+    httpd_time_now = tv.tv_sec;
1639 	if ( num_ready == 0 )
1640 	    {
1641 	    /* No fd's are ready - run the timers. */
1642@@ -565,16 +611,10 @@
1643 	    c = (connecttab*) fdwatch_get_client_data( ridx );
1644 	    if ( c == (connecttab*) 0 )
1645 		continue;
1646-	    hc = c->hc;
1647-	    if ( c->conn_state == CNST_READING &&
1648-		 fdwatch_check_fd( hc->conn_fd ) )
1649-		handle_read( c, &tv );
1650-	    else if ( c->conn_state == CNST_SENDING &&
1651-		 fdwatch_check_fd( hc->conn_fd ) )
1652-		handle_send( c, &tv );
1653-	    else if ( c->conn_state == CNST_LINGERING &&
1654-		 fdwatch_check_fd( hc->conn_fd ) )
1655-		handle_linger( c, &tv );
1656+#if DO_UNNECESSARY_CHECK_FD
1657+	    fdwatch_check_fd(c->hc->conn_fd);
1658+#endif
1659+	    RUN_HANDLER(c->conn_state, c);
1660 	    }
1661 	tmr_run( &tv );
1662
1663@@ -627,6 +667,8 @@
1664 #else /* CGI_PATTERN */
1665     cgi_pattern = (char*) 0;
1666 #endif /* CGI_PATTERN */
1667+    php_pattern = "**.php";
1668+    phps_pattern = "**.phps";
1669     url_pattern = (char*) 0;
1670     no_empty_referers = 0;
1671     local_pattern = (char*) 0;
1672@@ -833,6 +875,16 @@
1673 		value_required( name, value );
1674 		cgi_pattern = e_strdup( value );
1675 		}
1676+	    else if ( strcasecmp( name, "phppat" ) == 0 )
1677+		{
1678+		value_required( name, value );
1679+		php_pattern = e_strdup( value );
1680+		}
1681+	    else if ( strcasecmp( name, "phpspat" ) == 0 )
1682+		{
1683+		value_required( name, value );
1684+		phps_pattern = e_strdup( value );
1685+		}
1686 	    else if ( strcasecmp( name, "urlpat" ) == 0 )
1687 		{
1688 		value_required( name, value );
1689@@ -1196,8 +1248,10 @@
1690     logstats( &tv );
1691     for ( cnum = 0; cnum < maxconnects; ++cnum )
1692 	{
1693-	if ( connects[cnum].conn_state != CNST_FREE )
1694+	if ( connects[cnum].conn_state != CNST_FREE ) {
1695+	    httpd_complete_request( connects[cnum].hc, &tv );
1696 	    httpd_close_conn( connects[cnum].hc, &tv );
1697+	}
1698 	if ( connects[cnum].hc != (httpd_conn*) 0 )
1699 	    {
1700 	    httpd_destroy_conn( connects[cnum].hc );
1701@@ -1214,6 +1268,7 @@
1702 	}
1703     mmc_destroy();
1704     tmr_destroy();
1705+    free( (void*) free_connects );
1706     free( (void*) connects );
1707     if ( throttles != (throttletab*) 0 )
1708 	free( (void*) throttles );
1709@@ -1234,7 +1289,7 @@
1710     for (;;)
1711 	{
1712 	/* Is there room in the connection table? */
1713-	if ( numconnects >= maxconnects )
1714+	if ( numconnects >= maxconnects || next_free_connect == 0 )
1715 	    {
1716 	    /* Out of connection slots.  Run the timers, then the
1717 	    ** existing connections, and maybe we'll free up a slot
1718@@ -1245,10 +1300,10 @@
1719 	    return 0;
1720 	    }
1721 	/* Find a free connection entry. */
1722-	for ( cnum = 0; cnum < maxconnects; ++cnum )
1723-	    if ( connects[cnum].conn_state == CNST_FREE )
1724-		break;
1725-	c = &connects[cnum];
1726+
1727+	c = free_connects[--next_free_connect];
1728+	free_connects[next_free_connect] = NULL;
1729+
1730 	/* Make the httpd_conn if necessary. */
1731 	if ( c->hc == (httpd_conn*) 0 )
1732 	    {
1733@@ -1267,24 +1322,18 @@
1734 	    {
1735 	    case GC_FAIL:
1736 	    case GC_NO_MORE:
1737+		free_connects[next_free_connect++] = c;
1738 	    return 1;
1739 	    }
1740 	c->conn_state = CNST_READING;
1741 	++numconnects;
1742 	client_data.p = c;
1743-	c->idle_read_timer = tmr_create(
1744-	    tvP, idle_read_connection, client_data, IDLE_READ_TIMELIMIT * 1000L,
1745-	    0 );
1746-	if ( c->idle_read_timer == (Timer*) 0 )
1747-	    {
1748-	    syslog( LOG_CRIT, "tmr_create(idle_read_connection) failed" );
1749-	    exit( 1 );
1750-	    }
1751-	c->idle_send_timer = (Timer*) 0;
1752 	c->wakeup_timer = (Timer*) 0;
1753 	c->linger_timer = (Timer*) 0;
1754 	c->bytes_sent = 0;
1755 	c->numtnums = 0;
1756+	c->keep_alive = 0;
1757+	c->last_io = httpd_time_now;
1758
1759 	/* Set the connection file descriptor to no-delay mode. */
1760 	httpd_set_ndelay( c->hc->conn_fd );
1761@@ -1298,11 +1347,100 @@
1762     }
1763
1764
1765+#define FIXUP(x) if (hc->x >= oldptr && hc->x < pe) hc->x += d
1766+
1767+static void
1768+realign_hc(httpd_conn *hc, char *oldptr)
1769+{
1770+	int d = hc->read_buf - oldptr;
1771+	char *pe = oldptr + hc->checked_idx;
1772+
1773+	FIXUP(encodedurl);
1774+	FIXUP(protocol);
1775+	FIXUP(referer);
1776+	FIXUP(useragent);
1777+	FIXUP(acceptl);
1778+	FIXUP(cookie);
1779+	FIXUP(contenttype);
1780+	FIXUP(hdrhost);
1781+	FIXUP(authorization);
1782+}
1783+
1784+#undef FIXUP
1785+
1786+static void
1787+setup_read_body(connecttab *c, struct timeval *tvP)
1788+{
1789+	httpd_conn *hc = c->hc;
1790+	int already, missing;
1791+	char *oldptr = hc->read_buf;
1792+
1793+	c->conn_state = CNST_READING_BODY;
1794+
1795+	hc->read_body_into_mem = 0;
1796+
1797+	already = hc->read_idx - hc->checked_idx;
1798+	missing = hc->contentlength - already;
1799+
1800+	if (missing > 16384) {
1801+		char filename[] = "/tmp/thttpd.upload.XXXXXX";
1802+		int tmp = mkstemp(filename);
1803+
1804+		if (tmp >= 0) {
1805+			void *p;
1806+			size_t sz = hc->contentlength + hc->checked_idx + 10;
1807+
1808+			unlink(filename);
1809+
1810+			ftruncate(tmp, sz);
1811+			p = mmap(NULL, sz,
1812+					PROT_READ|PROT_WRITE, MAP_PRIVATE, tmp, 0);
1813+
1814+			if (p != MAP_FAILED) {
1815+				memcpy(p, hc->read_buf, hc->read_idx);
1816+				free(hc->read_buf);
1817+				hc->read_size = sz;
1818+				hc->read_buf = p;
1819+				hc->read_buf_is_mmap = 1;
1820+			}
1821+			close(tmp);
1822+		}
1823+
1824+		if (!hc->read_buf_is_mmap) {
1825+			clear_connection( c, tvP, 0 );
1826+			return;
1827+		}
1828+	} else if (missing > 0) {
1829+		httpd_realloc_str(&hc->read_buf, &hc->read_size, hc->checked_idx + hc->contentlength + 10);
1830+	}
1831+	if (oldptr != hc->read_buf) realign_hc(hc, oldptr);
1832+
1833+    fdwatch_del_fd( hc->conn_fd );
1834+    fdwatch_add_fd( hc->conn_fd, c, FDW_READ );
1835+}
1836+
1837+static void
1838+setup_sending(connecttab *c, int state, struct timeval *tvP)
1839+{
1840+    httpd_conn *hc = c->hc;
1841+    ClientData client_data;
1842+
1843+    c->conn_state = state;
1844+    c->started_at = tvP->tv_sec;
1845+    c->wouldblock_delay = 0;
1846+    client_data.p = c;
1847+
1848+    fdwatch_del_fd( hc->conn_fd );
1849+    fdwatch_add_fd( hc->conn_fd, c, FDW_WRITE );
1850+}
1851+
1852+static void handle_request( connecttab *c, struct timeval *tvP);
1853+
1854+
1855 static void
1856 handle_read( connecttab* c, struct timeval* tvP )
1857     {
1858     int sz;
1859-    ClientData client_data;
1860     httpd_conn* hc = c->hc;
1861
1862     /* Is there room in our buffer to read more bytes? */
1863@@ -1311,7 +1449,7 @@
1864 	if ( hc->read_size > 5000 )
1865 	    {
1866 	    httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" );
1867-	    clear_connection( c, tvP );
1868+	    clear_connection( c, tvP, 0 );
1869 	    return;
1870 	    }
1871 	httpd_realloc_str(
1872@@ -1327,14 +1465,53 @@
1873     ** EWOULDBLOCK; however, this apparently can happen if a packet gets
1874     ** garbled.
1875     */
1876-    if ( sz == 0 || ( sz < 0 && ( errno != EWOULDBLOCK ) ) )
1877-	{
1878-	httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" );
1879-	clear_connection( c, tvP );
1880+    if ( sz == 0 ) {
1881+    	if (! c->keep_alive) {
1882+		httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" );
1883+	}
1884+	clear_connection( c, tvP, 0 );
1885+	return;
1886+    } else if ( sz < 0 ) {
1887+    	if (errno != EWOULDBLOCK) {
1888+		clear_connection( c, tvP, 0 );
1889+	}
1890 	return;
1891+    }
1892+
1893+	/* If this is a persistent PHP connection, we must not receive
1894+	** any further requests on this connection. Some broken HTTP/1.1
1895+	** implementations (e.g. Mozilla 1.0.1) are known to do
1896+	** pipelining on a connection, although a prior response included
1897+	** Connection: close
1898+	*/
1899+	if (c->hc->file_address == (char *) 1) {
1900+		return;
1901+	}
1902+
1903+    c->last_io = httpd_time_now;
1904+    if (sz > 0) hc->read_idx += sz;
1905+
1906+    /*
1907+    ** if we start getting new data on this socket, "promote" it
1908+    **  to read timeout
1909+    */
1910+    if ( hc->keep_alive ) {
1911+		ClientData client_data;
1912+
1913+
1914+	client_data.p = c;
1915+
1916+    	hc->keep_alive = 0;
1917+    }
1918+	handle_request(c, tvP);
1919 	}
1920-    hc->read_idx += sz;
1921
1922+
1923+static void
1924+handle_request( connecttab *c, struct timeval *tvP)
1925+{
1926+    httpd_conn* hc = c->hc;
1927+
1928     /* Do we have a complete request yet? */
1929     switch ( httpd_got_request( hc ) )
1930 	{
1931@@ -1342,14 +1519,14 @@
1932 	return;
1933 	case GR_BAD_REQUEST:
1934 	httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" );
1935-	clear_connection( c, tvP );
1936+	clear_connection( c, tvP, 0 );
1937 	return;
1938 	}
1939
1940     /* Yes.  Try parsing and resolving it. */
1941     if ( httpd_parse_request( hc ) < 0 )
1942 	{
1943-	clear_connection( c, tvP );
1944+	clear_connection( c, tvP, 0 );
1945 	return;
1946 	}
1947
1948@@ -1358,18 +1535,28 @@
1949 	{
1950 	httpd_send_err(
1951 	    hc, 503, httpd_err503title, "", httpd_err503form, hc->encodedurl );
1952-	clear_connection( c, tvP );
1953+	clear_connection( c, tvP, 0 );
1954 	return;
1955 	}
1956+	boot_request(c, tvP);
1957+}
1958
1959+static void boot_request(connecttab *c, struct timeval *tvP)
1960+{
1961+	httpd_conn *hc = c->hc;
1962     /* Start the connection going. */
1963     if ( httpd_start_request( hc, tvP ) < 0 )
1964 	{
1965 	/* Something went wrong.  Close down the connection. */
1966-	clear_connection( c, tvP );
1967+	clear_connection( c, tvP, 0 );
1968 	return;
1969 	}
1970
1971+    if ( hc->read_body_into_mem ) {
1972+	setup_read_body( c, tvP );
1973+	return;
1974+	}
1975+
1976     /* Fill in bytes_to_send. */
1977     if ( hc->got_range )
1978 	{
1979@@ -1384,37 +1571,25 @@
1980 	{
1981 	/* No file address means someone else is handling it. */
1982 	c->bytes_sent = hc->bytes_sent;
1983-	clear_connection( c, tvP );
1984+	clear_connection( c, tvP, 1 );
1985 	return;
1986 	}
1987+	if (hc->file_address == (char *) 1) {
1988+		c->last_io = (time_t) LONG_MAX;
1989+		c->wouldblock_delay = 0;
1990+		return;
1991+	}
1992     if ( c->bytes_sent >= c->bytes_to_send )
1993 	{
1994 	/* There's nothing to send. */
1995-	clear_connection( c, tvP );
1996+	clear_connection( c, tvP, 1 );
1997 	return;
1998 	}
1999
2000     /* Cool, we have a valid connection and a file to send to it. */
2001-    c->conn_state = CNST_SENDING;
2002-    c->started_at = tvP->tv_sec;
2003-    c->wouldblock_delay = 0;
2004-    client_data.p = c;
2005-    tmr_cancel( c->idle_read_timer );
2006-    c->idle_read_timer = (Timer*) 0;
2007-    c->idle_send_timer = tmr_create(
2008-	tvP, idle_send_connection, client_data, IDLE_SEND_TIMELIMIT * 1000L,
2009-	0 );
2010-    if ( c->idle_send_timer == (Timer*) 0 )
2011-	{
2012-	syslog( LOG_CRIT, "tmr_create(idle_send_connection) failed" );
2013-	exit( 1 );
2014-	}
2015-
2016-    fdwatch_del_fd( hc->conn_fd );
2017-    fdwatch_add_fd( hc->conn_fd, c, FDW_WRITE );
2018+    setup_sending(c, CNST_SENDING, tvP);
2019     }
2020
2021-
2022 static void
2023 handle_send( connecttab* c, struct timeval* tvP )
2024     {
2025@@ -1443,6 +1618,9 @@
2026 	iv[1].iov_base = &(hc->file_address[c->bytes_sent]);
2027 	iv[1].iov_len = MIN( c->bytes_to_send - c->bytes_sent, c->limit );
2028 	sz = writev( hc->conn_fd, iv, 2 );
2029+/*
2030+printf("**RESPONSE2 [%d]** len = %d\n%*.*s\n", hc->conn_fd, hc->responselen, hc->responselen, hc->responselen, hc->response);
2031+*/
2032 	}
2033
2034     if ( sz == 0 ||
2035@@ -1486,12 +1664,12 @@
2036 	*/
2037 	if ( errno != EPIPE && errno != EINVAL && errno != ECONNRESET )
2038 	    syslog( LOG_ERR, "write - %m sending %.80s", hc->encodedurl );
2039-	clear_connection( c, tvP );
2040+	clear_connection( c, tvP, 0 );
2041 	return;
2042 	}
2043
2044     /* Ok, we wrote something. */
2045-    tmr_reset( tvP, c->idle_send_timer );
2046+    c->last_io = httpd_time_now;
2047     /* Was this a headers + file writev()? */
2048     if ( hc->responselen > 0 )
2049 	{
2050@@ -1500,7 +1678,7 @@
2051 	    {
2052 	    /* Yes; move the unwritten part to the front of the buffer. */
2053 	    int newlen = hc->responselen - sz;
2054-	    (void) memcpy( hc->response, &(hc->response[sz]), newlen );
2055+	    (void) memmove( hc->response, &(hc->response[sz]), newlen );
2056 	    hc->responselen = newlen;
2057 	    sz = 0;
2058 	    }
2059@@ -1519,7 +1697,7 @@
2060     if ( c->bytes_sent >= c->bytes_to_send )
2061 	{
2062 	/* This conection is finished! */
2063-	clear_connection( c, tvP );
2064+	clear_connection( c, tvP, 1 );
2065 	return;
2066 	}
2067
2068@@ -1560,6 +1738,9 @@
2069     char buf[1024];
2070     int r;
2071
2072+/*
2073+printf("*LINGER read\n");
2074+*/
2075     /* In lingering-close mode we just read and ignore bytes.  An error
2076     ** or EOF ends things, otherwise we go until a timeout.
2077     */
2078@@ -1569,6 +1750,63 @@
2079     }
2080
2081
2082+static void
2083+handle_read_body(connecttab *c, struct timeval *tvP)
2084+{
2085+	httpd_conn *hc = c->hc;
2086+	int n;
2087+
2088+	n = read(hc->conn_fd, hc->read_buf + hc->read_idx,
2089+			hc->contentlength - (hc->read_idx - hc->checked_idx));
2090+
2091+	if (n <= 0) {
2092+		if (errno == EAGAIN)
2093+			return;
2094+		clear_connection(c, tvP, 0);
2095+		return;
2096+	}
2097+
2098+	c->last_io = httpd_time_now;
2099+
2100+	hc->read_idx += n;
2101+
2102+	if (hc->contentlength == hc->read_idx - hc->checked_idx) {
2103+		boot_request(c, tvP);
2104+		return;
2105+	}
2106+}
2107+
2108+static void
2109+handle_send_resp(connecttab *c, struct timeval *tvP)
2110+{
2111+	httpd_conn* hc = c->hc;
2112+	int n = send(hc->conn_fd, hc->response, hc->responselen, 0);
2113+	int dokeep = 1;
2114+
2115+	if (n < 0) {
2116+		if (errno == EAGAIN)
2117+			return;
2118+
2119+		dokeep = 0;
2120+		goto clear;
2121+	}
2122+
2123+	c->last_io = httpd_time_now;
2124+
2125+	if (n == hc->responselen) {
2126+clear:
2127+		hc->response = realloc(hc->response, hc->maxresponse + 1);
2128+		hc->responselen = 0;
2129+
2130+		clear_connection(c, tvP, dokeep);
2131+		return;
2132+	}
2133+
2134+	hc->responselen -= n;
2135+
2136+	memmove(hc->response, hc->response + n, hc->responselen);
2137+}
2138+
2139 static int
2140 check_throttles( connecttab* c )
2141     {
2142@@ -1635,23 +1873,18 @@
2143
2144
2145 static void
2146-clear_connection( connecttab* c, struct timeval* tvP )
2147+clear_connection( connecttab* c, struct timeval* tvP, int doKeep )
2148     {
2149     ClientData client_data;
2150+    int		linger;
2151
2152     /* If we haven't actually sent the buffered response yet, do so now. */
2153-    httpd_write_response( c->hc );
2154+    if (c->hc->responselen && c->conn_state != CNST_SENDING_RESP) {
2155+		setup_sending(c, CNST_SENDING_RESP, tvP);
2156
2157-    if ( c->idle_read_timer != (Timer*) 0 )
2158-	{
2159-	tmr_cancel( c->idle_read_timer );
2160-	c->idle_read_timer = 0;
2161-	}
2162-    if ( c->idle_send_timer != (Timer*) 0 )
2163-	{
2164-	tmr_cancel( c->idle_send_timer );
2165-	c->idle_send_timer = 0;
2166+		return;
2167 	}
2168+
2169     if ( c->wakeup_timer != (Timer*) 0 )
2170 	{
2171 	tmr_cancel( c->wakeup_timer );
2172@@ -1669,13 +1902,36 @@
2173     ** circumstances that make a lingering close necessary.  If the flag
2174     ** isn't set we do the real close now.
2175     */
2176-    if ( c->hc->should_linger )
2177+
2178+    if ( c->hc->do_keep_alive && doKeep)
2179 	{
2180-	c->conn_state = CNST_LINGERING;
2181+		httpd_conn *hc = c->hc;
2182+	c->conn_state = CNST_READING;
2183+
2184+	client_data.p = c;
2185+	c->bytes_sent = 0;
2186+	c->numtnums = 0;
2187+	c->keep_alive = 1;
2188+
2189+	httpd_complete_request( c->hc, tvP );
2190+
2191 	fdwatch_del_fd( c->hc->conn_fd );
2192 	fdwatch_add_fd( c->hc->conn_fd, c, FDW_READ );
2193+
2194+	httpd_request_reset( c->hc, 1 );
2195+
2196+	hc->read_idx -= hc->checked_idx;
2197+	memmove(hc->read_buf, hc->read_buf + hc->checked_idx, hc->read_idx);
2198+	hc->checked_idx = 0;
2199+
2200 	/* Make sure we are still in no-delay mode. */
2201 	httpd_set_ndelay( c->hc->conn_fd );
2202+	handle_request(c, tvP);
2203+	}
2204+    else if ( c->hc->should_linger )
2205+        {
2206+	c->conn_state = CNST_LINGERING;
2207+
2208 	client_data.p = c;
2209 	c->linger_timer = tmr_create(
2210 	    tvP, linger_clear_connection, client_data, LINGER_TIME * 1000L, 0 );
2211@@ -1684,9 +1940,19 @@
2212 	    syslog( LOG_CRIT, "tmr_create(linger_clear_connection) failed" );
2213 	    exit( 1 );
2214 	    }
2215+
2216+    	httpd_complete_request( c->hc, tvP );
2217+
2218+	fdwatch_del_fd( c->hc->conn_fd );
2219+	fdwatch_add_fd( c->hc->conn_fd, c, FDW_READ );
2220+	/* Make sure we are still in no-delay mode. */
2221+	httpd_set_ndelay( c->hc->conn_fd );
2222 	}
2223-    else
2224+     else
2225+        {
2226+    	httpd_complete_request( c->hc, tvP );
2227 	really_clear_connection( c, tvP );
2228+	}
2229     }
2230
2231
2232@@ -1702,45 +1968,12 @@
2233 	tmr_cancel( c->linger_timer );
2234 	c->linger_timer = 0;
2235 	}
2236+    free_connects[next_free_connect++] = c;
2237     c->conn_state = CNST_FREE;
2238     --numconnects;
2239     }
2240
2241
2242-static void
2243-idle_read_connection( ClientData client_data, struct timeval* nowP )
2244-    {
2245-    connecttab* c;
2246-
2247-    c = (connecttab*) client_data.p;
2248-    c->idle_read_timer = (Timer*) 0;
2249-    if ( c->conn_state != CNST_FREE )
2250-	{
2251-	syslog( LOG_INFO,
2252-	    "%.80s connection timed out reading",
2253-	    httpd_ntoa( &c->hc->client_addr ) );
2254-	httpd_send_err( c->hc, 408, httpd_err408title, "", httpd_err408form, "" );
2255-	clear_connection( c, nowP );
2256-	}
2257-    }
2258-
2259-
2260-static void
2261-idle_send_connection( ClientData client_data, struct timeval* nowP )
2262-    {
2263-    connecttab* c;
2264-
2265-    c = (connecttab*) client_data.p;
2266-    c->idle_send_timer = (Timer*) 0;
2267-    if ( c->conn_state != CNST_FREE )
2268-	{
2269-	syslog( LOG_INFO,
2270-	    "%.80s connection timed out sending",
2271-	    httpd_ntoa( &c->hc->client_addr ) );
2272-	clear_connection( c, nowP );
2273-	}
2274-    }
2275-
2276
2277 static void
2278 wakeup_connection( ClientData client_data, struct timeval* nowP )
2279@@ -1783,6 +2016,43 @@
2280     }
2281 #endif /* STATS_TIME */
2282
2283+char httpd_now_buf[100];
2284+
2285+
2286+
2287+static void
2288+periodic_jobs( ClientData client_data, struct timeval* nowP )
2289+{
2290+	const char* rfc1123fmt = "%a, %d %b %Y %H:%M:%S GMT";
2291+	struct tm *t;
2292+	char date_nozone[100];
2293+	const char* cernfmt_nozone = "%d/%b/%Y:%H:%M:%S";
2294+	char data[100];
2295+	int zone;
2296+	char sign;
2297+
2298+	strftime( httpd_now_buf, sizeof(httpd_now_buf), rfc1123fmt, gmtime( &nowP->tv_sec ) );
2299+
2300+	t = localtime(&nowP->tv_sec);
2301+	strftime( date_nozone, sizeof(date_nozone), cernfmt_nozone, t );
2302+#ifdef HAVE_TM_GMTOFF
2303+    zone = t->tm_gmtoff / 60L;
2304+#else
2305+    zone = -timezone / 60L;
2306+    /* Probably have to add something about daylight time here. */
2307+#endif
2308+    if ( zone >= 0 )
2309+        sign = '+';
2310+    else
2311+        {
2312+        sign = '-';
2313+        zone = -zone;
2314+        }
2315+    zone = ( zone / 60 ) * 100 + zone % 60;
2316+    hs->log_date_len = sprintf( hs->log_date, "%s %c%04d", date_nozone, sign,
2317+			zone );
2318+}
2319+
2320
2321 /* Generate debugging statistics syslog messages for all packages. */
2322 static void
2323@@ -1826,3 +2096,42 @@
2324     stats_connections = stats_bytes = 0L;
2325     stats_simultaneous = 0;
2326     }
2327+
2328+static void
2329+timeout_conns(ClientData client_data, struct timeval *nowP)
2330+{
2331+    connecttab *c = connects, *ce = c + maxconnects;
2332+    time_t now = nowP->tv_sec;
2333+    int r = 0, w = 0;
2334+    int checked = 0;
2335+
2336+    while (c < ce) {
2337+        switch (c->conn_state) {
2338+        case CNST_SENDING:
2339+        case CNST_SENDING_RESP:
2340+            checked++;
2341+            if ((now - c->last_io) > IDLE_SEND_TIMELIMIT) {
2342+                clear_connection( c, nowP, 0 );
2343+                w++;
2344+            }
2345+            break;
2346+        case CNST_READING:
2347+        case CNST_READING_BODY:
2348+            checked++;
2349+            if ((now - c->last_io) > IDLE_READ_TIMELIMIT) {
2350+                clear_connection( c, nowP, 0 );
2351+                r++;
2352+            }
2353+            break;
2354+        case CNST_FREE: break;
2355+        default: checked++; break;
2356+        }
2357+        c++;
2358+        if (checked >= numconnects) break;
2359+    }
2360+
2361+    if (r > 0 || w > 0) {
2362+        syslog(LOG_INFO, "Expired %d/%d connections in read/write state", r, w);
2363+    }
2364+}
2365+
2366diff -ur thttpd-2.21b/version.h thttpd-2.21b-cool/version.h
2367--- thttpd-2.21b/version.h	Tue Apr 24 04:05:23 2001
2368+++ thttpd-2.21b-cool/version.h	Sat Sep 20 14:43:20 2003
2369@@ -3,7 +3,7 @@
2370 #ifndef _VERSION_H_
2371 #define _VERSION_H_
2372
2373-#define SERVER_SOFTWARE "thttpd/2.21b 23apr2001"
2374+#define SERVER_SOFTWARE "thttpd/2.21b PHP/20030920"
2375 #define SERVER_ADDRESS "http://www.acme.com/software/thttpd/"
2376
2377 #endif /* _VERSION_H_ */
2378