Olaf Stueben provided a patch that I edited slightly. It fixes the notorious
authorDaniel Stenberg <daniel@haxx.se>
Fri, 3 Nov 2006 12:43:55 +0000 (12:43 +0000)
committerDaniel Stenberg <daniel@haxx.se>
Fri, 3 Nov 2006 12:43:55 +0000 (12:43 +0000)
KNOWN_BUGS #25, which happens when a proxy closes the connection when
libcurl has sent CONNECT, as part of an authentication negotiation. Starting
now, libcurl will re-connect accordingly and continue the authentication as
it should.

CHANGES
RELEASE-NOTES
docs/KNOWN_BUGS
lib/http.c
lib/url.c
lib/urldata.h

diff --git a/CHANGES b/CHANGES
index 1865ee7..d078ccf 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -6,6 +6,13 @@
 
                                   Changelog
 
+Daniel (3 November 2006)
+- Olaf Stueben provided a patch that I edited slightly. It fixes the notorious
+  KNOWN_BUGS #25, which happens when a proxy closes the connection when
+  libcurl has sent CONNECT, as part of an authentication negotiation. Starting
+  now, libcurl will re-connect accordingly and continue the authentication as
+  it should.
+
 Daniel (2 November 2006)
 - James Housley brought support for SCP transfers, based on the libssh2 library
   for the actual network protocol stuff.
index aa0d826..1114d82 100644 (file)
@@ -15,7 +15,7 @@ This release includes the following changes:
 
 This release includes the following bugfixes:
 
- o 
+ o proxy close during CONNECT authentication is now dealt with nicely
 
 Other curl-related news:
 
index 713c451..e7231b8 100644 (file)
@@ -44,11 +44,6 @@ may have been fixed since this was written!
   "system context" will make it use wrong(?) user name - at least when compared
   to what winhttp does. See http://curl.haxx.se/bug/view.cgi?id=1281867
 
-25. When doing a CONNECT request with curl it doesn't properly handle if the
-  proxy closes the connection within the authentication "negotiation phase".
-  Like if you do HTTPS or similar over a proxy and you use perhaps
-  --proxy-anyauth.
-
 23. We don't support SOCKS for IPv6. We don't support FTPS over a SOCKS proxy.
   We don't have any test cases for SOCKS proxy. We probably have even more
   bugs and lack of features when a SOCKS proxy is used. And there seem to be a
index e31730e..0670f1e 100644 (file)
@@ -903,8 +903,8 @@ CURLcode add_buffer_send(send_buffer *in,
       Curl_debug(conn->data, CURLINFO_HEADER_OUT, ptr,
                  (size_t)(amount-included_body_bytes), conn);
       if (included_body_bytes)
-        Curl_debug(conn->data, CURLINFO_DATA_OUT, 
-                   ptr+amount-included_body_bytes, 
+        Curl_debug(conn->data, CURLINFO_DATA_OUT,
+                   ptr+amount-included_body_bytes,
                    (size_t)included_body_bytes, conn);
     }
 
@@ -1110,6 +1110,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
   curl_socket_t tunnelsocket = conn->sock[sockindex];
   send_buffer *req_buffer;
   curl_off_t cl=0;
+  bool closeConnection = FALSE;
 
 #define SELECT_OK      0
 #define SELECT_ERROR   1
@@ -1117,6 +1118,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
   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) {
@@ -1258,7 +1260,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
 
               /* output debug if that is requested */
               if(data->set.verbose)
-                Curl_debug(data, CURLINFO_HEADER_IN, 
+                Curl_debug(data, CURLINFO_HEADER_IN,
                            line_start, (size_t)perline, conn);
 
               /* send the header to the callback */
@@ -1310,6 +1312,9 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
                 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)) {
@@ -1336,11 +1341,21 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
          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;
+    }
   } while(data->reqdata.newurl);
 
   if(200 != k->httpcode) {
     failf(data, "Received HTTP code %d from proxy after CONNECT",
           k->httpcode);
+
+    if (closeConnection && data->reqdata.newurl)
+      conn->bits.proxy_connect_closed = TRUE;
+
     return CURLE_RECV_ERROR;
   }
 
index 92e4a3b..73b9deb 100644 (file)
--- a/lib/url.c
+++ b/lib/url.c
@@ -2394,7 +2394,8 @@ CURLcode Curl_protocol_connect(struct connectdata *conn,
 
     /* it has started, possibly even completed but that knowledge isn't stored
        in this bit! */
-    conn->bits.protoconnstart = TRUE;
+    if (!result)
+      conn->bits.protoconnstart = TRUE;
   }
 
   return result; /* pass back status */
@@ -3957,30 +3958,41 @@ static CURLcode SetupConnection(struct connectdata *conn,
   data->state.crlf_conversions = 0; /* reset CRLF conversion counter */
 #endif /* CURL_DO_LINEEND_CONV */
 
-  if(CURL_SOCKET_BAD == conn->sock[FIRSTSOCKET]) {
-    bool connected = FALSE;
+  for(;;) {
+    /* loop for CURL_SERVER_CLOSED_CONNECTION */
 
-    /* Connect only if not already connected! */
-    result = ConnectPlease(data, conn, hostaddr, &connected);
+    if(CURL_SOCKET_BAD == conn->sock[FIRSTSOCKET]) {
+      bool connected = FALSE;
 
-    if(connected) {
-      result = Curl_protocol_connect(conn, protocol_done);
-      if(CURLE_OK == result)
-        conn->bits.tcpconnect = TRUE;
-    }
-    else
-      conn->bits.tcpconnect = FALSE;
+      /* Connect only if not already connected! */
+      result = ConnectPlease(data, conn, hostaddr, &connected);
 
+      if(connected) {
+        result = Curl_protocol_connect(conn, protocol_done);
+        if(CURLE_OK == result)
+          conn->bits.tcpconnect = TRUE;
+      }
+      else
+        conn->bits.tcpconnect = FALSE;
 
-    if(CURLE_OK != result)
-      return result;
-  }
-  else {
-    Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */
-    conn->bits.tcpconnect = TRUE;
-    *protocol_done = TRUE;
-    if(data->set.verbose)
-      verboseconnect(conn);
+      /* if the connection was closed by the server while exchanging
+         authentication informations, retry with the new set
+         authentication information */
+      if(conn->bits.proxy_connect_closed)
+        continue;
+
+      if(CURLE_OK != result)
+        return result;
+    }
+    else {
+      Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */
+      conn->bits.tcpconnect = TRUE;
+      *protocol_done = TRUE;
+      if(data->set.verbose)
+        verboseconnect(conn);
+    }
+    /* Stop the loop now */
+    break;
   }
 
   conn->now = Curl_tvnow(); /* time this *after* the connect is done, we
index a42b09c..440646d 100644 (file)
@@ -485,8 +485,12 @@ struct ConnectBits {
                          when Curl_done() is called, to prevent Curl_done() to
                          get invoked twice when the multi interface is
                          used. */
-  bool stream_was_rewound; /* Indicates that the stream was rewound after a request
-                              read past the end of its response byte boundary */
+  bool stream_was_rewound; /* Indicates that the stream was rewound after a
+                              request read past the end of its response byte
+                              boundary */
+  bool proxy_connect_closed; /* set true if a proxy disconnected the
+                                connection in a CONNECT request with auth, so
+                                that libcurl should reconnect and continue. */
 };
 
 struct hostname {