diff -Nur 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 Fri Jul 26 18:12:50 2002 @@ -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. 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@ @@ -151,6 +153,9 @@ tags: ctags -wtd *.c *.h + +php_thttpd.o: php_thttpd.c + $(CC) $(PHP_CFLAGS) $(CFLAGS) -c php_thttpd.c tar: @name=`sed -n -e '/SERVER_SOFTWARE/!d' -e 's,.*thttpd/,thttpd-,' -e 's, .*,,p' version.h` ; \ diff -Nur 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 Fri Jul 26 18:12:50 2002 @@ -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 -Nur 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 Fri Jul 26 18:12:50 2002 @@ -460,7 +460,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 +472,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 -Nur 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 Fri Jul 26 18:12:50 2002 @@ -85,6 +85,8 @@ #include "match.h" #include "tdate_parse.h" +#include "php_thttpd.h" + #ifndef STDIN_FILENO #define STDIN_FILENO 0 #endif @@ -242,6 +244,8 @@ 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->charset != (char*) 0 ) free( (void*) hs->charset ); if ( hs->url_pattern != (char*) 0 ) @@ -249,6 +253,7 @@ if ( hs->local_pattern != (char*) 0 ) free( (void*) hs->local_pattern ); free( (void*) hs ); + thttpd_php_shutdown(); } @@ -312,6 +317,7 @@ } hs->port = port; + hs->php_pattern = strdup("**.php"); if ( cgi_pattern == (char*) 0 ) hs->cgi_pattern = (char*) 0; else @@ -385,6 +391,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 ); @@ -582,6 +590,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; } @@ -657,9 +668,9 @@ (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", + "%.20s %d %s\r\nServer: %s\r\nContent-Type: %s\r\nDate: %s\r\nLast-Modified: %s\r\nAccept-Ranges: bytes\r\n", hc->protocol, status, title, EXPOSED_SERVER_SOFTWARE, fixed_type, - nowbuf, modbuf ); + nowbuf, modbuf); add_response( hc, buf ); if ( encodings[0] != '\0' ) { @@ -681,6 +692,14 @@ "Content-Length: %d\r\n", length ); add_response( hc, buf ); } + else { + hc->do_keep_alive = 0; + } + if (hc->do_keep_alive) { + add_response( hc, "Connection: keep-alive\r\n" ); + } else { + add_response( hc, "Connection: close\r\n" ); + } if ( extraheads[0] != '\0' ) add_response( hc, extraheads ); add_response( hc, "\r\n" ); @@ -1603,6 +1622,61 @@ int +httpd_request_reset(httpd_conn* hc, int preserve_read_buf ) +{ + if (!preserve_read_buf) { + 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->do_keep_alive = 0; + hc->should_linger = 0; + hc->file_address = (char*) 0; + return GC_OK; +} + +int httpd_get_conn( httpd_server* hs, int listen_fd, httpd_conn* hc ) { httpd_sockaddr sa; @@ -1657,53 +1731,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 +1753,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 +1948,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 +2168,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 +2208,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 +2220,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 +2392,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, int logit ) +{ + if (logit) + 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 ); @@ -3026,11 +3078,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 +3363,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 ); @@ -3561,6 +3616,11 @@ 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 ); + } + /* 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. @@ -3611,14 +3671,18 @@ } else { + char *extraheads = ""; hc->file_address = mmc_map( hc->expnfilename, &(hc->sb), nowP ); if ( hc->file_address == (char*) 0 ) { httpd_send_err( hc, 500, err500title, "", err500form, hc->encodedurl ); return -1; } + if (strncmp(hc->decodedurl, "/nocache/", sizeof("/nocache/")-1) == 0) + extraheads = "Expires: Thu, 19 Nov 1981 08:52:00 GMT\r\nCache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0\r\nPragma: no-cache\r\n"; + send_mime( - hc, 200, ok200title, hc->encodings, "", hc->type, hc->sb.st_size, + hc, 200, ok200title, hc->encodings, extraheads, hc->type, hc->sb.st_size, hc->sb.st_mtime ); } diff -Nur 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 Fri Jul 26 18:12:50 2002 @@ -69,6 +69,7 @@ char* server_hostname; int port; char* cgi_pattern; + char* php_pattern; char* charset; char* cwd; int listen4_fd, listen6_fd; @@ -132,7 +133,7 @@ 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; @@ -229,6 +230,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 logit ); +int httpd_request_reset(httpd_conn* hc,int ); /* Call this to de-initialize a connection struct and *really* free the ** mallocced strings. diff -Nur 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 Fri Jul 26 18:12:50 2002 @@ -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 -Nur 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 Fri Jul 26 18:12:50 2002 @@ -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 -Nur 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 Fri Jul 26 18:14:25 2002 @@ -95,6 +95,7 @@ httpd_conn* hc; int tnums[MAXTHROTTLENUMS]; /* throttle indexes */ int numtnums; + int keep_alive; long limit; time_t started_at; Timer* idle_read_timer; @@ -111,12 +112,15 @@ 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_TOTAL_NR +}; static httpd_server* hs = (httpd_server*) 0; int terminate = 0; @@ -140,11 +144,12 @@ 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_linger( connecttab* c, struct timeval* tvP ); static int check_throttles( connecttab* c ); 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 ); @@ -157,6 +162,12 @@ static void logstats( struct timeval* nowP ); static void thttpd_logstats( long secs ); +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}; + +#define RUN_HANDLER(type, c) handler_array[type](c, &tv) static void handle_term( int sig ) @@ -566,15 +577,17 @@ 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 ); + switch (c->conn_state) { + case CNST_READING: + case CNST_SENDING: + case CNST_LINGERING: + case CNST_SENDING_RESP: + fdwatch_check_fd(hc->conn_fd); + RUN_HANDLER(c->conn_state, c); + break; + } + + } tmr_run( &tv ); @@ -1196,8 +1209,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, 1 ); httpd_close_conn( connects[cnum].hc, &tv ); + } if ( connects[cnum].hc != (httpd_conn*) 0 ) { httpd_destroy_conn( connects[cnum].hc ); @@ -1285,6 +1300,7 @@ c->linger_timer = (Timer*) 0; c->bytes_sent = 0; c->numtnums = 0; + c->keep_alive = 0; /* Set the connection file descriptor to no-delay mode. */ httpd_set_ndelay( c->hc->conn_fd ); @@ -1297,12 +1313,40 @@ } } +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; + if (c->idle_read_timer != 0) { + 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 ); +} + +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 +1355,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,29 +1371,69 @@ ** 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) { + httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" ); + clear_connection( c, tvP, 0 ); + } return; + } + 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; + + if ( c->idle_read_timer != (Timer*) 0 ) + { + tmr_cancel( c->idle_read_timer ); + c->idle_read_timer = 0; + } + + 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 ); + } + + hc->keep_alive = 0; + } + handle_request(c, tvP); } - hc->read_idx += sz; - /* Do we have a complete request yet? */ +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 ) ) { case GR_NO_REQUEST: 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,7 +1442,7 @@ { httpd_send_err( hc, 503, httpd_err503title, "", httpd_err503form, hc->encodedurl ); - clear_connection( c, tvP ); + clear_connection( c, tvP, 0 ); return; } @@ -1366,7 +1450,7 @@ if ( httpd_start_request( hc, tvP ) < 0 ) { /* Something went wrong. Close down the connection. */ - clear_connection( c, tvP ); + clear_connection( c, tvP, 0 ); return; } @@ -1384,37 +1468,26 @@ { /* 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) { + tmr_cancel( c->idle_read_timer ); + c->idle_read_timer = (Timer*) 0; + 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 +1516,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,7 +1562,7 @@ */ 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; } @@ -1500,7 +1576,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 +1595,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 +1636,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 +1648,37 @@ } +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; + } + + tmr_reset( tvP, c->idle_send_timer ); + + 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,12 +1745,17 @@ 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); + + return; + } if ( c->idle_read_timer != (Timer*) 0 ) { @@ -1669,13 +1784,45 @@ ** 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->idle_read_timer = tmr_create( + tvP, idle_read_connection, client_data, IDLE_KEEPALIVE_TIMELIMIT * 1000L, + 0 ); + if ( c->idle_read_timer == (Timer*) 0 ) + { + syslog( LOG_CRIT, "tmr_create(idle_read_connection) failed" ); + exit( 1 ); + } + + c->bytes_sent = 0; + c->numtnums = 0; + c->keep_alive = 1; + + httpd_complete_request( c->hc, tvP, 1 ); + 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 +1831,19 @@ syslog( LOG_CRIT, "tmr_create(linger_clear_connection) failed" ); exit( 1 ); } + + httpd_complete_request( c->hc, tvP, 1 ); + + 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, !c->keep_alive ); really_clear_connection( c, tvP ); + } } @@ -1716,11 +1873,13 @@ 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 ); + if (! c->keep_alive) { + 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, 0 ); } } @@ -1737,7 +1896,7 @@ syslog( LOG_INFO, "%.80s connection timed out sending", httpd_ntoa( &c->hc->client_addr ) ); - clear_connection( c, nowP ); + clear_connection( c, nowP, 0 ); } }