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 #include +#ifdef HAVE_NETINET_TCP_H +#include +#endif + #ifdef HAVE_OSRELDATE_H #include #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), "%d %s\n

%d %s

\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 +#include + +#include + #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_ */