X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=blobdiff_plain;f=jcc.c;h=3b8b3aacba170aaf781923c68988f9f9a840e41f;hp=ac7cadd4373b2e29d6b57df5432cdfe6068513de;hb=6e0d8fdc6320c0b65897184be8062f29d4016527;hpb=c652fa856a46670e64f74d3f1a1f714b60fa774c diff --git a/jcc.c b/jcc.c index ac7cadd4..3b8b3aac 100644 --- a/jcc.c +++ b/jcc.c @@ -1,4 +1,4 @@ -const char jcc_rcs[] = "$Id: jcc.c,v 1.321 2010/07/12 16:01:23 fabiankeil Exp $"; +const char jcc_rcs[] = "$Id: jcc.c,v 1.341 2011/03/03 14:41:29 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/jcc.c,v $ @@ -120,7 +120,7 @@ const char jcc_h_rcs[] = JCC_H_VERSION; const char project_h_rcs[] = PROJECT_H_VERSION; int daemon_mode = 1; -struct client_state clients[1]; +struct client_states clients[1]; struct file_list files[1]; #ifdef FEATURE_STATISTICS @@ -1151,14 +1151,20 @@ static void verify_request_length(struct client_state *csp) *********************************************************************/ static void mark_server_socket_tainted(struct client_state *csp) { + /* + * For consistency we always mark the server socket + * tainted, however, to reduce the log noise we only + * emit a log message if the server socket could have + * actually been reused. + */ if ((csp->flags & CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE) && !(csp->flags |= CSP_FLAG_SERVER_SOCKET_TAINTED)) { log_error(LOG_LEVEL_CONNECT, "Marking the server socket %d tainted.", csp->server_connection.sfd); - csp->flags |= CSP_FLAG_SERVER_SOCKET_TAINTED; } + csp->flags |= CSP_FLAG_SERVER_SOCKET_TAINTED; } /********************************************************************* @@ -1521,9 +1527,7 @@ static void chat(struct client_state *csp) const struct forward_spec *fwd; struct http_request *http; long len = 0; /* for buffer sizes (and negative error codes) */ - - /* Function that does the content filtering for the current request */ - filter_function_ptr content_filter = NULL; + int buffer_and_filter_content = 0; /* Skeleton for HTTP response, if we should intercept the request */ struct http_response *rsp; @@ -1615,12 +1619,8 @@ static void chat(struct client_state *csp) if (crunch_response_triggered(csp, crunchers_all)) { /* - * Yes. The client got the crunch response - * and we are done here after cleaning up. + * Yes. The client got the crunch response and we're done here. */ - /* XXX: why list_remove_all()? */ - list_remove_all(csp->headers); - return; } @@ -1793,9 +1793,14 @@ static void chat(struct client_state *csp) && ((csp->iob->eod - csp->iob->cur) >= 5) && !memcmp(csp->iob->eod-5, "0\r\n\r\n", 5)) { + /* + * XXX: This check should be obsolete now, + * but let's wait a while to be sure. + */ log_error(LOG_LEVEL_CONNECT, - "Looks like we read the last chunk together with " - "the server headers. We better stop reading."); + "Looks like we got the last chunk together with " + "the server headers but didn't detect it earlier. " + "We better stop reading."); byte_count = (unsigned long long)(csp->iob->eod - csp->iob->cur); csp->expected_content_length = byte_count; csp->flags |= CSP_FLAG_CONTENT_LENGTH_SET; @@ -1944,7 +1949,14 @@ static void chat(struct client_state *csp) if (FD_ISSET(csp->server_connection.sfd, &rfds)) { #ifdef FEATURE_CONNECTION_KEEP_ALIVE - if (!socket_is_still_alive(csp->cfd)) + /* + * If we are buffering content, we don't want to eat up to + * buffer-limit bytes if the client no longer cares about them. + * If we aren't buffering, however, a dead client socket will be + * noticed pretty much right away anyway, so we can reduce the + * overhead by skipping the check. + */ + if (buffer_and_filter_content && !socket_is_still_alive(csp->cfd)) { #ifdef _WIN32 log_error(LOG_LEVEL_CONNECT, @@ -2048,11 +2060,11 @@ static void chat(struct client_state *csp) * now is the time to apply content modification * and send the result to the client. */ - if (content_filter) + if (buffer_and_filter_content) { - p = execute_content_filter(csp, content_filter); + p = execute_content_filters(csp); /* - * If the content filter fails, use the original + * If content filtering fails, use the original * buffer and length. * (see p != NULL ? p : csp->iob->cur below) */ @@ -2114,7 +2126,7 @@ static void chat(struct client_state *csp) */ if (server_body || http->ssl) { - if (content_filter) + if (buffer_and_filter_content) { /* * If there is no memory left for buffering the content, or the buffer limit @@ -2162,7 +2174,7 @@ static void chat(struct client_state *csp) */ byte_count = (unsigned long long)flushed; freez(hdr); - content_filter = NULL; + buffer_and_filter_content = 0; server_body = 1; } } @@ -2298,6 +2310,19 @@ static void chat(struct client_state *csp) log_error(LOG_LEVEL_FATAL, "Out of memory parsing server header"); } + if ((csp->flags & CSP_FLAG_CHUNKED) + && !(csp->flags & CSP_FLAG_CONTENT_LENGTH_SET) + && ((csp->iob->eod - csp->iob->cur) >= 5) + && !memcmp(csp->iob->eod-5, "0\r\n\r\n", 5)) + { + log_error(LOG_LEVEL_CONNECT, + "Looks like we got the last chunk together with " + "the server headers. We better stop reading."); + byte_count = (unsigned long long)(csp->iob->eod - csp->iob->cur); + csp->expected_content_length = byte_count; + csp->flags |= CSP_FLAG_CONTENT_LENGTH_SET; + } + csp->server_connection.response_received = time(NULL); if (crunch_response_triggered(csp, crunchers_light)) @@ -2316,12 +2341,12 @@ static void chat(struct client_state *csp) if (!http->ssl) /* We talk plaintext */ { - content_filter = get_filter_function(csp); + buffer_and_filter_content = content_requires_filtering(csp); } /* * Only write if we're not buffering for content modification */ - if (!content_filter) + if (!buffer_and_filter_content) { /* * Write the server's (modified) header to @@ -2376,7 +2401,7 @@ static void chat(struct client_state *csp) if (csp->content_length == 0) { /* - * If Privoxy didn't recalculate the Content-Lenght, + * If Privoxy didn't recalculate the Content-Length, * byte_count is still correct. */ csp->content_length = byte_count; @@ -2469,6 +2494,7 @@ static void serve(struct client_state *csp) do { unsigned int latency; + int config_file_change_detected = 0; /* Only used for debugging */ chat(csp); @@ -2484,7 +2510,8 @@ static void serve(struct client_state *csp) && (((csp->flags & CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE) && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED)) || (csp->flags & CSP_FLAG_CRUNCHED)) - && (csp->cfd != JB_INVALID_SOCKET); + && (csp->cfd != JB_INVALID_SOCKET) + && (csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE); if (continue_chatting && !(csp->flags & CSP_FLAG_CRUNCHED)) { @@ -2503,6 +2530,12 @@ static void serve(struct client_state *csp) } } + if (continue_chatting && any_loaded_file_changed(csp->config->config_file_list)) + { + continue_chatting = 0; + config_file_change_detected = 1; + } + if (continue_chatting) { unsigned int client_timeout; @@ -2526,9 +2559,8 @@ static void serve(struct client_state *csp) && data_is_available(csp->cfd, (int)client_timeout) && socket_is_still_alive(csp->cfd)) { - log_error(LOG_LEVEL_CONNECT, "Client request arrived in " - "time or the client closed the connection on socket %d.", - csp->cfd); + log_error(LOG_LEVEL_CONNECT, + "Client request arrived in time on socket %d.", csp->cfd); prepare_csp_for_next_request(csp); } else @@ -2542,7 +2574,7 @@ static void serve(struct client_state *csp) { time_t time_open = time(NULL) - csp->server_connection.timestamp; - if (csp->server_connection.keep_alive_timeout < time_open + latency) + if (csp->server_connection.keep_alive_timeout < time_open - (time_t)latency) { break; } @@ -2569,8 +2601,17 @@ static void serve(struct client_state *csp) else if (csp->server_connection.sfd != JB_INVALID_SOCKET) { log_error(LOG_LEVEL_CONNECT, - "The connection on server socket %d to %s isn't reusable. " - "Closing.", csp->server_connection.sfd, csp->server_connection.host); + "The connection on server socket %d to %s isn't reusable. Closing. " + "Server connection: keep-alive %u, tainted: %u, socket alive %u. " + "Client connection: socket alive: %u. Server timeout: %u. " + "Configuration file change detected: %u", + csp->server_connection.sfd, csp->server_connection.host, + 0 != (csp->flags & CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE), + 0 != (csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED), + socket_is_still_alive(csp->server_connection.sfd), + socket_is_still_alive(csp->cfd), + csp->server_connection.keep_alive_timeout, + config_file_change_detected); } } while (continue_chatting); @@ -3345,6 +3386,7 @@ void w32_service_listen_loop(void *p) *********************************************************************/ static void listen_loop(void) { + struct client_states *csp_list = NULL; struct client_state *csp = NULL; jb_socket bfd; struct configuration_spec *config; @@ -3394,11 +3436,36 @@ static void listen_loop(void) } #endif - if ( NULL == (csp = (struct client_state *) zalloc(sizeof(*csp))) ) + csp_list = (struct client_states *)zalloc(sizeof(*csp_list)); + if (NULL == csp_list) + { + log_error(LOG_LEVEL_FATAL, + "malloc(%d) for csp_list failed: %E", sizeof(*csp_list)); + continue; + } + csp = &csp_list->csp; + + log_error(LOG_LEVEL_CONNECT, "Listening for new connections ... "); + + if (!accept_connection(csp, bfd)) { - log_error(LOG_LEVEL_FATAL, "malloc(%d) for csp failed: %E", sizeof(*csp)); + log_error(LOG_LEVEL_CONNECT, "accept failed: %E"); + +#ifdef AMIGA + if(!childs) + { + exit(1); + } +#endif + freez(csp_list); continue; } + else + { + log_error(LOG_LEVEL_CONNECT, + "accepted connection from %s on socket %d", + csp->ip_addr_str, csp->cfd); + } csp->flags |= CSP_FLAG_ACTIVE; csp->server_connection.sfd = JB_INVALID_SOCKET; @@ -3425,26 +3492,6 @@ static void listen_loop(void) bfd = bind_port_helper(config); } - log_error(LOG_LEVEL_CONNECT, "Listening for new connections ... "); - - if (!accept_connection(csp, bfd)) - { - log_error(LOG_LEVEL_CONNECT, "accept failed: %E"); - -#ifdef AMIGA - if(!childs) - { - exit(1); - } -#endif - freez(csp); - continue; - } - else - { - log_error(LOG_LEVEL_CONNECT, "accepted connection from %s", csp->ip_addr_str); - } - #ifdef FEATURE_TOGGLE if (global_toggle_state) #endif /* def FEATURE_TOGGLE */ @@ -3464,7 +3511,7 @@ static void listen_loop(void) log_error(LOG_LEVEL_CONNECT, "Connection from %s dropped due to ACL", csp->ip_addr_str); close_socket(csp->cfd); freez(csp->ip_addr_str); - freez(csp); + freez(csp_list); continue; } #endif /* def FEATURE_ACL */ @@ -3479,13 +3526,13 @@ static void listen_loop(void) strlen(TOO_MANY_CONNECTIONS_RESPONSE)); close_socket(csp->cfd); freez(csp->ip_addr_str); - freez(csp); + freez(csp_list); continue; } /* add it to the list of clients */ - csp->next = clients->next; - clients->next = csp; + csp_list->next = clients->next; + clients->next = csp_list; if (config->multi_threaded) { @@ -3704,7 +3751,6 @@ static void listen_loop(void) #if defined(unix) freez(basedir); #endif - freez(configfile); #if defined(_WIN32) && !defined(_WIN_CONSOLE) /* Cleanup - remove taskbar icon etc. */