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. */
|
||||
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. */
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
if(conn->given->flags & PROTOPT_SSL) {
|
||||
/* perform SSL initialization */
|
||||
|
|
|
@ -48,6 +48,40 @@
|
|||
/* The last #include file should be: */
|
||||
#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
|
||||
* 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
|
||||
int error = SELECT_OK;
|
||||
|
||||
if(conn->tunnel_state[sockindex] == TUNNEL_COMPLETE)
|
||||
return CURLE_OK; /* CONNECT is already completed */
|
||||
|
||||
conn->bits.proxy_connect_closed = FALSE;
|
||||
|
||||
do {
|
||||
if(!conn->bits.tunnel_connecting) { /* BEGIN CONNECT PHASE */
|
||||
if(TUNNEL_INIT == conn->tunnel_state[sockindex]) {
|
||||
/* BEGIN CONNECT PHASE */
|
||||
char *host_port;
|
||||
Curl_send_buffer *req_buffer;
|
||||
|
||||
|
@ -190,7 +228,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
|
|||
if(result)
|
||||
return result;
|
||||
|
||||
conn->bits.tunnel_connecting = TRUE;
|
||||
conn->tunnel_state[sockindex] = TUNNEL_CONNECT;
|
||||
} /* END CONNECT PHASE */
|
||||
|
||||
/* 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
|
||||
now have some data waiting.
|
||||
In any case, the tunnel_connecting phase is over. */
|
||||
conn->bits.tunnel_connecting = FALSE;
|
||||
|
||||
{ /* BEGIN NEGOTIATION PHASE */
|
||||
size_t nread; /* total size read */
|
||||
|
@ -516,9 +553,14 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
|
|||
if(closeConnection && data->req.newurl)
|
||||
conn->bits.proxy_connect_closed = TRUE;
|
||||
|
||||
/* to back to init state */
|
||||
conn->tunnel_state[sockindex] = TUNNEL_INIT;
|
||||
|
||||
return CURLE_RECV_ERROR;
|
||||
}
|
||||
|
||||
conn->tunnel_state[sockindex] = TUNNEL_COMPLETE;
|
||||
|
||||
/* 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
|
||||
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
|
||||
* you should have received as part of this distribution. The terms
|
||||
|
@ -21,6 +21,9 @@
|
|||
* KIND, either express or implied.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
CURLcode Curl_proxy_connect(struct connectdata *conn);
|
||||
|
||||
#if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP)
|
||||
/* ftp can use this as well */
|
||||
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
|
||||
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_WRITESOCK(0);
|
||||
|
@ -1066,7 +1066,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
|||
CURLM_STATE_WAITDO:CURLM_STATE_DO);
|
||||
else {
|
||||
#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);
|
||||
else
|
||||
#endif
|
||||
|
@ -1111,7 +1111,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
|||
CURLM_STATE_WAITDO:CURLM_STATE_DO);
|
||||
else {
|
||||
#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);
|
||||
else
|
||||
#endif
|
||||
|
@ -1144,7 +1144,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
|||
multistate(easy, CURLM_STATE_CONNECT);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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
|
||||
*/
|
||||
#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);
|
||||
else
|
||||
#endif
|
||||
|
|
33
lib/url.c
33
lib/url.c
|
@ -3391,36 +3391,9 @@ CURLcode Curl_protocol_connect(struct connectdata *conn,
|
|||
is later set again for the progress meter purpose */
|
||||
conn->now = Curl_tvnow();
|
||||
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
#else
|
||||
return CURLE_NOT_BUILT_IN;
|
||||
#endif
|
||||
}
|
||||
result = Curl_proxy_connect(conn);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
if(conn->handler->connect_it) {
|
||||
/* is there a protocol-specific connect() procedure? */
|
||||
|
|
|
@ -422,8 +422,6 @@ struct ConnectBits {
|
|||
This is implicit when SSL-protocols are used through
|
||||
proxies, but can also be enabled explicitly by
|
||||
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
|
||||
that we are creating a request with an auth header,
|
||||
but it is not the final request in the auth
|
||||
|
@ -964,6 +962,12 @@ struct connectdata {
|
|||
unsigned short localport;
|
||||
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. */
|
||||
|
|
Загрузка…
Ссылка в новой задаче