-const char jcc_rcs[] = "$Id: jcc.c,v 1.322 2010/07/21 14:30:40 fabiankeil Exp $";
+const char jcc_rcs[] = "$Id: jcc.c,v 1.340 2011/01/22 12:30:22 fabiankeil Exp $";
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/jcc.c,v $
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
*********************************************************************/
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;
}
/*********************************************************************
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;
&& ((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;
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,
* 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)
*/
*/
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
*/
byte_count = (unsigned long long)flushed;
freez(hdr);
- content_filter = NULL;
+ buffer_and_filter_content = 0;
server_body = 1;
}
}
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))
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
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;
do
{
unsigned int latency;
+ int config_file_change_detected = 0; /* Only used for debugging */
chat(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;
&& 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
{
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;
}
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);
*********************************************************************/
static void listen_loop(void)
{
+ struct client_states *csp_list = NULL;
struct client_state *csp = NULL;
jb_socket bfd;
struct configuration_spec *config;
}
#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 failed: %E", sizeof(*csp));
+ 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_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;
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 */
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 */
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)
{
#if defined(unix)
freez(basedir);
#endif
- freez(configfile);
#if defined(_WIN32) && !defined(_WIN_CONSOLE)
/* Cleanup - remove taskbar icon etc. */