-const char cgi_rcs[] = "$Id: cgi.c,v 1.156 2012/10/21 12:54:15 fabiankeil Exp $";
+const char cgi_rcs[] = "$Id: cgi.c,v 1.157 2012/11/09 10:47:42 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/cgi.c,v $
          case SOCKS_5:
             socks_type = "socks5-";
             break;
+         case SOCKS_5T:
+            socks_type = "socks5t-";
+            break;
          default:
             log_error(LOG_LEVEL_FATAL, "Unknown socks type: %d.", fwd->type);
       }
 
-const char cgisimple_rcs[] = "$Id: cgisimple.c,v 1.116 2012/10/21 12:39:27 fabiankeil Exp $";
+const char cgisimple_rcs[] = "$Id: cgisimple.c,v 1.117 2012/10/21 12:55:29 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/cgisimple.c,v $
                   case SOCKS_5:
                      socks_type = "socks5";
                      break;
+                  case SOCKS_5T:
+                     socks_type = "socks5t";
+                     break;
                   default:
                      log_error(LOG_LEVEL_FATAL, "Unknown socks type: %d.", fwd->type);
                }
 
-const char filters_rcs[] = "$Id: filters.c,v 1.174 2012/10/21 12:35:15 fabiankeil Exp $";
+const char filters_rcs[] = "$Id: filters.c,v 1.175 2012/10/21 12:58:03 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/filters.c,v $
          fwd->type = SOCKS_5;
          socks_proxy = vec[1];
       }
+      else if (!strcasecmp(vec[0], "forward-socks5t"))
+      {
+         fwd->type = SOCKS_5T;
+         socks_proxy = vec[1];
+      }
 
       if (NULL != socks_proxy)
       {
 
-const char gateway_rcs[] = "$Id: gateway.c,v 1.91 2012/10/21 12:56:38 fabiankeil Exp $";
+const char gateway_rcs[] = "$Id: gateway.c,v 1.92 2012/10/23 10:16:52 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/gateway.c,v $
 #include "jbsockets.h"
 #include "gateway.h"
 #include "miscutil.h"
+#include "list.h"
+
 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
 #ifdef HAVE_POLL
 #ifdef __GLIBC__
          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:
       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,
       return(JB_INVALID_SOCKET);
    }
 
+   /*
+    * Optimistically send the request headers with the initial
+    * request if the user requested 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 been already read completely.
+    *
+    * Not optimistically sending the request body (if there is one)
+    * makes it easier to implement, but isn't an actual requirement.
+    */
+   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);
+   }
+
    server_size = read_socket(sfd, sbuf, sizeof(sbuf));
    if (server_size != sizeof(sbuf))
    {
 
-const char jcc_rcs[] = "$Id: jcc.c,v 1.418 2012/12/07 12:43:05 fabiankeil Exp $";
+const char jcc_rcs[] = "$Id: jcc.c,v 1.419 2012/12/07 12:43:55 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/jcc.c,v $
 
    csp->server_connection.requests_sent_total++;
 
-   if (fwd->forward_host || (http->ssl == 0))
+   if ((fwd->type == SOCKS_5T) && (NULL == csp->headers->first))
+   {
+      /* Client headers have been sent optimistically */
+      assert(csp->headers->last == NULL);
+   }
+   else if (fwd->forward_host || (http->ssl == 0))
    {
       int write_failure;
       hdr = list_to_text(csp->headers);
 
    log_error(LOG_LEVEL_CONNECT, "to %s successful", http->hostport);
 
+   /* XXX: should the time start earlier for optimistically sent data? */
    csp->server_connection.request_sent = time(NULL);
 
    maxfd = (csp->cfd > csp->server_connection.sfd) ?
 
-const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.133 2012/10/21 12:32:21 fabiankeil Exp $";
+const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.134 2012/10/21 12:53:33 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/loadcfg.c,v $
 #define hash_forward_socks4              3963965521U /* "forward-socks4" */
 #define hash_forward_socks4a             2639958518U /* "forward-socks4a" */
 #define hash_forward_socks5              3963965522U /* "forward-socks5" */
+#define hash_forward_socks5t             2639958542U /* "forward-socks5t" */
 #define hash_forwarded_connect_retries    101465292U /* "forwarded-connect-retries" */
 #define hash_handle_as_empty_returns_ok  1444873247U /* "handle-as-empty-doc-returns-ok" */
 #define hash_hostname                      10308071U /* "hostname" */
  * *************************************************************************/
          case hash_forward_socks4a:
          case hash_forward_socks5:
+         case hash_forward_socks5t:
             strlcpy(tmp, arg, sizeof(tmp));
             vec_count = ssplit(tmp, " \t", vec, SZ(vec));
 
             {
                cur_fwd->type = SOCKS_4A;
             }
-            else
+            else if (directive_hash == hash_forward_socks5)
             {
                cur_fwd->type = SOCKS_5;
             }
+            else
+            {
+               assert(directive_hash == hash_forward_socks5t);
+               cur_fwd->type = SOCKS_5T;
+            }
 
             /* Save the URL pattern */
             if (create_url_spec(cur_fwd->url, vec[0]))
 
 #ifndef PROJECT_H_INCLUDED
 #define PROJECT_H_INCLUDED
 /** Version string. */
-#define PROJECT_H_VERSION "$Id: project.h,v 1.193 2012/11/24 13:55:51 fabiankeil Exp $"
+#define PROJECT_H_VERSION "$Id: project.h,v 1.194 2012/12/07 12:43:55 fabiankeil Exp $"
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/project.h,v $
    SOCKS_4A   = 41,
    /**< SOCKS 5 with hostnames, DNS resolution is done by the SOCKS server */
    SOCKS_5    = 50,
+   /**< Like SOCKS5, but uses non-standard Tor extensions (currently only optimistic data) */
+   SOCKS_5T,
 };
 
 /*