mirror of
https://github.com/curl/curl.git
synced 2026-07-24 17:07:16 +03:00
url.c: code/comment cleanup around conn creation
Several comments were outdated and parameters to create_conn() and ConnectionExists() were not needed. Give functions better names and consistently use terms `needle` and `conn`. No functional change. Closes #20464
This commit is contained in:
parent
161be30854
commit
d7a9f1ab15
1 changed files with 199 additions and 229 deletions
428
lib/url.c
428
lib/url.c
|
|
@ -1268,25 +1268,22 @@ static bool url_match_result(bool result, void *userdata)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Given one filled in connection struct (named needle), this function should
|
* Given a transfer and a prototype connection (needle),
|
||||||
* detect if there already is one that has all the significant details
|
* find and attach an existing connection that matches.
|
||||||
* exactly the same and thus should be used instead.
|
|
||||||
*
|
*
|
||||||
* If there is a match, this function returns TRUE - and has marked the
|
* Return TRUE if an existing connection was attached.
|
||||||
* connection as 'in-use'. It must later be called with ConnectionDone() to
|
* `waitpipe` is TRUE if no existing connection matched, but there
|
||||||
* return back to 'idle' (unused) state.
|
* might be suitable one in the near future (common cause: multiplexing
|
||||||
*
|
* capability has not been determined yet, e.g. ALPN handshake).
|
||||||
* The force_reuse flag is set if the connection must be used.
|
|
||||||
*/
|
*/
|
||||||
static bool ConnectionExists(struct Curl_easy *data,
|
static bool url_attach_existing(struct Curl_easy *data,
|
||||||
struct connectdata *needle,
|
struct connectdata *needle,
|
||||||
struct connectdata **usethis,
|
bool *waitpipe)
|
||||||
bool *force_reuse,
|
|
||||||
bool *waitpipe)
|
|
||||||
{
|
{
|
||||||
struct url_conn_match match;
|
struct url_conn_match match;
|
||||||
bool result;
|
bool result;
|
||||||
|
|
||||||
|
DEBUGASSERT(!data->conn);
|
||||||
memset(&match, 0, sizeof(match));
|
memset(&match, 0, sizeof(match));
|
||||||
match.data = data;
|
match.data = data;
|
||||||
match.needle = needle;
|
match.needle = needle;
|
||||||
|
|
@ -1310,8 +1307,6 @@ static bool ConnectionExists(struct Curl_easy *data,
|
||||||
|
|
||||||
/* wait_pipe is TRUE if we encounter a bundle that is undecided. There
|
/* wait_pipe is TRUE if we encounter a bundle that is undecided. There
|
||||||
* is no matching connection then, yet. */
|
* is no matching connection then, yet. */
|
||||||
*usethis = match.found;
|
|
||||||
*force_reuse = (bool)match.force_reuse;
|
|
||||||
*waitpipe = (bool)match.wait_pipe;
|
*waitpipe = (bool)match.wait_pipe;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -3118,42 +3113,41 @@ static void url_move_hostname(struct hostname *dest, struct hostname *src)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Cleanup the connection `temp`, just allocated for `data`, before using the
|
* Adjust reused connection settings to the transfer/needle.
|
||||||
* previously `existing` one for `data`. All relevant info is copied over
|
|
||||||
* and `temp` is freed.
|
|
||||||
*/
|
*/
|
||||||
static void reuse_conn(struct Curl_easy *data,
|
static void url_conn_reuse_adjust(struct Curl_easy *data,
|
||||||
struct connectdata *temp,
|
struct connectdata *needle)
|
||||||
struct connectdata *existing)
|
|
||||||
{
|
{
|
||||||
/* get the user+password information from the temp struct since it may
|
struct connectdata *conn = data->conn;
|
||||||
* be new for this request even when we reuse an existing connection */
|
|
||||||
if(temp->user) {
|
/* get the user+password information from the needle since it may
|
||||||
|
* be new for this request even when we reuse conn */
|
||||||
|
if(needle->user) {
|
||||||
/* use the new username and password though */
|
/* use the new username and password though */
|
||||||
curlx_free(existing->user);
|
curlx_free(conn->user);
|
||||||
curlx_free(existing->passwd);
|
curlx_free(conn->passwd);
|
||||||
existing->user = temp->user;
|
conn->user = needle->user;
|
||||||
existing->passwd = temp->passwd;
|
conn->passwd = needle->passwd;
|
||||||
temp->user = NULL;
|
needle->user = NULL;
|
||||||
temp->passwd = NULL;
|
needle->passwd = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef CURL_DISABLE_PROXY
|
#ifndef CURL_DISABLE_PROXY
|
||||||
existing->bits.proxy_user_passwd = temp->bits.proxy_user_passwd;
|
conn->bits.proxy_user_passwd = needle->bits.proxy_user_passwd;
|
||||||
if(existing->bits.proxy_user_passwd) {
|
if(conn->bits.proxy_user_passwd) {
|
||||||
/* use the new proxy username and proxy password though */
|
/* use the new proxy username and proxy password though */
|
||||||
curlx_free(existing->http_proxy.user);
|
curlx_free(conn->http_proxy.user);
|
||||||
curlx_free(existing->socks_proxy.user);
|
curlx_free(conn->socks_proxy.user);
|
||||||
curlx_free(existing->http_proxy.passwd);
|
curlx_free(conn->http_proxy.passwd);
|
||||||
curlx_free(existing->socks_proxy.passwd);
|
curlx_free(conn->socks_proxy.passwd);
|
||||||
existing->http_proxy.user = temp->http_proxy.user;
|
conn->http_proxy.user = needle->http_proxy.user;
|
||||||
existing->socks_proxy.user = temp->socks_proxy.user;
|
conn->socks_proxy.user = needle->socks_proxy.user;
|
||||||
existing->http_proxy.passwd = temp->http_proxy.passwd;
|
conn->http_proxy.passwd = needle->http_proxy.passwd;
|
||||||
existing->socks_proxy.passwd = temp->socks_proxy.passwd;
|
conn->socks_proxy.passwd = needle->socks_proxy.passwd;
|
||||||
temp->http_proxy.user = NULL;
|
needle->http_proxy.user = NULL;
|
||||||
temp->socks_proxy.user = NULL;
|
needle->socks_proxy.user = NULL;
|
||||||
temp->http_proxy.passwd = NULL;
|
needle->http_proxy.passwd = NULL;
|
||||||
temp->socks_proxy.passwd = NULL;
|
needle->socks_proxy.passwd = NULL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -3163,27 +3157,19 @@ static void reuse_conn(struct Curl_easy *data,
|
||||||
* - we use a proxy (not tunneling). we want to send all requests
|
* - we use a proxy (not tunneling). we want to send all requests
|
||||||
* that use the same proxy on this connection.
|
* that use the same proxy on this connection.
|
||||||
* - we have a "connect-to" setting that may redirect the hostname of
|
* - we have a "connect-to" setting that may redirect the hostname of
|
||||||
* a new request to the same remote endpoint of an existing conn.
|
* a new request to the same remote endpoint of an conn conn.
|
||||||
* We want to reuse an existing conn to the remote endpoint.
|
* We want to reuse an conn conn to the remote endpoint.
|
||||||
* Since connection reuse does not match on conn->host necessarily, we
|
* Since connection reuse does not match on conn->host necessarily, we
|
||||||
* switch `existing` conn to `temp` conn's host settings.
|
* switch conn to needle's host settings.
|
||||||
* Is this correct in the case of TLS connections that have
|
|
||||||
* used the original hostname in SNI to negotiate? Do we send
|
|
||||||
* requests for another host through the different SNI?
|
|
||||||
*/
|
*/
|
||||||
url_move_hostname(&existing->host, &temp->host);
|
url_move_hostname(&conn->host, &needle->host);
|
||||||
url_move_hostname(&existing->conn_to_host, &temp->conn_to_host);
|
url_move_hostname(&conn->conn_to_host, &needle->conn_to_host);
|
||||||
|
|
||||||
existing->conn_to_port = temp->conn_to_port;
|
conn->conn_to_port = needle->conn_to_port;
|
||||||
existing->remote_port = temp->remote_port;
|
conn->remote_port = needle->remote_port;
|
||||||
curlx_free(existing->hostname_resolve);
|
curlx_free(conn->hostname_resolve);
|
||||||
existing->hostname_resolve = temp->hostname_resolve;
|
conn->hostname_resolve = needle->hostname_resolve;
|
||||||
temp->hostname_resolve = NULL;
|
needle->hostname_resolve = NULL;
|
||||||
|
|
||||||
/* reuse init */
|
|
||||||
existing->bits.reuse = TRUE; /* yes, we are reusing here */
|
|
||||||
|
|
||||||
Curl_conn_free(data, temp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void conn_meta_freeentry(void *p)
|
static void conn_meta_freeentry(void *p)
|
||||||
|
|
@ -3195,35 +3181,11 @@ static void conn_meta_freeentry(void *p)
|
||||||
DEBUGASSERT(p == NULL);
|
DEBUGASSERT(p == NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static CURLcode url_create_needle(struct Curl_easy *data,
|
||||||
* create_conn() sets up a new connectdata struct, or reuses an already
|
struct connectdata **pneedle)
|
||||||
* existing one, and resolves hostname.
|
|
||||||
*
|
|
||||||
* if this function returns CURLE_OK and *async is set to TRUE, the resolve
|
|
||||||
* response will be coming asynchronously. If *async is FALSE, the name is
|
|
||||||
* already resolved.
|
|
||||||
*
|
|
||||||
* @param data The sessionhandle pointer
|
|
||||||
* @param in_connect is set to the next connection data pointer
|
|
||||||
* @param reusedp is set to to TRUE if connection was reused
|
|
||||||
* @see Curl_setup_conn()
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
static CURLcode create_conn(struct Curl_easy *data,
|
|
||||||
struct connectdata **in_connect,
|
|
||||||
bool *reusedp)
|
|
||||||
{
|
{
|
||||||
|
struct connectdata *needle = NULL;
|
||||||
CURLcode result = CURLE_OK;
|
CURLcode result = CURLE_OK;
|
||||||
struct connectdata *conn;
|
|
||||||
struct connectdata *existing = NULL;
|
|
||||||
bool reuse;
|
|
||||||
bool connections_available = TRUE;
|
|
||||||
bool force_reuse = FALSE;
|
|
||||||
bool waitpipe = FALSE;
|
|
||||||
|
|
||||||
*reusedp = FALSE;
|
|
||||||
*in_connect = NULL;
|
|
||||||
|
|
||||||
/*************************************************************
|
/*************************************************************
|
||||||
* Check input data
|
* Check input data
|
||||||
|
|
@ -3237,37 +3199,31 @@ static CURLcode create_conn(struct Curl_easy *data,
|
||||||
parts for checking against the already present connections. In order
|
parts for checking against the already present connections. In order
|
||||||
to not have to modify everything at once, we allocate a temporary
|
to not have to modify everything at once, we allocate a temporary
|
||||||
connection data struct and fill in for comparison purposes. */
|
connection data struct and fill in for comparison purposes. */
|
||||||
conn = allocate_conn(data);
|
needle = allocate_conn(data);
|
||||||
|
if(!needle) {
|
||||||
if(!conn) {
|
|
||||||
result = CURLE_OUT_OF_MEMORY;
|
result = CURLE_OUT_OF_MEMORY;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We must set the return variable as soon as possible, so that our
|
|
||||||
parent can cleanup any possible allocs we may have done before
|
|
||||||
any failure */
|
|
||||||
*in_connect = conn;
|
|
||||||
|
|
||||||
/* Do the unfailable inits first, before checks that may early return */
|
/* Do the unfailable inits first, before checks that may early return */
|
||||||
Curl_hash_init(&conn->meta_hash, 23,
|
Curl_hash_init(&needle->meta_hash, 23,
|
||||||
Curl_hash_str, curlx_str_key_compare, conn_meta_freeentry);
|
Curl_hash_str, curlx_str_key_compare, conn_meta_freeentry);
|
||||||
|
|
||||||
result = parseurlandfillconn(data, conn);
|
result = parseurlandfillconn(data, needle);
|
||||||
if(result)
|
if(result)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if(data->set.str[STRING_SASL_AUTHZID]) {
|
if(data->set.str[STRING_SASL_AUTHZID]) {
|
||||||
conn->sasl_authzid = curlx_strdup(data->set.str[STRING_SASL_AUTHZID]);
|
needle->sasl_authzid = curlx_strdup(data->set.str[STRING_SASL_AUTHZID]);
|
||||||
if(!conn->sasl_authzid) {
|
if(!needle->sasl_authzid) {
|
||||||
result = CURLE_OUT_OF_MEMORY;
|
result = CURLE_OUT_OF_MEMORY;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(data->set.str[STRING_BEARER]) {
|
if(data->set.str[STRING_BEARER]) {
|
||||||
conn->oauth_bearer = curlx_strdup(data->set.str[STRING_BEARER]);
|
needle->oauth_bearer = curlx_strdup(data->set.str[STRING_BEARER]);
|
||||||
if(!conn->oauth_bearer) {
|
if(!needle->oauth_bearer) {
|
||||||
result = CURLE_OUT_OF_MEMORY;
|
result = CURLE_OUT_OF_MEMORY;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
@ -3275,20 +3231,20 @@ static CURLcode create_conn(struct Curl_easy *data,
|
||||||
|
|
||||||
#ifdef USE_UNIX_SOCKETS
|
#ifdef USE_UNIX_SOCKETS
|
||||||
if(data->set.str[STRING_UNIX_SOCKET_PATH]) {
|
if(data->set.str[STRING_UNIX_SOCKET_PATH]) {
|
||||||
conn->unix_domain_socket =
|
needle->unix_domain_socket =
|
||||||
curlx_strdup(data->set.str[STRING_UNIX_SOCKET_PATH]);
|
curlx_strdup(data->set.str[STRING_UNIX_SOCKET_PATH]);
|
||||||
if(!conn->unix_domain_socket) {
|
if(!needle->unix_domain_socket) {
|
||||||
result = CURLE_OUT_OF_MEMORY;
|
result = CURLE_OUT_OF_MEMORY;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
conn->bits.abstract_unix_socket = data->set.abstract_unix_socket;
|
needle->bits.abstract_unix_socket = data->set.abstract_unix_socket;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* After the Unix socket init but before the proxy vars are used, parse and
|
/* After the Unix socket init but before the proxy vars are used, parse and
|
||||||
initialize the proxy vars */
|
initialize the proxy vars */
|
||||||
#ifndef CURL_DISABLE_PROXY
|
#ifndef CURL_DISABLE_PROXY
|
||||||
result = create_conn_helper_init_proxy(data, conn);
|
result = create_conn_helper_init_proxy(data, needle);
|
||||||
if(result)
|
if(result)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
|
@ -3296,24 +3252,24 @@ static CURLcode create_conn(struct Curl_easy *data,
|
||||||
* If the protocol is using SSL and HTTP proxy is used, we set
|
* If the protocol is using SSL and HTTP proxy is used, we set
|
||||||
* the tunnel_proxy bit.
|
* the tunnel_proxy bit.
|
||||||
*************************************************************/
|
*************************************************************/
|
||||||
if((conn->given->flags & PROTOPT_SSL) && conn->bits.httpproxy)
|
if((needle->given->flags & PROTOPT_SSL) && needle->bits.httpproxy)
|
||||||
conn->bits.tunnel_proxy = TRUE;
|
needle->bits.tunnel_proxy = TRUE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*************************************************************
|
/*************************************************************
|
||||||
* Figure out the remote port number and fix it in the URL
|
* Figure out the remote port number and fix it in the URL
|
||||||
*************************************************************/
|
*************************************************************/
|
||||||
result = parse_remote_port(data, conn);
|
result = parse_remote_port(data, needle);
|
||||||
if(result)
|
if(result)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* Check for overridden login details and set them accordingly so that
|
/* Check for overridden login details and set them accordingly so that
|
||||||
they are known when protocol->setup_connection is called! */
|
they are known when protocol->setup_connection is called! */
|
||||||
result = override_login(data, conn);
|
result = override_login(data, needle);
|
||||||
if(result)
|
if(result)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
result = set_login(data, conn); /* default credentials */
|
result = set_login(data, needle); /* default credentials */
|
||||||
if(result)
|
if(result)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
|
@ -3321,7 +3277,7 @@ static CURLcode create_conn(struct Curl_easy *data,
|
||||||
* Process the "connect to" linked list of hostname/port mappings.
|
* Process the "connect to" linked list of hostname/port mappings.
|
||||||
* Do this after the remote port number has been fixed in the URL.
|
* Do this after the remote port number has been fixed in the URL.
|
||||||
*************************************************************/
|
*************************************************************/
|
||||||
result = parse_connect_to_slist(data, conn, data->set.connect_to);
|
result = parse_connect_to_slist(data, needle, data->set.connect_to);
|
||||||
if(result)
|
if(result)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
|
@ -3329,38 +3285,39 @@ static CURLcode create_conn(struct Curl_easy *data,
|
||||||
* IDN-convert the proxy hostnames
|
* IDN-convert the proxy hostnames
|
||||||
*************************************************************/
|
*************************************************************/
|
||||||
#ifndef CURL_DISABLE_PROXY
|
#ifndef CURL_DISABLE_PROXY
|
||||||
if(conn->bits.httpproxy) {
|
if(needle->bits.httpproxy) {
|
||||||
result = Curl_idnconvert_hostname(&conn->http_proxy.host);
|
result = Curl_idnconvert_hostname(&needle->http_proxy.host);
|
||||||
if(result)
|
if(result)
|
||||||
return result;
|
goto out;
|
||||||
}
|
}
|
||||||
if(conn->bits.socksproxy) {
|
if(needle->bits.socksproxy) {
|
||||||
result = Curl_idnconvert_hostname(&conn->socks_proxy.host);
|
result = Curl_idnconvert_hostname(&needle->socks_proxy.host);
|
||||||
if(result)
|
if(result)
|
||||||
return result;
|
goto out;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if(conn->bits.conn_to_host) {
|
if(needle->bits.conn_to_host) {
|
||||||
result = Curl_idnconvert_hostname(&conn->conn_to_host);
|
result = Curl_idnconvert_hostname(&needle->conn_to_host);
|
||||||
if(result)
|
if(result)
|
||||||
return result;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************************************************************
|
/*************************************************************
|
||||||
* Check whether the host and the "connect to host" are equal.
|
* Check whether the host and the "connect to host" are equal.
|
||||||
* Do this after the hostnames have been IDN-converted.
|
* Do this after the hostnames have been IDN-converted.
|
||||||
*************************************************************/
|
*************************************************************/
|
||||||
if(conn->bits.conn_to_host &&
|
if(needle->bits.conn_to_host &&
|
||||||
curl_strequal(conn->conn_to_host.name, conn->host.name)) {
|
curl_strequal(needle->conn_to_host.name, needle->host.name)) {
|
||||||
conn->bits.conn_to_host = FALSE;
|
needle->bits.conn_to_host = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************************************************************
|
/*************************************************************
|
||||||
* Check whether the port and the "connect to port" are equal.
|
* Check whether the port and the "connect to port" are equal.
|
||||||
* Do this after the remote port number has been fixed in the URL.
|
* Do this after the remote port number has been fixed in the URL.
|
||||||
*************************************************************/
|
*************************************************************/
|
||||||
if(conn->bits.conn_to_port && conn->conn_to_port == conn->remote_port) {
|
if(needle->bits.conn_to_port &&
|
||||||
conn->bits.conn_to_port = FALSE;
|
needle->conn_to_port == needle->remote_port) {
|
||||||
|
needle->bits.conn_to_port = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef CURL_DISABLE_PROXY
|
#ifndef CURL_DISABLE_PROXY
|
||||||
|
|
@ -3368,101 +3325,137 @@ static CURLcode create_conn(struct Curl_easy *data,
|
||||||
* If the "connect to" feature is used with an HTTP proxy,
|
* If the "connect to" feature is used with an HTTP proxy,
|
||||||
* we set the tunnel_proxy bit.
|
* we set the tunnel_proxy bit.
|
||||||
*************************************************************/
|
*************************************************************/
|
||||||
if((conn->bits.conn_to_host || conn->bits.conn_to_port) &&
|
if((needle->bits.conn_to_host || needle->bits.conn_to_port) &&
|
||||||
conn->bits.httpproxy)
|
needle->bits.httpproxy)
|
||||||
conn->bits.tunnel_proxy = TRUE;
|
needle->bits.tunnel_proxy = TRUE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*************************************************************
|
/*************************************************************
|
||||||
* Setup internals depending on protocol. Needs to be done after
|
* Setup internals depending on protocol. Needs to be done after
|
||||||
* we figured out what/if proxy to use.
|
* we figured out what/if proxy to use.
|
||||||
*************************************************************/
|
*************************************************************/
|
||||||
result = setup_connection_internals(data, conn);
|
result = setup_connection_internals(data, needle);
|
||||||
if(result)
|
if(result)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
if(needle->scheme->flags & PROTOPT_ALPN) {
|
||||||
|
/* The protocol wants it, so set the bits if enabled in the easy handle
|
||||||
|
(default) */
|
||||||
|
if(data->set.ssl_enable_alpn)
|
||||||
|
needle->bits.tls_enable_alpn = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!(needle->scheme->flags & PROTOPT_NONETWORK)) {
|
||||||
|
/* Setup callbacks for network connections */
|
||||||
|
needle->recv[FIRSTSOCKET] = Curl_cf_recv;
|
||||||
|
needle->send[FIRSTSOCKET] = Curl_cf_send;
|
||||||
|
needle->recv[SECONDARYSOCKET] = Curl_cf_recv;
|
||||||
|
needle->send[SECONDARYSOCKET] = Curl_cf_send;
|
||||||
|
needle->bits.tcp_fastopen = data->set.tcp_fastopen;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
if(!result) {
|
||||||
|
DEBUGASSERT(needle);
|
||||||
|
*pneedle = needle;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*pneedle = NULL;
|
||||||
|
if(needle)
|
||||||
|
Curl_conn_free(data, needle);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find an existing connection for the transfer or create a new one.
|
||||||
|
* Returns
|
||||||
|
* - CURLE_OK on success with a connection attached to data
|
||||||
|
* - CURLE_NO_CONNECTION_AVAILABLE when connection limits apply or when
|
||||||
|
* a suitable connection has not determined its multiplex capability.
|
||||||
|
* - a fatal error
|
||||||
|
*/
|
||||||
|
static CURLcode url_find_or_create_conn(struct Curl_easy *data)
|
||||||
|
{
|
||||||
|
struct connectdata *needle = NULL;
|
||||||
|
bool waitpipe = FALSE;
|
||||||
|
CURLcode result;
|
||||||
|
|
||||||
|
/* create the template connection for transfer data. Use this needle to
|
||||||
|
* find an existing connection or, if none exists, convert needle
|
||||||
|
* to a full connection and attach it to data. */
|
||||||
|
result = url_create_needle(data, &needle);
|
||||||
|
if(result)
|
||||||
|
goto out;
|
||||||
|
DEBUGASSERT(needle);
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* file: is a special case in that it does not need a network connection
|
* file: is a special case in that it does not need a network connection
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
#ifndef CURL_DISABLE_FILE
|
#ifndef CURL_DISABLE_FILE
|
||||||
if(conn->scheme->flags & PROTOPT_NONETWORK) {
|
if(needle->scheme->flags & PROTOPT_NONETWORK) {
|
||||||
bool done;
|
bool done;
|
||||||
/* this is supposed to be the connect function so we better at least check
|
/* this is supposed to be the connect function so we better at least check
|
||||||
that the file is present here! */
|
that the file is present here! */
|
||||||
DEBUGASSERT(conn->scheme->run->connect_it);
|
DEBUGASSERT(needle->scheme->run->connect_it);
|
||||||
data->info.conn_scheme = conn->scheme->name;
|
data->info.conn_scheme = needle->scheme->name;
|
||||||
/* conn_protocol can only provide "old" protocols */
|
/* conn_protocol can only provide "old" protocols */
|
||||||
data->info.conn_protocol = (conn->scheme->protocol) & CURLPROTO_MASK;
|
data->info.conn_protocol = (needle->scheme->protocol) & CURLPROTO_MASK;
|
||||||
result = conn->scheme->run->connect_it(data, &done);
|
result = needle->scheme->run->connect_it(data, &done);
|
||||||
if(result)
|
if(result)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* Setup a "faked" transfer that will do nothing */
|
/* Setup a "faked" transfer that will do nothing */
|
||||||
Curl_attach_connection(data, conn);
|
Curl_attach_connection(data, needle);
|
||||||
result = Curl_cpool_add(data, conn);
|
needle = NULL;
|
||||||
|
result = Curl_cpool_add(data, data->conn);
|
||||||
if(!result) {
|
if(!result) {
|
||||||
/* Setup whatever necessary for a resumed transfer */
|
/* Setup whatever necessary for a resumed transfer */
|
||||||
result = setup_range(data);
|
result = setup_range(data);
|
||||||
if(!result) {
|
if(!result) {
|
||||||
Curl_xfer_setup_nop(data);
|
Curl_xfer_setup_nop(data);
|
||||||
result = Curl_init_do(data, conn);
|
result = Curl_init_do(data, data->conn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(result) {
|
if(result) {
|
||||||
DEBUGASSERT(conn->scheme->run->done);
|
DEBUGASSERT(data->conn->scheme->run->done);
|
||||||
/* we ignore the return code for the protocol-specific DONE */
|
/* we ignore the return code for the protocol-specific DONE */
|
||||||
(void)conn->scheme->run->done(data, result, FALSE);
|
(void)data->conn->scheme->run->done(data, result, FALSE);
|
||||||
}
|
}
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Setup filter for network connections */
|
|
||||||
conn->recv[FIRSTSOCKET] = Curl_cf_recv;
|
|
||||||
conn->send[FIRSTSOCKET] = Curl_cf_send;
|
|
||||||
conn->recv[SECONDARYSOCKET] = Curl_cf_recv;
|
|
||||||
conn->send[SECONDARYSOCKET] = Curl_cf_send;
|
|
||||||
conn->bits.tcp_fastopen = data->set.tcp_fastopen;
|
|
||||||
|
|
||||||
/* Complete the easy's SSL configuration for connection cache matching */
|
/* Complete the easy's SSL configuration for connection cache matching */
|
||||||
result = Curl_ssl_easy_config_complete(data);
|
result = Curl_ssl_easy_config_complete(data);
|
||||||
if(result)
|
if(result)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
/* Get rid of any dead connections so limit are easier kept. */
|
||||||
Curl_cpool_prune_dead(data);
|
Curl_cpool_prune_dead(data);
|
||||||
|
|
||||||
/*************************************************************
|
/*************************************************************
|
||||||
* Check the current list of connections to see if we can
|
* Reuse of existing connection is not allowed when
|
||||||
* reuse an already existing one or if we have to create a
|
* - connect_only is set or
|
||||||
* new one.
|
* - reuse_fresh is set and this is not a follow-up request
|
||||||
|
* (like with HTTP followlocation)
|
||||||
*************************************************************/
|
*************************************************************/
|
||||||
|
if((!data->set.reuse_fresh || data->state.followlocation) &&
|
||||||
|
!data->set.connect_only) {
|
||||||
|
/* Ok, try to find and attach an existing one */
|
||||||
|
url_attach_existing(data, needle, &waitpipe);
|
||||||
|
}
|
||||||
|
|
||||||
DEBUGASSERT(conn->user);
|
if(data->conn) {
|
||||||
DEBUGASSERT(conn->passwd);
|
/* We attached an existing connection for this transfer. Copy
|
||||||
|
* over transfer specific properties over from needle. */
|
||||||
/* reuse_fresh is TRUE if we are told to use a new connection by force, but
|
struct connectdata *conn = data->conn;
|
||||||
we only acknowledge this option if this is not a reused connection
|
VERBOSE(bool tls_upgraded = (!(needle->given->flags & PROTOPT_SSL) &&
|
||||||
already (which happens due to follow-location or during an HTTP
|
|
||||||
authentication phase). CONNECT_ONLY transfers also refuse reuse. */
|
|
||||||
if((data->set.reuse_fresh && !data->state.followlocation) ||
|
|
||||||
data->set.connect_only)
|
|
||||||
reuse = FALSE;
|
|
||||||
else
|
|
||||||
reuse = ConnectionExists(data, conn, &existing, &force_reuse, &waitpipe);
|
|
||||||
|
|
||||||
if(reuse) {
|
|
||||||
/*
|
|
||||||
* We already have a connection for this, we got the former connection in
|
|
||||||
* `existing` and thus we need to cleanup the one we just
|
|
||||||
* allocated before we can move along and use `existing`.
|
|
||||||
*/
|
|
||||||
VERBOSE(bool tls_upgraded = (!(conn->given->flags & PROTOPT_SSL) &&
|
|
||||||
Curl_conn_is_ssl(conn, FIRSTSOCKET)));
|
Curl_conn_is_ssl(conn, FIRSTSOCKET)));
|
||||||
|
|
||||||
reuse_conn(data, conn, existing);
|
conn->bits.reuse = TRUE;
|
||||||
conn = existing;
|
url_conn_reuse_adjust(data, needle);
|
||||||
*in_connect = conn;
|
|
||||||
|
|
||||||
#ifndef CURL_DISABLE_PROXY
|
#ifndef CURL_DISABLE_PROXY
|
||||||
infof(data, "Reusing existing %s: connection%s with %s %s",
|
infof(data, "Reusing existing %s: connection%s with %s %s",
|
||||||
|
|
@ -3483,27 +3476,21 @@ static CURLcode create_conn(struct Curl_easy *data,
|
||||||
/* We have decided that we want a new connection. However, we may not
|
/* We have decided that we want a new connection. However, we may not
|
||||||
be able to do that if we have reached the limit of how many
|
be able to do that if we have reached the limit of how many
|
||||||
connections we are allowed to open. */
|
connections we are allowed to open. */
|
||||||
DEBUGF(infof(data, "new connection, bits.close=%d", conn->bits.close));
|
DEBUGF(infof(data, "new connection, bits.close=%d", needle->bits.close));
|
||||||
|
|
||||||
if(conn->scheme->flags & PROTOPT_ALPN) {
|
|
||||||
/* The protocol wants it, so set the bits if enabled in the easy handle
|
|
||||||
(default) */
|
|
||||||
if(data->set.ssl_enable_alpn)
|
|
||||||
conn->bits.tls_enable_alpn = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(waitpipe) {
|
if(waitpipe) {
|
||||||
/* There is a connection that *might* become usable for multiplexing
|
/* There is a connection that *might* become usable for multiplexing
|
||||||
"soon", and we wait for that */
|
"soon", and we wait for that */
|
||||||
infof(data, "Waiting on connection to negotiate possible multiplexing.");
|
infof(data, "Waiting on connection to negotiate possible multiplexing.");
|
||||||
connections_available = FALSE;
|
result = CURLE_NO_CONNECTION_AVAILABLE;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
switch(Curl_cpool_check_limits(data, conn)) {
|
switch(Curl_cpool_check_limits(data, needle)) {
|
||||||
case CPOOL_LIMIT_DEST:
|
case CPOOL_LIMIT_DEST:
|
||||||
infof(data, "No more connections allowed to host");
|
infof(data, "No more connections allowed to host");
|
||||||
connections_available = FALSE;
|
result = CURLE_NO_CONNECTION_AVAILABLE;
|
||||||
break;
|
goto out;
|
||||||
case CPOOL_LIMIT_TOTAL:
|
case CPOOL_LIMIT_TOTAL:
|
||||||
if(data->master_mid != UINT32_MAX)
|
if(data->master_mid != UINT32_MAX)
|
||||||
CURL_TRC_M(data, "Allowing sub-requests (like DoH) to override "
|
CURL_TRC_M(data, "Allowing sub-requests (like DoH) to override "
|
||||||
|
|
@ -3511,7 +3498,8 @@ static CURLcode create_conn(struct Curl_easy *data,
|
||||||
else {
|
else {
|
||||||
infof(data, "No connections available, total of %zu reached.",
|
infof(data, "No connections available, total of %zu reached.",
|
||||||
data->multi->max_total_connections);
|
data->multi->max_total_connections);
|
||||||
connections_available = FALSE;
|
result = CURLE_NO_CONNECTION_AVAILABLE;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
@ -3519,29 +3507,20 @@ static CURLcode create_conn(struct Curl_easy *data,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!connections_available) {
|
/* Convert needle into a full connection by filling in all the
|
||||||
Curl_conn_free(data, conn);
|
* remaining parts like the cloned SSL configuration. */
|
||||||
*in_connect = NULL;
|
result = Curl_ssl_conn_config_init(data, needle);
|
||||||
|
if(result) {
|
||||||
result = CURLE_NO_CONNECTION_AVAILABLE;
|
DEBUGF(curl_mfprintf(stderr, "Error: init connection ssl config\n"));
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
else {
|
/* attach it and no longer own it */
|
||||||
/*
|
Curl_attach_connection(data, needle);
|
||||||
* This is a brand new connection, so let's store it in the connection
|
needle = NULL;
|
||||||
* cache of ours!
|
|
||||||
*/
|
|
||||||
result = Curl_ssl_conn_config_init(data, conn);
|
|
||||||
if(result) {
|
|
||||||
DEBUGF(curl_mfprintf(stderr, "Error: init connection ssl config\n"));
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
Curl_attach_connection(data, conn);
|
result = Curl_cpool_add(data, data->conn);
|
||||||
result = Curl_cpool_add(data, conn);
|
if(result)
|
||||||
if(result)
|
goto out;
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef USE_NTLM
|
#ifdef USE_NTLM
|
||||||
/* If NTLM is requested in a part of this connection, make sure we do not
|
/* If NTLM is requested in a part of this connection, make sure we do not
|
||||||
|
|
@ -3564,43 +3543,34 @@ static CURLcode create_conn(struct Curl_easy *data,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setup and init stuff before DO starts, in preparing for the transfer. */
|
/* Setup and init stuff before DO starts, in preparing for the transfer. */
|
||||||
result = Curl_init_do(data, conn);
|
result = Curl_init_do(data, data->conn);
|
||||||
if(result)
|
if(result)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/*
|
/* Setup whatever necessary for a resumed transfer */
|
||||||
* Setup whatever necessary for a resumed transfer
|
|
||||||
*/
|
|
||||||
result = setup_range(data);
|
result = setup_range(data);
|
||||||
if(result)
|
if(result)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* Continue connectdata initialization here. */
|
|
||||||
|
|
||||||
if(conn->bits.reuse) {
|
|
||||||
/* We are reusing the connection - no need to resolve anything, and
|
|
||||||
idnconvert_hostname() was called already in create_conn() for the reuse
|
|
||||||
case. */
|
|
||||||
*reusedp = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* persist the scheme and handler the transfer is using */
|
/* persist the scheme and handler the transfer is using */
|
||||||
data->info.conn_scheme = conn->scheme->name;
|
data->info.conn_scheme = data->conn->scheme->name;
|
||||||
/* conn_protocol can only provide "old" protocols */
|
/* conn_protocol can only provide "old" protocols */
|
||||||
data->info.conn_protocol = (conn->scheme->protocol) & CURLPROTO_MASK;
|
data->info.conn_protocol = (data->conn->scheme->protocol) & CURLPROTO_MASK;
|
||||||
data->info.used_proxy =
|
data->info.used_proxy =
|
||||||
#ifdef CURL_DISABLE_PROXY
|
#ifdef CURL_DISABLE_PROXY
|
||||||
0
|
0
|
||||||
#else
|
#else
|
||||||
conn->bits.proxy
|
data->conn->bits.proxy
|
||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
|
|
||||||
/* Everything general done, inform filters that they need
|
/* Lastly, inform connection filters that a new transfer is attached */
|
||||||
* to prepare for a data transfer. */
|
|
||||||
result = Curl_conn_ev_data_setup(data);
|
result = Curl_conn_ev_data_setup(data);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
if(needle)
|
||||||
|
Curl_conn_free(data, needle);
|
||||||
|
DEBUGASSERT(result || data->conn);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3636,7 +3606,6 @@ CURLcode Curl_connect(struct Curl_easy *data,
|
||||||
{
|
{
|
||||||
CURLcode result;
|
CURLcode result;
|
||||||
struct connectdata *conn;
|
struct connectdata *conn;
|
||||||
bool reused = FALSE;
|
|
||||||
|
|
||||||
*asyncp = FALSE; /* assume synchronous resolves by default */
|
*asyncp = FALSE; /* assume synchronous resolves by default */
|
||||||
*protocol_done = FALSE;
|
*protocol_done = FALSE;
|
||||||
|
|
@ -3644,8 +3613,9 @@ CURLcode Curl_connect(struct Curl_easy *data,
|
||||||
/* Set the request to virgin state based on transfer settings */
|
/* Set the request to virgin state based on transfer settings */
|
||||||
Curl_req_hard_reset(&data->req, data);
|
Curl_req_hard_reset(&data->req, data);
|
||||||
|
|
||||||
/* call the stuff that needs to be called */
|
/* Get or create a connection for the transfer. */
|
||||||
result = create_conn(data, &conn, &reused);
|
result = url_find_or_create_conn(data);
|
||||||
|
conn = data->conn;
|
||||||
|
|
||||||
if(result == CURLE_NO_CONNECTION_AVAILABLE) {
|
if(result == CURLE_NO_CONNECTION_AVAILABLE) {
|
||||||
DEBUGASSERT(!conn);
|
DEBUGASSERT(!conn);
|
||||||
|
|
@ -3655,7 +3625,7 @@ CURLcode Curl_connect(struct Curl_easy *data,
|
||||||
if(!result) {
|
if(!result) {
|
||||||
DEBUGASSERT(conn);
|
DEBUGASSERT(conn);
|
||||||
Curl_pgrsTime(data, TIMER_POSTQUEUE);
|
Curl_pgrsTime(data, TIMER_POSTQUEUE);
|
||||||
if(reused) {
|
if(conn->bits.reuse) {
|
||||||
if(conn->attached_xfers > 1)
|
if(conn->attached_xfers > 1)
|
||||||
/* multiplexed */
|
/* multiplexed */
|
||||||
*protocol_done = TRUE;
|
*protocol_done = TRUE;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue