📄 thttpd_patch
字号:
/* Done with an mmap()ed area that was returned by mmc_map(). ** If you have a stat buffer on the file, pass it in, otherwise pass 0.diff -ur thttpd-2.21b/thttpd.c thttpd-2.21b-cool/thttpd.c--- thttpd-2.21b/thttpd.c Tue Apr 24 00:41:57 2001+++ thttpd-2.21b-cool/thttpd.c Sat Sep 20 14:43:20 2003@@ -53,6 +53,10 @@ #endif #include <unistd.h> +#include <sys/mman.h>++#include <limits.h>+ #include "fdwatch.h" #include "libhttpd.h" #include "mmc.h"@@ -66,6 +70,8 @@ static char* dir; static int do_chroot, no_log, no_symlink, do_vhost, do_global_passwd; static char* cgi_pattern;+static char* php_pattern;+static char* phps_pattern; static char* url_pattern; static int no_empty_referers; static char* local_pattern;@@ -95,10 +101,10 @@ httpd_conn* hc; int tnums[MAXTHROTTLENUMS]; /* throttle indexes */ int numtnums;+ int keep_alive; long limit; time_t started_at;- Timer* idle_read_timer;- Timer* idle_send_timer;+ time_t last_io; Timer* wakeup_timer; Timer* linger_timer; long wouldblock_delay;@@ -106,17 +112,22 @@ off_t bytes_sent; off_t bytes_to_send; } connecttab;-static connecttab* connects;+static connecttab* connects, **free_connects;+static int next_free_connect; static int numconnects, maxconnects; static int httpd_conn_count; /* The connection states. */-#define CNST_FREE 0-#define CNST_READING 1-#define CNST_SENDING 2-#define CNST_PAUSING 3-#define CNST_LINGERING 4-+enum {+ CNST_FREE = 0,+ CNST_READING,+ CNST_SENDING,+ CNST_PAUSING,+ CNST_LINGERING,+ CNST_SENDING_RESP,+ CNST_READING_BODY,+ CNST_TOTAL_NR+}; static httpd_server* hs = (httpd_server*) 0; int terminate = 0;@@ -140,23 +151,32 @@ static int handle_newconnect( struct timeval* tvP, int listen_fd ); static void handle_read( connecttab* c, struct timeval* tvP ); static void handle_send( connecttab* c, struct timeval* tvP );+static void handle_send_resp( connecttab* c, struct timeval* tvP );+static void handle_read_body( connecttab* c, struct timeval* tvP ); static void handle_linger( connecttab* c, struct timeval* tvP ); static int check_throttles( connecttab* c );+static void timeout_conns( ClientData client_data, struct timeval* nowP ); static void clear_throttles( connecttab* c, struct timeval* tvP ); static void update_throttles( ClientData client_data, struct timeval* nowP );-static void clear_connection( connecttab* c, struct timeval* tvP );+static void clear_connection( connecttab* c, struct timeval* tvP, int ); static void really_clear_connection( connecttab* c, struct timeval* tvP );-static void idle_read_connection( ClientData client_data, struct timeval* nowP );-static void idle_send_connection( ClientData client_data, struct timeval* nowP ); static void wakeup_connection( ClientData client_data, struct timeval* nowP ); static void linger_clear_connection( ClientData client_data, struct timeval* nowP ); static void occasional( ClientData client_data, struct timeval* nowP );+static void periodic_jobs( ClientData client_data, struct timeval* nowP ); #ifdef STATS_TIME static void show_stats( ClientData client_data, struct timeval* nowP ); #endif /* STATS_TIME */ static void logstats( struct timeval* nowP ); static void thttpd_logstats( long secs );+static void boot_request(connecttab *c, struct timeval *tvP);++typedef void (*handler_func)(connecttab*, struct timeval *);++handler_func handler_array[CNST_TOTAL_NR] =+{NULL, handle_read, handle_send, NULL, handle_linger, handle_send_resp, handle_read_body}; +#define RUN_HANDLER(type, c) if (handler_array[type]) handler_array[type](c, &tv) static void handle_term( int sig )@@ -177,7 +197,7 @@ return; /* Re-open the log file. */- if ( logfile != (char*) 0 )+ if ( logfile != (char*) 0 && strcmp(logfile, "-") != 0) { logfp = fopen( logfile, "a" ); if ( logfp == (FILE*) 0 )@@ -198,6 +218,8 @@ } +time_t httpd_time_now;+ static void handle_usr2( int sig ) {@@ -217,7 +239,6 @@ int num_ready; int cnum, ridx; connecttab* c;- httpd_conn* hc; httpd_sockaddr sa4; httpd_sockaddr sa6; int gotv4, gotv6;@@ -270,7 +291,9 @@ no_log = 1; logfp = (FILE*) 0; }- else+ else if (strcmp(logfile, "-") == 0) {+ logfp = stdout;+ } else { logfp = fopen( logfile, "a" ); if ( logfp == (FILE*) 0 )@@ -420,7 +443,8 @@ hostname, gotv4 ? &sa4 : (httpd_sockaddr*) 0, gotv6 ? &sa6 : (httpd_sockaddr*) 0, port, cgi_pattern, charset, cwd, no_log, logfp, no_symlink, do_vhost,- do_global_passwd, url_pattern, local_pattern, no_empty_referers );+ do_global_passwd, url_pattern, local_pattern, no_empty_referers,+ php_pattern, phps_pattern); if ( hs == (httpd_server*) 0 ) exit( 1 ); @@ -430,6 +454,12 @@ syslog( LOG_CRIT, "tmr_create(occasional) failed" ); exit( 1 ); }++ if (tmr_create(0, timeout_conns, JunkClientData, 30 * 1000, 1) == 0) {+ syslog(LOG_CRIT, "tmr_create(timeout_conns) failed");+ exit(1);+ }+ if ( numthrottles > 0 ) { /* Set up the throttles timer. */@@ -439,6 +469,12 @@ exit( 1 ); } }++ if (tmr_create(0, periodic_jobs, JunkClientData, 2000, 1) == 0) {+ syslog(LOG_CRIT, "tmr_create failed");+ exit(1);+ }+ #ifdef STATS_TIME /* Set up the stats timer. */ if ( tmr_create( (struct timeval*) 0, show_stats, JunkClientData, STATS_TIME * 1000L, 1 ) == (Timer*) 0 )@@ -454,12 +490,14 @@ /* If we're root, try to become someone else. */ if ( getuid() == 0 ) {+#ifndef __CYGWIN__ /* Set aux groups to null. */ if ( setgroups( 0, (const gid_t*) 0 ) < 0 ) { syslog( LOG_CRIT, "setgroups - %m" ); exit( 1 ); }+#endif /* Set primary group. */ if ( setgid( gid ) < 0 ) {@@ -495,13 +533,17 @@ } maxconnects -= SPARE_FDS; connects = NEW( connecttab, maxconnects );+ free_connects = malloc(sizeof(connecttab *) * maxconnects);+ next_free_connect = maxconnects; if ( connects == (connecttab*) 0 ) { syslog( LOG_CRIT, "out of memory allocating a connecttab" ); exit( 1 ); }+ for ( cnum = 0; cnum < maxconnects; ++cnum ) {+ free_connects[cnum] = &connects[maxconnects - cnum - 1]; connects[cnum].conn_state = CNST_FREE; connects[cnum].hc = (httpd_conn*) 0; }@@ -518,6 +560,9 @@ /* Main loop. */ (void) gettimeofday( &tv, (struct timezone*) 0 );+ httpd_time_now = tv.tv_sec;+ periodic_jobs(JunkClientData, &tv);+ while ( ( ! terminate ) || numconnects > 0 ) { /* Do the fd watch. */@@ -530,6 +575,7 @@ exit( 1 ); } (void) gettimeofday( &tv, (struct timezone*) 0 );+ httpd_time_now = tv.tv_sec; if ( num_ready == 0 ) { /* No fd's are ready - run the timers. */@@ -565,16 +611,10 @@ c = (connecttab*) fdwatch_get_client_data( ridx ); if ( c == (connecttab*) 0 ) continue;- hc = c->hc;- if ( c->conn_state == CNST_READING &&- fdwatch_check_fd( hc->conn_fd ) )- handle_read( c, &tv );- else if ( c->conn_state == CNST_SENDING &&- fdwatch_check_fd( hc->conn_fd ) )- handle_send( c, &tv );- else if ( c->conn_state == CNST_LINGERING &&- fdwatch_check_fd( hc->conn_fd ) )- handle_linger( c, &tv );+#if DO_UNNECESSARY_CHECK_FD+ fdwatch_check_fd(c->hc->conn_fd);+#endif+ RUN_HANDLER(c->conn_state, c); } tmr_run( &tv ); @@ -627,6 +667,8 @@ #else /* CGI_PATTERN */ cgi_pattern = (char*) 0; #endif /* CGI_PATTERN */+ php_pattern = "**.php";+ phps_pattern = "**.phps"; url_pattern = (char*) 0; no_empty_referers = 0; local_pattern = (char*) 0;@@ -833,6 +875,16 @@ value_required( name, value ); cgi_pattern = e_strdup( value ); }+ else if ( strcasecmp( name, "phppat" ) == 0 )+ {+ value_required( name, value );+ php_pattern = e_strdup( value );+ }+ else if ( strcasecmp( name, "phpspat" ) == 0 )+ {+ value_required( name, value );+ phps_pattern = e_strdup( value );+ } else if ( strcasecmp( name, "urlpat" ) == 0 ) { value_required( name, value );@@ -1196,8 +1248,10 @@ logstats( &tv ); for ( cnum = 0; cnum < maxconnects; ++cnum ) {- if ( connects[cnum].conn_state != CNST_FREE )+ if ( connects[cnum].conn_state != CNST_FREE ) {+ httpd_complete_request( connects[cnum].hc, &tv ); httpd_close_conn( connects[cnum].hc, &tv );+ } if ( connects[cnum].hc != (httpd_conn*) 0 ) { httpd_destroy_conn( connects[cnum].hc );@@ -1214,6 +1268,7 @@ } mmc_destroy(); tmr_destroy();+ free( (void*) free_connects ); free( (void*) connects ); if ( throttles != (throttletab*) 0 ) free( (void*) throttles );@@ -1234,7 +1289,7 @@ for (;;) { /* Is there room in the connection table? */- if ( numconnects >= maxconnects )+ if ( numconnects >= maxconnects || next_free_connect == 0 ) { /* Out of connection slots. Run the timers, then the ** existing connections, and maybe we'll free up a slot@@ -1245,10 +1300,10 @@ return 0; } /* Find a free connection entry. */- for ( cnum = 0; cnum < maxconnects; ++cnum )- if ( connects[cnum].conn_state == CNST_FREE )- break;- c = &connects[cnum];++ c = free_connects[--next_free_connect];+ free_connects[next_free_connect] = NULL;+ /* Make the httpd_conn if necessary. */ if ( c->hc == (httpd_conn*) 0 ) {@@ -1267,24 +1322,18 @@ { case GC_FAIL: case GC_NO_MORE:+ free_connects[next_free_connect++] = c; return 1; } c->conn_state = CNST_READING; ++numconnects; client_data.p = c;- c->idle_read_timer = tmr_create(- tvP, idle_read_connection, client_data, IDLE_READ_TIMELIMIT * 1000L,- 0 );- if ( c->idle_read_timer == (Timer*) 0 )- {- syslog( LOG_CRIT, "tmr_create(idle_read_connection) failed" );- exit( 1 );- }- c->idle_send_timer = (Timer*) 0; c->wakeup_timer = (Timer*) 0; c->linger_timer = (Timer*) 0; c->bytes_sent = 0; c->numtnums = 0;+ c->keep_alive = 0;+ c->last_io = httpd_time_now; /* Set the connection file descriptor to no-delay mode. */ httpd_set_ndelay( c->hc->conn_fd );@@ -1298,11 +1347,100 @@ } +#define FIXUP(x) if (hc->x >= oldptr && hc->x < pe) hc->x += d++static void+realign_hc(httpd_conn *hc, char *oldptr)+{+ int d = hc->read_buf - oldptr;+ char *pe = oldptr + hc->checked_idx;++ FIXUP(encodedurl);+ FIXUP(protocol);+ FIXUP(referer);+ FIXUP(useragent);+ FIXUP(acceptl);+ FIXUP(cookie);+ FIXUP(contenttype);+ FIXUP(hdrhost);+ FIXUP(authorization);+}++#undef FIXUP++static void+setup_read_body(connecttab *c, struct timeval *tvP) +{+ httpd_conn *hc = c->hc;+ int already, missing;+ char *oldptr = hc->read_buf;+ + c->conn_state = CNST_READING_BODY;++ hc->read_body_into_mem = 0;+ + already = hc->read_idx - hc->checked_idx;+ missing = hc->contentlength - already;++ if (missing > 16384) {+ char filename[] = "/tmp/thttpd.upload.XXXXXX";+ int tmp = mkstemp(filename);+ + if (tmp >= 0) {+ void *p;+ size_t sz = hc->contentlength + hc->checked_idx + 10;++ unlink(filename);++ ftruncate(tmp, sz);+ p = mmap(NULL, sz,+ PROT_READ|PROT_WRITE, MAP_PRIVATE, tmp, 0);++ if (p != MAP_FAILED) {+ memcpy(p, hc->read_buf, hc->read_idx);+ free(hc->read_buf);+ hc->read_size = sz;+ hc->read_buf = p;+ hc->read_buf_is_mmap = 1;+ }+ close(tmp);+ }+ + if (!hc->read_buf_is_mmap) {+ clear_connection( c, tvP, 0 );+ return;+ }+ } else if (missing > 0) {+ httpd_realloc_str(&hc->read_buf, &hc->read_size, hc->checked_idx + hc->contentlength + 10);+ }+ if (oldptr != hc->read_buf) realign_hc(hc, oldptr);++ fdwatch_del_fd( hc->conn_fd );+ fdwatch_add_fd( hc->conn_fd, c, FDW_READ );+}++static void+setup_sending(connecttab *c, int state, struct timeval *tvP)+{+ httpd_conn *hc = c->hc;+ ClientData client_data;++ c->conn_state = state;+ c->started_at = tvP->tv_sec;+ c->wouldblock_delay = 0;+ client_data.p = c;++ fdwatch_del_fd( hc->conn_fd );+ fdwatch_add_fd( hc->conn_fd, c, FDW_WRITE );+}++static void handle_request( connecttab *c, struct timeval *tvP);++ static void handle_read( connecttab* c, struct timeval* tvP ) { int sz;- ClientData client_data; httpd_conn* hc = c->hc; /* Is there room in our buffer to read more bytes? */@@ -1311,7 +1449,7 @@ if ( hc->read_size > 5000 ) { httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" );- clear_connection( c, tvP );+ clear_connection( c, tvP, 0 ); return; } httpd_realloc_str(@@ -1327,14 +1465,53 @@ ** EWOULDBLOCK; however, this apparently can happen if a packet gets ** garbled. */- if ( sz == 0 || ( sz < 0 && ( errno != EWOULDBLOCK ) ) )- {- httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" );- clear_connection( c, tvP );+ if ( sz == 0 ) {+ if (! c->keep_alive) {+ httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" );+ }+ clear_connection( c, tvP, 0 );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -