Loading CHANGES +5 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,11 @@ Changelog Daniel (25 February 2007) - Adam D. Moss made the HTTP CONNECT procedure less blocking when used from the multi interface. Note that it still does a part of the connection in a blocking manner. Daniel (23 February 2007) - Added warning outputs if the command line uses more than one of the options -v, --trace and --trace-ascii, since it could really confuse the user. Loading RELEASE-NOTES +3 −1 Original line number Diff line number Diff line Loading @@ -33,6 +33,8 @@ This release includes the following bugfixes: o curl-config --libs and libcurl.pc no longer list unnecessary dependencies o fixed an issue with CCC not working on some servers o several HTTP pipelining problems o HTTP CONNECT thru a proxy is now less blocking when the multi interface is used This release includes the following known bugs: Loading @@ -52,6 +54,6 @@ advice from friends like these: Yang Tse, Manfred Schwarb, Michael Wallner, Jeff Pohlmeyer, Shmulik Regev, Rob Crittenden, Robert A. Monat, Dan Fandrich, Duncan Mac-Vicar Prett, Michal Marek, Robson Braga Araujo, Ian Turner, Linus Nielsen Feltzing, Ravi Pratap Ravi Pratap, Adam D. Moss Thanks! (and sorry if I forgot to mention someone) lib/http.c +273 −218 Original line number Diff line number Diff line Loading @@ -1115,33 +1115,32 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, struct Curl_transfer_keeper *k = &data->reqdata.keep; CURLcode result; int res; size_t nread; /* total size read */ int perline; /* count bytes per line */ int keepon=TRUE; ssize_t gotbytes; char *ptr; long timeout = data->set.timeout?data->set.timeout:3600000; /* in milliseconds */ char *line_start; char *host_port; curl_socket_t tunnelsocket = conn->sock[sockindex]; send_buffer *req_buffer; curl_off_t cl=0; bool closeConnection = FALSE; long check; #define SELECT_OK 0 #define SELECT_ERROR 1 #define SELECT_TIMEOUT 2 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 (!conn->bits.tunnel_connecting) { /* BEGIN CONNECT PHASE */ char *host_port; send_buffer *req_buffer; infof(data, "Establish HTTP proxy tunnel to %s:%d\n", hostname, remote_port); if(data->reqdata.newurl) { /* This only happens if we've looped here due to authentication reasons, and we don't really use the newly cloned URL here then. Just free() it. */ /* This only happens if we've looped here due to authentication reasons, and we don't really use the newly cloned URL here then. Just free() it. */ free(data->reqdata.newurl); data->reqdata.newurl = NULL; } Loading Loading @@ -1214,6 +1213,53 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, if(result) return result; conn->bits.tunnel_connecting = TRUE; } /* END CONNECT PHASE */ /* now we've issued the CONNECT and we're waiting to hear back - we try not to block here in multi-mode because that might be a LONG wait if the proxy cannot connect-through to the remote host. */ /* if timeout is requested, find out how much remaining time we have */ check = timeout - /* timeout time */ Curl_tvdiff(Curl_tvnow(), conn->now); /* spent time */ if(check <=0 ) { failf(data, "Proxy CONNECT aborted due to timeout"); error = SELECT_TIMEOUT; /* already too little time */ break; } /* if we're in multi-mode and we would block, return instead for a retry */ if (Curl_if_multi == data->state.used_interface) { if (0 == Curl_select(tunnelsocket, CURL_SOCKET_BAD, 0)) /* return so we'll be called again polling-style */ return CURLE_OK; else { DEBUGF(infof(data, "Multi mode finished polling for response from " "proxy CONNECT.")); } } else { DEBUGF(infof(data, "Easy mode waiting for response from proxy CONNECT.")); } /* at this point, either: 1) we're in easy-mode and so it's okay to block waiting for a CONNECT response 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 */ int perline; /* count bytes per line */ int keepon=TRUE; ssize_t gotbytes; char *ptr; char *line_start; ptr=data->state.buffer; line_start = ptr; Loading @@ -1224,7 +1270,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, while((nread<BUFSIZE) && (keepon && !error)) { /* if timeout is requested, find out how much remaining time we have */ long check = timeout - /* timeout time */ check = timeout - /* timeout time */ Curl_tvdiff(Curl_tvnow(), conn->now); /* spent time */ if(check <= 0) { failf(data, "Proxy CONNECT aborted due to timeout"); Loading Loading @@ -1255,8 +1301,9 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, } else { /* * We got a whole chunk of data, which can be anything from one byte * to a set of lines and possibly just a piece of the last line. * We got a whole chunk of data, which can be anything from one * byte to a set of lines and possibly just a piece of the last * line. */ int i; Loading @@ -1264,8 +1311,8 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, if(keepon > TRUE) { /* This means we are currently ignoring a response-body, so we simply count down our counter and make sure to break out of the loop when we're done! */ simply count down our counter and make sure to break out of the loop when we're done! */ cl -= gotbytes; if(cl<=0) { keepon = FALSE; Loading Loading @@ -1300,15 +1347,16 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, if(('\r' == line_start[0]) || ('\n' == line_start[0])) { /* end of response-headers from the proxy */ if(cl && (407 == k->httpcode) && !data->state.authproblem) { /* If we get a 407 response code with content length when we * have no auth problem, we must ignore the whole * response-body */ if(cl && (407 == k->httpcode) && !data->state.authproblem) { /* If we get a 407 response code with content length * when we have no auth problem, we must ignore the * whole response-body */ keepon = 2; infof(data, "Ignore %" FORMAT_OFF_T " bytes of response-body\n", cl); cl -= (gotbytes - i);/* remove the remaining chunk of what we already read */ cl -= (gotbytes - i);/* remove the remaining chunk of what we already read */ if(cl<=0) /* if the whole thing was already read, we are done! */ keepon=FALSE; Loading @@ -1325,7 +1373,8 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, (401 == k->httpcode)) || (checkprefix("Proxy-authenticate:", line_start) && (407 == k->httpcode))) { result = Curl_http_input_auth(conn, k->httpcode, line_start); result = Curl_http_input_auth(conn, k->httpcode, line_start); if(result) return result; } Loading Loading @@ -1368,6 +1417,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, conn->sock[sockindex] = CURL_SOCKET_BAD; break; } } /* END NEGOTIATION PHASE */ } while(data->reqdata.newurl); if(200 != k->httpcode) { Loading Loading @@ -1423,6 +1473,11 @@ CURLcode Curl_http_connect(struct connectdata *conn, bool *done) return result; } if (conn->bits.tunnel_connecting) { /* nothing else to do except wait right now - we're not done here. */ return CURLE_OK; } if(!data->state.this_is_a_follow) { /* this is not a followed location, get the original host name */ if (data->state.first_host) Loading lib/multi.c +26 −6 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ #include "multiif.h" #include "sendf.h" #include "timeval.h" #include "http.h" /* The last #include file should be: */ #include "memdebug.h" Loading @@ -62,6 +63,7 @@ typedef enum { CURLM_STATE_CONNECT, /* resolve/connect has been sent off */ CURLM_STATE_WAITRESOLVE, /* awaiting the resolve to finalize */ CURLM_STATE_WAITCONNECT, /* awaiting the connect to finalize */ CURLM_STATE_WAITPROXYCONNECT, /* awaiting proxy CONNECT to finalize */ CURLM_STATE_PROTOCONNECT, /* completing the protocol-specific connect phase */ CURLM_STATE_WAITDO, /* wait for our turn to send the request */ Loading Loading @@ -791,7 +793,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, multistate(easy, CURLM_STATE_CONNECT); result = CURLM_CALL_MULTI_PERFORM; easy->result = CURLE_OK; } else { } else { easy->result = CURLE_COULDNT_CONNECT; multistate(easy, CURLM_STATE_COMPLETED); } Loading Loading @@ -871,9 +874,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, WAITDO! */ result = CURLM_CALL_MULTI_PERFORM; if(protocol_connect) { if(protocol_connect) multistate(easy, CURLM_STATE_WAITDO); } else { else { if (easy->easy_conn->bits.tunnel_connecting) multistate(easy, CURLM_STATE_WAITPROXYCONNECT); else multistate(easy, CURLM_STATE_WAITCONNECT); } } Loading Loading @@ -903,10 +909,14 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, result = CURLM_CALL_MULTI_PERFORM; if(protocol_connect) multistate(easy, CURLM_STATE_DO); else { if (easy->easy_conn->bits.tunnel_connecting) multistate(easy, CURLM_STATE_WAITPROXYCONNECT); else multistate(easy, CURLM_STATE_WAITCONNECT); } } } if(CURLE_OK != easy->result) { /* failure detected */ Loading @@ -917,6 +927,16 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, } break; case CURLM_STATE_WAITPROXYCONNECT: /* this is HTTP-specific, but sending CONNECT to a proxy is HTTP... */ easy->result = Curl_http_connect(easy->easy_conn, &protocol_connect); if(CURLE_OK == easy->result) { if (!easy->easy_conn->bits.tunnel_connecting) multistate(easy, CURLM_STATE_WAITCONNECT); } break; case CURLM_STATE_WAITCONNECT: /* awaiting a completion of an asynch connect */ easy->result = Curl_is_connected(easy->easy_conn, Loading lib/urldata.h +2 −0 Original line number Diff line number Diff line Loading @@ -470,6 +470,8 @@ 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 Loading Loading
CHANGES +5 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,11 @@ Changelog Daniel (25 February 2007) - Adam D. Moss made the HTTP CONNECT procedure less blocking when used from the multi interface. Note that it still does a part of the connection in a blocking manner. Daniel (23 February 2007) - Added warning outputs if the command line uses more than one of the options -v, --trace and --trace-ascii, since it could really confuse the user. Loading
RELEASE-NOTES +3 −1 Original line number Diff line number Diff line Loading @@ -33,6 +33,8 @@ This release includes the following bugfixes: o curl-config --libs and libcurl.pc no longer list unnecessary dependencies o fixed an issue with CCC not working on some servers o several HTTP pipelining problems o HTTP CONNECT thru a proxy is now less blocking when the multi interface is used This release includes the following known bugs: Loading @@ -52,6 +54,6 @@ advice from friends like these: Yang Tse, Manfred Schwarb, Michael Wallner, Jeff Pohlmeyer, Shmulik Regev, Rob Crittenden, Robert A. Monat, Dan Fandrich, Duncan Mac-Vicar Prett, Michal Marek, Robson Braga Araujo, Ian Turner, Linus Nielsen Feltzing, Ravi Pratap Ravi Pratap, Adam D. Moss Thanks! (and sorry if I forgot to mention someone)
lib/http.c +273 −218 Original line number Diff line number Diff line Loading @@ -1115,33 +1115,32 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, struct Curl_transfer_keeper *k = &data->reqdata.keep; CURLcode result; int res; size_t nread; /* total size read */ int perline; /* count bytes per line */ int keepon=TRUE; ssize_t gotbytes; char *ptr; long timeout = data->set.timeout?data->set.timeout:3600000; /* in milliseconds */ char *line_start; char *host_port; curl_socket_t tunnelsocket = conn->sock[sockindex]; send_buffer *req_buffer; curl_off_t cl=0; bool closeConnection = FALSE; long check; #define SELECT_OK 0 #define SELECT_ERROR 1 #define SELECT_TIMEOUT 2 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 (!conn->bits.tunnel_connecting) { /* BEGIN CONNECT PHASE */ char *host_port; send_buffer *req_buffer; infof(data, "Establish HTTP proxy tunnel to %s:%d\n", hostname, remote_port); if(data->reqdata.newurl) { /* This only happens if we've looped here due to authentication reasons, and we don't really use the newly cloned URL here then. Just free() it. */ /* This only happens if we've looped here due to authentication reasons, and we don't really use the newly cloned URL here then. Just free() it. */ free(data->reqdata.newurl); data->reqdata.newurl = NULL; } Loading Loading @@ -1214,6 +1213,53 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, if(result) return result; conn->bits.tunnel_connecting = TRUE; } /* END CONNECT PHASE */ /* now we've issued the CONNECT and we're waiting to hear back - we try not to block here in multi-mode because that might be a LONG wait if the proxy cannot connect-through to the remote host. */ /* if timeout is requested, find out how much remaining time we have */ check = timeout - /* timeout time */ Curl_tvdiff(Curl_tvnow(), conn->now); /* spent time */ if(check <=0 ) { failf(data, "Proxy CONNECT aborted due to timeout"); error = SELECT_TIMEOUT; /* already too little time */ break; } /* if we're in multi-mode and we would block, return instead for a retry */ if (Curl_if_multi == data->state.used_interface) { if (0 == Curl_select(tunnelsocket, CURL_SOCKET_BAD, 0)) /* return so we'll be called again polling-style */ return CURLE_OK; else { DEBUGF(infof(data, "Multi mode finished polling for response from " "proxy CONNECT.")); } } else { DEBUGF(infof(data, "Easy mode waiting for response from proxy CONNECT.")); } /* at this point, either: 1) we're in easy-mode and so it's okay to block waiting for a CONNECT response 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 */ int perline; /* count bytes per line */ int keepon=TRUE; ssize_t gotbytes; char *ptr; char *line_start; ptr=data->state.buffer; line_start = ptr; Loading @@ -1224,7 +1270,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, while((nread<BUFSIZE) && (keepon && !error)) { /* if timeout is requested, find out how much remaining time we have */ long check = timeout - /* timeout time */ check = timeout - /* timeout time */ Curl_tvdiff(Curl_tvnow(), conn->now); /* spent time */ if(check <= 0) { failf(data, "Proxy CONNECT aborted due to timeout"); Loading Loading @@ -1255,8 +1301,9 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, } else { /* * We got a whole chunk of data, which can be anything from one byte * to a set of lines and possibly just a piece of the last line. * We got a whole chunk of data, which can be anything from one * byte to a set of lines and possibly just a piece of the last * line. */ int i; Loading @@ -1264,8 +1311,8 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, if(keepon > TRUE) { /* This means we are currently ignoring a response-body, so we simply count down our counter and make sure to break out of the loop when we're done! */ simply count down our counter and make sure to break out of the loop when we're done! */ cl -= gotbytes; if(cl<=0) { keepon = FALSE; Loading Loading @@ -1300,15 +1347,16 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, if(('\r' == line_start[0]) || ('\n' == line_start[0])) { /* end of response-headers from the proxy */ if(cl && (407 == k->httpcode) && !data->state.authproblem) { /* If we get a 407 response code with content length when we * have no auth problem, we must ignore the whole * response-body */ if(cl && (407 == k->httpcode) && !data->state.authproblem) { /* If we get a 407 response code with content length * when we have no auth problem, we must ignore the * whole response-body */ keepon = 2; infof(data, "Ignore %" FORMAT_OFF_T " bytes of response-body\n", cl); cl -= (gotbytes - i);/* remove the remaining chunk of what we already read */ cl -= (gotbytes - i);/* remove the remaining chunk of what we already read */ if(cl<=0) /* if the whole thing was already read, we are done! */ keepon=FALSE; Loading @@ -1325,7 +1373,8 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, (401 == k->httpcode)) || (checkprefix("Proxy-authenticate:", line_start) && (407 == k->httpcode))) { result = Curl_http_input_auth(conn, k->httpcode, line_start); result = Curl_http_input_auth(conn, k->httpcode, line_start); if(result) return result; } Loading Loading @@ -1368,6 +1417,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, conn->sock[sockindex] = CURL_SOCKET_BAD; break; } } /* END NEGOTIATION PHASE */ } while(data->reqdata.newurl); if(200 != k->httpcode) { Loading Loading @@ -1423,6 +1473,11 @@ CURLcode Curl_http_connect(struct connectdata *conn, bool *done) return result; } if (conn->bits.tunnel_connecting) { /* nothing else to do except wait right now - we're not done here. */ return CURLE_OK; } if(!data->state.this_is_a_follow) { /* this is not a followed location, get the original host name */ if (data->state.first_host) Loading
lib/multi.c +26 −6 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ #include "multiif.h" #include "sendf.h" #include "timeval.h" #include "http.h" /* The last #include file should be: */ #include "memdebug.h" Loading @@ -62,6 +63,7 @@ typedef enum { CURLM_STATE_CONNECT, /* resolve/connect has been sent off */ CURLM_STATE_WAITRESOLVE, /* awaiting the resolve to finalize */ CURLM_STATE_WAITCONNECT, /* awaiting the connect to finalize */ CURLM_STATE_WAITPROXYCONNECT, /* awaiting proxy CONNECT to finalize */ CURLM_STATE_PROTOCONNECT, /* completing the protocol-specific connect phase */ CURLM_STATE_WAITDO, /* wait for our turn to send the request */ Loading Loading @@ -791,7 +793,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, multistate(easy, CURLM_STATE_CONNECT); result = CURLM_CALL_MULTI_PERFORM; easy->result = CURLE_OK; } else { } else { easy->result = CURLE_COULDNT_CONNECT; multistate(easy, CURLM_STATE_COMPLETED); } Loading Loading @@ -871,9 +874,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, WAITDO! */ result = CURLM_CALL_MULTI_PERFORM; if(protocol_connect) { if(protocol_connect) multistate(easy, CURLM_STATE_WAITDO); } else { else { if (easy->easy_conn->bits.tunnel_connecting) multistate(easy, CURLM_STATE_WAITPROXYCONNECT); else multistate(easy, CURLM_STATE_WAITCONNECT); } } Loading Loading @@ -903,10 +909,14 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, result = CURLM_CALL_MULTI_PERFORM; if(protocol_connect) multistate(easy, CURLM_STATE_DO); else { if (easy->easy_conn->bits.tunnel_connecting) multistate(easy, CURLM_STATE_WAITPROXYCONNECT); else multistate(easy, CURLM_STATE_WAITCONNECT); } } } if(CURLE_OK != easy->result) { /* failure detected */ Loading @@ -917,6 +927,16 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, } break; case CURLM_STATE_WAITPROXYCONNECT: /* this is HTTP-specific, but sending CONNECT to a proxy is HTTP... */ easy->result = Curl_http_connect(easy->easy_conn, &protocol_connect); if(CURLE_OK == easy->result) { if (!easy->easy_conn->bits.tunnel_connecting) multistate(easy, CURLM_STATE_WAITCONNECT); } break; case CURLM_STATE_WAITCONNECT: /* awaiting a completion of an asynch connect */ easy->result = Curl_is_connected(easy->easy_conn, Loading
lib/urldata.h +2 −0 Original line number Diff line number Diff line Loading @@ -470,6 +470,8 @@ 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 Loading