📄 thttpd_patch
字号:
+ 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++;+ }+
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -