-const char jcc_rcs[] = "$Id: jcc.c,v 1.253 2009/06/08 16:50:35 fabiankeil Exp $";
+const char jcc_rcs[] = "$Id: jcc.c,v 1.264 2009/07/07 16:42:26 fabiankeil Exp $";
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/jcc.c,v $
"Connection: close\r\n\r\n"
"Bad request. Privoxy was unable to extract the destination.\r\n";
-/* XXX: should be a template */
-static const char NO_SERVER_DATA_RESPONSE[] =
- "HTTP/1.0 502 Server or forwarder response empty\r\n"
- "Proxy-Agent: Privoxy " VERSION "\r\n"
- "Content-Type: text/plain\r\n"
- "Connection: close\r\n\r\n"
- "Empty server or forwarder response.\r\n"
- "The connection has been closed but Privoxy didn't receive any data.\r\n";
-
/* XXX: should be a template */
static const char INVALID_SERVER_HEADERS_RESPONSE[] =
"HTTP/1.0 502 Server or forwarder response invalid\r\n"
"Connection: close\r\n\r\n"
"Maximum number of open connections reached.\r\n";
-/* XXX: should be a template */
-static const char CONNECTION_TIMEOUT_RESPONSE[] =
+static const char CLIENT_CONNECTION_TIMEOUT_RESPONSE[] =
"HTTP/1.0 504 Connection timeout\r\n"
"Proxy-Agent: Privoxy " VERSION "\r\n"
"Content-Type: text/plain\r\n"
"Connection: close\r\n\r\n"
- "The connection timed out.\r\n";
+ "The connection timed out because the client request didn't arrive in time.\r\n";
/* A function to crunch a response */
typedef struct http_response *(*crunch_func_ptr)(struct client_state *);
case RSP_REASON_OUT_OF_MEMORY:
reason = "Out of memory (may mask other reasons)";
break;
+ case RSP_REASON_CONNECTION_TIMEOUT:
+ reason = "Connection timeout";
+ break;
+ case RSP_REASON_NO_SERVER_DATA:
+ reason = "No server data received";
+ break;
default:
reason = "No reason recorded";
break;
{
if ((csp->flags & CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE))
{
- log_error(LOG_LEVEL_CONNECT, "Unsetting keep-alive flag.");
- csp->flags &= ~CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE;
+ log_error(LOG_LEVEL_CONNECT,
+ "Marking the server socket %d tainted.", csp->sfd);
+ csp->flags |= CSP_FLAG_SERVER_SOCKET_TAINTED;
}
}
{
log_error(LOG_LEVEL_ERROR,
"Stopped waiting for the request line.");
- write_socket(csp->cfd, CONNECTION_TIMEOUT_RESPONSE,
- strlen(CONNECTION_TIMEOUT_RESPONSE));
+ write_socket(csp->cfd, CLIENT_CONNECTION_TIMEOUT_RESPONSE,
+ strlen(CLIENT_CONNECTION_TIMEOUT_RESPONSE));
return NULL;
}
struct http_request *http = csp->http;
jb_err err;
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+ if ((!strcmpic(csp->http->ver, "HTTP/1.1"))
+ && (csp->http->ssl == 0))
+ {
+ /* Assume persistence until further notice */
+ csp->flags |= CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE;
+ }
+#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
+
err = sed(csp, FILTER_CLIENT_HEADERS);
if (JB_ERR_OK != err)
{
return JB_ERR_PARSE;
}
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+ if ((csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE))
+ {
+ if (csp->iob->cur[0] != '\0')
+ {
+ csp->flags |= CSP_FLAG_SERVER_SOCKET_TAINTED;
+ if (!strcmpic(csp->http->gpc, "POST"))
+ {
+ /* XXX: this is an incomplete hack */
+ csp->flags &= ~CSP_FLAG_CLIENT_REQUEST_COMPLETELY_READ;
+ log_error(LOG_LEVEL_CONNECT,
+ "POST request detected. The connection will not be kept alive.");
+ }
+ else
+ {
+ /* XXX: and so is this */
+ csp->flags |= CSP_FLAG_CLIENT_REQUEST_COMPLETELY_READ;
+ log_error(LOG_LEVEL_CONNECT,
+ "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->iob->buf[0] = '\0';
+ csp->iob->eod = csp->iob->cur = csp->iob->buf;
+ }
+ }
+ else
+ {
+ csp->flags |= CSP_FLAG_CLIENT_REQUEST_COMPLETELY_READ;
+ log_error(LOG_LEVEL_CONNECT, "Complete client request received.");
+ }
+ }
+#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
+
return JB_ERR_OK;
}
#else
FD_ZERO(&rfds);
#endif
- FD_SET(csp->cfd, &rfds);
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+ if ((csp->flags & CSP_FLAG_CLIENT_REQUEST_COMPLETELY_READ))
+ {
+ maxfd = csp->sfd;
+ }
+ else
+#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
+ {
+ FD_SET(csp->cfd, &rfds);
+ }
+
FD_SET(csp->sfd, &rfds);
#ifdef FEATURE_CONNECTION_KEEP_ALIVE
"Didn't receive data in time: %s", http->url);
if ((byte_count == 0) && (http->ssl == 0))
{
- write_socket(csp->cfd, CONNECTION_TIMEOUT_RESPONSE,
- strlen(CONNECTION_TIMEOUT_RESPONSE));
+ send_crunch_response(csp, error_response(csp, "connection-timeout"));
}
mark_server_socket_tainted(csp);
return;
/* Did we actually get anything? */
if (NULL == csp->headers->first)
{
- log_error(LOG_LEVEL_ERROR, "Empty server or forwarder response.");
+ log_error(LOG_LEVEL_ERROR,
+ "Empty server or forwarder response received on socket %d.", csp->sfd);
log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 502 0", csp->ip_addr_str, http->cmd);
- write_socket(csp->cfd, NO_SERVER_DATA_RESPONSE, strlen(NO_SERVER_DATA_RESPONSE));
+ send_crunch_response(csp, error_response(csp, "no-server-data"));
free_http_request(http);
mark_server_socket_tainted(csp);
return;
continue_chatting = (csp->config->feature_flags
& RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)
&& (csp->flags & CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE)
+ && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED)
&& (csp->cfd != JB_INVALID_SOCKET)
&& (csp->sfd != JB_INVALID_SOCKET)
&& socket_is_still_usable(csp->sfd);
(NULL != config->haddr) ? config->haddr : "INADDR_ANY", config->hport);
default :
- log_error(LOG_LEVEL_FATAL, "can't bind to %s:%d: because %E",
+ log_error(LOG_LEVEL_FATAL, "can't bind to %s:%d: %E",
(NULL != config->haddr) ? config->haddr : "INADDR_ANY", config->hport);
}