Increase socks5_connect()'s optimism
[privoxy.git] / gateway.c
index dad4c40..60f2aa2 100644 (file)
--- a/gateway.c
+++ b/gateway.c
@@ -1,4 +1,4 @@
-const char gateway_rcs[] = "$Id: gateway.c,v 1.90 2012/10/17 18:13:26 fabiankeil Exp $";
+const char gateway_rcs[] = "$Id: gateway.c,v 1.93 2012/12/07 12:45:20 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/gateway.c,v $
@@ -66,6 +66,9 @@ const char gateway_rcs[] = "$Id: gateway.c,v 1.90 2012/10/17 18:13:26 fabiankeil
 #include "jbsockets.h"
 #include "gateway.h"
 #include "miscutil.h"
+#include "list.h"
+#include "parsers.h"
+
 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
 #ifdef HAVE_POLL
 #ifdef __GLIBC__
@@ -262,7 +265,6 @@ void remember_connection(const struct reusable_connection *connection)
 #endif /* def FEATURE_CONNECTION_SHARING */
 
 
-#ifdef FEATURE_CONNECTION_KEEP_ALIVE
 /*********************************************************************
  *
  * Function    :  mark_connection_closed
@@ -292,7 +294,6 @@ void mark_connection_closed(struct reusable_connection *closed_connection)
    freez(closed_connection->forward_host);
    closed_connection->forward_port = 0;
 }
-#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
 
 
 #ifdef FEATURE_CONNECTION_SHARING
@@ -641,6 +642,7 @@ jb_socket forwarded_connect(const struct forward_spec * fwd,
          sfd = socks4_connect(fwd, dest_host, dest_port, csp);
          break;
       case SOCKS_5:
+      case SOCKS_5T:
          sfd = socks5_connect(fwd, dest_host, dest_port, csp);
          break;
       default:
@@ -966,7 +968,7 @@ static jb_socket socks5_connect(const struct forward_spec *fwd,
       err = 1;
    }
 
-   if (fwd->type != SOCKS_5)
+   if ((fwd->type != SOCKS_5) && (fwd->type != SOCKS_5T))
    {
       /* Should never get here */
       log_error(LOG_LEVEL_FATAL,
@@ -1080,6 +1082,57 @@ static jb_socket socks5_connect(const struct forward_spec *fwd,
       return(JB_INVALID_SOCKET);
    }
 
+   /*
+    * Optimistically send the HTTP request with the initial
+    * SOCKS request if the user enabled the use of Tor extensions,
+    * the CONNECT method isn't being used (in which case the client
+    * doesn't send data until it gets our 200 response) and the
+    * client request has actually been completely read already.
+    */
+   if ((fwd->type == SOCKS_5T) && (csp->http->ssl == 0)
+      && (csp->flags & CSP_FLAG_CLIENT_REQUEST_COMPLETELY_READ))
+   {
+      char *client_headers = list_to_text(csp->headers);
+      size_t header_length;
+
+      if (client_headers == NULL)
+      {
+         log_error(LOG_LEVEL_FATAL, "Out of memory rebuilding client headers");
+      }
+      list_remove_all(csp->headers);
+      header_length= strlen(client_headers);
+
+      log_error(LOG_LEVEL_CONNECT,
+         "Optimistically sending %d bytes of client headers intended for %s",
+         header_length, csp->http->hostport);
+
+      if (write_socket(sfd, client_headers, header_length))
+      {
+         log_error(LOG_LEVEL_CONNECT,
+            "optimistically writing header to: %s failed: %E", csp->http->hostport);
+         freez(client_headers);
+         return(JB_INVALID_SOCKET);
+      }
+      freez(client_headers);
+      if (csp->expected_client_content_length != 0)
+      {
+         unsigned long long buffered_request_bytes =
+            (unsigned long long)(csp->client_iob->eod - csp->client_iob->cur);
+         log_error(LOG_LEVEL_CONNECT,
+            "Optimistically sending %d bytes of client body. Expected %d",
+            csp->expected_client_content_length, buffered_request_bytes);
+         assert(csp->expected_client_content_length == buffered_request_bytes);
+         if (write_socket(sfd, csp->client_iob->cur, buffered_request_bytes))
+         {
+            log_error(LOG_LEVEL_CONNECT,
+               "optimistically writing %d bytes of client body to: %s failed: %E",
+               buffered_request_bytes, csp->http->hostport);
+            return(JB_INVALID_SOCKET);
+         }
+         clear_iob(csp->client_iob);
+      }
+   }
+
    server_size = read_socket(sfd, sbuf, sizeof(sbuf));
    if (server_size != sizeof(sbuf))
    {