mirror of
https://github.com/curl/curl.git
synced 2026-07-30 04:28:02 +03:00
lib: transfer origin and proxy handling
Add `data->state.origin` as the origin the transfer is sending the current request to/gets the response from. Use it for request specific properties like authentication, hsts and cookie handling, etc. Unless talking to a forwarding HTTP proxy (e.g. not tunneling), `data->state.origin` and `conn->origin` are the same. With a forwarding HTTP proxy in play, `conn->origin` is set to `conn->http_proxy.peer` and `conn->bits.origin_is_proxy` (a new bit) is set. Remove the connection bits, now replaced with: * `conn->bits.socksproxy` -> `conn->socks_proy.peer` * `conn->bits.httpproxy` -> `conn->http_proy.peer` * `conn->bits.proxy` -> `(conn->socks_proy.peer || conn->http_proy.peer`) * `conn->bits.tunnel_proxy` -> (`conn->http_proy.peer && !conn->bits.origin_is_proxy`) * `(conn->bits.httpproxy && !conn->bits.tunnel_proxy)` -> `conn->bits.origin_is_proxy` Rename `noproxy.[ch]` to `proxy.[ch]`. Move the connection proxy setup code from `url.c` to `proxy.c`. Remove `data->info.conn_remote_port` as no one uses it. Add test_40_02b for a SOCKS connection to a forwarding HTTPS proxy. Update internal documentation about peers and creds. Closes #21967
This commit is contained in:
parent
c951368579
commit
73daec6620
30 changed files with 1083 additions and 1014 deletions
781
lib/url.c
781
lib/url.c
|
|
@ -86,7 +86,7 @@
|
|||
#include "urlapi-int.h"
|
||||
#include "system_win32.h"
|
||||
#include "hsts.h"
|
||||
#include "noproxy.h"
|
||||
#include "proxy.h"
|
||||
#include "cfilters.h"
|
||||
#include "idn.h"
|
||||
#include "http_proxy.h"
|
||||
|
|
@ -245,6 +245,7 @@ CURLcode Curl_close(struct Curl_easy **datap)
|
|||
|
||||
/* Close down all open SSL info and sessions */
|
||||
Curl_ssl_close_all(data);
|
||||
Curl_peer_unlink(&data->state.origin);
|
||||
Curl_peer_unlink(&data->state.initial_origin);
|
||||
Curl_ssl_free_certinfo(data);
|
||||
|
||||
|
|
@ -840,36 +841,27 @@ static bool url_match_ssl_use(struct connectdata *conn,
|
|||
static bool url_match_proxy_use(struct connectdata *conn,
|
||||
struct url_conn_match *m)
|
||||
{
|
||||
if(m->needle->bits.httpproxy != conn->bits.httpproxy ||
|
||||
m->needle->bits.socksproxy != conn->bits.socksproxy)
|
||||
if(m->needle->bits.origin_is_proxy != conn->bits.origin_is_proxy)
|
||||
return FALSE;
|
||||
|
||||
if(m->needle->bits.socksproxy &&
|
||||
!proxy_info_matches(&m->needle->socks_proxy, &conn->socks_proxy))
|
||||
if(!proxy_info_matches(&m->needle->socks_proxy, &conn->socks_proxy))
|
||||
return FALSE;
|
||||
|
||||
if(m->needle->bits.httpproxy) {
|
||||
if(m->needle->bits.tunnel_proxy != conn->bits.tunnel_proxy)
|
||||
return FALSE;
|
||||
if(!proxy_info_matches(&m->needle->http_proxy, &conn->http_proxy))
|
||||
return FALSE;
|
||||
|
||||
if(!proxy_info_matches(&m->needle->http_proxy, &conn->http_proxy))
|
||||
if(CURL_PROXY_IS_HTTPS(m->needle->http_proxy.proxytype)) {
|
||||
/* https proxies come in different types, http/1.1, h2, ... */
|
||||
/* match SSL config to proxy */
|
||||
if(!Curl_ssl_conn_config_match(m->data, conn, TRUE)) {
|
||||
DEBUGF(infof(m->data,
|
||||
"Connection #%" FMT_OFF_T
|
||||
" has different SSL proxy parameters, cannot reuse",
|
||||
conn->connection_id));
|
||||
return FALSE;
|
||||
|
||||
if(IS_HTTPS_PROXY(m->needle->http_proxy.proxytype)) {
|
||||
/* https proxies come in different types, http/1.1, h2, ... */
|
||||
if(m->needle->http_proxy.proxytype != conn->http_proxy.proxytype)
|
||||
return FALSE;
|
||||
/* match SSL config to proxy */
|
||||
if(!Curl_ssl_conn_config_match(m->data, conn, TRUE)) {
|
||||
DEBUGF(infof(m->data,
|
||||
"Connection #%" FMT_OFF_T
|
||||
" has different SSL proxy parameters, cannot reuse",
|
||||
conn->connection_id));
|
||||
return FALSE;
|
||||
}
|
||||
/* the SSL config to the server, which may apply here is checked
|
||||
* further below */
|
||||
}
|
||||
/* the SSL config to the server, which may apply here is checked
|
||||
* further below */
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -981,14 +973,6 @@ static bool url_match_destination(struct connectdata *conn,
|
|||
if(!Curl_peer_same_destination(m->needle->via_peer, conn->via_peer))
|
||||
return FALSE;
|
||||
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
if(m->needle->bits.httpproxy && !m->needle->bits.tunnel_proxy) {
|
||||
/* Talking to a non-tunneling HTTP proxy matches on proxy peers. */
|
||||
return Curl_peer_equal(m->needle->http_proxy.peer,
|
||||
conn->http_proxy.peer);
|
||||
}
|
||||
#endif
|
||||
|
||||
if(m->needle->origin->scheme != conn->origin->scheme) {
|
||||
/* `needle` and `conn` not having the same scheme.
|
||||
* This is allowed for the same family *if* conn is using TLS.
|
||||
|
|
@ -1310,28 +1294,6 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
|
|||
/* Store current time to give a baseline to keepalive connection times. */
|
||||
conn->keepalive = conn->created;
|
||||
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
conn->http_proxy.proxytype = data->set.proxytype;
|
||||
conn->socks_proxy.proxytype = CURLPROXY_SOCKS4;
|
||||
|
||||
/* note that these two proxy bits are set on what looks to be
|
||||
requested, they may be altered down the road */
|
||||
conn->bits.proxy = (data->set.str[STRING_PROXY] &&
|
||||
*data->set.str[STRING_PROXY]);
|
||||
conn->bits.httpproxy = (conn->bits.proxy &&
|
||||
(conn->http_proxy.proxytype == CURLPROXY_HTTP ||
|
||||
conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0 ||
|
||||
IS_HTTPS_PROXY(conn->http_proxy.proxytype)));
|
||||
conn->bits.socksproxy = (conn->bits.proxy && !conn->bits.httpproxy);
|
||||
|
||||
if(data->set.str[STRING_PRE_PROXY] && *data->set.str[STRING_PRE_PROXY]) {
|
||||
conn->bits.proxy = TRUE;
|
||||
conn->bits.socksproxy = TRUE;
|
||||
}
|
||||
|
||||
conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy;
|
||||
#endif /* CURL_DISABLE_PROXY */
|
||||
|
||||
#ifndef CURL_DISABLE_FTP
|
||||
conn->bits.ftp_use_epsv = data->set.ftp_use_epsv;
|
||||
conn->bits.ftp_use_eprt = data->set.ftp_use_eprt;
|
||||
|
|
@ -1406,14 +1368,13 @@ CURLcode Curl_uc_to_curlcode(CURLUcode uc)
|
|||
|
||||
#ifndef CURL_DISABLE_HSTS
|
||||
static CURLcode hsts_upgrade(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
CURLU *uh,
|
||||
uint16_t port_override,
|
||||
uint32_t scope_id)
|
||||
{
|
||||
/* HSTS upgrade */
|
||||
if(data->hsts && (conn->origin->scheme == &Curl_scheme_http) &&
|
||||
Curl_hsts_applies(data->hsts, conn->origin)) {
|
||||
if(data->hsts && (data->state.origin->scheme == &Curl_scheme_http) &&
|
||||
Curl_hsts_applies(data->hsts, data->state.origin)) {
|
||||
char *url;
|
||||
CURLUcode uc;
|
||||
CURLcode result;
|
||||
|
|
@ -1430,7 +1391,7 @@ static CURLcode hsts_upgrade(struct Curl_easy *data,
|
|||
Curl_bufref_set(&data->state.url, url, 0, curl_free);
|
||||
|
||||
result = Curl_peer_from_url(uh, data, port_override, scope_id,
|
||||
&data->state.up, &conn->origin);
|
||||
&data->state.up, &data->state.origin);
|
||||
if(result)
|
||||
return result;
|
||||
infof(data, "Switched from HTTP to HTTPS due to HSTS => %s", url);
|
||||
|
|
@ -1438,7 +1399,7 @@ static CURLcode hsts_upgrade(struct Curl_easy *data,
|
|||
return CURLE_OK;
|
||||
}
|
||||
#else
|
||||
#define hsts_upgrade(x, y, z, a, b) CURLE_OK
|
||||
#define hsts_upgrade(x, y, z, a) CURLE_OK
|
||||
#endif
|
||||
|
||||
#ifndef CURL_DISABLE_NETRC
|
||||
|
|
@ -1460,7 +1421,6 @@ static bool str_has_ctrl(const char *input)
|
|||
* option or a .netrc file, if applicable.
|
||||
*/
|
||||
static CURLcode url_set_data_creds_netrc(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
struct Curl_creds **pcreds)
|
||||
{
|
||||
struct Curl_creds *ncreds_out = NULL;
|
||||
|
|
@ -1500,7 +1460,7 @@ static CURLcode url_set_data_creds_netrc(struct Curl_easy *data,
|
|||
goto out;
|
||||
|
||||
ret = Curl_netrc_scan(data, &data->state.netrc,
|
||||
conn->origin->hostname,
|
||||
data->state.origin->hostname,
|
||||
Curl_creds_user(ncreds_in),
|
||||
data->set.str[STRING_NETRC_FILE],
|
||||
&ncreds_out);
|
||||
|
|
@ -1512,7 +1472,7 @@ static CURLcode url_set_data_creds_netrc(struct Curl_easy *data,
|
|||
else if(ret && ((ret == NETRC_NO_MATCH) ||
|
||||
(data->set.use_netrc == CURL_NETRC_OPTIONAL))) {
|
||||
infof(data, "Could not find host %s in the %s file; using defaults",
|
||||
conn->origin->hostname,
|
||||
data->state.origin->hostname,
|
||||
(data->set.str[STRING_NETRC_FILE] ?
|
||||
data->set.str[STRING_NETRC_FILE] : ".netrc"));
|
||||
}
|
||||
|
|
@ -1523,7 +1483,7 @@ static CURLcode url_set_data_creds_netrc(struct Curl_easy *data,
|
|||
goto out;
|
||||
}
|
||||
else if(ncreds_out) {
|
||||
if(!(conn->scheme->flags & PROTOPT_USERPWDCTRL)) {
|
||||
if(!(data->state.origin->scheme->flags & PROTOPT_USERPWDCTRL)) {
|
||||
/* if the protocol cannot handle control codes in credentials, make
|
||||
sure there are none */
|
||||
if(str_has_ctrl(ncreds_out->user) ||
|
||||
|
|
@ -1534,7 +1494,7 @@ static CURLcode url_set_data_creds_netrc(struct Curl_easy *data,
|
|||
}
|
||||
}
|
||||
CURL_TRC_M(data, "netrc: using credentials for %s as %s",
|
||||
conn->origin->hostname, ncreds_out->user);
|
||||
data->state.origin->hostname, ncreds_out->user);
|
||||
result = Curl_creds_merge(ncreds_out->user, ncreds_out->passwd,
|
||||
*pcreds, CREDS_NETRC, pcreds);
|
||||
if(result)
|
||||
|
|
@ -1553,15 +1513,17 @@ static CURLcode url_set_data_creds_netrc(struct Curl_easy *data,
|
|||
DEBUGASSERT(0);
|
||||
}
|
||||
|
||||
#ifdef CURLVERBOSE
|
||||
Curl_creds_trace(data, data->state.creds, "transfer credentials");
|
||||
#endif
|
||||
|
||||
out:
|
||||
Curl_creds_unlink(&ncreds_out);
|
||||
return result;
|
||||
}
|
||||
#endif /* CURL_DISABLE_NETRC */
|
||||
|
||||
static CURLcode url_set_data_creds(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
CURLU *uh)
|
||||
static CURLcode url_set_data_creds(struct Curl_easy *data, CURLU *uh)
|
||||
{
|
||||
struct Curl_creds *newcreds = NULL;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
|
@ -1571,7 +1533,7 @@ static CURLcode url_set_data_creds(struct Curl_easy *data,
|
|||
data->set.str[STRING_BEARER] ||
|
||||
data->set.str[STRING_SASL_AUTHZID] ||
|
||||
data->set.str[STRING_SERVICE_NAME]) &&
|
||||
Curl_auth_allowed_to_origin(data, conn->origin)) {
|
||||
Curl_auth_allowed_to_origin(data, data->state.origin)) {
|
||||
result = Curl_creds_create(data->set.str[STRING_USERNAME],
|
||||
data->set.str[STRING_PASSWORD],
|
||||
data->set.str[STRING_BEARER],
|
||||
|
|
@ -1599,12 +1561,14 @@ static CURLcode url_set_data_creds(struct Curl_easy *data,
|
|||
}
|
||||
if(!result && data->state.up.user) {
|
||||
result = Curl_urldecode(data->state.up.user, 0, &udecoded, NULL,
|
||||
conn->scheme->flags&PROTOPT_USERPWDCTRL ?
|
||||
(data->state.origin->scheme->flags &
|
||||
PROTOPT_USERPWDCTRL) ?
|
||||
REJECT_ZERO : REJECT_CTRL);
|
||||
}
|
||||
if(!result && data->state.up.password) {
|
||||
result = Curl_urldecode(data->state.up.password, 0, &pdecoded, NULL,
|
||||
conn->scheme->flags&PROTOPT_USERPWDCTRL ?
|
||||
(data->state.origin->scheme->flags &
|
||||
PROTOPT_USERPWDCTRL) ?
|
||||
REJECT_ZERO : REJECT_CTRL);
|
||||
}
|
||||
if(!result)
|
||||
|
|
@ -1622,7 +1586,7 @@ static CURLcode url_set_data_creds(struct Curl_easy *data,
|
|||
#ifndef CURL_DISABLE_NETRC
|
||||
/* Check for overridden login details and set them accordingly so that
|
||||
they are known when protocol->setup_connection is called! */
|
||||
result = url_set_data_creds_netrc(data, conn, &newcreds);
|
||||
result = url_set_data_creds_netrc(data, &newcreds);
|
||||
#endif /* CURL_DISABLE_NETRC */
|
||||
|
||||
out:
|
||||
|
|
@ -1634,139 +1598,37 @@ out:
|
|||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse URL and fill in the relevant members of the connection struct.
|
||||
*/
|
||||
static CURLcode parseurlandfillconn(struct Curl_easy *data,
|
||||
struct connectdata *conn)
|
||||
static CURLcode url_set_conn_origin_etc(struct Curl_easy *data,
|
||||
struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
CURLU *uh;
|
||||
CURLUcode uc;
|
||||
bool use_set_uh = (data->set.uh && !data->state.this_is_a_follow);
|
||||
uint16_t port_override = data->state.allow_port ? data->set.use_port : 0;
|
||||
uint32_t scope_id = 0;
|
||||
|
||||
up_free(data); /* cleanup previous leftovers first */
|
||||
Curl_peer_link(&conn->origin, data->state.origin);
|
||||
|
||||
/* parse the URL */
|
||||
if(use_set_uh)
|
||||
uh = data->state.uh = curl_url_dup(data->set.uh);
|
||||
else
|
||||
uh = data->state.uh = curl_url();
|
||||
if(!uh) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Calculate the *real* URL this transfer uses, applying defaults
|
||||
* where information is missing. */
|
||||
if(data->set.str[STRING_DEFAULT_PROTOCOL] &&
|
||||
!Curl_is_absolute_url(Curl_bufref_ptr(&data->state.url), NULL, 0, TRUE)) {
|
||||
char *url = curl_maprintf("%s://%s",
|
||||
data->set.str[STRING_DEFAULT_PROTOCOL],
|
||||
Curl_bufref_ptr(&data->state.url));
|
||||
if(!url) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
Curl_bufref_set(&data->state.url, url, 0, curl_free);
|
||||
}
|
||||
|
||||
if(!use_set_uh) {
|
||||
char *newurl;
|
||||
uc = curl_url_set(uh, CURLUPART_URL, Curl_bufref_ptr(&data->state.url),
|
||||
(unsigned int)(CURLU_GUESS_SCHEME |
|
||||
CURLU_NON_SUPPORT_SCHEME |
|
||||
(data->set.disallow_username_in_url ?
|
||||
CURLU_DISALLOW_USER : 0) |
|
||||
(data->set.path_as_is ? CURLU_PATH_AS_IS : 0)));
|
||||
if(uc) {
|
||||
failf(data, "URL rejected: %s", curl_url_strerror(uc));
|
||||
result = Curl_uc_to_curlcode(uc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* after it was parsed, get the generated normalized version */
|
||||
uc = curl_url_get(uh, CURLUPART_URL, &newurl, CURLU_GET_EMPTY);
|
||||
if(uc) {
|
||||
result = Curl_uc_to_curlcode(uc);
|
||||
goto out;
|
||||
}
|
||||
Curl_bufref_set(&data->state.url, newurl, 0, curl_free);
|
||||
}
|
||||
|
||||
#ifdef USE_IPV6
|
||||
scope_id = data->set.scope_id;
|
||||
#endif
|
||||
|
||||
/* `uh` is now as the connection should use it, probably. */
|
||||
result = Curl_peer_from_url(uh, data, port_override, scope_id,
|
||||
&data->state.up, &conn->origin);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
result = hsts_upgrade(data, conn, uh, port_override, scope_id);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
/* now that the origin is fixed, check and set the connection scheme */
|
||||
/* set the connection scheme */
|
||||
result = url_set_conn_scheme(data, conn, conn->origin->scheme);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
/* When the transfers initial_origin is not set, this is the initial
|
||||
* request. Remember this starting point. This is used to
|
||||
* select credentials. */
|
||||
if(!data->state.initial_origin)
|
||||
Curl_peer_link(&data->state.initial_origin, conn->origin);
|
||||
|
||||
result = url_set_data_creds(data, conn, uh);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
uc = curl_url_get(uh, CURLUPART_OPTIONS, &data->state.up.options,
|
||||
CURLU_URLDECODE);
|
||||
if(!uc) {
|
||||
conn->options = curlx_strdup(data->state.up.options);
|
||||
if(!conn->options) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
else if(uc != CURLUE_NO_OPTIONS) {
|
||||
result = Curl_uc_to_curlcode(uc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
uc = curl_url_get(uh, CURLUPART_PATH, &data->state.up.path, CURLU_URLENCODE);
|
||||
if(uc) {
|
||||
result = Curl_uc_to_curlcode(uc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
uc = curl_url_get(uh, CURLUPART_QUERY, &data->state.up.query,
|
||||
CURLU_GET_EMPTY);
|
||||
if(uc && (uc != CURLUE_NO_QUERY)) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef USE_IPV6
|
||||
/* Fill in the conn parts that do not use authority, yet. */
|
||||
conn->scope_id = conn->origin->scopeid;
|
||||
#endif
|
||||
/* set the connection options */
|
||||
if(data->set.str[STRING_OPTIONS]) {
|
||||
curlx_free(conn->options);
|
||||
conn->options = curlx_strdup(data->set.str[STRING_OPTIONS]);
|
||||
if(!conn->options) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
else if(data->state.up.options) {
|
||||
conn->options = curlx_strdup(data->state.up.options);
|
||||
if(!conn->options) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CURLVERBOSE
|
||||
Curl_creds_trace(data, data->state.creds, "transfer credentials");
|
||||
#ifdef USE_IPV6
|
||||
conn->scope_id = data->set.scope_id ?
|
||||
data->set.scope_id : data->state.origin->scopeid;
|
||||
#endif
|
||||
|
||||
out:
|
||||
|
|
@ -1852,379 +1714,6 @@ static CURLcode setup_connection_internals(struct Curl_easy *data,
|
|||
return CURLE_OK;
|
||||
}
|
||||
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
|
||||
#ifndef CURL_DISABLE_HTTP
|
||||
/****************************************************************
|
||||
* Detect what (if any) proxy to use. Remember that this selects a host
|
||||
* name and is not limited to HTTP proxies only.
|
||||
* The returned pointer must be freed by the caller (unless NULL)
|
||||
****************************************************************/
|
||||
static char *url_detect_proxy(struct Curl_easy *data,
|
||||
struct connectdata *conn)
|
||||
{
|
||||
char *proxy = NULL;
|
||||
|
||||
/* If proxy was not specified, we check for default proxy environment
|
||||
* variables, to enable i.e Lynx compliance:
|
||||
*
|
||||
* http_proxy=http://some.server.dom:port/
|
||||
* https_proxy=http://some.server.dom:port/
|
||||
* ftp_proxy=http://some.server.dom:port/
|
||||
* no_proxy=domain1.dom,host.domain2.dom
|
||||
* (a comma-separated list of hosts which should
|
||||
* not be proxied, or an asterisk to override
|
||||
* all proxy variables)
|
||||
* all_proxy=http://some.server.dom:port/
|
||||
* (seems to exist for the CERN www lib. Probably
|
||||
* the first to check for.)
|
||||
*
|
||||
* For compatibility, the all-uppercase versions of these variables are
|
||||
* checked if the lowercase versions do not exist.
|
||||
*/
|
||||
char proxy_env[20];
|
||||
const char *envp;
|
||||
VERBOSE(envp = proxy_env);
|
||||
|
||||
curl_msnprintf(proxy_env, sizeof(proxy_env), "%s_proxy",
|
||||
conn->scheme->name);
|
||||
|
||||
/* read the protocol proxy: */
|
||||
proxy = curl_getenv(proxy_env);
|
||||
|
||||
/*
|
||||
* We do not try the uppercase version of HTTP_PROXY because of
|
||||
* security reasons:
|
||||
*
|
||||
* When curl is used in a webserver application
|
||||
* environment (cgi or php), this environment variable can
|
||||
* be controlled by the web server user by setting the
|
||||
* http header 'Proxy:' to some value.
|
||||
*
|
||||
* This can cause 'internal' http/ftp requests to be
|
||||
* arbitrarily redirected by any external attacker.
|
||||
*/
|
||||
if(!proxy && !curl_strequal("http_proxy", proxy_env)) {
|
||||
/* There was no lowercase variable, try the uppercase version: */
|
||||
Curl_strntoupper(proxy_env, proxy_env, sizeof(proxy_env));
|
||||
proxy = curl_getenv(proxy_env);
|
||||
}
|
||||
|
||||
if(!proxy) {
|
||||
#ifndef CURL_DISABLE_WEBSOCKETS
|
||||
/* websocket proxy fallbacks */
|
||||
if(curl_strequal("ws_proxy", proxy_env)) {
|
||||
proxy = curl_getenv("http_proxy");
|
||||
}
|
||||
else if(curl_strequal("wss_proxy", proxy_env)) {
|
||||
proxy = curl_getenv("https_proxy");
|
||||
if(!proxy)
|
||||
proxy = curl_getenv("HTTPS_PROXY");
|
||||
}
|
||||
if(!proxy) {
|
||||
#endif
|
||||
envp = "all_proxy";
|
||||
proxy = curl_getenv(envp); /* default proxy to use */
|
||||
if(!proxy) {
|
||||
envp = "ALL_PROXY";
|
||||
proxy = curl_getenv(envp);
|
||||
}
|
||||
#ifndef CURL_DISABLE_WEBSOCKETS
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if(proxy)
|
||||
infof(data, "Uses proxy env variable %s == '%s'", envp, proxy);
|
||||
|
||||
return proxy;
|
||||
}
|
||||
#endif /* CURL_DISABLE_HTTP */
|
||||
|
||||
/*
|
||||
* If this is supposed to use a proxy, we need to figure out the proxy
|
||||
* hostname, so that we can reuse an existing connection
|
||||
* that may exist registered to the same proxy host.
|
||||
*/
|
||||
static CURLcode parse_proxy(struct Curl_easy *data,
|
||||
const char *proxy,
|
||||
bool for_pre_proxy,
|
||||
struct proxy_info *proxyinfo)
|
||||
{
|
||||
char *proxyuser = NULL;
|
||||
char *proxypasswd = NULL;
|
||||
char *scheme = NULL;
|
||||
CURLcode result = CURLE_OK;
|
||||
/* Set the start proxy type for url scheme guessing */
|
||||
uint8_t proxytype = for_pre_proxy ? CURLPROXY_SOCKS4 : data->set.proxytype;
|
||||
CURLU *uhp = curl_url();
|
||||
CURLUcode uc;
|
||||
|
||||
if(!uhp) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto error;
|
||||
}
|
||||
/* When parsing the proxy, allowing non-supported schemes since we have
|
||||
these made up ones for proxies. Guess scheme for URLs without it. */
|
||||
uc = curl_url_set(uhp, CURLUPART_URL, proxy,
|
||||
CURLU_NON_SUPPORT_SCHEME | CURLU_GUESS_SCHEME);
|
||||
if(!uc) {
|
||||
/* parsed okay as a URL - only update proxytype when scheme was explicit */
|
||||
uc = curl_url_get(uhp, CURLUPART_SCHEME, &scheme, CURLU_NO_GUESS_SCHEME);
|
||||
if(!uc) {
|
||||
result = Curl_scheme_to_proxytype(data, scheme, &proxytype, proxy);
|
||||
if(result)
|
||||
goto error;
|
||||
}
|
||||
else if(uc != CURLUE_NO_SCHEME) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto error;
|
||||
}
|
||||
/* else: no explicit scheme, keep the configured proxytype */
|
||||
}
|
||||
else {
|
||||
failf(data, "Unsupported proxy syntax in \'%s\': %s", proxy,
|
||||
curl_url_strerror(uc));
|
||||
result = CURLE_COULDNT_RESOLVE_PROXY;
|
||||
goto error;
|
||||
}
|
||||
|
||||
result = Curl_peer_from_proxy_url(uhp, data, proxy, proxytype,
|
||||
&proxyinfo->peer, &proxytype);
|
||||
if(result)
|
||||
goto error;
|
||||
|
||||
switch(proxytype) {
|
||||
case CURLPROXY_HTTP:
|
||||
case CURLPROXY_HTTP_1_0:
|
||||
case CURLPROXY_HTTPS:
|
||||
case CURLPROXY_HTTPS2:
|
||||
case CURLPROXY_HTTPS3:
|
||||
if(for_pre_proxy) {
|
||||
failf(data, "Unsupported pre-proxy type for \'%s\'", proxy);
|
||||
result = CURLE_COULDNT_RESOLVE_PROXY;
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
case CURLPROXY_SOCKS4:
|
||||
case CURLPROXY_SOCKS4A:
|
||||
case CURLPROXY_SOCKS5:
|
||||
case CURLPROXY_SOCKS5_HOSTNAME:
|
||||
break;
|
||||
default:
|
||||
failf(data, "Unsupported proxy type %u for \'%s\'", proxytype, proxy);
|
||||
result = CURLE_COULDNT_RESOLVE_PROXY;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Is there a username and password given in this proxy URL? */
|
||||
uc = curl_url_get(uhp, CURLUPART_USER, &proxyuser, CURLU_URLDECODE);
|
||||
if(uc && (uc != CURLUE_NO_USER)) {
|
||||
result = Curl_uc_to_curlcode(uc);
|
||||
goto error;
|
||||
}
|
||||
uc = curl_url_get(uhp, CURLUPART_PASSWORD, &proxypasswd, CURLU_URLDECODE);
|
||||
if(uc && (uc != CURLUE_NO_PASSWORD)) {
|
||||
result = Curl_uc_to_curlcode(uc);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if(proxyuser || proxypasswd) {
|
||||
result = Curl_creds_create(proxyuser, proxypasswd, NULL, NULL,
|
||||
data->set.str[STRING_PROXY_SERVICE_NAME],
|
||||
CREDS_URL, &proxyinfo->creds);
|
||||
if(result)
|
||||
goto error;
|
||||
}
|
||||
else if(!for_pre_proxy &&
|
||||
(data->set.str[STRING_PROXYUSERNAME] ||
|
||||
data->set.str[STRING_PROXYPASSWORD] ||
|
||||
data->set.str[STRING_PROXY_SERVICE_NAME])) {
|
||||
/* No user/passwd in URL, if this is not a pre-proxy, the
|
||||
* CURLOPT_PROXY* settings apply. */
|
||||
result = Curl_creds_create(data->set.str[STRING_PROXYUSERNAME],
|
||||
data->set.str[STRING_PROXYPASSWORD],
|
||||
NULL, NULL,
|
||||
data->set.str[STRING_PROXY_SERVICE_NAME],
|
||||
CREDS_OPTION, &proxyinfo->creds);
|
||||
}
|
||||
else
|
||||
Curl_creds_unlink(&proxyinfo->creds);
|
||||
|
||||
proxyinfo->proxytype = proxytype;
|
||||
|
||||
error:
|
||||
curlx_free(scheme);
|
||||
curlx_free(proxyuser);
|
||||
curlx_free(proxypasswd);
|
||||
curl_url_cleanup(uhp);
|
||||
#ifdef DEBUGBUILD
|
||||
if(!result) {
|
||||
DEBUGASSERT(proxyinfo);
|
||||
DEBUGASSERT(proxyinfo->peer);
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode url_set_conn_proxies(struct Curl_easy *data,
|
||||
struct connectdata *conn)
|
||||
{
|
||||
char *proxy = NULL;
|
||||
char *pre_proxy = NULL;
|
||||
char *no_proxy = NULL;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
/*************************************************************
|
||||
* Detect what (if any) proxy to use
|
||||
*************************************************************/
|
||||
if(data->set.str[STRING_PROXY]) {
|
||||
proxy = curlx_strdup(data->set.str[STRING_PROXY]);
|
||||
/* if global proxy is set, this is it */
|
||||
if(!proxy) {
|
||||
failf(data, "memory shortage");
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if(data->set.str[STRING_PRE_PROXY]) {
|
||||
pre_proxy = curlx_strdup(data->set.str[STRING_PRE_PROXY]);
|
||||
/* if global socks proxy is set, this is it */
|
||||
if(!pre_proxy) {
|
||||
failf(data, "memory shortage");
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if(!data->set.str[STRING_NOPROXY]) {
|
||||
const char *p = "no_proxy";
|
||||
no_proxy = curl_getenv(p);
|
||||
if(!no_proxy) {
|
||||
p = "NO_PROXY";
|
||||
no_proxy = curl_getenv(p);
|
||||
}
|
||||
if(no_proxy) {
|
||||
infof(data, "Uses proxy env variable %s == '%s'", p, no_proxy);
|
||||
}
|
||||
}
|
||||
|
||||
if(Curl_check_noproxy(conn->origin->hostname, data->set.str[STRING_NOPROXY] ?
|
||||
data->set.str[STRING_NOPROXY] : no_proxy)) {
|
||||
curlx_safefree(proxy);
|
||||
curlx_safefree(pre_proxy);
|
||||
}
|
||||
#ifndef CURL_DISABLE_HTTP
|
||||
else if(!proxy && !pre_proxy)
|
||||
/* if the host is not in the noproxy list, detect proxy. */
|
||||
proxy = url_detect_proxy(data, conn);
|
||||
#endif /* CURL_DISABLE_HTTP */
|
||||
curlx_safefree(no_proxy);
|
||||
|
||||
if(proxy && (!*proxy || (conn->scheme->flags & PROTOPT_NONETWORK))) {
|
||||
curlx_safefree(proxy); /* Do not bother with an empty proxy string
|
||||
or if the protocol does not work with network */
|
||||
}
|
||||
if(pre_proxy && (!*pre_proxy ||
|
||||
(conn->scheme->flags & PROTOPT_NONETWORK))) {
|
||||
curlx_safefree(pre_proxy); /* Do not bother with an empty socks proxy
|
||||
string or if the protocol does not work
|
||||
with network */
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* If this is supposed to use a proxy, we need to figure out the proxy host
|
||||
* name, proxy type and port number, so that we can reuse an existing
|
||||
* connection that may exist registered to the same proxy host.
|
||||
***********************************************************************/
|
||||
if(proxy || pre_proxy) {
|
||||
if(pre_proxy) {
|
||||
result = parse_proxy(data, pre_proxy, TRUE, &conn->socks_proxy);
|
||||
if(result)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if(proxy) {
|
||||
result = parse_proxy(data, proxy, FALSE, &conn->http_proxy);
|
||||
if(result)
|
||||
goto out;
|
||||
switch(conn->http_proxy.proxytype) {
|
||||
case CURLPROXY_SOCKS4:
|
||||
case CURLPROXY_SOCKS4A:
|
||||
case CURLPROXY_SOCKS5:
|
||||
case CURLPROXY_SOCKS5_HOSTNAME:
|
||||
/* Whoops, it's not a HTTP proxy */
|
||||
if(conn->socks_proxy.peer) {
|
||||
/* and we already have a SOCKS pre-proxy. Cannot have both */
|
||||
failf(data, "Having a SOCKS pre-proxy and proxy is not "
|
||||
"supported with \'%s\'", proxy);
|
||||
result = CURLE_COULDNT_RESOLVE_PROXY;
|
||||
goto out;
|
||||
}
|
||||
/* switch */
|
||||
conn->socks_proxy = conn->http_proxy;
|
||||
memset(&conn->http_proxy, 0, sizeof(conn->http_proxy));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(conn->http_proxy.peer) {
|
||||
#ifdef CURL_DISABLE_HTTP
|
||||
/* asking for an HTTP proxy is a bit funny when HTTP is disabled... */
|
||||
result = CURLE_UNSUPPORTED_PROTOCOL;
|
||||
goto out;
|
||||
#else
|
||||
#ifndef CURL_DISABLE_DIGEST_AUTH
|
||||
if(!Curl_safecmp(data->state.envproxy, proxy)) {
|
||||
/* proxy changed */
|
||||
Curl_auth_digest_cleanup(&data->state.proxydigest);
|
||||
curlx_free(data->state.envproxy);
|
||||
data->state.envproxy = curlx_strdup(proxy);
|
||||
}
|
||||
#endif
|
||||
if(conn->scheme->flags & PROTOPT_HTTP_PROXY_TUNNEL) {
|
||||
conn->bits.tunnel_proxy = TRUE;
|
||||
}
|
||||
else if(!(conn->scheme->protocol & PROTO_FAMILY_HTTP)) {
|
||||
/* force this connection's protocol to become HTTP if compatible */
|
||||
if((conn->scheme->flags & PROTOPT_PROXY_AS_HTTP) &&
|
||||
!conn->bits.tunnel_proxy)
|
||||
conn->scheme = &Curl_scheme_http;
|
||||
else
|
||||
/* if not converting to HTTP over the proxy, enforce tunneling */
|
||||
conn->bits.tunnel_proxy = TRUE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
conn->bits.tunnel_proxy = FALSE; /* no tunneling if not HTTP */
|
||||
}
|
||||
|
||||
conn->bits.socksproxy = !!conn->socks_proxy.peer;
|
||||
conn->bits.httpproxy = !!conn->http_proxy.peer;
|
||||
conn->bits.proxy = conn->bits.httpproxy || conn->bits.socksproxy;
|
||||
|
||||
if(!conn->bits.proxy) {
|
||||
/* we are not using the proxy after all... */
|
||||
conn->bits.proxy = FALSE;
|
||||
conn->bits.httpproxy = FALSE;
|
||||
conn->bits.socksproxy = FALSE;
|
||||
conn->bits.tunnel_proxy = FALSE;
|
||||
/* CURLPROXY_HTTPS does not have its own flag in conn->bits, yet we need
|
||||
to signal that CURLPROXY_HTTPS is not used for this connection */
|
||||
conn->http_proxy.proxytype = CURLPROXY_HTTP;
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
curlx_free(pre_proxy);
|
||||
curlx_free(proxy);
|
||||
return result;
|
||||
}
|
||||
#endif /* CURL_DISABLE_PROXY */
|
||||
|
||||
/*
|
||||
* Curl_parse_login_details()
|
||||
*
|
||||
|
|
@ -2601,14 +2090,6 @@ static CURLcode url_create_needle(struct Curl_easy *data,
|
|||
CURLcode result = CURLE_OK;
|
||||
bool network_scheme = TRUE; /* almost all are */
|
||||
|
||||
/*************************************************************
|
||||
* Check input data
|
||||
*************************************************************/
|
||||
if(!Curl_bufref_ptr(&data->state.url)) {
|
||||
result = CURLE_URL_MALFORMAT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* First, split up the current URL in parts so that we can use the
|
||||
parts for checking against the already present connections. In order
|
||||
to not have to modify everything at once, we allocate a temporary
|
||||
|
|
@ -2627,7 +2108,7 @@ static CURLcode url_create_needle(struct Curl_easy *data,
|
|||
* Determine `conn->origin` and propulate `data->state.up` and
|
||||
* other URL related properties.
|
||||
*************************************************************/
|
||||
result = parseurlandfillconn(data, needle);
|
||||
result = url_set_conn_origin_etc(data, needle);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
|
|
@ -2661,22 +2142,11 @@ static CURLcode url_create_needle(struct Curl_easy *data,
|
|||
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
/* Going via a unix socket ignores any proxy settings */
|
||||
if(needle->via_peer && needle->via_peer->unix_socket) {
|
||||
needle->bits.socksproxy = FALSE;
|
||||
needle->bits.httpproxy = FALSE;
|
||||
needle->bits.proxy = FALSE;
|
||||
}
|
||||
else if(network_scheme) {
|
||||
result = url_set_conn_proxies(data, needle);
|
||||
if(network_scheme &&
|
||||
(!needle->via_peer || !needle->via_peer->unix_socket)) {
|
||||
result = Curl_proxy_init_conn(data, needle);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
/*************************************************************
|
||||
* If the protocol is using SSL and HTTP proxy is used, we set
|
||||
* the tunnel_proxy bit.
|
||||
*************************************************************/
|
||||
if((needle->given->flags & PROTOPT_SSL) && needle->bits.httpproxy)
|
||||
needle->bits.tunnel_proxy = TRUE;
|
||||
}
|
||||
#endif /* CURL_DISABLE_PROXY */
|
||||
|
||||
|
|
@ -2692,15 +2162,6 @@ static CURLcode url_create_needle(struct Curl_easy *data,
|
|||
Curl_peer_unlink(&needle->via_peer);
|
||||
}
|
||||
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
/*************************************************************
|
||||
* If the "connect to" feature is used with an HTTP proxy,
|
||||
* we set the tunnel_proxy bit.
|
||||
*************************************************************/
|
||||
if(needle->via_peer && needle->bits.httpproxy)
|
||||
needle->bits.tunnel_proxy = TRUE;
|
||||
#endif
|
||||
|
||||
/*************************************************************
|
||||
* Setup internals depending on protocol. Needs to be done after
|
||||
* we figured out what/if proxy to use.
|
||||
|
|
@ -2743,6 +2204,118 @@ out:
|
|||
return result;
|
||||
}
|
||||
|
||||
static CURLcode url_set_data_origin_and_creds(struct Curl_easy *data)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
CURLU *uh;
|
||||
CURLUcode uc;
|
||||
bool use_set_uh = (data->set.uh && !data->state.this_is_a_follow);
|
||||
uint16_t port_override = data->state.allow_port ? data->set.use_port : 0;
|
||||
uint32_t scope_id = 0;
|
||||
|
||||
/*************************************************************
|
||||
* Check input data
|
||||
*************************************************************/
|
||||
if(!Curl_bufref_ptr(&data->state.url)) {
|
||||
result = CURLE_URL_MALFORMAT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
up_free(data); /* cleanup previous leftovers first */
|
||||
|
||||
/* parse the URL */
|
||||
if(use_set_uh)
|
||||
uh = data->state.uh = curl_url_dup(data->set.uh);
|
||||
else
|
||||
uh = data->state.uh = curl_url();
|
||||
if(!uh) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Calculate the *real* URL this transfer uses, applying defaults
|
||||
* where information is missing. */
|
||||
if(data->set.str[STRING_DEFAULT_PROTOCOL] &&
|
||||
!Curl_is_absolute_url(Curl_bufref_ptr(&data->state.url), NULL, 0, TRUE)) {
|
||||
char *url = curl_maprintf("%s://%s",
|
||||
data->set.str[STRING_DEFAULT_PROTOCOL],
|
||||
Curl_bufref_ptr(&data->state.url));
|
||||
if(!url) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
Curl_bufref_set(&data->state.url, url, 0, curl_free);
|
||||
}
|
||||
|
||||
if(!use_set_uh) {
|
||||
char *newurl;
|
||||
uc = curl_url_set(uh, CURLUPART_URL, Curl_bufref_ptr(&data->state.url),
|
||||
(unsigned int)(CURLU_GUESS_SCHEME |
|
||||
CURLU_NON_SUPPORT_SCHEME |
|
||||
(data->set.disallow_username_in_url ?
|
||||
CURLU_DISALLOW_USER : 0) |
|
||||
(data->set.path_as_is ? CURLU_PATH_AS_IS : 0)));
|
||||
if(uc) {
|
||||
failf(data, "URL rejected: %s", curl_url_strerror(uc));
|
||||
result = Curl_uc_to_curlcode(uc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* after it was parsed, get the generated normalized version */
|
||||
uc = curl_url_get(uh, CURLUPART_URL, &newurl, CURLU_GET_EMPTY);
|
||||
if(uc) {
|
||||
result = Curl_uc_to_curlcode(uc);
|
||||
goto out;
|
||||
}
|
||||
Curl_bufref_set(&data->state.url, newurl, 0, curl_free);
|
||||
}
|
||||
|
||||
#ifdef USE_IPV6
|
||||
scope_id = data->set.scope_id;
|
||||
#endif
|
||||
|
||||
/* `uh` is now as the connection should use it, probably. */
|
||||
result = Curl_peer_from_url(uh, data, port_override, scope_id,
|
||||
&data->state.up, &data->state.origin);
|
||||
if(result)
|
||||
goto out;
|
||||
/* The origin might get changed when HSTS applies */
|
||||
result = hsts_upgrade(data, uh, port_override, scope_id);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
/* When the transfers initial_origin is not set, this is the initial
|
||||
* request. Remember this starting point. */
|
||||
if(!data->state.initial_origin)
|
||||
Curl_peer_link(&data->state.initial_origin, data->state.origin);
|
||||
|
||||
uc = curl_url_get(uh, CURLUPART_PATH, &data->state.up.path, CURLU_URLENCODE);
|
||||
if(uc) {
|
||||
result = Curl_uc_to_curlcode(uc);
|
||||
goto out;
|
||||
}
|
||||
uc = curl_url_get(uh, CURLUPART_QUERY, &data->state.up.query,
|
||||
CURLU_GET_EMPTY);
|
||||
if(uc && (uc != CURLUE_NO_QUERY)) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
uc = curl_url_get(uh, CURLUPART_OPTIONS, &data->state.up.options,
|
||||
CURLU_URLDECODE);
|
||||
if(uc && (uc != CURLUE_NO_OPTIONS)) {
|
||||
result = Curl_uc_to_curlcode(uc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
result = url_set_data_creds(data, uh);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an existing connection for the transfer or create a new one.
|
||||
* Returns
|
||||
|
|
@ -2837,7 +2410,7 @@ static CURLcode url_find_or_create_conn(struct Curl_easy *data)
|
|||
infof(data, "Reusing existing %s: connection%s with %s %s",
|
||||
conn->given->name,
|
||||
tls_upgraded ? " (upgraded to SSL)" : "",
|
||||
conn->bits.proxy ? "proxy" : "host",
|
||||
(conn->socks_proxy.peer || conn->http_proxy.peer) ? "proxy" : "host",
|
||||
conn->socks_proxy.peer ? conn->socks_proxy.peer->user_hostname :
|
||||
conn->http_proxy.peer ? conn->http_proxy.peer->user_hostname :
|
||||
conn->origin->hostname);
|
||||
|
|
@ -2936,7 +2509,7 @@ static CURLcode url_find_or_create_conn(struct Curl_easy *data)
|
|||
#ifdef CURL_DISABLE_PROXY
|
||||
0
|
||||
#else
|
||||
data->conn->bits.proxy
|
||||
(data->conn->socks_proxy.peer || data->conn->http_proxy.peer)
|
||||
#endif
|
||||
;
|
||||
|
||||
|
|
@ -2953,21 +2526,33 @@ out:
|
|||
CURLcode Curl_connect(struct Curl_easy *data, bool *pconnected)
|
||||
{
|
||||
CURLcode result;
|
||||
struct connectdata *conn;
|
||||
struct connectdata *conn = NULL;
|
||||
|
||||
*pconnected = FALSE;
|
||||
|
||||
/* Set the request to virgin state based on transfer settings */
|
||||
Curl_req_hard_reset(&data->req, data);
|
||||
/* Determine the origin of the transfer and what credentials to use */
|
||||
result = url_set_data_origin_and_creds(data);
|
||||
if(result)
|
||||
goto out;
|
||||
if(!data->state.origin) { /* just make really sure */
|
||||
DEBUGASSERT(0);
|
||||
result = CURLE_FAILED_INIT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Get or create a connection for the transfer. */
|
||||
result = url_find_or_create_conn(data);
|
||||
conn = data->conn;
|
||||
|
||||
if(result)
|
||||
goto out;
|
||||
if(!data->conn) { /* just make really sure */
|
||||
DEBUGASSERT(0);
|
||||
result = CURLE_FAILED_INIT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
DEBUGASSERT(conn);
|
||||
Curl_pgrsTime(data, TIMER_POSTQUEUE);
|
||||
if(conn->bits.reuse) {
|
||||
if(conn->attached_xfers > 1)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue