diff --git a/CHANGES b/CHANGES index 1865ee78a..d078ccf32 100644 --- 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. diff --git a/RELEASE-NOTES b/RELEASE-NOTES index aa0d82618..1114d8252 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -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: diff --git a/docs/KNOWN_BUGS b/docs/KNOWN_BUGS index 713c4515c..e7231b8f6 100644 --- a/docs/KNOWN_BUGS +++ b/docs/KNOWN_BUGS @@ -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 diff --git a/lib/http.c b/lib/http.c index e31730e7d..0670f1e78 100644 --- a/lib/http.c +++ b/lib/http.c @@ -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; } diff --git a/lib/url.c b/lib/url.c index 92e4a3b09..73b9debbe 100644 --- 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; + /* 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 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 - 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); + 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 diff --git a/lib/urldata.h b/lib/urldata.h index a42b09c76..440646d08 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -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 {