CONNECT: fix multi interface regression
The refactoring of HTTP CONNECT handling in commit 41b0237834
that
made it protocol independent broke it for the multi interface. This fix
now introduce a better state handling and moved some logic to the
http_proxy.c source file.
Reported by: Yang Tse
Bug: http://curl.haxx.se/mail/lib-2012-03/0162.html
This commit is contained in:
Родитель
805788e043
Коммит
c83de6d076
11
lib/http.c
11
lib/http.c
|
@ -1309,10 +1309,17 @@ CURLcode Curl_http_connect(struct connectdata *conn, bool *done)
|
||||||
function to make the re-use checks properly be able to check this bit. */
|
function to make the re-use checks properly be able to check this bit. */
|
||||||
conn->bits.close = FALSE;
|
conn->bits.close = FALSE;
|
||||||
|
|
||||||
if(conn->bits.tunnel_connecting) {
|
if(data->state.used_interface == Curl_if_multi) {
|
||||||
|
/* when the multi interface is used, the CONNECT procedure might not have
|
||||||
|
been completed */
|
||||||
|
result = Curl_proxy_connect(conn);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)
|
||||||
/* nothing else to do except wait right now - we're not done here. */
|
/* nothing else to do except wait right now - we're not done here. */
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
|
||||||
|
|
||||||
if(conn->given->flags & PROTOPT_SSL) {
|
if(conn->given->flags & PROTOPT_SSL) {
|
||||||
/* perform SSL initialization */
|
/* perform SSL initialization */
|
||||||
|
|
|
@ -48,6 +48,40 @@
|
||||||
/* The last #include file should be: */
|
/* The last #include file should be: */
|
||||||
#include "memdebug.h"
|
#include "memdebug.h"
|
||||||
|
|
||||||
|
CURLcode Curl_proxy_connect(struct connectdata *conn)
|
||||||
|
{
|
||||||
|
if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
|
||||||
|
#ifndef CURL_DISABLE_PROXY
|
||||||
|
/* for [protocol] tunneled through HTTP proxy */
|
||||||
|
struct HTTP http_proxy;
|
||||||
|
void *prot_save;
|
||||||
|
CURLcode result;
|
||||||
|
|
||||||
|
/* BLOCKING */
|
||||||
|
/* We want "seamless" operations through HTTP proxy tunnel */
|
||||||
|
|
||||||
|
/* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the
|
||||||
|
* member conn->proto.http; we want [protocol] through HTTP and we have
|
||||||
|
* to change the member temporarily for connecting to the HTTP
|
||||||
|
* proxy. After Curl_proxyCONNECT we have to set back the member to the
|
||||||
|
* original pointer
|
||||||
|
*/
|
||||||
|
prot_save = conn->data->state.proto.generic;
|
||||||
|
memset(&http_proxy, 0, sizeof(http_proxy));
|
||||||
|
conn->data->state.proto.http = &http_proxy;
|
||||||
|
result = Curl_proxyCONNECT(conn, FIRSTSOCKET,
|
||||||
|
conn->host.name, conn->remote_port);
|
||||||
|
conn->data->state.proto.generic = prot_save;
|
||||||
|
if(CURLE_OK != result)
|
||||||
|
return result;
|
||||||
|
#else
|
||||||
|
return CURLE_NOT_BUILT_IN;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
/* no HTTP tunnel proxy, just return */
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Curl_proxyCONNECT() requires that we're connected to a HTTP proxy. This
|
* Curl_proxyCONNECT() requires that we're connected to a HTTP proxy. This
|
||||||
* function will issue the necessary commands to get a seamless tunnel through
|
* function will issue the necessary commands to get a seamless tunnel through
|
||||||
|
@ -83,10 +117,14 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
|
||||||
#define SELECT_TIMEOUT 2
|
#define SELECT_TIMEOUT 2
|
||||||
int error = SELECT_OK;
|
int error = SELECT_OK;
|
||||||
|
|
||||||
|
if(conn->tunnel_state[sockindex] == TUNNEL_COMPLETE)
|
||||||
|
return CURLE_OK; /* CONNECT is already completed */
|
||||||
|
|
||||||
conn->bits.proxy_connect_closed = FALSE;
|
conn->bits.proxy_connect_closed = FALSE;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if(!conn->bits.tunnel_connecting) { /* BEGIN CONNECT PHASE */
|
if(TUNNEL_INIT == conn->tunnel_state[sockindex]) {
|
||||||
|
/* BEGIN CONNECT PHASE */
|
||||||
char *host_port;
|
char *host_port;
|
||||||
Curl_send_buffer *req_buffer;
|
Curl_send_buffer *req_buffer;
|
||||||
|
|
||||||
|
@ -190,7 +228,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
|
||||||
if(result)
|
if(result)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
conn->bits.tunnel_connecting = TRUE;
|
conn->tunnel_state[sockindex] = TUNNEL_CONNECT;
|
||||||
} /* END CONNECT PHASE */
|
} /* END CONNECT PHASE */
|
||||||
|
|
||||||
/* now we've issued the CONNECT and we're waiting to hear back -
|
/* now we've issued the CONNECT and we're waiting to hear back -
|
||||||
|
@ -226,7 +264,6 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
|
||||||
2) we're in multi-mode and we didn't block - it's either an error or we
|
2) we're in multi-mode and we didn't block - it's either an error or we
|
||||||
now have some data waiting.
|
now have some data waiting.
|
||||||
In any case, the tunnel_connecting phase is over. */
|
In any case, the tunnel_connecting phase is over. */
|
||||||
conn->bits.tunnel_connecting = FALSE;
|
|
||||||
|
|
||||||
{ /* BEGIN NEGOTIATION PHASE */
|
{ /* BEGIN NEGOTIATION PHASE */
|
||||||
size_t nread; /* total size read */
|
size_t nread; /* total size read */
|
||||||
|
@ -516,9 +553,14 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
|
||||||
if(closeConnection && data->req.newurl)
|
if(closeConnection && data->req.newurl)
|
||||||
conn->bits.proxy_connect_closed = TRUE;
|
conn->bits.proxy_connect_closed = TRUE;
|
||||||
|
|
||||||
|
/* to back to init state */
|
||||||
|
conn->tunnel_state[sockindex] = TUNNEL_INIT;
|
||||||
|
|
||||||
return CURLE_RECV_ERROR;
|
return CURLE_RECV_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
conn->tunnel_state[sockindex] = TUNNEL_COMPLETE;
|
||||||
|
|
||||||
/* If a proxy-authorization header was used for the proxy, then we should
|
/* If a proxy-authorization header was used for the proxy, then we should
|
||||||
make sure that it isn't accidentally used for the document request
|
make sure that it isn't accidentally used for the document request
|
||||||
after we've connected. So let's free and clear it here. */
|
after we've connected. So let's free and clear it here. */
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2012, 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
|
||||||
|
@ -21,6 +21,9 @@
|
||||||
* KIND, either express or implied.
|
* KIND, either express or implied.
|
||||||
*
|
*
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
|
CURLcode Curl_proxy_connect(struct connectdata *conn);
|
||||||
|
|
||||||
#if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP)
|
#if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP)
|
||||||
/* ftp can use this as well */
|
/* ftp can use this as well */
|
||||||
CURLcode Curl_proxyCONNECT(struct connectdata *conn,
|
CURLcode Curl_proxyCONNECT(struct connectdata *conn,
|
||||||
|
|
10
lib/multi.c
10
lib/multi.c
|
@ -812,7 +812,7 @@ static int waitconnect_getsock(struct connectdata *conn,
|
||||||
|
|
||||||
/* 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->bits.tunnel_connecting)
|
if(conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)
|
||||||
return GETSOCK_READSOCK(0);
|
return GETSOCK_READSOCK(0);
|
||||||
|
|
||||||
return GETSOCK_WRITESOCK(0);
|
return GETSOCK_WRITESOCK(0);
|
||||||
|
@ -1066,7 +1066,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
||||||
CURLM_STATE_WAITDO:CURLM_STATE_DO);
|
CURLM_STATE_WAITDO:CURLM_STATE_DO);
|
||||||
else {
|
else {
|
||||||
#ifndef CURL_DISABLE_HTTP
|
#ifndef CURL_DISABLE_HTTP
|
||||||
if(easy->easy_conn->bits.tunnel_connecting)
|
if(easy->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)
|
||||||
multistate(easy, CURLM_STATE_WAITPROXYCONNECT);
|
multistate(easy, CURLM_STATE_WAITPROXYCONNECT);
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
|
@ -1111,7 +1111,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
||||||
CURLM_STATE_WAITDO:CURLM_STATE_DO);
|
CURLM_STATE_WAITDO:CURLM_STATE_DO);
|
||||||
else {
|
else {
|
||||||
#ifndef CURL_DISABLE_HTTP
|
#ifndef CURL_DISABLE_HTTP
|
||||||
if(easy->easy_conn->bits.tunnel_connecting)
|
if(easy->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)
|
||||||
multistate(easy, CURLM_STATE_WAITPROXYCONNECT);
|
multistate(easy, CURLM_STATE_WAITPROXYCONNECT);
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
|
@ -1144,7 +1144,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
||||||
multistate(easy, CURLM_STATE_CONNECT);
|
multistate(easy, CURLM_STATE_CONNECT);
|
||||||
}
|
}
|
||||||
else if(CURLE_OK == easy->result) {
|
else if(CURLE_OK == easy->result) {
|
||||||
if(!easy->easy_conn->bits.tunnel_connecting)
|
if(easy->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_COMPLETE)
|
||||||
multistate(easy, CURLM_STATE_WAITCONNECT);
|
multistate(easy, CURLM_STATE_WAITCONNECT);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1179,7 +1179,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
||||||
BUT if we are using a proxy we must change to WAITPROXYCONNECT
|
BUT if we are using a proxy we must change to WAITPROXYCONNECT
|
||||||
*/
|
*/
|
||||||
#ifndef CURL_DISABLE_HTTP
|
#ifndef CURL_DISABLE_HTTP
|
||||||
if(easy->easy_conn->bits.tunnel_connecting)
|
if(easy->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)
|
||||||
multistate(easy, CURLM_STATE_WAITPROXYCONNECT);
|
multistate(easy, CURLM_STATE_WAITPROXYCONNECT);
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
|
|
31
lib/url.c
31
lib/url.c
|
@ -3391,36 +3391,9 @@ CURLcode Curl_protocol_connect(struct connectdata *conn,
|
||||||
is later set again for the progress meter purpose */
|
is later set again for the progress meter purpose */
|
||||||
conn->now = Curl_tvnow();
|
conn->now = Curl_tvnow();
|
||||||
|
|
||||||
if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
|
result = Curl_proxy_connect(conn);
|
||||||
#ifndef CURL_DISABLE_PROXY
|
if(result)
|
||||||
/* for [protocol] tunneled through HTTP proxy */
|
|
||||||
struct HTTP http_proxy;
|
|
||||||
void *prot_save;
|
|
||||||
|
|
||||||
/* BLOCKING */
|
|
||||||
/* We want "seamless" operations through HTTP proxy tunnel */
|
|
||||||
|
|
||||||
/* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the
|
|
||||||
* member conn->proto.http; we want [protocol] through HTTP and we have
|
|
||||||
* to change the member temporarily for connecting to the HTTP
|
|
||||||
* proxy. After Curl_proxyCONNECT we have to set back the member to the
|
|
||||||
* original pointer
|
|
||||||
*/
|
|
||||||
prot_save = data->state.proto.generic;
|
|
||||||
memset(&http_proxy, 0, sizeof(http_proxy));
|
|
||||||
data->state.proto.http = &http_proxy;
|
|
||||||
|
|
||||||
result = Curl_proxyCONNECT(conn, FIRSTSOCKET,
|
|
||||||
conn->host.name, conn->remote_port);
|
|
||||||
|
|
||||||
data->state.proto.generic = prot_save;
|
|
||||||
|
|
||||||
if(CURLE_OK != result)
|
|
||||||
return result;
|
return result;
|
||||||
#else
|
|
||||||
return CURLE_NOT_BUILT_IN;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if(conn->handler->connect_it) {
|
if(conn->handler->connect_it) {
|
||||||
/* is there a protocol-specific connect() procedure? */
|
/* is there a protocol-specific connect() procedure? */
|
||||||
|
|
|
@ -422,8 +422,6 @@ struct ConnectBits {
|
||||||
This is implicit when SSL-protocols are used through
|
This is implicit when SSL-protocols are used through
|
||||||
proxies, but can also be enabled explicitly by
|
proxies, but can also be enabled explicitly by
|
||||||
apps */
|
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
|
bool authneg; /* TRUE when the auth phase has started, which means
|
||||||
that we are creating a request with an auth header,
|
that we are creating a request with an auth header,
|
||||||
but it is not the final request in the auth
|
but it is not the final request in the auth
|
||||||
|
@ -964,6 +962,12 @@ struct connectdata {
|
||||||
unsigned short localport;
|
unsigned short localport;
|
||||||
int localportrange;
|
int localportrange;
|
||||||
|
|
||||||
|
/* tunnel as in tunnel through a HTTP proxy with CONNECT */
|
||||||
|
enum {
|
||||||
|
TUNNEL_INIT, /* init/default/no tunnel state */
|
||||||
|
TUNNEL_CONNECT, /* CONNECT has been sent off */
|
||||||
|
TUNNEL_COMPLETE /* CONNECT response received completely */
|
||||||
|
} tunnel_state[2]; /* two separate ones to allow FTP */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The end of connectdata. */
|
/* The end of connectdata. */
|
||||||
|
|
Загрузка…
Ссылка в новой задаче