mirror of
https://github.com/moparisthebest/curl
synced 2024-11-11 03:55:03 -05:00
multi: fix *getsock() with CONNECT
The code used some happy eyeballs logic even _after_ CONNECT has been sent to a proxy, while the happy eyeball phase is already (should be) over by then. This is solved by splitting the multi state into two separate states introducing the new SENDPROTOCONNECT state. Bug: http://curl.haxx.se/mail/lib-2015-01/0170.html Reported-by: Peter Laser
This commit is contained in:
parent
9da14a96ab
commit
c19349951d
@ -72,6 +72,7 @@ CURLcode Curl_proxy_connect(struct connectdata *conn)
|
|||||||
conn->data->req.protop = prot_save;
|
conn->data->req.protop = prot_save;
|
||||||
if(CURLE_OK != result)
|
if(CURLE_OK != result)
|
||||||
return result;
|
return result;
|
||||||
|
Curl_safefree(conn->allocptr.proxyuserpwd);
|
||||||
#else
|
#else
|
||||||
return CURLE_NOT_BUILT_IN;
|
return CURLE_NOT_BUILT_IN;
|
||||||
#endif
|
#endif
|
||||||
|
90
lib/multi.c
90
lib/multi.c
@ -86,6 +86,7 @@ static const char * const statename[]={
|
|||||||
"WAITRESOLVE",
|
"WAITRESOLVE",
|
||||||
"WAITCONNECT",
|
"WAITCONNECT",
|
||||||
"WAITPROXYCONNECT",
|
"WAITPROXYCONNECT",
|
||||||
|
"SENDPROTOCONNECT",
|
||||||
"PROTOCONNECT",
|
"PROTOCONNECT",
|
||||||
"WAITDO",
|
"WAITDO",
|
||||||
"DO",
|
"DO",
|
||||||
@ -646,14 +647,24 @@ static int waitconnect_getsock(struct connectdata *conn,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int waitproxyconnect_getsock(struct connectdata *conn,
|
||||||
|
curl_socket_t *sock,
|
||||||
|
int numsocks)
|
||||||
|
{
|
||||||
|
if(!numsocks)
|
||||||
|
return GETSOCK_BLANK;
|
||||||
|
|
||||||
|
sock[0] = conn->sock[FIRSTSOCKET];
|
||||||
|
|
||||||
/* when we've sent a CONNECT to a proxy, we should rather wait for the
|
/* when we've sent a CONNECT to a proxy, we should rather wait for the
|
||||||
socket to become readable to be able to get the response headers */
|
socket to become readable to be able to get the response headers */
|
||||||
if(conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT) {
|
if(conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)
|
||||||
sock[0] = conn->sock[FIRSTSOCKET];
|
return GETSOCK_READSOCK(0);
|
||||||
rc = GETSOCK_READSOCK(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
return GETSOCK_WRITESOCK(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int domore_getsock(struct connectdata *conn,
|
static int domore_getsock(struct connectdata *conn,
|
||||||
@ -706,6 +717,7 @@ static int multi_getsock(struct SessionHandle *data,
|
|||||||
return Curl_resolver_getsock(data->easy_conn, socks, numsocks);
|
return Curl_resolver_getsock(data->easy_conn, socks, numsocks);
|
||||||
|
|
||||||
case CURLM_STATE_PROTOCONNECT:
|
case CURLM_STATE_PROTOCONNECT:
|
||||||
|
case CURLM_STATE_SENDPROTOCONNECT:
|
||||||
return Curl_protocol_getsock(data->easy_conn, socks, numsocks);
|
return Curl_protocol_getsock(data->easy_conn, socks, numsocks);
|
||||||
|
|
||||||
case CURLM_STATE_DO:
|
case CURLM_STATE_DO:
|
||||||
@ -713,6 +725,8 @@ static int multi_getsock(struct SessionHandle *data,
|
|||||||
return Curl_doing_getsock(data->easy_conn, socks, numsocks);
|
return Curl_doing_getsock(data->easy_conn, socks, numsocks);
|
||||||
|
|
||||||
case CURLM_STATE_WAITPROXYCONNECT:
|
case CURLM_STATE_WAITPROXYCONNECT:
|
||||||
|
return waitproxyconnect_getsock(data->easy_conn, socks, numsocks);
|
||||||
|
|
||||||
case CURLM_STATE_WAITCONNECT:
|
case CURLM_STATE_WAITCONNECT:
|
||||||
return waitconnect_getsock(data->easy_conn, socks, numsocks);
|
return waitconnect_getsock(data->easy_conn, socks, numsocks);
|
||||||
|
|
||||||
@ -1164,40 +1178,28 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
|||||||
/* this is HTTP-specific, but sending CONNECT to a proxy is HTTP... */
|
/* this is HTTP-specific, but sending CONNECT to a proxy is HTTP... */
|
||||||
result = Curl_http_connect(data->easy_conn, &protocol_connect);
|
result = Curl_http_connect(data->easy_conn, &protocol_connect);
|
||||||
|
|
||||||
|
rc = CURLM_CALL_MULTI_PERFORM;
|
||||||
if(data->easy_conn->bits.proxy_connect_closed) {
|
if(data->easy_conn->bits.proxy_connect_closed) {
|
||||||
/* connect back to proxy again */
|
/* connect back to proxy again */
|
||||||
result = CURLE_OK;
|
result = CURLE_OK;
|
||||||
rc = CURLM_CALL_MULTI_PERFORM;
|
|
||||||
multistate(data, CURLM_STATE_CONNECT);
|
multistate(data, CURLM_STATE_CONNECT);
|
||||||
}
|
}
|
||||||
else if(!result) {
|
else if(!result) {
|
||||||
if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_COMPLETE)
|
if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_COMPLETE)
|
||||||
multistate(data, CURLM_STATE_WAITCONNECT);
|
/* initiate protocol connect phase */
|
||||||
|
multistate(data, CURLM_STATE_SENDPROTOCONNECT);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
case CURLM_STATE_WAITCONNECT:
|
case CURLM_STATE_WAITCONNECT:
|
||||||
/* awaiting a completion of an asynch connect */
|
/* awaiting a completion of an asynch TCP connect */
|
||||||
result = Curl_is_connected(data->easy_conn,
|
result = Curl_is_connected(data->easy_conn, FIRSTSOCKET, &connected);
|
||||||
FIRSTSOCKET,
|
if(connected && !result) {
|
||||||
&connected);
|
|
||||||
if(connected) {
|
|
||||||
|
|
||||||
if(!result)
|
|
||||||
/* if everything is still fine we do the protocol-specific connect
|
|
||||||
setup */
|
|
||||||
result = Curl_protocol_connect(data->easy_conn,
|
|
||||||
&protocol_connect);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(data->easy_conn->bits.proxy_connect_closed) {
|
|
||||||
/* connect back to proxy again since it was closed in a proxy CONNECT
|
|
||||||
setup */
|
|
||||||
result = CURLE_OK;
|
|
||||||
rc = CURLM_CALL_MULTI_PERFORM;
|
rc = CURLM_CALL_MULTI_PERFORM;
|
||||||
multistate(data, CURLM_STATE_CONNECT);
|
multistate(data, data->easy_conn->bits.tunnel_proxy?
|
||||||
break;
|
CURLM_STATE_WAITPROXYCONNECT:
|
||||||
|
CURLM_STATE_SENDPROTOCONNECT);
|
||||||
}
|
}
|
||||||
else if(result) {
|
else if(result) {
|
||||||
/* failure detected */
|
/* failure detected */
|
||||||
@ -1205,29 +1207,25 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
|||||||
disconnect_conn = TRUE;
|
disconnect_conn = TRUE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
if(connected) {
|
case CURLM_STATE_SENDPROTOCONNECT:
|
||||||
if(!protocol_connect) {
|
result = Curl_protocol_connect(data->easy_conn, &protocol_connect);
|
||||||
/* We have a TCP connection, but 'protocol_connect' may be false
|
if(!protocol_connect)
|
||||||
and then we continue to 'STATE_PROTOCONNECT'. If protocol
|
/* switch to waiting state */
|
||||||
connect is TRUE, we move on to STATE_DO.
|
multistate(data, CURLM_STATE_PROTOCONNECT);
|
||||||
BUT if we are using a proxy we must change to WAITPROXYCONNECT
|
else if(!result) {
|
||||||
*/
|
/* protocol connect has completed, go WAITDO or DO */
|
||||||
#ifndef CURL_DISABLE_HTTP
|
multistate(data, multi->pipelining_enabled?
|
||||||
if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)
|
CURLM_STATE_WAITDO:CURLM_STATE_DO);
|
||||||
multistate(data, CURLM_STATE_WAITPROXYCONNECT);
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
multistate(data, CURLM_STATE_PROTOCONNECT);
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
/* after the connect has completed, go WAITDO or DO */
|
|
||||||
multistate(data, multi->pipelining_enabled?
|
|
||||||
CURLM_STATE_WAITDO:CURLM_STATE_DO);
|
|
||||||
|
|
||||||
rc = CURLM_CALL_MULTI_PERFORM;
|
rc = CURLM_CALL_MULTI_PERFORM;
|
||||||
}
|
}
|
||||||
|
else if(result) {
|
||||||
|
/* failure detected */
|
||||||
|
Curl_posttransfer(data);
|
||||||
|
Curl_done(&data->easy_conn, result, TRUE);
|
||||||
|
disconnect_conn = TRUE;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CURLM_STATE_PROTOCONNECT:
|
case CURLM_STATE_PROTOCONNECT:
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@ -35,22 +35,23 @@ typedef enum {
|
|||||||
CURLM_STATE_CONNECT_PEND, /* 1 - no connections, waiting for one */
|
CURLM_STATE_CONNECT_PEND, /* 1 - no connections, waiting for one */
|
||||||
CURLM_STATE_CONNECT, /* 2 - resolve/connect has been sent off */
|
CURLM_STATE_CONNECT, /* 2 - resolve/connect has been sent off */
|
||||||
CURLM_STATE_WAITRESOLVE, /* 3 - awaiting the resolve to finalize */
|
CURLM_STATE_WAITRESOLVE, /* 3 - awaiting the resolve to finalize */
|
||||||
CURLM_STATE_WAITCONNECT, /* 4 - awaiting the connect to finalize */
|
CURLM_STATE_WAITCONNECT, /* 4 - awaiting the TCP connect to finalize */
|
||||||
CURLM_STATE_WAITPROXYCONNECT, /* 5 - awaiting proxy CONNECT to finalize */
|
CURLM_STATE_WAITPROXYCONNECT, /* 5 - awaiting proxy CONNECT to finalize */
|
||||||
CURLM_STATE_PROTOCONNECT, /* 6 - completing the protocol-specific connect
|
CURLM_STATE_SENDPROTOCONNECT, /* 6 - initiate protocol connect procedure */
|
||||||
|
CURLM_STATE_PROTOCONNECT, /* 7 - completing the protocol-specific connect
|
||||||
phase */
|
phase */
|
||||||
CURLM_STATE_WAITDO, /* 7 - wait for our turn to send the request */
|
CURLM_STATE_WAITDO, /* 8 - wait for our turn to send the request */
|
||||||
CURLM_STATE_DO, /* 8 - start send off the request (part 1) */
|
CURLM_STATE_DO, /* 9 - start send off the request (part 1) */
|
||||||
CURLM_STATE_DOING, /* 9 - sending off the request (part 1) */
|
CURLM_STATE_DOING, /* 10 - sending off the request (part 1) */
|
||||||
CURLM_STATE_DO_MORE, /* 10 - send off the request (part 2) */
|
CURLM_STATE_DO_MORE, /* 11 - send off the request (part 2) */
|
||||||
CURLM_STATE_DO_DONE, /* 11 - done sending off request */
|
CURLM_STATE_DO_DONE, /* 12 - done sending off request */
|
||||||
CURLM_STATE_WAITPERFORM, /* 12 - wait for our turn to read the response */
|
CURLM_STATE_WAITPERFORM, /* 13 - wait for our turn to read the response */
|
||||||
CURLM_STATE_PERFORM, /* 13 - transfer data */
|
CURLM_STATE_PERFORM, /* 14 - transfer data */
|
||||||
CURLM_STATE_TOOFAST, /* 14 - wait because limit-rate exceeded */
|
CURLM_STATE_TOOFAST, /* 15 - wait because limit-rate exceeded */
|
||||||
CURLM_STATE_DONE, /* 15 - post data transfer operation */
|
CURLM_STATE_DONE, /* 16 - post data transfer operation */
|
||||||
CURLM_STATE_COMPLETED, /* 16 - operation complete */
|
CURLM_STATE_COMPLETED, /* 17 - operation complete */
|
||||||
CURLM_STATE_MSGSENT, /* 17 - the operation complete message is sent */
|
CURLM_STATE_MSGSENT, /* 18 - the operation complete message is sent */
|
||||||
CURLM_STATE_LAST /* 18 - not a true state, never use this */
|
CURLM_STATE_LAST /* 19 - not a true state, never use this */
|
||||||
} CURLMstate;
|
} CURLMstate;
|
||||||
|
|
||||||
/* we support N sockets per easy handle. Set the corresponding bit to what
|
/* we support N sockets per easy handle. Set the corresponding bit to what
|
||||||
|
Loading…
Reference in New Issue
Block a user