-const char jcc_rcs[] = "$Id: jcc.c,v 1.399 2012/10/21 12:53:33 fabiankeil Exp $";
+const char jcc_rcs[] = "$Id: jcc.c,v 1.416 2012/11/24 14:01:25 fabiankeil Exp $";
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/jcc.c,v $
*/
csp->expected_content_length = 0;
content_length_known = TRUE;
+ csp->flags |= CSP_FLAG_SERVER_CONTENT_LENGTH_SET;
}
if (csp->http->status == 204 || csp->http->status == 304)
*/
csp->expected_content_length = 0;
content_length_known = TRUE;
+ csp->flags |= CSP_FLAG_SERVER_CONTENT_LENGTH_SET;
}
return (content_length_known && ((0 == csp->expected_content_length)
* we do.
*
* Data that doesn't belong to the current request is
- * thrown away to let the client retry on a clean socket.
- *
- * XXX: This is a hack until we can deal with multiple
- * pipelined requests at the same time.
- *
+ * either thrown away to let the client retry on a clean
+ * socket, or stashed to be dealt with after the current
+ * request is served.
*
* Parameters :
* 1 : csp = Current client state (buffers, headers, etc...)
}
if (!(csp->flags & CSP_FLAG_CLIENT_REQUEST_COMPLETELY_READ)
- && ((csp->client_iob->cur[0] != '\0') || (csp->expected_client_content_length != 0)))
+ && ((csp->client_iob->cur < csp->client_iob->eod)
+ || (csp->expected_client_content_length != 0)))
{
if (strcmpic(csp->http->gpc, "GET")
&& strcmpic(csp->http->gpc, "HEAD")
{
/* XXX: this is an incomplete hack */
csp->flags &= ~CSP_FLAG_CLIENT_REQUEST_COMPLETELY_READ;
- csp->flags |= CSP_FLAG_SERVER_SOCKET_TAINTED;
- log_error(LOG_LEVEL_CONNECT,
- "There might be a request body. The connection will not be kept alive.");
+ log_error(LOG_LEVEL_CONNECT, "There better be a request body.");
}
else
{
"Possible pipeline attempt detected. The connection will not "
"be kept alive and we will only serve the first request.");
/* Nuke the pipelined requests from orbit, just to be sure. */
- csp->client_iob->buf[0] = '\0';
- csp->client_iob->eod = csp->client_iob->cur = csp->client_iob->buf;
+ clear_iob(csp->client_iob);
}
else
{
* it once we're done serving the current request.
*/
csp->flags |= CSP_FLAG_PIPELINED_REQUEST_WAITING;
- assert(csp->client_iob->eod > csp->client_iob->cur);
+ assert(csp->client_iob->eod >= csp->client_iob->cur);
log_error(LOG_LEVEL_CONNECT, "Complete client request followed by "
"%d bytes of pipelined data received.",
(int)(csp->client_iob->eod - csp->client_iob->cur));
* actually been reused.
*/
if ((csp->flags & CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE)
- && !(csp->flags |= CSP_FLAG_SERVER_SOCKET_TAINTED))
+ && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED))
{
log_error(LOG_LEVEL_CONNECT,
"Marking the server socket %d tainted.",
struct list header_list;
struct list *headers = &header_list;
+ /* We don't care if the arriving data is a valid HTTP request or not. */
+ csp->requests_received_total++;
+
http = csp->http;
memset(buf, 0, sizeof(buf));
{
if (csp->server_connection.sfd != JB_INVALID_SOCKET)
{
- log_error(LOG_LEVEL_CONNECT,
- "Closing server socket %u. Opened for %s.",
- csp->server_connection.sfd, csp->server_connection.host);
- close_socket(csp->server_connection.sfd);
+#ifdef FEATURE_CONNECTION_SHARING
+ if (csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_SHARING)
+ {
+ remember_connection(&csp->server_connection);
+ }
+ else
+#endif /* def FEATURE_CONNECTION_SHARING */
+ {
+ log_error(LOG_LEVEL_CONNECT,
+ "Closing server socket %d connected to %s. Total requests: %u.",
+ csp->server_connection.sfd, csp->server_connection.host,
+ csp->server_connection.requests_sent_total);
+ close_socket(csp->server_connection.sfd);
+ }
mark_connection_closed(&csp->server_connection);
}
#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
{
return;
}
- IOB_RESET(csp->client_iob);
+ clear_iob(csp->client_iob);
}
log_error(LOG_LEVEL_CONNECT, "to %s successful", http->hostport);
server_body = 0;
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
watch_client_socket = 0 == (csp->flags & CSP_FLAG_PIPELINED_REQUEST_WAITING);
+#endif
for (;;)
{
csp->expected_content_length = 0;
csp->expected_client_content_length = 0;
list_remove_all(csp->headers);
- IOB_RESET(csp->iob);
+ clear_iob(csp->iob);
freez(csp->error_message);
free_http_request(csp->http);
destroy_list(csp->headers);
* Freeing the buffer itself isn't technically necessary,
* but makes debugging more convenient.
*/
- IOB_RESET(csp->client_iob);
+ clear_iob(csp->client_iob);
}
}
#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
static void serve(struct client_state *csp)
#endif /* def AMIGA */
{
+ int config_file_change_detected = 0; /* Only used for debugging */
#ifdef FEATURE_CONNECTION_KEEP_ALIVE
#ifdef FEATURE_CONNECTION_SHARING
static int monitor_thread_running = 0;
#endif /* def FEATURE_CONNECTION_SHARING */
int continue_chatting = 0;
- int config_file_change_detected = 0; /* Only used for debugging */
log_error(LOG_LEVEL_CONNECT, "Accepted connection from %s on socket %d",
csp->ip_addr_str, csp->cfd);
& RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)
&& !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED)
&& (csp->cfd != JB_INVALID_SOCKET)
- && ((csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE)
- || (csp->config->feature_flags &
- RUNTIME_FEATURE_CONNECTION_SHARING));
+ && (csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE)
+ && ((csp->flags & CSP_FLAG_SERVER_CONTENT_LENGTH_SET)
+ || (csp->flags & CSP_FLAG_CHUNKED));
if (!(csp->flags & CSP_FLAG_CRUNCHED)
&& (csp->server_connection.sfd != JB_INVALID_SOCKET))
|| !(latency < csp->server_connection.keep_alive_timeout))
{
log_error(LOG_LEVEL_CONNECT,
- "Closing connection on server socket %d to %s: "
- "keep-alive %u, tainted: %u, socket alive %u. %s timeout: %u.",
+ "Closing server socket %d connected to %s. "
+ "Keep-alive %u. Tainted: %u. Socket alive %u. Timeout: %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),
- ((csp->flags & CSP_FLAG_SERVER_KEEP_ALIVE_TIMEOUT_SET) ?
- "Specified" : "Assumed"), csp->server_connection.keep_alive_timeout);
+ csp->server_connection.keep_alive_timeout);
#ifdef FEATURE_CONNECTION_SHARING
if (csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_SHARING)
{
if (((csp->flags & CSP_FLAG_PIPELINED_REQUEST_WAITING) != 0)
&& socket_is_still_alive(csp->cfd))
{
- log_error(LOG_LEVEL_CONNECT, "A client request has been "
+ log_error(LOG_LEVEL_CONNECT, "Client request %d has been "
"pipelined on socket %d and the socket is still alive.",
- csp->cfd);
+ csp->requests_received_total+1, csp->cfd);
prepare_csp_for_next_request(csp);
continue;
}
&& socket_is_still_alive(csp->cfd))
{
log_error(LOG_LEVEL_CONNECT,
- "Client request arrived in time on socket %d.", csp->cfd);
+ "Client request %u arrived in time on socket %d.",
+ csp->requests_received_total+1, csp->cfd);
prepare_csp_for_next_request(csp);
}
else
else if (csp->server_connection.sfd != JB_INVALID_SOCKET)
{
log_error(LOG_LEVEL_CONNECT,
- "Closing server socket %d connected to %s. Keep-alive %u. "
- "Tainted: %u. Socket alive %u. Timeout: %u. "
+ "Closing server socket %d connected to %s. Keep-alive: %u. "
+ "Tainted: %u. Socket alive: %u. Timeout: %u. "
"Configuration file change detected: %u",
csp->server_connection.sfd, csp->server_connection.host,
0 != (csp->flags & CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE),
if (csp->cfd != JB_INVALID_SOCKET)
{
log_error(LOG_LEVEL_CONNECT, "Closing client socket %d. "
- "Keep-alive: %u, Socket alive: %u. Data available: %u. "
- "Configuration file change detected: %u.",
+ "Keep-alive: %u. Socket alive: %u. Data available: %u. "
+ "Configuration file change detected: %u. Requests received: %u.",
csp->cfd, 0 != (csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE),
socket_is_still_alive(csp->cfd), data_is_available(csp->cfd, 0),
- config_file_change_detected);
+ config_file_change_detected, csp->requests_received_total);
drain_and_close_socket(csp->cfd);
}
static void usage(const char *myname)
{
printf("Privoxy version " VERSION " (" HOME_PAGE_URL ")\n"
- "Usage: %s "
+ "Usage: %s [--config-test] "
#if defined(unix)
"[--chroot] "
#endif /* defined(unix) */
#endif
{
int argc_pos = 0;
+ int do_config_test = 0;
unsigned int random_seed;
#ifdef unix
struct passwd *pw = NULL;
}
#endif /* defined(unix) */
+ else if (strcmp(argv[argc_pos], "--config-test") == 0)
+ {
+ do_config_test = 1;
+ }
+
else if (argc_pos + 1 != argc)
{
/*
# endif /* def _WIN_CONSOLE */
#endif /* def _WIN32 */
+ if (do_config_test)
+ {
+ exit(NULL == load_config());
+ }
/* Initialize the CGI subsystem */
cgi_init_error_messages();