thttpd_patch   [plain text]


diff -ur thttpd-2.21b/Makefile.in thttpd-2.21b-cool/Makefile.in
--- thttpd-2.21b/Makefile.in	Thu Mar 29 20:36:21 2001
+++ thttpd-2.21b-cool/Makefile.in	Sat Sep 20 14:43:20 2003
@@ -46,13 +46,15 @@
 
 # You shouldn't need to edit anything below here.
 
+include php_makefile
+
 CC =		@CC@
 CCOPT =		@V_CCOPT@
 DEFS =		@DEFS@
-INCLS =		-I.
+INCLS =		-I. $(PHP_CFLAGS)
 CFLAGS =	$(CCOPT) $(DEFS) $(INCLS)
-LDFLAGS =	@LDFLAGS@
-LIBS =		@LIBS@
+LDFLAGS =	@LDFLAGS@ $(PHP_LDFLAGS)
+LIBS =		@LIBS@ $(PHP_LIBS)
 NETLIBS =	@V_NETLIBS@
 INSTALL =	@INSTALL@
 
@@ -62,7 +64,7 @@
 	@rm -f $@
 	$(CC) $(CFLAGS) -c $*.c
 
-SRC =		thttpd.c libhttpd.c fdwatch.c mmc.c timers.c match.c tdate_parse.c syslog.c
+SRC =		thttpd.c libhttpd.c fdwatch.c mmc.c timers.c match.c tdate_parse.c syslog.c php_thttpd.c
 
 OBJ =		$(SRC:.c=.o) @LIBOBJS@
 
@@ -77,7 +79,7 @@
 all:		this subdirs
 this:		$(ALL)
 
-thttpd: $(OBJ)
+thttpd: $(OBJ) libphp5.a
 	@rm -f $@
 	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJ) $(LIBS) $(NETLIBS)
 
diff -ur thttpd-2.21b/config.h thttpd-2.21b-cool/config.h
--- thttpd-2.21b/config.h	Mon Apr  9 23:57:36 2001
+++ thttpd-2.21b-cool/config.h	Sat Sep 20 14:43:20 2003
@@ -82,6 +82,11 @@
 */
 #define IDLE_READ_TIMELIMIT 60
 
+/* CONFIGURE: How many seconds to allow for reading the subsequent requests
+** on a keep-alive connection.  Should be simiar to LINGER_TIME
+*/
+#define IDLE_KEEPALIVE_TIMELIMIT 2
+
 /* CONFIGURE: How many seconds before an idle connection gets closed.
 */
 #define IDLE_SEND_TIMELIMIT 300
@@ -316,7 +321,7 @@
 /* CONFIGURE: A list of index filenames to check.  The files are searched
 ** for in this order.
 */
-#define INDEX_NAMES "index.html", "index.htm", "Default.htm", "index.cgi"
+#define INDEX_NAMES "index.php", "index.html", "index.htm", "Default.htm", "index.cgi"
 
 /* CONFIGURE: If this is defined then thttpd will automatically generate
 ** index pages for directories that don't have an explicit index file.
diff -ur thttpd-2.21b/configure thttpd-2.21b-cool/configure
--- thttpd-2.21b/configure	Sat Apr 21 02:07:14 2001
+++ thttpd-2.21b-cool/configure	Sat Sep 20 14:43:20 2003
@@ -1021,7 +1021,7 @@
 fi
 echo "$ac_t""$CPP" 1>&6
 
-for ac_hdr in fcntl.h grp.h memory.h paths.h poll.h sys/poll.h sys/event.h osreldate.h
+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
 do
 ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
 echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
diff -ur thttpd-2.21b/configure.in thttpd-2.21b-cool/configure.in
--- thttpd-2.21b/configure.in	Sat Apr 21 02:06:23 2001
+++ thttpd-2.21b-cool/configure.in	Sat Sep 20 14:43:20 2003
@@ -64,7 +64,7 @@
 	AC_MSG_RESULT(no)   
 fi
 
-AC_CHECK_HEADERS(fcntl.h grp.h memory.h paths.h poll.h sys/poll.h sys/event.h osreldate.h)
+AC_CHECK_HEADERS(fcntl.h grp.h memory.h paths.h poll.h sys/poll.h sys/event.h osreldate.h netinet/tcp.h)
 AC_HEADER_TIME
 AC_HEADER_DIRENT
 
diff -ur thttpd-2.21b/fdwatch.c thttpd-2.21b-cool/fdwatch.c
--- thttpd-2.21b/fdwatch.c	Fri Apr 13 07:36:08 2001
+++ thttpd-2.21b-cool/fdwatch.c	Sat Sep 20 14:43:20 2003
@@ -419,6 +419,7 @@
     if ( pollfds == (struct pollfd*) 0 || poll_fdidx == (int*) 0 ||
 	 poll_rfdidx == (int*) 0 )
 	return -1;
+	memset(pollfds, 0, sizeof(struct pollfd) * nfiles);
     return 0;
     }
 
@@ -460,7 +461,7 @@
 
     ridx = 0;
     for ( i = 0; i < npollfds; ++i )
-	if ( pollfds[i].revents & ( POLLIN | POLLOUT ) )
+	if ( pollfds[i].revents & ( POLLIN | POLLOUT | POLLERR | POLLHUP | POLLNVAL ) )
 	    poll_rfdidx[ridx++] = pollfds[i].fd;
 
     return r;
@@ -472,8 +473,8 @@
     {
     switch ( fd_rw[fd] )
 	{
-	case FDW_READ: return pollfds[poll_fdidx[fd]].revents & POLLIN;
-	case FDW_WRITE: return pollfds[poll_fdidx[fd]].revents & POLLOUT;
+	case FDW_READ: return pollfds[poll_fdidx[fd]].revents & ( POLLIN | POLLERR | POLLHUP | POLLNVAL );
+	case FDW_WRITE: return pollfds[poll_fdidx[fd]].revents & (  POLLOUT | POLLERR | POLLHUP | POLLNVAL );
 	default: return 0;
 	}
     }
diff -ur thttpd-2.21b/libhttpd.c thttpd-2.21b-cool/libhttpd.c
--- thttpd-2.21b/libhttpd.c	Tue Apr 24 00:42:40 2001
+++ thttpd-2.21b-cool/libhttpd.c	Sat Sep 20 14:43:29 2003
@@ -56,6 +56,10 @@
 #include <unistd.h>
 #include <stdarg.h>
 
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+
 #ifdef HAVE_OSRELDATE_H
 #include <osreldate.h>
 #endif /* HAVE_OSRELDATE_H */
@@ -85,6 +89,12 @@
 #include "match.h"
 #include "tdate_parse.h"
 
+#include "php_thttpd.h"
+
+#ifdef __CYGWIN__
+# define timezone _timezone
+#endif
+
 #ifndef STDIN_FILENO
 #define STDIN_FILENO 0
 #endif
@@ -111,7 +121,7 @@
 static int initialize_listen_socket( httpd_sockaddr* saP );
 static void unlisten( httpd_server* hs );
 static void add_response( httpd_conn* hc, char* str );
-static void send_mime( httpd_conn* hc, int status, char* title, char* encodings, char* extraheads, char* type, int length, time_t mod );
+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 );
 static void send_response( httpd_conn* hc, int status, char* title, char* extraheads, char* form, char* arg );
 static void send_response_tail( httpd_conn* hc );
 static void defang( char* str, char* dfstr, int dfsize );
@@ -242,6 +252,10 @@
 	free( (void*) hs->cwd );
     if ( hs->cgi_pattern != (char*) 0 )
 	free( (void*) hs->cgi_pattern );
+    if ( hs->php_pattern != (char*) 0 )
+	free( (void*) hs->php_pattern );
+    if ( hs->phps_pattern != (char*) 0 )
+	free( (void*) hs->phps_pattern );
     if ( hs->charset != (char*) 0 )
 	free( (void*) hs->charset );
     if ( hs->url_pattern != (char*) 0 )
@@ -249,6 +263,7 @@
     if ( hs->local_pattern != (char*) 0 )
 	free( (void*) hs->local_pattern );
     free( (void*) hs );
+    thttpd_php_shutdown();
     }
 
 
@@ -257,7 +272,8 @@
     char* hostname, httpd_sockaddr* sa4P, httpd_sockaddr* sa6P, int port,
     char* cgi_pattern, char* charset, char* cwd, int no_log, FILE* logfp,
     int no_symlink, int vhost, int global_passwd, char* url_pattern,
-    char* local_pattern, int no_empty_referers )
+    char* local_pattern, int no_empty_referers, char* php_pattern,
+    char* phps_pattern )
     {
     httpd_server* hs;
     static char ghnbuf[256];
@@ -312,6 +328,8 @@
 	}
 
     hs->port = port;
+    hs->php_pattern = strdup(php_pattern);
+    hs->phps_pattern = strdup(phps_pattern);
     if ( cgi_pattern == (char*) 0 )
 	hs->cgi_pattern = (char*) 0;
     else
@@ -329,7 +347,7 @@
 	while ( ( cp = strstr( hs->cgi_pattern, "|/" ) ) != (char*) 0 )
 	    (void) strcpy( cp + 1, cp + 2 );
 	}
-    hs->charset = strdup( charset );
+	hs->charset = strdup( charset );
     hs->cwd = strdup( cwd );
     if ( hs->cwd == (char*) 0 )
 	{
@@ -385,6 +403,8 @@
 	return (httpd_server*) 0;
 	}
 
+    thttpd_php_init();
+
     /* Done initializing. */
     if ( hs->binding_hostname == (char*) 0 )
 	syslog( LOG_INFO, "%.80s starting on port %d", SERVER_SOFTWARE, hs->port );
@@ -418,6 +438,11 @@
 	}
     (void) fcntl( listen_fd, F_SETFD, 1 );
 
+#if defined(TCP_DEFER_ACCEPT) && defined(SOL_TCP)
+	on = 30; /* give clients 30s to send first data packet */
+	setsockopt(listen_fd, SOL_TCP, TCP_DEFER_ACCEPT, &on, sizeof(on));
+#endif
+	
     /* Allow reuse of local addresses. */
     on = 1;
     if ( setsockopt(
@@ -582,6 +607,9 @@
     /* And send it, if necessary. */
     if ( hc->responselen > 0 )
 	{
+/*
+printf("**RESPONSE [%d]** len = %d\n%*.*s\n", hc->conn_fd, hc->responselen, hc->responselen, hc->responselen, hc->response); 
+*/
 	(void) write( hc->conn_fd, hc->response, hc->responselen );
 	hc->responselen = 0;
 	}
@@ -619,18 +647,22 @@
 	}
     }
 
+extern time_t httpd_time_now;
+extern char httpd_now_buf[];
+
+#define SMART_STR_USE_REALLOC
+
+#include "ext/standard/php_smart_str.h"
 
 static void
-send_mime( httpd_conn* hc, int status, char* title, char* encodings, char* extraheads, char* type, int length, time_t mod )
+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)
     {
-    time_t now;
     const char* rfc1123fmt = "%a, %d %b %Y %H:%M:%S GMT";
-    char nowbuf[100];
     char modbuf[100];
-    char fixed_type[500];
-    char buf[1000];
     int partial_content;
-
+	smart_str s = {0};
+	int type_len;
+	
     hc->status = status;
     hc->bytes_to_send = length;
     if ( hc->mime_flag )
@@ -649,41 +681,89 @@
 	else
 	    partial_content = 0;
 
-	now = time( (time_t*) 0 );
 	if ( mod == (time_t) 0 )
-	    mod = now;
-	(void) strftime( nowbuf, sizeof(nowbuf), rfc1123fmt, gmtime( &now ) );
-	(void) strftime( modbuf, sizeof(modbuf), rfc1123fmt, gmtime( &mod ) );
-	(void) my_snprintf(
-	    fixed_type, sizeof(fixed_type), type, hc->hs->charset );
-	(void) my_snprintf( buf, sizeof(buf),
-	    "%.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",
-	    hc->protocol, status, title, EXPOSED_SERVER_SOFTWARE, fixed_type,
-	    nowbuf, modbuf );
-	add_response( hc, buf );
+	    mod = httpd_time_now;
+	
+	if (last_modified == 0) {
+		(void) strftime( modbuf, sizeof(modbuf), rfc1123fmt, gmtime( &mod ) );
+		last_modified = modbuf;
+		last_modified_len = strlen(modbuf);
+	}
+	
+	type_len = strlen(type);
+	
+	if (hc->response) {
+		s.c = hc->response;
+		s.len = 0;
+		s.a = hc->maxresponse;
+		hc->response = 0;
+		hc->maxresponse = 0;
+	}
+	
+	smart_str_appends(&s, "HTTP/1.1 ");
+	smart_str_append_long(&s, status);
+	smart_str_appends(&s, " HTTP\r\nServer: " EXPOSED_SERVER_SOFTWARE "\r\n"
+			"Content-Type: ");
+	
+	if (type[type_len-2] == '%' && type[type_len-1] == 's') {
+		smart_str_appendl(&s, type, type_len - 2);
+		smart_str_appends(&s, hc->hs->charset);
+	} else {
+		smart_str_appendl(&s, type, type_len);
+	}
+
+	
+	smart_str_appends(&s, "\r\nDate: ");
+	smart_str_appends(&s, httpd_now_buf);
+	smart_str_appends(&s, "\r\nLast-Modified: ");
+	smart_str_appendl(&s, last_modified, last_modified_len);
+	smart_str_appends(&s, "\r\nAccept-Ranges: bytes\r\n");
+
 	if ( encodings[0] != '\0' )
 	    {
-	    (void) my_snprintf( buf, sizeof(buf),
-		"Content-Encoding: %s\r\n", encodings );
-	    add_response( hc, buf );
+			smart_str_appends(&s, "Content-Encoding: ");
+			smart_str_appends(&s, encodings);
+			smart_str_appends(&s, "\r\n");
 	    }
 	if ( partial_content )
 	    {
-	    (void) my_snprintf( buf, sizeof(buf),
-		"Content-Range: bytes %ld-%ld/%d\r\nContent-Length: %ld\r\n",
-		(long) hc->init_byte_loc, (long) hc->end_byte_loc, length,
-		(long) ( hc->end_byte_loc - hc->init_byte_loc + 1 ) );
-	    add_response( hc, buf );
+
+			smart_str_appends(&s, "Content-Range: bytes ");
+			smart_str_append_long(&s, hc->init_byte_loc);
+			smart_str_appendc(&s, '-');
+			smart_str_append_long(&s, hc->end_byte_loc);
+			smart_str_appendc(&s, '/');
+			smart_str_append_long(&s, length);
+			smart_str_appends(&s, "\r\nContent-Length: ");
+			smart_str_append_long(&s, hc->end_byte_loc - hc->init_byte_loc + 1);
+			smart_str_appends(&s, "\r\n");
+
 	    }
 	else if ( length >= 0 )
 	    {
-	    (void) my_snprintf( buf, sizeof(buf),
-		"Content-Length: %d\r\n", length );
-	    add_response( hc, buf );
+			smart_str_appends(&s, "Content-Length: ");
+			smart_str_append_long(&s, length);
+			smart_str_appends(&s, "\r\n");
 	    }
+	else {
+		hc->do_keep_alive = 0;
+	}
 	if ( extraheads[0] != '\0' )
-	    add_response( hc, extraheads );
-	add_response( hc, "\r\n" );
+		smart_str_appends(&s, extraheads);
+	if (hc->do_keep_alive) {
+		smart_str_appends(&s, "Connection: keep-alive\r\n\r\n" );
+	} else {
+		smart_str_appends(&s, "Connection: close\r\n\r\n" );
+	}
+	smart_str_0(&s);
+
+	if (hc->response) {
+		free(hc->response);
+	}
+	hc->response = s.c;
+	hc->maxresponse = s.a;
+	hc->responselen = s.len;
+
 	}
     }
 
@@ -725,7 +805,7 @@
     {
     char defanged_arg[1000], buf[2000];
 
-    send_mime( hc, status, title, "", extraheads, "text/html", -1, 0 );
+    send_mime( hc, status, title, "", extraheads, "text/html", -1, 0, 0, 0 );
     (void) my_snprintf( buf, sizeof(buf),
 	"<HTML><HEAD><TITLE>%d %s</TITLE></HEAD>\n<BODY BGCOLOR=\"#cc9999\"><H2>%d %s</H2>\n",
 	status, title, status, title );
@@ -764,7 +844,7 @@
     char* cp2;
 
     for ( cp1 = str, cp2 = dfstr;
-	  *cp1 != '\0' && cp2 - dfstr < dfsize - 1;
+	  *cp1 != '\0' && cp2 - dfstr < dfsize - 5;
 	  ++cp1, ++cp2 )
 	{
 	switch ( *cp1 )
@@ -834,7 +914,7 @@
     fp = fopen( filename, "r" );
     if ( fp == (FILE*) 0 )
 	return 0;
-    send_mime( hc, status, title, "", extraheads, "text/html", -1, 0 );
+    send_mime( hc, status, title, "", extraheads, "text/html", -1, 0, 0, 0 );
     for (;;)
 	{
 	r = fread( buf, 1, sizeof(buf) - 1, fp );
@@ -1336,6 +1416,9 @@
     if ( hc->tildemapped )
 	return 1;
 
+    if ( hc->hostname[0] == '.' || strchr( hc->hostname, '/' ) != (char*) 0 )
+	return 0;
+
     /* Figure out the host directory. */
 #ifdef VHOST_DIRLEVELS
     httpd_realloc_str(
@@ -1436,7 +1519,7 @@
     restlen = strlen( path );
     httpd_realloc_str( &rest, &maxrest, restlen );
     (void) strcpy( rest, path );
-    if ( rest[restlen - 1] == '/' )
+    if ( restlen > 0 && rest[restlen - 1] == '/' )
 	rest[--restlen] = '\0';         /* trim trailing slash */
     if ( ! tildemapped )
 	/* Remove any leading slashes. */
@@ -1603,6 +1686,70 @@
 
 
 int
+httpd_request_reset(httpd_conn* hc, int preserve_read_buf )
+{
+	if (!preserve_read_buf) {
+	    hc->read_idx = 0;
+    	hc->checked_idx = 0;
+	}
+		
+		if (hc->read_buf_is_mmap) {
+			hc->read_buf_is_mmap = 0;
+			munmap(hc->read_buf, hc->read_size);
+			hc->read_buf = NULL;
+			hc->read_size = 0;
+			httpd_realloc_str( &hc->read_buf, &hc->read_size, 500 );
+		}
+    hc->checked_state = CHST_FIRSTWORD;
+    hc->method = METHOD_UNKNOWN;
+    hc->status = 0;
+    hc->bytes_to_send = 0;
+    hc->bytes_sent = 0;
+    hc->encodedurl = "";
+    hc->decodedurl[0] = '\0';
+    hc->protocol = "UNKNOWN";
+    hc->origfilename[0] = '\0';
+    hc->expnfilename[0] = '\0';
+    hc->encodings[0] = '\0';
+    hc->pathinfo[0] = '\0';
+    hc->query[0] = '\0';
+    hc->referer = "";
+    hc->useragent = "";
+    hc->accept[0] = '\0';
+    hc->accepte[0] = '\0';
+    hc->acceptl = "";
+    hc->cookie = "";
+    hc->contenttype = "";
+    hc->reqhost[0] = '\0';
+    hc->hdrhost = "";
+    hc->hostdir[0] = '\0';
+    hc->authorization = "";
+    hc->remoteuser[0] = '\0';
+    hc->response[0] = '\0';
+#ifdef TILDE_MAP_2
+    hc->altdir[0] = '\0';
+#endif /* TILDE_MAP_2 */
+    hc->responselen = 0;
+    hc->if_modified_since = (time_t) -1;
+    hc->range_if = (time_t) -1;
+    hc->contentlength = -1;
+    hc->type = "";
+    hc->hostname = (char*) 0;
+    hc->mime_flag = 1;
+    hc->one_one = 0;
+    hc->got_range = 0;
+    hc->tildemapped = 0;
+    hc->init_byte_loc = 0;
+    hc->end_byte_loc = -1;
+    hc->keep_alive = 0;
+    hc->do_keep_alive = 0;
+    hc->should_linger = 0;
+    hc->file_address = (char*) 0;
+    hc->read_body_into_mem = 0;
+    return GC_OK;
+}
+
+int
 httpd_get_conn( httpd_server* hs, int listen_fd, httpd_conn* hc )
     {
     httpd_sockaddr sa;
@@ -1612,6 +1759,7 @@
 	{
 	hc->read_size = 0;
 	httpd_realloc_str( &hc->read_buf, &hc->read_size, 500 );
+	hc->read_buf_is_mmap = 0;
 	hc->maxdecodedurl =
 	    hc->maxorigfilename = hc->maxexpnfilename = hc->maxencodings =
 	    hc->maxpathinfo = hc->maxquery = hc->maxaccept =
@@ -1631,12 +1779,19 @@
 	httpd_realloc_str( &hc->reqhost, &hc->maxreqhost, 0 );
 	httpd_realloc_str( &hc->hostdir, &hc->maxhostdir, 0 );
 	httpd_realloc_str( &hc->remoteuser, &hc->maxremoteuser, 0 );
-	httpd_realloc_str( &hc->response, &hc->maxresponse, 0 );
+	httpd_realloc_str( &hc->response, &hc->maxresponse, 350 );
 #ifdef TILDE_MAP_2
 	httpd_realloc_str( &hc->altdir, &hc->maxaltdir, 0 );
 #endif /* TILDE_MAP_2 */
 	hc->initialized = 1;
 	}
+		if (hc->read_buf_is_mmap) {
+			hc->read_buf_is_mmap = 0;
+			munmap(hc->read_buf, hc->read_size);
+			hc->read_buf = NULL;
+			hc->read_size = 0;
+			httpd_realloc_str( &hc->read_buf, &hc->read_size, 500 );
+		}
 
     /* Accept the new connection. */
     sz = sizeof(sa);
@@ -1657,53 +1812,12 @@
     hc->hs = hs;
     memset( &hc->client_addr, 0, sizeof(hc->client_addr) );
     memcpy( &hc->client_addr, &sa, sockaddr_len( &sa ) );
-    hc->read_idx = 0;
-    hc->checked_idx = 0;
-    hc->checked_state = CHST_FIRSTWORD;
-    hc->method = METHOD_UNKNOWN;
-    hc->status = 0;
-    hc->bytes_to_send = 0;
-    hc->bytes_sent = 0;
-    hc->encodedurl = "";
-    hc->decodedurl[0] = '\0';
-    hc->protocol = "UNKNOWN";
-    hc->origfilename[0] = '\0';
-    hc->expnfilename[0] = '\0';
-    hc->encodings[0] = '\0';
-    hc->pathinfo[0] = '\0';
-    hc->query[0] = '\0';
-    hc->referer = "";
-    hc->useragent = "";
-    hc->accept[0] = '\0';
-    hc->accepte[0] = '\0';
-    hc->acceptl = "";
-    hc->cookie = "";
-    hc->contenttype = "";
-    hc->reqhost[0] = '\0';
-    hc->hdrhost = "";
-    hc->hostdir[0] = '\0';
-    hc->authorization = "";
-    hc->remoteuser[0] = '\0';
-    hc->response[0] = '\0';
-#ifdef TILDE_MAP_2
-    hc->altdir[0] = '\0';
-#endif /* TILDE_MAP_2 */
-    hc->responselen = 0;
-    hc->if_modified_since = (time_t) -1;
-    hc->range_if = (time_t) -1;
-    hc->contentlength = -1;
-    hc->type = "";
-    hc->hostname = (char*) 0;
-    hc->mime_flag = 1;
-    hc->one_one = 0;
-    hc->got_range = 0;
-    hc->tildemapped = 0;
-    hc->init_byte_loc = 0;
-    hc->end_byte_loc = -1;
-    hc->keep_alive = 0;
-    hc->should_linger = 0;
-    hc->file_address = (char*) 0;
-    return GC_OK;
+
+/*
+printf("doing httpd_get_con(%d)\n", hc->conn_fd);
+*/
+
+    return httpd_request_reset(hc, 0);
     }
 
 
@@ -1720,6 +1834,9 @@
     {
     char c;
 
+/*
+printf("**REQUEST [%d]**\n%*.*s\n", hc->conn_fd, hc->read_idx, hc->read_idx, hc->read_buf);
+*/
     for ( ; hc->checked_idx < hc->read_idx; ++hc->checked_idx )
 	{
 	c = hc->read_buf[hc->checked_idx];
@@ -1912,8 +2029,11 @@
 	    eol = strpbrk( protocol, " \t\n\r" );
 	    if ( eol != (char*) 0 )
 		*eol = '\0';
-	    if ( strcasecmp( protocol, "HTTP/1.0" ) != 0 )
+	    if ( strcasecmp( protocol, "HTTP/1.0" ) != 0 ) {
 		hc->one_one = 1;
+		hc->keep_alive = 1;
+		hc->do_keep_alive = 1;
+		}
 	    }
 	}
     /* Check for HTTP/1.1 absolute URL. */
@@ -2129,6 +2249,7 @@
 		cp = &buf[11];
 		cp += strspn( cp, " \t" );
 		if ( strcasecmp( cp, "keep-alive" ) == 0 )
+		    hc->do_keep_alive = 1;
 		    hc->keep_alive = 1;
 		}
 #ifdef LOG_UNKNOWN_HEADERS
@@ -2168,6 +2289,9 @@
 	    }
 	}
 
+/*
+printf("one_one = %d   keep_alive = %d\n", hc->one_one, hc->keep_alive);
+*/
     if ( hc->one_one )
 	{
 	/* Check that HTTP/1.1 requests specify a host, as required. */
@@ -2177,14 +2301,14 @@
 	    return -1;
 	    }
 
-	/* If the client wants to do keep-alives, it might also be doing
-	** pipelining.  There's no way for us to tell.  Since we don't
-	** implement keep-alives yet, if we close such a connection there
-	** might be unread pipelined requests waiting.  So, we have to
-	** do a lingering close.
+	/*
+	**  Disable keep alive support for bad browsers, 
+	**    list taken from Apache 1.3.19
 	*/
-	if ( hc->keep_alive )
-	    hc->should_linger = 1;
+	if ( hc->do_keep_alive && 
+	    ( strstr(hc->useragent, "Mozilla/2") != NULL ||
+	      strstr(hc->useragent, "MSIE 4.0b2;") != NULL))
+		hc->do_keep_alive = 0;
 	}
 
     /* Ok, the request has been parsed.  Now we resolve stuff that
@@ -2349,15 +2473,24 @@
 
 
 void
-httpd_close_conn( httpd_conn* hc, struct timeval* nowP )
-    {
-    make_log_entry( hc, nowP );
+httpd_complete_request( httpd_conn* hc, struct timeval* nowP)
+{
+	if (hc->method != METHOD_UNKNOWN)
+		make_log_entry( hc, nowP );
 
-    if ( hc->file_address != (char*) 0 )
+	if ( hc->file_address == (char*) 1 )
+    {
+	thttpd_closed_conn(hc->conn_fd);
+    } else if ( hc->file_address != (char*) 0 )
 	{
 	mmc_unmap( hc->file_address, &(hc->sb), nowP );
 	hc->file_address = (char*) 0;
 	}
+	}
+
+void
+httpd_close_conn( httpd_conn* hc, struct timeval* nowP )
+{
     if ( hc->conn_fd >= 0 )
 	{
 	(void) close( hc->conn_fd );
@@ -2370,7 +2503,12 @@
     {
     if ( hc->initialized )
 	{
-	free( (void*) hc->read_buf );
+
+	if ( hc->read_buf_is_mmap ) {
+	    munmap( hc->read_buf, hc->read_size );
+	} else {
+	    free( (void*) hc->read_buf );
+	}
 	free( (void*) hc->decodedurl );
 	free( (void*) hc->origfilename );
 	free( (void*) hc->expnfilename );
@@ -2556,7 +2694,7 @@
 	return -1;
 	}
 
-    send_mime( hc, 200, ok200title, "", "", "text/html", -1, hc->sb.st_mtime );
+    send_mime( hc, 200, ok200title, "", "", "text/html", -1, hc->sb.st_mtime, 0, 0 );
     if ( hc->method == METHOD_HEAD )
 	closedir( dirp );
     else if ( hc->method == METHOD_GET )
@@ -3026,11 +3164,9 @@
 post_post_garbage_hack( httpd_conn* hc )
     {
     char buf[2];
-    int r;
 
-    r = recv( hc->conn_fd, buf, sizeof(buf), MSG_PEEK );
-    if ( r > 0 )
-	(void) read( hc->conn_fd, buf, r );
+	fcntl(hc->conn_fd, F_SETFL, O_NONBLOCK);
+	(void) read( hc->conn_fd, buf, 2 );
     }
 
 
@@ -3313,6 +3449,11 @@
     int r;
     ClientData client_data;
 
+    /*
+    **  We are not going to leave the socket open after a CGI... too hard
+    */
+    hc->do_keep_alive = 0;
+
     if ( hc->method == METHOD_GET || hc->method == METHOD_POST )
 	{
 	httpd_clear_ndelay( hc->conn_fd );
@@ -3369,6 +3510,7 @@
     int expnlen, indxlen;
     char* cp;
     char* pi;
+    int nocache = 0;
 
     expnlen = strlen( hc->expnfilename );
 
@@ -3561,6 +3703,16 @@
 	 match( hc->hs->cgi_pattern, hc->expnfilename ) )
 	return cgi( hc );
 
+	if ( hc->hs->php_pattern != (char*) 0 &&
+			match( hc->hs->php_pattern, hc->expnfilename)) {
+		return thttpd_php_request( hc, 0 );
+	}
+
+	if ( hc->hs->phps_pattern != (char*) 0 &&
+			match( hc->hs->phps_pattern, hc->expnfilename)) {
+		return thttpd_php_request( hc, 1 );
+	}
+
     /* It's not CGI.  If it's executable or there's pathinfo, someone's
     ** trying to either serve or run a non-CGI file as CGI.   Either case
     ** is prohibited.
@@ -3594,32 +3746,46 @@
 	hc->end_byte_loc = hc->sb.st_size - 1;
 
     figure_mime( hc );
+    if ( strncmp(hc->decodedurl, "/nocache/", sizeof("/nocache/") - 1 ) == 0 )
+	nocache = 1;
 
     if ( hc->method == METHOD_HEAD )
 	{
 	send_mime(
 	    hc, 200, ok200title, hc->encodings, "", hc->type, hc->sb.st_size,
-	    hc->sb.st_mtime );
+	    hc->sb.st_mtime, 0, 0 );
 	}
-    else if ( hc->if_modified_since != (time_t) -1 &&
+    else if ( !nocache && hc->if_modified_since != (time_t) -1 &&
 	 hc->if_modified_since >= hc->sb.st_mtime )
 	{
-	hc->method = METHOD_HEAD;
 	send_mime(
-	    hc, 304, err304title, hc->encodings, "", hc->type, hc->sb.st_size,
-	    hc->sb.st_mtime );
+	    hc, 304, err304title, hc->encodings, "", hc->type, -1,
+	    hc->sb.st_mtime, 0, 0 );
 	}
     else
 	{
-	hc->file_address = mmc_map( hc->expnfilename, &(hc->sb), nowP );
+	char *extraheads = "";
+	char *lm;
+	size_t lml;
+
+	if ( nocache ) 
+	    {
+	    extraheads = "Expires: Thu, 19 Nov 1981 08:52:00 GMT\r\n"
+		"Cache-Control: no-store, no-cache, must-revalidate, "
+		"post-check=0, pre-check=0\r\n"
+		"Pragma: no-cache\r\n";
+	    }
+		
+	hc->file_address = mmc_map( hc->expnfilename, &(hc->sb), nowP, nocache, &lm, &lml );
 	if ( hc->file_address == (char*) 0 )
 	    {
 	    httpd_send_err( hc, 500, err500title, "", err500form, hc->encodedurl );
 	    return -1;
 	    }
+
 	send_mime(
-	    hc, 200, ok200title, hc->encodings, "", hc->type, hc->sb.st_size,
-	    hc->sb.st_mtime );
+	    hc, 200, ok200title, hc->encodings, extraheads, hc->type, hc->sb.st_size,
+	    hc->sb.st_mtime, lm, lml );
 	}
 
     return 0;
@@ -3638,6 +3804,9 @@
     return r;
     }
 
+#define smart_str_append_const(a,b) smart_str_appendl(a,b,sizeof(b)-1)
+
+static smart_str bentries;
 
 static void
 make_log_entry( httpd_conn* hc, struct timeval* nowP )
@@ -3648,88 +3817,62 @@
 
     if ( hc->hs->no_log )
 	return;
-
-    /* This is straight CERN Combined Log Format - the only tweak
-    ** being that if we're using syslog() we leave out the date, because
-    ** syslogd puts it in.  The included syslogtocern script turns the
-    ** results into true CERN format.
-    */
-
     /* Format remote user. */
     if ( hc->remoteuser[0] != '\0' )
-	ru = hc->remoteuser;
+    ru = hc->remoteuser;
     else
-	ru = "-";
+    ru = "-";
     /* If we're vhosting, prepend the hostname to the url.  This is
     ** a little weird, perhaps writing separate log files for
     ** each vhost would make more sense.
     */
-    if ( hc->hs->vhost && ! hc->tildemapped )
-	(void) my_snprintf( url, sizeof(url),
-	    "/%.100s%.200s",
-	    hc->hostname == (char*) 0 ? hc->hs->server_hostname : hc->hostname,
-	    hc->encodedurl );
-    else
-	(void) my_snprintf( url, sizeof(url),
-	    "%.200s", hc->encodedurl );
-    /* Format the bytes. */
-    if ( (long) hc->bytes_sent >= 0 )
-	(void) my_snprintf( bytes, sizeof(bytes),
-	    "%ld", (long) hc->bytes_sent );
-    else
-	(void) strcpy( bytes, "-" );
 
     /* Logfile or syslog? */
     if ( hc->hs->logfp != (FILE*) 0 )
-	{
-	time_t now;
-	struct tm* t;
-	const char* cernfmt_nozone = "%d/%b/%Y:%H:%M:%S";
-	char date_nozone[100];
-	int zone;
-	char sign;
-	char date[100];
-
-	/* Get the current time, if necessary. */
-	if ( nowP != (struct timeval*) 0 )
-	    now = nowP->tv_sec;
-	else
-	    now = time( (time_t*) 0 );
-	/* Format the time, forcing a numeric timezone (some log analyzers
-	** are stoooopid about this).
-	*/
-	t = localtime( &now );
-	(void) strftime( date_nozone, sizeof(date_nozone), cernfmt_nozone, t );
-#ifdef HAVE_TM_GMTOFF
-	zone = t->tm_gmtoff / 60L;
-#else
-	zone = -timezone / 60L;
-	/* Probably have to add something about daylight time here. */
-#endif
-	if ( zone >= 0 )
-	    sign = '+';
-	else
-	    {
-	    sign = '-';
-	    zone = -zone;
-	    }
-	zone = ( zone / 60 ) * 100 + zone % 60;
-	(void) my_snprintf( date, sizeof(date),
-	    "%s %c%04d", date_nozone, sign, zone );
-	/* And write the log entry. */
-	(void) fprintf( hc->hs->logfp,
-	    "%.80s - %.80s [%s] \"%.80s %.300s %.80s\" %d %s \"%.200s\" \"%.80s\"\n",
-	    httpd_ntoa( &hc->client_addr ), ru, date,
-	    httpd_method_str( hc->method ), url, hc->protocol,
-	    hc->status, bytes, hc->referer, hc->useragent );
-	(void) fflush( hc->hs->logfp );	/* don't need to flush every time */
-	}
-    else
-	syslog( LOG_INFO,
-	    "%.80s - %.80s \"%.80s %.200s %.80s\" %d %s \"%.200s\" \"%.80s\"",
-	    httpd_ntoa( &hc->client_addr ), ru,
-	    httpd_method_str( hc->method ), url, hc->protocol,
-	    hc->status, bytes, hc->referer, hc->useragent );
+    {
+    /* XXXXXXX */
+
+    smart_str_appends(&bentries, httpd_ntoa(&hc->client_addr));
+    smart_str_append_const(&bentries, " - ");
+    smart_str_appends(&bentries, ru);
+    smart_str_append_const(&bentries, " [");
+    smart_str_appendl(&bentries, hc->hs->log_date, hc->hs->log_date_len);
+    smart_str_append_const(&bentries, "] \"");
+    smart_str_appends(&bentries, httpd_method_str(hc->method));
+    smart_str_appendc(&bentries, ' ');
+
+    if (hc->hs->vhost && ! hc->tildemapped) {
+        smart_str_appendc(&bentries, '/');
+        if (hc->hostname)
+            smart_str_appends(&bentries, hc->hostname);
+        else
+            smart_str_appends(&bentries, hc->hs->server_hostname);
+    }
+    smart_str_appends(&bentries, hc->encodedurl);
+
+    smart_str_appendc(&bentries, ' ');
+    smart_str_appends(&bentries, hc->protocol);
+    smart_str_append_const(&bentries, "\" ");
+    smart_str_append_long(&bentries, hc->status);
+    if (hc->bytes_sent >= 0) {
+        smart_str_appendc(&bentries, ' ');
+        smart_str_append_long(&bentries, hc->bytes_sent);
+        smart_str_append_const(&bentries, " \"");
+    } else {
+        smart_str_append_const(&bentries, " - \"");
+    }
+    smart_str_appends(&bentries, hc->referer);
+    smart_str_append_const(&bentries, "\" \"");
+    smart_str_appends(&bentries, hc->useragent);
+    smart_str_append_const(&bentries, "\"\n");
+
+    if (bentries.len > 16384) {
+        int fd = fileno(hc->hs->logfp);
+        write(fd, bentries.c, bentries.len);
+        bentries.len = 0;
+    }
+    }
+
     }
 
 
@@ -3840,7 +3983,24 @@
     {
 #ifdef HAVE_GETNAMEINFO
     static char str[200];
+	static smart_str httpd_ntoa_buf;
+
+	if (saP->sa_in.sin_family == AF_INET) {
+        unsigned long n = ntohl(saP->sa_in.sin_addr.s_addr);
 
+        httpd_ntoa_buf.len = 0;
+        smart_str_append_long(&httpd_ntoa_buf, (n >> 24));
+        smart_str_appendc(&httpd_ntoa_buf, '.');
+        smart_str_append_long(&httpd_ntoa_buf, (n >> 16) & 255);
+        smart_str_appendc(&httpd_ntoa_buf, '.');
+        smart_str_append_long(&httpd_ntoa_buf, (n >> 8) & 255);
+        smart_str_appendc(&httpd_ntoa_buf, '.');
+        smart_str_append_long(&httpd_ntoa_buf, (n >> 0) & 255);
+        smart_str_0(&httpd_ntoa_buf);
+
+        return httpd_ntoa_buf.c;
+	}
+	
     if ( getnameinfo( &saP->sa, sockaddr_len( saP ), str, sizeof(str), 0, 0, NI_NUMERICHOST ) != 0 )
 	{
 	str[0] = '?';
diff -ur thttpd-2.21b/libhttpd.h thttpd-2.21b-cool/libhttpd.h
--- thttpd-2.21b/libhttpd.h	Tue Apr 24 00:36:50 2001
+++ thttpd-2.21b-cool/libhttpd.h	Sat Sep 20 14:43:20 2003
@@ -69,6 +69,8 @@
     char* server_hostname;
     int port;
     char* cgi_pattern;
+    char* php_pattern;
+    char* phps_pattern;
     char* charset;
     char* cwd;
     int listen4_fd, listen6_fd;
@@ -80,6 +82,8 @@
     char* url_pattern;
     char* local_pattern;
     int no_empty_referers;
+	size_t log_date_len;
+	char log_date[100];
     } httpd_server;
 
 /* A connection. */
@@ -88,6 +92,7 @@
     httpd_server* hs;
     httpd_sockaddr client_addr;
     char* read_buf;
+    char read_buf_is_mmap;
     int read_size, read_idx, checked_idx;
     int checked_state;
     int method;
@@ -132,11 +137,12 @@
     int got_range;
     int tildemapped;	/* this connection got tilde-mapped */
     off_t init_byte_loc, end_byte_loc;
-    int keep_alive;
+    int keep_alive, do_keep_alive;
     int should_linger;
     struct stat sb;
     int conn_fd;
     char* file_address;
+    char read_body_into_mem;
     } httpd_conn;
 
 /* Methods. */
@@ -168,7 +174,8 @@
     char* hostname, httpd_sockaddr* sa4P, httpd_sockaddr* sa6P, int port,
     char* cgi_pattern, char* charset, char* cwd, int no_log, FILE* logfp,
     int no_symlink, int vhost, int global_passwd, char* url_pattern,
-    char* local_pattern, int no_empty_referers );
+    char* local_pattern, int no_empty_referers, char* php_pattern,
+    char* phps_pattern );
 
 /* Change the log file. */
 extern void httpd_set_logfp( httpd_server* hs, FILE* logfp );
@@ -229,6 +236,8 @@
 ** If you don't have a current timeval handy just pass in 0.
 */
 extern void httpd_close_conn( httpd_conn* hc, struct timeval* nowP );
+void httpd_complete_request( httpd_conn* hc, struct timeval* nowP);
+int httpd_request_reset(httpd_conn* hc,int );
 
 /* Call this to de-initialize a connection struct and *really* free the
 ** mallocced strings.
diff -ur thttpd-2.21b/mime_encodings.txt thttpd-2.21b-cool/mime_encodings.txt
--- thttpd-2.21b/mime_encodings.txt	Wed May 10 03:22:28 2000
+++ thttpd-2.21b-cool/mime_encodings.txt	Sat Sep 20 14:43:20 2003
@@ -3,6 +3,6 @@
 # A list of file extensions followed by the corresponding MIME encoding.
 # Extensions not found in the table proceed to the mime_types table.
 
-Z	x-compress
-gz	x-gzip
+Z	compress
+gz	gzip
 uu	x-uuencode
diff -ur thttpd-2.21b/mime_types.txt thttpd-2.21b-cool/mime_types.txt
--- thttpd-2.21b/mime_types.txt	Sat Apr 14 04:53:30 2001
+++ thttpd-2.21b-cool/mime_types.txt	Sat Sep 20 14:43:20 2003
@@ -1,135 +1,138 @@
-# mime_types.txt
-#
-# A list of file extensions followed by the corresponding MIME type.
-# Extensions not found in the table are returned as text/plain.
-
-html	text/html; charset=%s
-htm	text/html; charset=%s
-txt	text/plain; charset=%s
-rtx	text/richtext
-etx	text/x-setext
-tsv	text/tab-separated-values
-css	text/css
-xml	text/xml
-dtd	text/xml
-
-gif	image/gif
-jpg	image/jpeg
-jpeg	image/jpeg
-jpe	image/jpeg
-jfif	image/jpeg
-tif	image/tiff
-tiff	image/tiff
-pbm	image/x-portable-bitmap
-pgm	image/x-portable-graymap
-ppm	image/x-portable-pixmap
-pnm	image/x-portable-anymap
-xbm	image/x-xbitmap
-xpm	image/x-xpixmap
-xwd	image/x-xwindowdump
-ief	image/ief
-png	image/png
-
-au	audio/basic
-snd	audio/basic
-aif	audio/x-aiff
-aiff	audio/x-aiff
-aifc	audio/x-aiff
-ra	audio/x-pn-realaudio
-ram	audio/x-pn-realaudio
-rm	audio/x-pn-realaudio
-rpm	audio/x-pn-realaudio-plugin
-wav	audio/wav
-mid	audio/midi
-midi	audio/midi
-kar	audio/midi
-mpga	audio/mpeg
-mp2	audio/mpeg
-mp3	audio/mpeg
-
-mpeg	video/mpeg
-mpg	video/mpeg
-mpe	video/mpeg
-qt	video/quicktime
-mov	video/quicktime
-avi	video/x-msvideo
-movie	video/x-sgi-movie
-mv	video/x-sgi-movie
-vx	video/x-rad-screenplay
-
-a	application/octet-stream
+ez	application/andrew-inset
+hqx	application/mac-binhex40
+cpt	application/mac-compactpro
+doc	application/msword
 bin	application/octet-stream
+dms	application/octet-stream
+lha	application/octet-stream
+lzh	application/octet-stream
 exe	application/octet-stream
-dump	application/octet-stream
-o	application/octet-stream
-class	application/java
-js	application/x-javascript
+class	application/octet-stream
+so	application/octet-stream
+dll	application/octet-stream
+oda	application/oda
+pdf	application/pdf
 ai	application/postscript
 eps	application/postscript
 ps	application/postscript
-dir	application/x-director
+smi	application/smil
+smil	application/smil
+mif	application/vnd.mif
+xls	application/vnd.ms-excel
+ppt	application/vnd.ms-powerpoint
+wbxml	application/vnd.wap.wbxml
+wmlc	application/vnd.wap.wmlc
+wmlsc	application/vnd.wap.wmlscriptc
+bcpio	application/x-bcpio
+vcd	application/x-cdlink
+pgn	application/x-chess-pgn
+cpio	application/x-cpio
+csh	application/x-csh
 dcr	application/x-director
+dir	application/x-director
 dxr	application/x-director
-fgd	application/x-director
-aam	application/x-authorware-map
-aas	application/x-authorware-seg
-aab	application/x-authorware-bin
-fh4	image/x-freehand
-fh7	image/x-freehand
-fh5	image/x-freehand
-fhc	image/x-freehand
-fh	image/x-freehand
-spl	application/futuresplash
-swf	application/x-shockwave-flash
 dvi	application/x-dvi
+spl	application/x-futuresplash
 gtar	application/x-gtar
 hdf	application/x-hdf
-hqx	application/mac-binhex40
-iv	application/x-inventor
+js	application/x-javascript
+skp	application/x-koan
+skd	application/x-koan
+skt	application/x-koan
+skm	application/x-koan
 latex	application/x-latex
-man	application/x-troff-man
-me	application/x-troff-me
-mif	application/x-mif
-ms	application/x-troff-ms
-oda	application/oda
-pdf	application/pdf
-rtf	application/rtf
-bcpio	application/x-bcpio
-cpio	application/x-cpio
-sv4cpio	application/x-sv4cpio
-sv4crc	application/x-sv4crc
-sh	application/x-shar
+nc	application/x-netcdf
+cdf	application/x-netcdf
+sh	application/x-sh
 shar	application/x-shar
+swf	application/x-shockwave-flash
 sit	application/x-stuffit
+sv4cpio	application/x-sv4cpio
+sv4crc	application/x-sv4crc
 tar	application/x-tar
+tcl	application/x-tcl
 tex	application/x-tex
-texi	application/x-texinfo
 texinfo	application/x-texinfo
+texi	application/x-texinfo
+t	application/x-troff
 tr	application/x-troff
 roff	application/x-troff
 man	application/x-troff-man
 me	application/x-troff-me
 ms	application/x-troff-ms
-zip	application/x-zip-compressed
-tsp	application/dsptype
-wsrc	application/x-wais-source
 ustar	application/x-ustar
-cdf	application/x-netcdf
-nc	application/x-netcdf
-doc	application/msword
-ppt	application/powerpoint
-
-crt	application/x-x509-ca-cert
-crl	application/x-pkcs7-crl
-
+src	application/x-wais-source
+xhtml	application/xhtml+xml
+xht	application/xhtml+xml
+zip	application/zip
+au	audio/basic
+snd	audio/basic
+mid	audio/midi
+midi	audio/midi
+kar	audio/midi
+mpga	audio/mpeg
+mp2	audio/mpeg
+mp3	audio/mpeg
+aif	audio/x-aiff
+aiff	audio/x-aiff
+aifc	audio/x-aiff
+m3u	audio/x-mpegurl
+ram	audio/x-pn-realaudio
+rm	audio/x-pn-realaudio
+rpm	audio/x-pn-realaudio-plugin
+ra	audio/x-realaudio
+wav	audio/x-wav
+pdb	chemical/x-pdb
+xyz	chemical/x-xyz
+bmp	image/bmp
+gif	image/gif
+ief	image/ief
+jpeg	image/jpeg
+jpg	image/jpeg
+jpe	image/jpeg
+png	image/png
+tiff	image/tiff
+tif	image/tiff
+djvu	image/vnd.djvu
+djv	image/vnd.djvu
+wbmp	image/vnd.wap.wbmp
+ras	image/x-cmu-raster
+pnm	image/x-portable-anymap
+pbm	image/x-portable-bitmap
+pgm	image/x-portable-graymap
+ppm	image/x-portable-pixmap
+rgb	image/x-rgb
+xbm	image/x-xbitmap
+xpm	image/x-xpixmap
+xwd	image/x-xwindowdump
+igs	model/iges
+iges	model/iges
+msh	model/mesh
+mesh	model/mesh
+silo	model/mesh
 wrl	model/vrml
 vrml	model/vrml
-mime	message/rfc822
-
-pac	application/x-ns-proxy-autoconfig
-
+css	text/css
+html	text/html; charset=%s
+htm	text/html; charset=%s
+asc	text/plain; charset=%s
+txt	text/plain; charset=%s
+rtx	text/richtext
+rtf	text/rtf
+sgml	text/sgml
+sgm	text/sgml
+tsv	text/tab-separated-values
 wml	text/vnd.wap.wml
-wmlc	application/vnd.wap.wmlc
 wmls	text/vnd.wap.wmlscript
-wmlsc	application/vnd.wap.wmlscriptc
-wbmp	image/vnd.wap.wbmp
+etx	text/x-setext
+xml	text/xml
+xsl	text/xml
+mpeg	video/mpeg
+mpg	video/mpeg
+mpe	video/mpeg
+qt	video/quicktime
+mov	video/quicktime
+mxu	video/vnd.mpegurl
+avi	video/x-msvideo
+movie	video/x-sgi-movie
+ice	x-conference/x-cooltalk
diff -ur thttpd-2.21b/mmc.c thttpd-2.21b-cool/mmc.c
--- thttpd-2.21b/mmc.c	Fri Apr 13 23:02:15 2001
+++ thttpd-2.21b-cool/mmc.c	Sat Sep 20 14:43:20 2003
@@ -70,6 +70,9 @@
     unsigned int hash;
     int hash_idx;
     struct MapStruct* next;
+    char nocache;
+	size_t last_modified_len;
+	char last_modified[100];
     } Map;
 
 
@@ -93,12 +96,13 @@
 
 
 void*
-mmc_map( char* filename, struct stat* sbP, struct timeval* nowP )
+mmc_map( char* filename, struct stat* sbP, struct timeval* nowP, int nocache, char **last_modified, size_t *last_modified_len )
     {
     time_t now;
     struct stat sb;
     Map* m;
     int fd;
+	const char* rfc1123fmt = "%a, %d %b %Y %H:%M:%S GMT";
 
     /* Stat the file, if necessary. */
     if ( sbP != (struct stat*) 0 )
@@ -130,7 +134,7 @@
 	/* Yep.  Just return the existing map */
 	++m->refcount;
 	m->reftime = now;
-	return m->addr;
+	goto done;
 	}
 
     /* Open the file. */
@@ -167,12 +171,13 @@
     m->ctime = sb.st_ctime;
     m->refcount = 1;
     m->reftime = now;
+    m->nocache = (char) nocache;
 
     /* Avoid doing anything for zero-length files; some systems don't like
     ** to mmap them, other systems dislike mallocing zero bytes.
     */
     if ( m->size == 0 )
-	m->addr = (void*) 1;	/* arbitrary non-NULL address */
+	m->addr = (void*) 5;	/* arbitrary non-NULL address */
     else
 	{
 #ifdef HAVE_MMAP
@@ -223,6 +228,13 @@
     maps = m;
     ++map_count;
 
+	strftime( m->last_modified, sizeof(m->last_modified), rfc1123fmt, gmtime( &sb.st_mtime ) );
+	m->last_modified_len = strlen(m->last_modified);
+	
+done:
+	*last_modified = m->last_modified;
+	*last_modified_len = m->last_modified_len;
+
     /* And return the address. */
     return m->addr;
     }
@@ -231,27 +243,32 @@
 void
 mmc_unmap( void* addr, struct stat* sbP, struct timeval* nowP )
     {
-    Map* m = (Map*) 0;
+    Map* m = (Map*) 0, **mm = &maps;
 
     /* Find the Map entry for this address.  First try a hash. */
     if ( sbP != (struct stat*) 0 )
 	{
 	m = find_hash( sbP->st_ino, sbP->st_dev, sbP->st_size, sbP->st_ctime );
-	if ( m != (Map*) 0 && m->addr != addr )
+	if ( m != (Map*) 0 && ( m->addr != addr || m->nocache == 1 ) )
 	    m = (Map*) 0;
 	}
     /* If that didn't work, try a full search. */
     if ( m == (Map*) 0 )
-	for ( m = maps; m != (Map*) 0; m = m->next )
+	for ( m = maps; m != (Map*) 0; m = m->next ) {
 	    if ( m->addr == addr )
 		break;
+		mm = &m->next;
+	}
     if ( m == (Map*) 0 )
 	syslog( LOG_ERR, "mmc_unmap failed to find entry!" );
     else if ( m->refcount <= 0 )
 	syslog( LOG_ERR, "mmc_unmap found zero or negative refcount!" );
     else
 	{
-	--m->refcount;
+	if ( --m->refcount == 0 && m->nocache == 1 ) {
+		really_unmap( mm );
+		return;
+	}
 	if ( nowP != (struct timeval*) 0 )
 	    m->reftime = nowP->tv_sec;
 	else
diff -ur thttpd-2.21b/mmc.h thttpd-2.21b-cool/mmc.h
--- thttpd-2.21b/mmc.h	Fri Apr 13 07:36:54 2001
+++ thttpd-2.21b-cool/mmc.h	Sat Sep 20 14:43:20 2003
@@ -31,8 +31,9 @@
 /* Returns an mmap()ed area for the given file, or (void*) 0 on errors.
 ** If you have a stat buffer on the file, pass it in, otherwise pass 0.
 ** Same for the current time.
+** Set nocache to 1, if this entry is supposed to be removed quickly.
 */
-extern void* mmc_map( char* filename, struct stat* sbP, struct timeval* nowP );
+extern void* mmc_map( char* filename, struct stat* sbP, struct timeval* nowP, int nocache, char **last_modified, size_t *last_modified_len );
 
 /* Done with an mmap()ed area that was returned by mmc_map().
 ** If you have a stat buffer on the file, pass it in, otherwise pass 0.
diff -ur thttpd-2.21b/thttpd.c thttpd-2.21b-cool/thttpd.c
--- thttpd-2.21b/thttpd.c	Tue Apr 24 00:41:57 2001
+++ thttpd-2.21b-cool/thttpd.c	Sat Sep 20 14:43:20 2003
@@ -53,6 +53,10 @@
 #endif
 #include <unistd.h>
 
+#include <sys/mman.h>
+
+#include <limits.h>
+
 #include "fdwatch.h"
 #include "libhttpd.h"
 #include "mmc.h"
@@ -66,6 +70,8 @@
 static char* dir;
 static int do_chroot, no_log, no_symlink, do_vhost, do_global_passwd;
 static char* cgi_pattern;
+static char* php_pattern;
+static char* phps_pattern;
 static char* url_pattern;
 static int no_empty_referers;
 static char* local_pattern;
@@ -95,10 +101,10 @@
     httpd_conn* hc;
     int tnums[MAXTHROTTLENUMS];         /* throttle indexes */
     int numtnums;
+    int keep_alive;
     long limit;
     time_t started_at;
-    Timer* idle_read_timer;
-    Timer* idle_send_timer;
+    time_t last_io;
     Timer* wakeup_timer;
     Timer* linger_timer;
     long wouldblock_delay;
@@ -106,17 +112,22 @@
     off_t bytes_sent;
     off_t bytes_to_send;
     } connecttab;
-static connecttab* connects;
+static connecttab* connects, **free_connects;
+static int next_free_connect;
 static int numconnects, maxconnects;
 static int httpd_conn_count;
 
 /* The connection states. */
-#define CNST_FREE 0
-#define CNST_READING 1
-#define CNST_SENDING 2
-#define CNST_PAUSING 3
-#define CNST_LINGERING 4
-
+enum {
+	CNST_FREE = 0,
+	CNST_READING,
+	CNST_SENDING,
+	CNST_PAUSING,
+	CNST_LINGERING,
+	CNST_SENDING_RESP,
+	CNST_READING_BODY,
+	CNST_TOTAL_NR
+};
 
 static httpd_server* hs = (httpd_server*) 0;
 int terminate = 0;
@@ -140,23 +151,32 @@
 static int handle_newconnect( struct timeval* tvP, int listen_fd );
 static void handle_read( connecttab* c, struct timeval* tvP );
 static void handle_send( connecttab* c, struct timeval* tvP );
+static void handle_send_resp( connecttab* c, struct timeval* tvP );
+static void handle_read_body( connecttab* c, struct timeval* tvP );
 static void handle_linger( connecttab* c, struct timeval* tvP );
 static int check_throttles( connecttab* c );
+static void timeout_conns( ClientData client_data, struct timeval* nowP );
 static void clear_throttles( connecttab* c, struct timeval* tvP );
 static void update_throttles( ClientData client_data, struct timeval* nowP );
-static void clear_connection( connecttab* c, struct timeval* tvP );
+static void clear_connection( connecttab* c, struct timeval* tvP, int );
 static void really_clear_connection( connecttab* c, struct timeval* tvP );
-static void idle_read_connection( ClientData client_data, struct timeval* nowP );
-static void idle_send_connection( ClientData client_data, struct timeval* nowP );
 static void wakeup_connection( ClientData client_data, struct timeval* nowP );
 static void linger_clear_connection( ClientData client_data, struct timeval* nowP );
 static void occasional( ClientData client_data, struct timeval* nowP );
+static void periodic_jobs( ClientData client_data, struct timeval* nowP );
 #ifdef STATS_TIME
 static void show_stats( ClientData client_data, struct timeval* nowP );
 #endif /* STATS_TIME */
 static void logstats( struct timeval* nowP );
 static void thttpd_logstats( long secs );
+static void boot_request(connecttab *c, struct timeval *tvP);
+
+typedef void (*handler_func)(connecttab*, struct timeval *);
+
+handler_func handler_array[CNST_TOTAL_NR] =
+{NULL, handle_read, handle_send, NULL, handle_linger, handle_send_resp, handle_read_body};
 
+#define RUN_HANDLER(type, c) if (handler_array[type]) handler_array[type](c, &tv)
 
 static void
 handle_term( int sig )
@@ -177,7 +197,7 @@
 	return;
 
     /* Re-open the log file. */
-    if ( logfile != (char*) 0 )
+    if ( logfile != (char*) 0 && strcmp(logfile, "-") != 0)
 	{
 	logfp = fopen( logfile, "a" );
 	if ( logfp == (FILE*) 0 )
@@ -198,6 +218,8 @@
     }
 
 
+time_t httpd_time_now;
+
 static void
 handle_usr2( int sig )
     {
@@ -217,7 +239,6 @@
     int num_ready;
     int cnum, ridx;
     connecttab* c;
-    httpd_conn* hc;
     httpd_sockaddr sa4;
     httpd_sockaddr sa6;
     int gotv4, gotv6;
@@ -270,7 +291,9 @@
 	    no_log = 1;
 	    logfp = (FILE*) 0;
 	    }
-	else
+	else if (strcmp(logfile, "-") == 0) {
+		logfp = stdout;
+	} else
 	    {
 	    logfp = fopen( logfile, "a" );
 	    if ( logfp == (FILE*) 0 )
@@ -420,7 +443,8 @@
 	hostname,
 	gotv4 ? &sa4 : (httpd_sockaddr*) 0, gotv6 ? &sa6 : (httpd_sockaddr*) 0,
 	port, cgi_pattern, charset, cwd, no_log, logfp, no_symlink, do_vhost,
-	do_global_passwd, url_pattern, local_pattern, no_empty_referers );
+	do_global_passwd, url_pattern, local_pattern, no_empty_referers,
+	php_pattern, phps_pattern);
     if ( hs == (httpd_server*) 0 )
 	exit( 1 );
 
@@ -430,6 +454,12 @@
 	syslog( LOG_CRIT, "tmr_create(occasional) failed" );
 	exit( 1 );
 	}
+
+	if (tmr_create(0, timeout_conns, JunkClientData, 30 * 1000, 1) == 0) {
+		syslog(LOG_CRIT, "tmr_create(timeout_conns) failed");
+		exit(1);
+	}
+
     if ( numthrottles > 0 )
 	{
 	/* Set up the throttles timer. */
@@ -439,6 +469,12 @@
 	    exit( 1 );
 	    }
 	}
+
+	if (tmr_create(0, periodic_jobs, JunkClientData, 2000, 1) == 0) {
+		syslog(LOG_CRIT, "tmr_create failed");
+		exit(1);
+	}
+	
 #ifdef STATS_TIME
     /* Set up the stats timer. */
     if ( tmr_create( (struct timeval*) 0, show_stats, JunkClientData, STATS_TIME * 1000L, 1 ) == (Timer*) 0 )
@@ -454,12 +490,14 @@
     /* If we're root, try to become someone else. */
     if ( getuid() == 0 )
 	{
+#ifndef __CYGWIN__
 	/* Set aux groups to null. */
 	if ( setgroups( 0, (const gid_t*) 0 ) < 0 )
 	    {
 	    syslog( LOG_CRIT, "setgroups - %m" );
 	    exit( 1 );
 	    }
+#endif
 	/* Set primary group. */
 	if ( setgid( gid ) < 0 )
 	    {
@@ -495,13 +533,17 @@
 	}
     maxconnects -= SPARE_FDS;
     connects = NEW( connecttab, maxconnects );
+    free_connects = malloc(sizeof(connecttab *) * maxconnects);
+    next_free_connect = maxconnects;
     if ( connects == (connecttab*) 0 )
 	{
 	syslog( LOG_CRIT, "out of memory allocating a connecttab" );
 	exit( 1 );
 	}
+	
     for ( cnum = 0; cnum < maxconnects; ++cnum )
 	{
+	free_connects[cnum] = &connects[maxconnects - cnum - 1];
 	connects[cnum].conn_state = CNST_FREE;
 	connects[cnum].hc = (httpd_conn*) 0;
 	}
@@ -518,6 +560,9 @@
 
     /* Main loop. */
     (void) gettimeofday( &tv, (struct timezone*) 0 );
+    httpd_time_now = tv.tv_sec;
+	periodic_jobs(JunkClientData, &tv);
+
     while ( ( ! terminate ) || numconnects > 0 )
 	{
 	/* Do the fd watch. */
@@ -530,6 +575,7 @@
 	    exit( 1 );
 	    }
 	(void) gettimeofday( &tv, (struct timezone*) 0 );
+    httpd_time_now = tv.tv_sec;
 	if ( num_ready == 0 )
 	    {
 	    /* No fd's are ready - run the timers. */
@@ -565,16 +611,10 @@
 	    c = (connecttab*) fdwatch_get_client_data( ridx );
 	    if ( c == (connecttab*) 0 )
 		continue;
-	    hc = c->hc;
-	    if ( c->conn_state == CNST_READING &&
-		 fdwatch_check_fd( hc->conn_fd ) )
-		handle_read( c, &tv );
-	    else if ( c->conn_state == CNST_SENDING &&
-		 fdwatch_check_fd( hc->conn_fd ) )
-		handle_send( c, &tv );
-	    else if ( c->conn_state == CNST_LINGERING &&
-		 fdwatch_check_fd( hc->conn_fd ) )
-		handle_linger( c, &tv );
+#if DO_UNNECESSARY_CHECK_FD
+	    fdwatch_check_fd(c->hc->conn_fd);
+#endif
+	    RUN_HANDLER(c->conn_state, c);
 	    }
 	tmr_run( &tv );
 
@@ -627,6 +667,8 @@
 #else /* CGI_PATTERN */
     cgi_pattern = (char*) 0;
 #endif /* CGI_PATTERN */
+    php_pattern = "**.php";
+    phps_pattern = "**.phps";
     url_pattern = (char*) 0;
     no_empty_referers = 0;
     local_pattern = (char*) 0;
@@ -833,6 +875,16 @@
 		value_required( name, value );
 		cgi_pattern = e_strdup( value );
 		}
+	    else if ( strcasecmp( name, "phppat" ) == 0 )
+		{
+		value_required( name, value );
+		php_pattern = e_strdup( value );
+		}
+	    else if ( strcasecmp( name, "phpspat" ) == 0 )
+		{
+		value_required( name, value );
+		phps_pattern = e_strdup( value );
+		}
 	    else if ( strcasecmp( name, "urlpat" ) == 0 )
 		{
 		value_required( name, value );
@@ -1196,8 +1248,10 @@
     logstats( &tv );
     for ( cnum = 0; cnum < maxconnects; ++cnum )
 	{
-	if ( connects[cnum].conn_state != CNST_FREE )
+	if ( connects[cnum].conn_state != CNST_FREE ) {
+	    httpd_complete_request( connects[cnum].hc, &tv );
 	    httpd_close_conn( connects[cnum].hc, &tv );
+	}
 	if ( connects[cnum].hc != (httpd_conn*) 0 )
 	    {
 	    httpd_destroy_conn( connects[cnum].hc );
@@ -1214,6 +1268,7 @@
 	}
     mmc_destroy();
     tmr_destroy();
+    free( (void*) free_connects );
     free( (void*) connects );
     if ( throttles != (throttletab*) 0 )
 	free( (void*) throttles );
@@ -1234,7 +1289,7 @@
     for (;;)
 	{
 	/* Is there room in the connection table? */
-	if ( numconnects >= maxconnects )
+	if ( numconnects >= maxconnects || next_free_connect == 0 )
 	    {
 	    /* Out of connection slots.  Run the timers, then the
 	    ** existing connections, and maybe we'll free up a slot
@@ -1245,10 +1300,10 @@
 	    return 0;
 	    }
 	/* Find a free connection entry. */
-	for ( cnum = 0; cnum < maxconnects; ++cnum )
-	    if ( connects[cnum].conn_state == CNST_FREE )
-		break;
-	c = &connects[cnum];
+
+	c = free_connects[--next_free_connect];
+	free_connects[next_free_connect] = NULL;
+
 	/* Make the httpd_conn if necessary. */
 	if ( c->hc == (httpd_conn*) 0 )
 	    {
@@ -1267,24 +1322,18 @@
 	    {
 	    case GC_FAIL:
 	    case GC_NO_MORE:
+		free_connects[next_free_connect++] = c;
 	    return 1;
 	    }
 	c->conn_state = CNST_READING;
 	++numconnects;
 	client_data.p = c;
-	c->idle_read_timer = tmr_create(
-	    tvP, idle_read_connection, client_data, IDLE_READ_TIMELIMIT * 1000L,
-	    0 );
-	if ( c->idle_read_timer == (Timer*) 0 )
-	    {
-	    syslog( LOG_CRIT, "tmr_create(idle_read_connection) failed" );
-	    exit( 1 );
-	    }
-	c->idle_send_timer = (Timer*) 0;
 	c->wakeup_timer = (Timer*) 0;
 	c->linger_timer = (Timer*) 0;
 	c->bytes_sent = 0;
 	c->numtnums = 0;
+	c->keep_alive = 0;
+	c->last_io = httpd_time_now;
 
 	/* Set the connection file descriptor to no-delay mode. */
 	httpd_set_ndelay( c->hc->conn_fd );
@@ -1298,11 +1347,100 @@
     }
 
 
+#define FIXUP(x) if (hc->x >= oldptr && hc->x < pe) hc->x += d
+
+static void
+realign_hc(httpd_conn *hc, char *oldptr)
+{
+	int d = hc->read_buf - oldptr;
+	char *pe = oldptr + hc->checked_idx;
+
+	FIXUP(encodedurl);
+	FIXUP(protocol);
+	FIXUP(referer);
+	FIXUP(useragent);
+	FIXUP(acceptl);
+	FIXUP(cookie);
+	FIXUP(contenttype);
+	FIXUP(hdrhost);
+	FIXUP(authorization);
+}
+
+#undef FIXUP
+
+static void
+setup_read_body(connecttab *c, struct timeval *tvP) 
+{
+	httpd_conn *hc = c->hc;
+	int already, missing;
+	char *oldptr = hc->read_buf;
+	
+	c->conn_state = CNST_READING_BODY;
+
+	hc->read_body_into_mem = 0;
+	
+	already = hc->read_idx - hc->checked_idx;
+	missing = hc->contentlength - already;
+
+	if (missing > 16384) {
+		char filename[] = "/tmp/thttpd.upload.XXXXXX";
+		int tmp = mkstemp(filename);
+		
+		if (tmp >= 0) {
+			void *p;
+			size_t sz = hc->contentlength + hc->checked_idx + 10;
+
+			unlink(filename);
+
+			ftruncate(tmp, sz);
+			p = mmap(NULL, sz,
+					PROT_READ|PROT_WRITE, MAP_PRIVATE, tmp, 0);
+
+			if (p != MAP_FAILED) {
+				memcpy(p, hc->read_buf, hc->read_idx);
+				free(hc->read_buf);
+				hc->read_size = sz;
+				hc->read_buf = p;
+				hc->read_buf_is_mmap = 1;
+			}
+			close(tmp);
+		}
+	
+		if (!hc->read_buf_is_mmap) {
+			clear_connection( c, tvP, 0 );
+			return;
+		}
+	} else if (missing > 0) {
+		httpd_realloc_str(&hc->read_buf, &hc->read_size, hc->checked_idx + hc->contentlength + 10);
+	}
+	if (oldptr != hc->read_buf) realign_hc(hc, oldptr);
+
+    fdwatch_del_fd( hc->conn_fd );
+    fdwatch_add_fd( hc->conn_fd, c, FDW_READ );
+}
+
+static void
+setup_sending(connecttab *c, int state, struct timeval *tvP)
+{
+    httpd_conn *hc = c->hc;
+    ClientData client_data;
+
+    c->conn_state = state;
+    c->started_at = tvP->tv_sec;
+    c->wouldblock_delay = 0;
+    client_data.p = c;
+
+    fdwatch_del_fd( hc->conn_fd );
+    fdwatch_add_fd( hc->conn_fd, c, FDW_WRITE );
+}
+
+static void handle_request( connecttab *c, struct timeval *tvP);
+
+
 static void
 handle_read( connecttab* c, struct timeval* tvP )
     {
     int sz;
-    ClientData client_data;
     httpd_conn* hc = c->hc;
 
     /* Is there room in our buffer to read more bytes? */
@@ -1311,7 +1449,7 @@
 	if ( hc->read_size > 5000 )
 	    {
 	    httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" );
-	    clear_connection( c, tvP );
+	    clear_connection( c, tvP, 0 );
 	    return;
 	    }
 	httpd_realloc_str(
@@ -1327,14 +1465,53 @@
     ** EWOULDBLOCK; however, this apparently can happen if a packet gets
     ** garbled.
     */
-    if ( sz == 0 || ( sz < 0 && ( errno != EWOULDBLOCK ) ) )
-	{
-	httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" );
-	clear_connection( c, tvP );
+    if ( sz == 0 ) {
+    	if (! c->keep_alive) {
+		httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" );
+	}
+	clear_connection( c, tvP, 0 );
+	return;
+    } else if ( sz < 0 ) {
+    	if (errno != EWOULDBLOCK) {
+		clear_connection( c, tvP, 0 );
+	} 
 	return;
+    }
+
+	/* If this is a persistent PHP connection, we must not receive
+	** any further requests on this connection. Some broken HTTP/1.1
+	** implementations (e.g. Mozilla 1.0.1) are known to do
+	** pipelining on a connection, although a prior response included
+	** Connection: close
+	*/
+	if (c->hc->file_address == (char *) 1) {
+		return;
+	}
+	
+    c->last_io = httpd_time_now;
+    if (sz > 0) hc->read_idx += sz;
+
+    /* 
+    ** if we start getting new data on this socket, "promote" it 
+    **  to read timeout
+    */
+    if ( hc->keep_alive ) {
+		ClientData client_data;
+
+
+	client_data.p = c;
+    	
+    	hc->keep_alive = 0;
+    }
+	handle_request(c, tvP);
 	}
-    hc->read_idx += sz;
 
+
+static void
+handle_request( connecttab *c, struct timeval *tvP)
+{
+    httpd_conn* hc = c->hc;
+    
     /* Do we have a complete request yet? */
     switch ( httpd_got_request( hc ) )
 	{
@@ -1342,14 +1519,14 @@
 	return;
 	case GR_BAD_REQUEST:
 	httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" );
-	clear_connection( c, tvP );
+	clear_connection( c, tvP, 0 );
 	return;
 	}
 
     /* Yes.  Try parsing and resolving it. */
     if ( httpd_parse_request( hc ) < 0 )
 	{
-	clear_connection( c, tvP );
+	clear_connection( c, tvP, 0 );
 	return;
 	}
 
@@ -1358,18 +1535,28 @@
 	{
 	httpd_send_err(
 	    hc, 503, httpd_err503title, "", httpd_err503form, hc->encodedurl );
-	clear_connection( c, tvP );
+	clear_connection( c, tvP, 0 );
 	return;
 	}
+	boot_request(c, tvP);
+}
 
+static void boot_request(connecttab *c, struct timeval *tvP)
+{
+	httpd_conn *hc = c->hc;
     /* Start the connection going. */
     if ( httpd_start_request( hc, tvP ) < 0 )
 	{
 	/* Something went wrong.  Close down the connection. */
-	clear_connection( c, tvP );
+	clear_connection( c, tvP, 0 );
 	return;
 	}
 
+    if ( hc->read_body_into_mem ) {
+	setup_read_body( c, tvP );
+	return;
+	}
+	
     /* Fill in bytes_to_send. */
     if ( hc->got_range )
 	{
@@ -1384,37 +1571,25 @@
 	{
 	/* No file address means someone else is handling it. */
 	c->bytes_sent = hc->bytes_sent;
-	clear_connection( c, tvP );
+	clear_connection( c, tvP, 1 );
 	return;
 	}
+	if (hc->file_address == (char *) 1) {
+		c->last_io = (time_t) LONG_MAX;
+		c->wouldblock_delay = 0;
+		return;
+	}
     if ( c->bytes_sent >= c->bytes_to_send )
 	{
 	/* There's nothing to send. */
-	clear_connection( c, tvP );
+	clear_connection( c, tvP, 1 );
 	return;
 	}
 
     /* Cool, we have a valid connection and a file to send to it. */
-    c->conn_state = CNST_SENDING;
-    c->started_at = tvP->tv_sec;
-    c->wouldblock_delay = 0;
-    client_data.p = c;
-    tmr_cancel( c->idle_read_timer );
-    c->idle_read_timer = (Timer*) 0;
-    c->idle_send_timer = tmr_create(
-	tvP, idle_send_connection, client_data, IDLE_SEND_TIMELIMIT * 1000L,
-	0 );
-    if ( c->idle_send_timer == (Timer*) 0 )
-	{
-	syslog( LOG_CRIT, "tmr_create(idle_send_connection) failed" );
-	exit( 1 );
-	}
-
-    fdwatch_del_fd( hc->conn_fd );
-    fdwatch_add_fd( hc->conn_fd, c, FDW_WRITE );
+    setup_sending(c, CNST_SENDING, tvP);
     }
 
-
 static void
 handle_send( connecttab* c, struct timeval* tvP )
     {
@@ -1443,6 +1618,9 @@
 	iv[1].iov_base = &(hc->file_address[c->bytes_sent]);
 	iv[1].iov_len = MIN( c->bytes_to_send - c->bytes_sent, c->limit );
 	sz = writev( hc->conn_fd, iv, 2 );
+/*
+printf("**RESPONSE2 [%d]** len = %d\n%*.*s\n", hc->conn_fd, hc->responselen, hc->responselen, hc->responselen, hc->response); 
+*/
 	}
 
     if ( sz == 0 ||
@@ -1486,12 +1664,12 @@
 	*/
 	if ( errno != EPIPE && errno != EINVAL && errno != ECONNRESET )
 	    syslog( LOG_ERR, "write - %m sending %.80s", hc->encodedurl );
-	clear_connection( c, tvP );
+	clear_connection( c, tvP, 0 );
 	return;
 	}
 
     /* Ok, we wrote something. */
-    tmr_reset( tvP, c->idle_send_timer );
+    c->last_io = httpd_time_now;
     /* Was this a headers + file writev()? */
     if ( hc->responselen > 0 )
 	{
@@ -1500,7 +1678,7 @@
 	    {
 	    /* Yes; move the unwritten part to the front of the buffer. */
 	    int newlen = hc->responselen - sz;
-	    (void) memcpy( hc->response, &(hc->response[sz]), newlen );
+	    (void) memmove( hc->response, &(hc->response[sz]), newlen );
 	    hc->responselen = newlen;
 	    sz = 0;
 	    }
@@ -1519,7 +1697,7 @@
     if ( c->bytes_sent >= c->bytes_to_send )
 	{
 	/* This conection is finished! */
-	clear_connection( c, tvP );
+	clear_connection( c, tvP, 1 );
 	return;
 	}
 
@@ -1560,6 +1738,9 @@
     char buf[1024];
     int r;
 
+/*
+printf("*LINGER read\n");
+*/
     /* In lingering-close mode we just read and ignore bytes.  An error
     ** or EOF ends things, otherwise we go until a timeout.
     */
@@ -1569,6 +1750,63 @@
     }
 
 
+static void
+handle_read_body(connecttab *c, struct timeval *tvP)
+{
+	httpd_conn *hc = c->hc;
+	int n;
+	
+	n = read(hc->conn_fd, hc->read_buf + hc->read_idx, 
+			hc->contentlength - (hc->read_idx - hc->checked_idx));
+   	
+	if (n <= 0) {
+		if (errno == EAGAIN)
+			return;
+		clear_connection(c, tvP, 0);
+		return;
+	}
+ 
+	c->last_io = httpd_time_now;
+
+	hc->read_idx += n;
+
+	if (hc->contentlength == hc->read_idx - hc->checked_idx) {
+		boot_request(c, tvP);
+		return;
+	}
+}
+
+static void
+handle_send_resp(connecttab *c, struct timeval *tvP)
+{
+	httpd_conn* hc = c->hc;
+	int n = send(hc->conn_fd, hc->response, hc->responselen, 0);
+	int dokeep = 1;
+	
+	if (n < 0) {
+		if (errno == EAGAIN)
+			return;
+
+		dokeep = 0;
+		goto clear;
+	}
+
+	c->last_io = httpd_time_now;
+
+	if (n == hc->responselen) {
+clear:
+		hc->response = realloc(hc->response, hc->maxresponse + 1);
+		hc->responselen = 0;
+
+		clear_connection(c, tvP, dokeep);
+		return;
+	}
+
+	hc->responselen -= n;
+
+	memmove(hc->response, hc->response + n, hc->responselen);
+}
+
 static int
 check_throttles( connecttab* c )
     {
@@ -1635,23 +1873,18 @@
 
 
 static void
-clear_connection( connecttab* c, struct timeval* tvP )
+clear_connection( connecttab* c, struct timeval* tvP, int doKeep )
     {
     ClientData client_data;
+    int		linger;
 
     /* If we haven't actually sent the buffered response yet, do so now. */
-    httpd_write_response( c->hc );
+    if (c->hc->responselen && c->conn_state != CNST_SENDING_RESP) {
+		setup_sending(c, CNST_SENDING_RESP, tvP);
 
-    if ( c->idle_read_timer != (Timer*) 0 )
-	{
-	tmr_cancel( c->idle_read_timer );
-	c->idle_read_timer = 0;
-	}
-    if ( c->idle_send_timer != (Timer*) 0 )
-	{
-	tmr_cancel( c->idle_send_timer );
-	c->idle_send_timer = 0;
+		return;
 	}
+
     if ( c->wakeup_timer != (Timer*) 0 )
 	{
 	tmr_cancel( c->wakeup_timer );
@@ -1669,13 +1902,36 @@
     ** circumstances that make a lingering close necessary.  If the flag
     ** isn't set we do the real close now.
     */
-    if ( c->hc->should_linger )
+
+    if ( c->hc->do_keep_alive && doKeep)
 	{
-	c->conn_state = CNST_LINGERING;
+		httpd_conn *hc = c->hc;
+	c->conn_state = CNST_READING;
+
+	client_data.p = c;
+	c->bytes_sent = 0;
+	c->numtnums = 0;
+	c->keep_alive = 1;
+
+	httpd_complete_request( c->hc, tvP );
+
 	fdwatch_del_fd( c->hc->conn_fd );
 	fdwatch_add_fd( c->hc->conn_fd, c, FDW_READ );
+
+	httpd_request_reset( c->hc, 1 );
+
+	hc->read_idx -= hc->checked_idx;
+	memmove(hc->read_buf, hc->read_buf + hc->checked_idx, hc->read_idx);
+	hc->checked_idx = 0;
+	
 	/* Make sure we are still in no-delay mode. */
 	httpd_set_ndelay( c->hc->conn_fd );
+	handle_request(c, tvP);
+	}
+    else if ( c->hc->should_linger )
+        {
+	c->conn_state = CNST_LINGERING;
+
 	client_data.p = c;
 	c->linger_timer = tmr_create(
 	    tvP, linger_clear_connection, client_data, LINGER_TIME * 1000L, 0 );
@@ -1684,9 +1940,19 @@
 	    syslog( LOG_CRIT, "tmr_create(linger_clear_connection) failed" );
 	    exit( 1 );
 	    }
+
+    	httpd_complete_request( c->hc, tvP );
+
+	fdwatch_del_fd( c->hc->conn_fd );
+	fdwatch_add_fd( c->hc->conn_fd, c, FDW_READ );
+	/* Make sure we are still in no-delay mode. */
+	httpd_set_ndelay( c->hc->conn_fd );
 	}
-    else
+     else  
+        {
+    	httpd_complete_request( c->hc, tvP );
 	really_clear_connection( c, tvP );
+	}
     }
 
 
@@ -1702,45 +1968,12 @@
 	tmr_cancel( c->linger_timer );
 	c->linger_timer = 0;
 	}
+    free_connects[next_free_connect++] = c;
     c->conn_state = CNST_FREE;
     --numconnects;
     }
 
 
-static void
-idle_read_connection( ClientData client_data, struct timeval* nowP )
-    {
-    connecttab* c;
-
-    c = (connecttab*) client_data.p;
-    c->idle_read_timer = (Timer*) 0;
-    if ( c->conn_state != CNST_FREE )
-	{
-	syslog( LOG_INFO,
-	    "%.80s connection timed out reading",
-	    httpd_ntoa( &c->hc->client_addr ) );
-	httpd_send_err( c->hc, 408, httpd_err408title, "", httpd_err408form, "" );
-	clear_connection( c, nowP );
-	}
-    }
-
-
-static void
-idle_send_connection( ClientData client_data, struct timeval* nowP )
-    {
-    connecttab* c;
-
-    c = (connecttab*) client_data.p;
-    c->idle_send_timer = (Timer*) 0;
-    if ( c->conn_state != CNST_FREE )
-	{
-	syslog( LOG_INFO,
-	    "%.80s connection timed out sending",
-	    httpd_ntoa( &c->hc->client_addr ) );
-	clear_connection( c, nowP );
-	}
-    }
-
 
 static void
 wakeup_connection( ClientData client_data, struct timeval* nowP )
@@ -1783,6 +2016,43 @@
     }
 #endif /* STATS_TIME */
 
+char httpd_now_buf[100];
+
+
+
+static void
+periodic_jobs( ClientData client_data, struct timeval* nowP )
+{
+	const char* rfc1123fmt = "%a, %d %b %Y %H:%M:%S GMT";
+	struct tm *t;
+	char date_nozone[100];
+	const char* cernfmt_nozone = "%d/%b/%Y:%H:%M:%S";
+	char data[100];
+	int zone;
+	char sign;
+	
+	strftime( httpd_now_buf, sizeof(httpd_now_buf), rfc1123fmt, gmtime( &nowP->tv_sec ) );
+
+	t = localtime(&nowP->tv_sec);
+	strftime( date_nozone, sizeof(date_nozone), cernfmt_nozone, t );
+#ifdef HAVE_TM_GMTOFF
+    zone = t->tm_gmtoff / 60L;
+#else
+    zone = -timezone / 60L;
+    /* Probably have to add something about daylight time here. */
+#endif
+    if ( zone >= 0 )
+        sign = '+';
+    else
+        {
+        sign = '-';
+        zone = -zone;
+        }
+    zone = ( zone / 60 ) * 100 + zone % 60;
+    hs->log_date_len = sprintf( hs->log_date, "%s %c%04d", date_nozone, sign, 
+			zone );
+}
+
 
 /* Generate debugging statistics syslog messages for all packages. */
 static void
@@ -1826,3 +2096,42 @@
     stats_connections = stats_bytes = 0L;
     stats_simultaneous = 0;
     }
+
+static void
+timeout_conns(ClientData client_data, struct timeval *nowP)
+{
+    connecttab *c = connects, *ce = c + maxconnects;
+    time_t now = nowP->tv_sec;
+    int r = 0, w = 0;
+    int checked = 0;
+
+    while (c < ce) {
+        switch (c->conn_state) {
+        case CNST_SENDING:
+        case CNST_SENDING_RESP:
+            checked++;
+            if ((now - c->last_io) > IDLE_SEND_TIMELIMIT) {
+                clear_connection( c, nowP, 0 );
+                w++;
+            }
+            break;
+        case CNST_READING:
+        case CNST_READING_BODY:
+            checked++;
+            if ((now - c->last_io) > IDLE_READ_TIMELIMIT) {
+                clear_connection( c, nowP, 0 );
+                r++;
+            }
+            break;
+        case CNST_FREE: break;
+        default: checked++; break;
+        }
+        c++;
+        if (checked >= numconnects) break;
+    }
+
+    if (r > 0 || w > 0) {
+        syslog(LOG_INFO, "Expired %d/%d connections in read/write state", r, w);
+    }
+}
+
diff -ur thttpd-2.21b/version.h thttpd-2.21b-cool/version.h
--- thttpd-2.21b/version.h	Tue Apr 24 04:05:23 2001
+++ thttpd-2.21b-cool/version.h	Sat Sep 20 14:43:20 2003
@@ -3,7 +3,7 @@
 #ifndef _VERSION_H_
 #define _VERSION_H_
 
-#define SERVER_SOFTWARE "thttpd/2.21b 23apr2001"
+#define SERVER_SOFTWARE "thttpd/2.21b PHP/20030920"
 #define SERVER_ADDRESS "http://www.acme.com/software/thttpd/"
 
 #endif /* _VERSION_H_ */