Don't bother remembering connections that already timed out.
[privoxy.git] / jcc.c
diff --git a/jcc.c b/jcc.c
index 274124f..12dc1db 100644 (file)
--- a/jcc.c
+++ b/jcc.c
@@ -1,4 +1,4 @@
-const char jcc_rcs[] = "$Id: jcc.c,v 1.284 2009/09/06 14:07:56 fabiankeil Exp $";
+const char jcc_rcs[] = "$Id: jcc.c,v 1.293 2009/09/18 18:52:33 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/jcc.c,v $
@@ -1231,7 +1231,8 @@ static void verify_request_length(struct client_state *csp)
  *********************************************************************/
 static void mark_server_socket_tainted(struct client_state *csp)
 {
-   if ((csp->flags & CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE))
+   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->sfd);
@@ -1599,6 +1600,7 @@ static void chat(struct client_state *csp)
    /* Skeleton for HTTP response, if we should intercept the request */
    struct http_response *rsp;
    struct timeval timeout;
+   int watch_client_socket = 1;
 
    memset(buf, 0, sizeof(buf));
 
@@ -1840,21 +1842,13 @@ static void chat(struct client_state *csp)
       FD_ZERO(&rfds);
 #endif
 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
-      if ((csp->flags & CSP_FLAG_CLIENT_REQUEST_COMPLETELY_READ))
+      if (!watch_client_socket)
       {
          maxfd = csp->sfd;
       }
       else
 #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
       {
-#ifdef FEATURE_CONNECTION_KEEP_ALIVE
-         if (http->ssl == 0)
-         {
-            log_error(LOG_LEVEL_CONNECT,
-               "Allowing the client to continue talking. "
-               "Expecting %llu bytes.", csp->expected_client_content_length);
-         }
-#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
          FD_SET(csp->cfd, &rfds);
       }
 
@@ -1875,10 +1869,20 @@ static void chat(struct client_state *csp)
       }
       if (server_body && server_response_is_complete(csp, byte_count))
       {
-         log_error(LOG_LEVEL_CONNECT,
-            "Done reading from server. Expected content length: %llu. "
-            "Actual content length: %llu. Most recently received: %d.",
-            csp->expected_content_length, byte_count, len);
+         if (csp->expected_content_length == byte_count)
+         {
+            log_error(LOG_LEVEL_CONNECT,
+               "Done reading from server. Content length: %llu as expected. "
+               "Bytes most recently read: %d.",
+               byte_count, len);
+         }
+         else
+         {
+            log_error(LOG_LEVEL_CONNECT,
+               "Done reading from server. Expected content length: %llu. "
+               "Actual content length: %llu. Bytes most recently read: %d.",
+               csp->expected_content_length, byte_count, len);
+         }
          len = 0;
          /*
           * XXX: should not jump around,
@@ -1919,14 +1923,40 @@ static void chat(struct client_state *csp)
        */
       if (FD_ISSET(csp->cfd, &rfds))
       {
-         unsigned max_bytes_to_read = sizeof(buf) - 1;
+         int max_bytes_to_read = sizeof(buf) - 1;
 
 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
+         if ((csp->flags & CSP_FLAG_CLIENT_REQUEST_COMPLETELY_READ))
+         {
+            if (data_is_available(csp->cfd, 0))
+            {
+               /*
+                * If the next request is already waiting, we have
+                * to stop select()ing the client socket. Otherwise
+                * we would always return right away and get nothing
+                * else done.
+                */
+               watch_client_socket = 0;
+               log_error(LOG_LEVEL_CONNECT,
+                  "Stopping to watch the client socket. "
+                  "There's already another request waiting.");
+               continue;
+            }
+            /*
+             * If the client socket is set, but there's no data
+             * available on the socket, the client went fishing
+             * and continuing talking to the server makes no sense.
+             */
+            log_error(LOG_LEVEL_CONNECT, "The client closed socket %d while "
+               "the server socket %d is still open.", csp->cfd, csp->sfd);
+            mark_server_socket_tainted(csp);
+            break;
+         }
          if (csp->expected_client_content_length != 0)
          {
             if (csp->expected_client_content_length < (sizeof(buf) - 1))
             {
-               max_bytes_to_read = csp->expected_client_content_length;
+               max_bytes_to_read = (int)csp->expected_client_content_length;
             }
             log_error(LOG_LEVEL_CONNECT,
                "Waiting for up to %d bytes from the client.",
@@ -1948,7 +1978,7 @@ static void chat(struct client_state *csp)
          if (csp->expected_client_content_length != 0)
          {
             assert(len <= max_bytes_to_read);
-            csp->expected_client_content_length -= len;
+            csp->expected_client_content_length -= (unsigned)len;
             log_error(LOG_LEVEL_CONNECT,
                "Expected client content length set to %llu "
                "after reading %d bytes.",
@@ -2255,7 +2285,7 @@ static void chat(struct client_state *csp)
                    * we can parse the headers we just continue here.
                    */
                   log_error(LOG_LEVEL_CONNECT,
-                     "Continuing buffering headers. Most recently received: %d",
+                     "Continuing buffering headers. Bytes most recently read: %d.",
                      len);
                   continue;
                }
@@ -2449,12 +2479,16 @@ static void serve(struct client_state *csp)
    static int monitor_thread_running = 0;
 #endif /* def FEATURE_CONNECTION_SHARING */
    int continue_chatting = 0;
-   unsigned int latency = 0;
 
    do
    {
+      unsigned int latency;
+
       chat(csp);
 
+      latency = (unsigned)(csp->server_connection.response_received -
+         csp->server_connection.request_sent);
+
       continue_chatting = (csp->config->feature_flags
          & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)
          && (csp->flags & CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE)
@@ -2521,6 +2555,13 @@ static void serve(struct client_state *csp)
             if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_SHARING)
                && (socket_is_still_usable(csp->sfd)))
             {
+               time_t time_open = time(NULL) - csp->server_connection.timestamp;
+
+               if (csp->server_connection.keep_alive_timeout < time_open + latency)
+               {
+                  break;
+               }
+
                remember_connection(csp, forward_url(csp, csp->http));
                csp->sfd = JB_INVALID_SOCKET;
                close_socket(csp->cfd);
@@ -2791,9 +2832,9 @@ static void initialize_mutexes(void)
  *
  *********************************************************************/
 #ifdef __MINGW32__
-int real_main(int argc, const char *argv[])
+int real_main(int argc, char **argv)
 #else
-int main(int argc, const char *argv[])
+int main(int argc, char **argv)
 #endif
 {
    int argc_pos = 0;