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.
This commit is contained in:
Daniel Stenberg 2006-11-03 12:43:55 +00:00
parent 7f79b52dae
commit a777eb3d81
6 changed files with 66 additions and 33 deletions

View File

@ -6,6 +6,13 @@
Changelog 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) Daniel (2 November 2006)
- James Housley brought support for SCP transfers, based on the libssh2 library - James Housley brought support for SCP transfers, based on the libssh2 library
for the actual network protocol stuff. for the actual network protocol stuff.

View File

@ -15,7 +15,7 @@ This release includes the following changes:
This release includes the following bugfixes: This release includes the following bugfixes:
o o proxy close during CONNECT authentication is now dealt with nicely
Other curl-related news: Other curl-related news:

View 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 "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 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. 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 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 bugs and lack of features when a SOCKS proxy is used. And there seem to be a

View File

@ -903,8 +903,8 @@ CURLcode add_buffer_send(send_buffer *in,
Curl_debug(conn->data, CURLINFO_HEADER_OUT, ptr, Curl_debug(conn->data, CURLINFO_HEADER_OUT, ptr,
(size_t)(amount-included_body_bytes), conn); (size_t)(amount-included_body_bytes), conn);
if (included_body_bytes) if (included_body_bytes)
Curl_debug(conn->data, CURLINFO_DATA_OUT, Curl_debug(conn->data, CURLINFO_DATA_OUT,
ptr+amount-included_body_bytes, ptr+amount-included_body_bytes,
(size_t)included_body_bytes, conn); (size_t)included_body_bytes, conn);
} }
@ -1110,6 +1110,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
curl_socket_t tunnelsocket = conn->sock[sockindex]; curl_socket_t tunnelsocket = conn->sock[sockindex];
send_buffer *req_buffer; send_buffer *req_buffer;
curl_off_t cl=0; curl_off_t cl=0;
bool closeConnection = FALSE;
#define SELECT_OK 0 #define SELECT_OK 0
#define SELECT_ERROR 1 #define SELECT_ERROR 1
@ -1117,6 +1118,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
int error = SELECT_OK; int error = SELECT_OK;
infof(data, "Establish HTTP proxy tunnel to %s:%d\n", hostname, remote_port); infof(data, "Establish HTTP proxy tunnel to %s:%d\n", hostname, remote_port);
conn->bits.proxy_connect_closed = FALSE;
do { do {
if(data->reqdata.newurl) { if(data->reqdata.newurl) {
@ -1258,7 +1260,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
/* output debug if that is requested */ /* output debug if that is requested */
if(data->set.verbose) if(data->set.verbose)
Curl_debug(data, CURLINFO_HEADER_IN, Curl_debug(data, CURLINFO_HEADER_IN,
line_start, (size_t)perline, conn); line_start, (size_t)perline, conn);
/* send the header to the callback */ /* send the header to the callback */
@ -1310,6 +1312,9 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
cl = curlx_strtoofft(line_start + strlen("Content-Length:"), cl = curlx_strtoofft(line_start + strlen("Content-Length:"),
NULL, 10); NULL, 10);
} }
else if(Curl_compareheader(line_start,
"Connection:", "close"))
closeConnection = TRUE;
else if(2 == sscanf(line_start, "HTTP/1.%d %d", else if(2 == sscanf(line_start, "HTTP/1.%d %d",
&subversion, &subversion,
&k->httpcode)) { &k->httpcode)) {
@ -1336,11 +1341,21 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
headers. 'newurl' is set to a new URL if we must loop. */ headers. 'newurl' is set to a new URL if we must loop. */
Curl_http_auth_act(conn); 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); } while(data->reqdata.newurl);
if(200 != k->httpcode) { if(200 != k->httpcode) {
failf(data, "Received HTTP code %d from proxy after CONNECT", failf(data, "Received HTTP code %d from proxy after CONNECT",
k->httpcode); k->httpcode);
if (closeConnection && data->reqdata.newurl)
conn->bits.proxy_connect_closed = TRUE;
return CURLE_RECV_ERROR; return CURLE_RECV_ERROR;
} }

View File

@ -2394,7 +2394,8 @@ CURLcode Curl_protocol_connect(struct connectdata *conn,
/* it has started, possibly even completed but that knowledge isn't stored /* it has started, possibly even completed but that knowledge isn't stored
in this bit! */ in this bit! */
conn->bits.protoconnstart = TRUE; if (!result)
conn->bits.protoconnstart = TRUE;
} }
return result; /* pass back status */ return result; /* pass back status */
@ -3957,30 +3958,41 @@ static CURLcode SetupConnection(struct connectdata *conn,
data->state.crlf_conversions = 0; /* reset CRLF conversion counter */ data->state.crlf_conversions = 0; /* reset CRLF conversion counter */
#endif /* CURL_DO_LINEEND_CONV */ #endif /* CURL_DO_LINEEND_CONV */
if(CURL_SOCKET_BAD == conn->sock[FIRSTSOCKET]) { for(;;) {
bool connected = FALSE; /* loop for CURL_SERVER_CLOSED_CONNECTION */
/* Connect only if not already connected! */ if(CURL_SOCKET_BAD == conn->sock[FIRSTSOCKET]) {
result = ConnectPlease(data, conn, hostaddr, &connected); bool connected = FALSE;
if(connected) { /* Connect only if not already connected! */
result = Curl_protocol_connect(conn, protocol_done); result = ConnectPlease(data, conn, hostaddr, &connected);
if(CURLE_OK == result)
conn->bits.tcpconnect = TRUE; 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 else {
conn->bits.tcpconnect = FALSE; Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */
conn->bits.tcpconnect = TRUE;
*protocol_done = TRUE;
if(CURLE_OK != result) if(data->set.verbose)
return result; verboseconnect(conn);
} }
else { /* Stop the loop now */
Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */ break;
conn->bits.tcpconnect = TRUE;
*protocol_done = TRUE;
if(data->set.verbose)
verboseconnect(conn);
} }
conn->now = Curl_tvnow(); /* time this *after* the connect is done, we conn->now = Curl_tvnow(); /* time this *after* the connect is done, we

View File

@ -485,8 +485,12 @@ struct ConnectBits {
when Curl_done() is called, to prevent Curl_done() to when Curl_done() is called, to prevent Curl_done() to
get invoked twice when the multi interface is get invoked twice when the multi interface is
used. */ used. */
bool stream_was_rewound; /* Indicates that the stream was rewound after a request bool stream_was_rewound; /* Indicates that the stream was rewound after a
read past the end of its response byte boundary */ 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 { struct hostname {