Change code status from BETA to beta.
[privoxy.git] / jcc.c
diff --git a/jcc.c b/jcc.c
index ed17ba8..faf224f 100644 (file)
--- a/jcc.c
+++ b/jcc.c
@@ -1,4 +1,4 @@
-const char jcc_rcs[] = "$Id: jcc.c,v 1.264 2009/07/07 16:42:26 fabiankeil Exp $";
+const char jcc_rcs[] = "$Id: jcc.c,v 1.274 2009/07/19 11:19:50 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/jcc.c,v $
@@ -1077,6 +1077,8 @@ void save_connection_destination(jb_socket sfd,
 {
    assert(sfd != JB_INVALID_SOCKET);
    assert(NULL != http->host);
+
+   server_connection->sfd = sfd;
    server_connection->host = strdup(http->host);
    if (NULL == server_connection->host)
    {
@@ -1416,7 +1418,8 @@ static jb_err parse_client_request(struct client_state *csp)
    jb_err err;
 
 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
-   if ((!strcmpic(csp->http->ver, "HTTP/1.1"))
+   if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)
+    && (!strcmpic(csp->http->ver, "HTTP/1.1"))
     && (csp->http->ssl == 0))
    {
       /* Assume persistence until further notice */
@@ -1458,12 +1461,16 @@ static jb_err parse_client_request(struct client_state *csp)
       if (csp->iob->cur[0] != '\0')
       {
          csp->flags |= CSP_FLAG_SERVER_SOCKET_TAINTED;
-         if (!strcmpic(csp->http->gpc, "POST"))
+         if (strcmpic(csp->http->gpc, "GET")
+          && strcmpic(csp->http->gpc, "HEAD")
+          && strcmpic(csp->http->gpc, "TRACE")
+          && strcmpic(csp->http->gpc, "OPTIONS")
+          && strcmpic(csp->http->gpc, "DELETE"))
          {
             /* 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.");
+               "There might be a request body. The connection will not be kept alive.");
          }
          else
          {
@@ -1748,6 +1755,8 @@ static void chat(struct client_state *csp)
 
    log_error(LOG_LEVEL_CONNECT, "to %s successful", http->hostport);
 
+   csp->server_connection.request_sent = time(NULL);
+
    /* we're finished with the client's header */
    freez(hdr);
 
@@ -1867,6 +1876,21 @@ static void chat(struct client_state *csp)
        */
       if (FD_ISSET(csp->sfd, &rfds))
       {
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+         if (!socket_is_still_usable(csp->cfd))
+         {
+#ifdef _WIN32
+            log_error(LOG_LEVEL_CONNECT,
+               "The server still wants to talk, but the client may already have hung up on us.");
+#else
+            log_error(LOG_LEVEL_CONNECT,
+               "The server still wants to talk, but the client hung up on us.");
+            mark_server_socket_tainted(csp);
+            return;
+#endif /* def _WIN32 */
+         }
+#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
+
          fflush(NULL);
          len = read_socket(csp->sfd, buf, sizeof(buf) - 1);
 
@@ -2193,6 +2217,8 @@ static void chat(struct client_state *csp)
                log_error(LOG_LEVEL_FATAL, "Out of memory parsing server header");
             }
 
+            csp->server_connection.response_received = time(NULL);
+
             if (crunch_response_triggered(csp, crunchers_light))
             {
                /*
@@ -2300,6 +2326,8 @@ static void chat(struct client_state *csp)
 
    log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 200 %llu",
       csp->ip_addr_str, http->ocmd, csp->content_length);
+
+   csp->server_connection.timestamp = time(NULL);
 }
 
 
@@ -2326,27 +2354,39 @@ static void serve(struct client_state *csp)
 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
    static int monitor_thread_running = 0;
    int continue_chatting = 0;
+   unsigned int latency = 0;
+
    do
    {
       chat(csp);
 
+      if ((csp->flags & CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE)
+         && !(csp->flags & CSP_FLAG_SERVER_KEEP_ALIVE_TIMEOUT_SET))
+      {
+         log_error(LOG_LEVEL_CONNECT, "The server didn't specify how long "
+            "the connection will stay open. Assume it's only a second.");
+         csp->server_connection.keep_alive_timeout = 1;
+      }
+
       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);
+         && socket_is_still_usable(csp->sfd)
+         && (latency < csp->server_connection.keep_alive_timeout);
 
       if (continue_chatting)
       {
+         unsigned int client_timeout = (unsigned)csp->server_connection.keep_alive_timeout - latency;
          log_error(LOG_LEVEL_CONNECT,
             "Waiting for the next client request. "
             "Keeping the server socket %d to %s open.",
             csp->sfd, csp->server_connection.host);
 
          if ((csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE)
-            && data_is_available(csp->cfd, (int)csp->server_connection.keep_alive_timeout)
+            && data_is_available(csp->cfd, (int)client_timeout)
             && socket_is_still_usable(csp->cfd))
          {
             log_error(LOG_LEVEL_CONNECT, "Client request arrived in "
@@ -2379,11 +2419,10 @@ static void serve(struct client_state *csp)
          {
             log_error(LOG_LEVEL_CONNECT,
                "No additional client request received in time.");
-            if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_SHARING))
+            if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_SHARING)
+               && (socket_is_still_usable(csp->sfd)))
             {
-               remember_connection(csp->sfd, csp->http,
-                  forward_url(csp, csp->http),
-                  csp->server_connection.keep_alive_timeout);
+               remember_connection(csp, forward_url(csp, csp->http));
                csp->sfd = JB_INVALID_SOCKET;
                close_socket(csp->cfd);
                csp->cfd = JB_INVALID_SOCKET;