Redirect-test related cosmetics.
[privoxy.git] / jcc.c
diff --git a/jcc.c b/jcc.c
index 79c76ab..a09621e 100644 (file)
--- a/jcc.c
+++ b/jcc.c
@@ -1,4 +1,4 @@
-const char jcc_rcs[] = "$Id: jcc.c,v 1.283 2009/09/05 18:04:37 fabiankeil Exp $";
+const char jcc_rcs[] = "$Id: jcc.c,v 1.294 2009/09/18 18:57:20 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/jcc.c,v $
@@ -1026,6 +1026,7 @@ static int server_response_is_complete(struct client_state *csp,
 }
 
 
+#ifdef FEATURE_CONNECTION_SHARING
 /*********************************************************************
  *
  * Function    :  wait_for_alive_connections
@@ -1053,6 +1054,7 @@ static void wait_for_alive_connections(void)
    log_error(LOG_LEVEL_CONNECT, "No connections to wait for left.");
 
 }
+#endif /* def FEATURE_CONNECTION_SHARING */
 
 
 /*********************************************************************
@@ -1229,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);
@@ -1327,6 +1330,7 @@ static jb_err receive_client_request(struct client_state *csp)
    req = get_request_line(csp);
    if (req == NULL)
    {
+      mark_server_socket_tainted(csp);
       return JB_ERR_PARSE;
    }
    assert(*req != '\0');
@@ -1597,6 +1601,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));
 
@@ -1838,21 +1843,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);
       }
 
@@ -1873,10 +1870,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,
@@ -1917,14 +1924,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.",
@@ -1946,7 +1979,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.",
@@ -2253,7 +2286,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;
                }
@@ -2443,14 +2476,20 @@ static void serve(struct client_state *csp)
 #endif /* def AMIGA */
 {
 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
+#ifdef FEATURE_CONNECTION_SHARING
    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)
@@ -2513,9 +2552,17 @@ static void serve(struct client_state *csp)
          {
             log_error(LOG_LEVEL_CONNECT,
                "No additional client request received in time.");
+#ifdef FEATURE_CONNECTION_SHARING
             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);
@@ -2531,6 +2578,7 @@ static void serve(struct client_state *csp)
                }
                privoxy_mutex_unlock(&connection_reuse_mutex);
             }
+#endif /* def FEATURE_CONNECTION_SHARING */
             break;
          }
       }
@@ -2549,9 +2597,9 @@ static void serve(struct client_state *csp)
 
    if (csp->sfd != JB_INVALID_SOCKET)
    {
-#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+#ifdef FEATURE_CONNECTION_SHARING
       forget_connection(csp->sfd);
-#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
+#endif /* def FEATURE_CONNECTION_SHARING */
       close_socket(csp->sfd);
    }
 
@@ -2785,9 +2833,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;
@@ -3301,13 +3349,13 @@ static void listen_loop(void)
 
    config = load_config();
 
-#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+#ifdef FEATURE_CONNECTION_SHARING
    /*
     * XXX: Should be relocated once it no
     * longer needs to emit log messages.
     */
    initialize_reusable_connections();
-#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
+#endif /* def FEATURE_CONNECTION_SHARING */
 
    bfd = bind_port_helper(config);