]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
- Adam D. Moss made the HTTP CONNECT procedure less blocking when used from
authorDaniel Stenberg <daniel@haxx.se>
Sun, 25 Feb 2007 11:38:13 +0000 (11:38 +0000)
committerDaniel Stenberg <daniel@haxx.se>
Sun, 25 Feb 2007 11:38:13 +0000 (11:38 +0000)
  the multi interface. Note that it still does a part of the connection in a
  blocking manner.

CHANGES
RELEASE-NOTES
lib/http.c
lib/multi.c
lib/urldata.h

diff --git a/CHANGES b/CHANGES
index 3afd8474f3e2147c69d1f0ecc51abbbb273cb415..2867cb7b7e9b8e6b71013fa2e43b365aa870c973 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -6,6 +6,11 @@
 
                                   Changelog
 
+Daniel (25 February 2007)
+- Adam D. Moss made the HTTP CONNECT procedure less blocking when used from
+  the multi interface. Note that it still does a part of the connection in a
+  blocking manner.
+
 Daniel (23 February 2007)
 - Added warning outputs if the command line uses more than one of the options
   -v, --trace and --trace-ascii, since it could really confuse the user.
index 4da85fa176e959c4471f82821feb681d9aba4ca7..2322676a0cf3ba58bb9a9de2a9acd0e242edf305 100644 (file)
@@ -33,6 +33,8 @@ This release includes the following bugfixes:
  o curl-config --libs and libcurl.pc no longer list unnecessary dependencies
  o fixed an issue with CCC not working on some servers
  o several HTTP pipelining problems
+ o HTTP CONNECT thru a proxy is now less blocking when the multi interface is
+   used
 
 This release includes the following known bugs:
 
@@ -52,6 +54,6 @@ advice from friends like these:
  Yang Tse, Manfred Schwarb, Michael Wallner, Jeff Pohlmeyer, Shmulik Regev,
  Rob Crittenden, Robert A. Monat, Dan Fandrich, Duncan Mac-Vicar Prett,
  Michal Marek, Robson Braga Araujo, Ian Turner, Linus Nielsen Feltzing,
- Ravi Pratap
+ Ravi Pratap, Adam D. Moss
 
         Thanks! (and sorry if I forgot to mention someone)
index 522bc00f4b4e6bdce22632bdfc0370cc64a19360..16c59fb87cc19aac83ba5f36a35a39db6f11b95a 100644 (file)
@@ -1115,259 +1115,309 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
   struct Curl_transfer_keeper *k = &data->reqdata.keep;
   CURLcode result;
   int res;
-  size_t nread;   /* total size read */
-  int perline; /* count bytes per line */
-  int keepon=TRUE;
-  ssize_t gotbytes;
-  char *ptr;
   long timeout =
     data->set.timeout?data->set.timeout:3600000; /* in milliseconds */
-  char *line_start;
-  char *host_port;
   curl_socket_t tunnelsocket = conn->sock[sockindex];
-  send_buffer *req_buffer;
   curl_off_t cl=0;
   bool closeConnection = FALSE;
+  long check;
 
 #define SELECT_OK      0
 #define SELECT_ERROR   1
 #define SELECT_TIMEOUT 2
   int error = SELECT_OK;
 
-  infof(data, "Establish HTTP proxy tunnel to %s:%d\n", hostname, remote_port);
   conn->bits.proxy_connect_closed = FALSE;
 
   do {
-    if(data->reqdata.newurl) {
-      /* This only happens if we've looped here due to authentication reasons,
-         and we don't really use the newly cloned URL here then. Just free()
-         it. */
-      free(data->reqdata.newurl);
-      data->reqdata.newurl = NULL;
-    }
-
-    /* initialize a dynamic send-buffer */
-    req_buffer = add_buffer_init();
+    if (!conn->bits.tunnel_connecting) { /* BEGIN CONNECT PHASE */
+      char *host_port;
+      send_buffer *req_buffer;
+
+      infof(data, "Establish HTTP proxy tunnel to %s:%d\n",
+            hostname, remote_port);
+
+      if(data->reqdata.newurl) {
+        /* This only happens if we've looped here due to authentication
+           reasons, and we don't really use the newly cloned URL here
+           then. Just free() it. */
+        free(data->reqdata.newurl);
+        data->reqdata.newurl = NULL;
+      }
 
-    if(!req_buffer)
-      return CURLE_OUT_OF_MEMORY;
+      /* initialize a dynamic send-buffer */
+      req_buffer = add_buffer_init();
 
-    host_port = aprintf("%s:%d", hostname, remote_port);
-    if(!host_port)
-      return CURLE_OUT_OF_MEMORY;
+      if(!req_buffer)
+        return CURLE_OUT_OF_MEMORY;
 
-    /* Setup the proxy-authorization header, if any */
-    result = Curl_http_output_auth(conn, (char *)"CONNECT", host_port, TRUE);
+      host_port = aprintf("%s:%d", hostname, remote_port);
+      if(!host_port)
+        return CURLE_OUT_OF_MEMORY;
 
-    if(CURLE_OK == result) {
-      char *host=(char *)"";
-      const char *proxyconn="";
-      const char *useragent="";
+      /* Setup the proxy-authorization header, if any */
+      result = Curl_http_output_auth(conn, (char *)"CONNECT", host_port, TRUE);
 
-      if(!checkheaders(data, "Host:")) {
-        host = aprintf("Host: %s\r\n", host_port);
-        if(!host)
-          result = CURLE_OUT_OF_MEMORY;
-      }
-      if(!checkheaders(data, "Proxy-Connection:"))
-        proxyconn = "Proxy-Connection: Keep-Alive\r\n";
+      if(CURLE_OK == result) {
+        char *host=(char *)"";
+        const char *proxyconn="";
+        const char *useragent="";
+
+        if(!checkheaders(data, "Host:")) {
+          host = aprintf("Host: %s\r\n", host_port);
+          if(!host)
+            result = CURLE_OUT_OF_MEMORY;
+        }
+        if(!checkheaders(data, "Proxy-Connection:"))
+          proxyconn = "Proxy-Connection: Keep-Alive\r\n";
 
-      if(!checkheaders(data, "User-Agent:") && data->set.useragent)
-        useragent = conn->allocptr.uagent;
+        if(!checkheaders(data, "User-Agent:") && data->set.useragent)
+          useragent = conn->allocptr.uagent;
 
-      if(CURLE_OK == result) {
-        /* Send the connect request to the proxy */
-        /* BLOCKING */
-        result =
-          add_bufferf(req_buffer,
-                      "CONNECT %s:%d HTTP/1.0\r\n"
-                      "%s"  /* Host: */
-                      "%s"  /* Proxy-Authorization */
-                      "%s"  /* User-Agent */
-                      "%s", /* Proxy-Connection */
-                      hostname, remote_port,
-                      host,
-                      conn->allocptr.proxyuserpwd?
-                      conn->allocptr.proxyuserpwd:"",
-                      useragent,
-                      proxyconn);
-
-        if(CURLE_OK == result)
-          result = add_custom_headers(conn, req_buffer);
-
-        if(host && *host)
-          free(host);
-
-        if(CURLE_OK == result)
-          /* CRLF terminate the request */
-          result = add_bufferf(req_buffer, "\r\n");
-
-        if(CURLE_OK == result)
-          /* Now send off the request */
-          result = add_buffer_send(req_buffer, conn,
-                                   &data->info.request_size, 0, sockindex);
+        if(CURLE_OK == result) {
+          /* Send the connect request to the proxy */
+          /* BLOCKING */
+          result =
+            add_bufferf(req_buffer,
+                        "CONNECT %s:%d HTTP/1.0\r\n"
+                        "%s"  /* Host: */
+                        "%s"  /* Proxy-Authorization */
+                        "%s"  /* User-Agent */
+                        "%s", /* Proxy-Connection */
+                        hostname, remote_port,
+                        host,
+                        conn->allocptr.proxyuserpwd?
+                        conn->allocptr.proxyuserpwd:"",
+                        useragent,
+                        proxyconn);
+
+          if(CURLE_OK == result)
+            result = add_custom_headers(conn, req_buffer);
+
+          if(host && *host)
+            free(host);
+
+          if(CURLE_OK == result)
+            /* CRLF terminate the request */
+            result = add_bufferf(req_buffer, "\r\n");
+
+          if(CURLE_OK == result)
+            /* Now send off the request */
+            result = add_buffer_send(req_buffer, conn,
+                                     &data->info.request_size, 0, sockindex);
+        }
+        if(result)
+          failf(data, "Failed sending CONNECT to proxy");
       }
+      free(host_port);
       if(result)
-        failf(data, "Failed sending CONNECT to proxy");
-    }
-    free(host_port);
-    if(result)
-      return result;
+        return result;
 
-    ptr=data->state.buffer;
-    line_start = ptr;
+      conn->bits.tunnel_connecting = TRUE;
+    } /* END CONNECT PHASE */
 
-    nread=0;
-    perline=0;
-    keepon=TRUE;
+    /* now we've issued the CONNECT and we're waiting to hear back -
+       we try not to block here in multi-mode because that might be a LONG
+       wait if the proxy cannot connect-through to the remote host. */
 
-    while((nread<BUFSIZE) && (keepon && !error)) {
+    /* if timeout is requested, find out how much remaining time we have */
+    check = timeout - /* timeout time */
+      Curl_tvdiff(Curl_tvnow(), conn->now); /* spent time */
+    if(check <=0 ) {
+      failf(data, "Proxy CONNECT aborted due to timeout");
+      error = SELECT_TIMEOUT; /* already too little time */
+      break;
+    }
 
-      /* if timeout is requested, find out how much remaining time we have */
-      long check = timeout - /* timeout time */
-        Curl_tvdiff(Curl_tvnow(), conn->now); /* spent time */
-      if(check <= 0) {
-        failf(data, "Proxy CONNECT aborted due to timeout");
-        error = SELECT_TIMEOUT; /* already too little time */
-        break;
+    /* if we're in multi-mode and we would block, return instead for a retry */
+    if (Curl_if_multi == data->state.used_interface) {
+      if (0 == Curl_select(tunnelsocket, CURL_SOCKET_BAD, 0))
+        /* return so we'll be called again polling-style */
+        return CURLE_OK;
+      else {
+        DEBUGF(infof(data,
+                     "Multi mode finished polling for response from "
+                     "proxy CONNECT."));
       }
+    }
+    else {
+      DEBUGF(infof(data, "Easy mode waiting for response from proxy CONNECT."));
+    }
 
-      /* loop every second at least, less if the timeout is near */
-      switch (Curl_select(tunnelsocket, CURL_SOCKET_BAD,
-                          check<1000L?(int)check:1000)) {
-      case -1: /* select() error, stop reading */
-        error = SELECT_ERROR;
-        failf(data, "Proxy CONNECT aborted due to select() error");
-        break;
-      case 0: /* timeout */
-        break;
-      default:
-        res = Curl_read(conn, tunnelsocket, ptr, BUFSIZE-nread, &gotbytes);
-        if(res< 0)
-          /* EWOULDBLOCK */
-          continue; /* go loop yourself */
-        else if(res)
-          keepon = FALSE;
-        else if(gotbytes <= 0) {
-          keepon = FALSE;
-          error = SELECT_ERROR;
-          failf(data, "Proxy CONNECT aborted");
+    /* at this point, either:
+       1) we're in easy-mode and so it's okay to block waiting for a CONNECT
+       response
+       2) we're in multi-mode and we didn't block - it's either an error or we
+       now have some data waiting.
+       In any case, the tunnel_connecting phase is over. */
+    conn->bits.tunnel_connecting = FALSE;
+
+    { /* BEGIN NEGOTIATION PHASE */
+      size_t nread;   /* total size read */
+      int perline; /* count bytes per line */
+      int keepon=TRUE;
+      ssize_t gotbytes;
+      char *ptr;
+      char *line_start;
+
+      ptr=data->state.buffer;
+      line_start = ptr;
+
+      nread=0;
+      perline=0;
+      keepon=TRUE;
+
+      while((nread<BUFSIZE) && (keepon && !error)) {
+
+        /* if timeout is requested, find out how much remaining time we have */
+        check = timeout - /* timeout time */
+          Curl_tvdiff(Curl_tvnow(), conn->now); /* spent time */
+        if(check <= 0) {
+          failf(data, "Proxy CONNECT aborted due to timeout");
+          error = SELECT_TIMEOUT; /* already too little time */
+          break;
         }
-        else {
-          /*
-           * We got a whole chunk of data, which can be anything from one byte
-           * to a set of lines and possibly just a piece of the last line.
-           */
-          int i;
-
-          nread += gotbytes;
-
-          if(keepon > TRUE) {
-            /* This means we are currently ignoring a response-body, so we
-               simply count down our counter and make sure to break out of the
-               loop when we're done! */
-            cl -= gotbytes;
-            if(cl<=0) {
-              keepon = FALSE;
-              break;
-            }
-          }
-          else
-          for(i = 0; i < gotbytes; ptr++, i++) {
-            perline++; /* amount of bytes in this line so far */
-            if(*ptr=='\n') {
-              char letter;
-              int writetype;
-
-              /* output debug if that is requested */
-              if(data->set.verbose)
-                Curl_debug(data, CURLINFO_HEADER_IN,
-                           line_start, (size_t)perline, conn);
-
-              /* send the header to the callback */
-              writetype = CLIENTWRITE_HEADER;
-              if(data->set.include_header)
-                writetype |= CLIENTWRITE_BODY;
-
-              result = Curl_client_write(conn, writetype, line_start, perline);
-              if(result)
-                return result;
-
-              /* Newlines are CRLF, so the CR is ignored as the line isn't
-                 really terminated until the LF comes. Treat a following CR
-                 as end-of-headers as well.*/
-
-              if(('\r' == line_start[0]) ||
-                 ('\n' == line_start[0])) {
-                /* end of response-headers from the proxy */
-                if(cl && (407 == k->httpcode) && !data->state.authproblem) {
-                  /* If we get a 407 response code with content length when we
-                   * have no auth problem, we must ignore the whole
-                   * response-body */
-                  keepon = 2;
-                  infof(data, "Ignore %" FORMAT_OFF_T
-                        " bytes of response-body\n", cl);
-                  cl -= (gotbytes - i);/* remove the remaining chunk of what
-                                          we already read */
-                  if(cl<=0)
-                    /* if the whole thing was already read, we are done! */
-                    keepon=FALSE;
-                }
-                else
-                  keepon = FALSE;
-                break; /* breaks out of for-loop, not switch() */
-              }
 
-              /* keep a backup of the position we are about to blank */
-              letter = line_start[perline];
-              line_start[perline]=0; /* zero terminate the buffer */
-              if((checkprefix("WWW-Authenticate:", line_start) &&
-                  (401 == k->httpcode)) ||
-                 (checkprefix("Proxy-authenticate:", line_start) &&
-                  (407 == k->httpcode))) {
-                result = Curl_http_input_auth(conn, k->httpcode, line_start);
-                if(result)
-                  return result;
-              }
-              else if(checkprefix("Content-Length:", line_start)) {
-                cl = curlx_strtoofft(line_start + strlen("Content-Length:"),
-                                     NULL, 10);
-              }
-              else if(Curl_compareheader(line_start,
-                                         "Connection:", "close"))
-                closeConnection = TRUE;
-              else if(2 == sscanf(line_start, "HTTP/1.%d %d",
-                                  &subversion,
-                                  &k->httpcode)) {
-                /* store the HTTP code from the proxy */
-                data->info.httpproxycode = k->httpcode;
+        /* loop every second at least, less if the timeout is near */
+        switch (Curl_select(tunnelsocket, CURL_SOCKET_BAD,
+                            check<1000L?(int)check:1000)) {
+        case -1: /* select() error, stop reading */
+          error = SELECT_ERROR;
+          failf(data, "Proxy CONNECT aborted due to select() error");
+          break;
+        case 0: /* timeout */
+          break;
+        default:
+          res = Curl_read(conn, tunnelsocket, ptr, BUFSIZE-nread, &gotbytes);
+          if(res< 0)
+            /* EWOULDBLOCK */
+            continue; /* go loop yourself */
+          else if(res)
+            keepon = FALSE;
+          else if(gotbytes <= 0) {
+            keepon = FALSE;
+            error = SELECT_ERROR;
+            failf(data, "Proxy CONNECT aborted");
+          }
+          else {
+            /*
+             * We got a whole chunk of data, which can be anything from one
+             * byte to a set of lines and possibly just a piece of the last
+             * line.
+             */
+            int i;
+
+            nread += gotbytes;
+
+            if(keepon > TRUE) {
+              /* This means we are currently ignoring a response-body, so we
+                 simply count down our counter and make sure to break out of
+                 the loop when we're done! */
+              cl -= gotbytes;
+              if(cl<=0) {
+                keepon = FALSE;
+                break;
               }
-              /* put back the letter we blanked out before */
-              line_start[perline]= letter;
-
-              perline=0; /* line starts over here */
-              line_start = ptr+1; /* this skips the zero byte we wrote */
             }
+            else
+              for(i = 0; i < gotbytes; ptr++, i++) {
+                perline++; /* amount of bytes in this line so far */
+                if(*ptr=='\n') {
+                  char letter;
+                  int writetype;
+
+                  /* output debug if that is requested */
+                  if(data->set.verbose)
+                    Curl_debug(data, CURLINFO_HEADER_IN,
+                               line_start, (size_t)perline, conn);
+
+                  /* send the header to the callback */
+                  writetype = CLIENTWRITE_HEADER;
+                  if(data->set.include_header)
+                    writetype |= CLIENTWRITE_BODY;
+
+                  result = Curl_client_write(conn, writetype, line_start, perline);
+                  if(result)
+                    return result;
+
+                  /* Newlines are CRLF, so the CR is ignored as the line isn't
+                     really terminated until the LF comes. Treat a following CR
+                     as end-of-headers as well.*/
+
+                  if(('\r' == line_start[0]) ||
+                     ('\n' == line_start[0])) {
+                    /* end of response-headers from the proxy */
+                    if(cl && (407 == k->httpcode) &&
+                       !data->state.authproblem) {
+                      /* If we get a 407 response code with content length
+                       * when we have no auth problem, we must ignore the
+                       * whole response-body */
+                      keepon = 2;
+                      infof(data, "Ignore %" FORMAT_OFF_T
+                            " bytes of response-body\n", cl);
+                      cl -= (gotbytes - i);/* remove the remaining chunk of
+                                              what we already read */
+                      if(cl<=0)
+                        /* if the whole thing was already read, we are done! */
+                        keepon=FALSE;
+                    }
+                    else
+                      keepon = FALSE;
+                    break; /* breaks out of for-loop, not switch() */
+                  }
+
+                  /* keep a backup of the position we are about to blank */
+                  letter = line_start[perline];
+                  line_start[perline]=0; /* zero terminate the buffer */
+                  if((checkprefix("WWW-Authenticate:", line_start) &&
+                      (401 == k->httpcode)) ||
+                     (checkprefix("Proxy-authenticate:", line_start) &&
+                      (407 == k->httpcode))) {
+                    result = Curl_http_input_auth(conn, k->httpcode,
+                                                  line_start);
+                    if(result)
+                      return result;
+                  }
+                  else if(checkprefix("Content-Length:", line_start)) {
+                    cl = curlx_strtoofft(line_start + strlen("Content-Length:"),
+                                         NULL, 10);
+                  }
+                  else if(Curl_compareheader(line_start,
+                                             "Connection:", "close"))
+                    closeConnection = TRUE;
+                  else if(2 == sscanf(line_start, "HTTP/1.%d %d",
+                                      &subversion,
+                                      &k->httpcode)) {
+                    /* store the HTTP code from the proxy */
+                    data->info.httpproxycode = k->httpcode;
+                  }
+                  /* put back the letter we blanked out before */
+                  line_start[perline]= letter;
+
+                  perline=0; /* line starts over here */
+                  line_start = ptr+1; /* this skips the zero byte we wrote */
+                }
+              }
           }
-        }
+          break;
+        } /* switch */
+      } /* while there's buffer left and loop is requested */
+
+      if(error)
+        return CURLE_RECV_ERROR;
+
+      if(data->info.httpproxycode != 200)
+        /* Deal with the possibly already received authenticate
+           headers. 'newurl' is set to a new URL if we must loop. */
+        Curl_http_auth_act(conn);
+
+      if (closeConnection && data->reqdata.newurl) {
+        /* Connection closed by server. Don't use it anymore */
+        sclose(conn->sock[sockindex]);
+        conn->sock[sockindex] = CURL_SOCKET_BAD;
         break;
-      } /* switch */
-    } /* while there's buffer left and loop is requested */
-
-    if(error)
-      return CURLE_RECV_ERROR;
-
-    if(data->info.httpproxycode != 200)
-      /* Deal with the possibly already received authenticate
-         headers. 'newurl' is set to a new URL if we must loop. */
-      Curl_http_auth_act(conn);
-
-    if (closeConnection && data->reqdata.newurl) {
-      /* Connection closed by server. Don't use it anymore */
-      sclose(conn->sock[sockindex]);
-      conn->sock[sockindex] = CURL_SOCKET_BAD;
-      break;
-    }
+      }
+    } /* END NEGOTIATION PHASE */
   } while(data->reqdata.newurl);
 
   if(200 != k->httpcode) {
@@ -1423,6 +1473,11 @@ CURLcode Curl_http_connect(struct connectdata *conn, bool *done)
       return result;
   }
 
+  if (conn->bits.tunnel_connecting) {
+    /* nothing else to do except wait right now - we're not done here. */
+    return CURLE_OK;
+  }
+
   if(!data->state.this_is_a_follow) {
     /* this is not a followed location, get the original host name */
     if (data->state.first_host)
index 2a7f50baaeac8fa5c9d4e8849b86e1c627b9a379..e55cb69941be8a04f693812645db894e99ff1802 100644 (file)
@@ -47,6 +47,7 @@
 #include "multiif.h"
 #include "sendf.h"
 #include "timeval.h"
+#include "http.h"
 
 /* The last #include file should be: */
 #include "memdebug.h"
@@ -62,6 +63,7 @@ typedef enum {
   CURLM_STATE_CONNECT,     /* resolve/connect has been sent off */
   CURLM_STATE_WAITRESOLVE, /* awaiting the resolve to finalize */
   CURLM_STATE_WAITCONNECT, /* awaiting the connect to finalize */
+  CURLM_STATE_WAITPROXYCONNECT, /* awaiting proxy CONNECT to finalize */
   CURLM_STATE_PROTOCONNECT, /* completing the protocol-specific connect
                                phase */
   CURLM_STATE_WAITDO,      /* wait for our turn to send the request */
@@ -791,7 +793,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
         multistate(easy, CURLM_STATE_CONNECT);
         result = CURLM_CALL_MULTI_PERFORM;
         easy->result = CURLE_OK;
-      } else {
+      }
+      else {
         easy->result = CURLE_COULDNT_CONNECT;
         multistate(easy, CURLM_STATE_COMPLETED);
       }
@@ -871,10 +874,13 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
              WAITDO! */
           result = CURLM_CALL_MULTI_PERFORM;
 
-          if(protocol_connect) {
+          if(protocol_connect)
             multistate(easy, CURLM_STATE_WAITDO);
-          } else {
-            multistate(easy, CURLM_STATE_WAITCONNECT);
+          else {
+            if (easy->easy_conn->bits.tunnel_connecting)
+              multistate(easy, CURLM_STATE_WAITPROXYCONNECT);
+            else
+              multistate(easy, CURLM_STATE_WAITCONNECT);
           }
         }
       }
@@ -903,8 +909,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
           result = CURLM_CALL_MULTI_PERFORM;
           if(protocol_connect)
             multistate(easy, CURLM_STATE_DO);
-          else
-            multistate(easy, CURLM_STATE_WAITCONNECT);
+          else {
+            if (easy->easy_conn->bits.tunnel_connecting)
+              multistate(easy, CURLM_STATE_WAITPROXYCONNECT);
+            else
+              multistate(easy, CURLM_STATE_WAITCONNECT);
+          }
         }
       }
 
@@ -917,6 +927,16 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
     }
     break;
 
+    case CURLM_STATE_WAITPROXYCONNECT:
+      /* this is HTTP-specific, but sending CONNECT to a proxy is HTTP... */
+      easy->result = Curl_http_connect(easy->easy_conn, &protocol_connect);
+
+      if(CURLE_OK == easy->result) {
+        if (!easy->easy_conn->bits.tunnel_connecting)
+          multistate(easy, CURLM_STATE_WAITCONNECT);
+      }
+      break;
+
     case CURLM_STATE_WAITCONNECT:
       /* awaiting a completion of an asynch connect */
       easy->result = Curl_is_connected(easy->easy_conn,
index 6a1f7045eee85a3940cafd3fd6f6a93d206ce3e2..2e13f604618651a0e2b138dbbcc3f631848c1366 100644 (file)
@@ -470,6 +470,8 @@ struct ConnectBits {
                          This is implicit when SSL-protocols are used through
                          proxies, but can also be enabled explicitly by
                          apps */
+  bool tunnel_connecting; /* TRUE while we're still waiting for a proxy CONNECT
+                          */
   bool authneg;       /* TRUE when the auth phase has started, which means
                          that we are creating a request with an auth header,
                          but it is not the final request in the auth