summaryrefslogtreecommitdiff
path: root/libs/libcurl/src/url.c
diff options
context:
space:
mode:
authordartraiden <wowemuh@gmail.com>2018-06-01 22:53:12 +0300
committerdartraiden <wowemuh@gmail.com>2018-06-01 23:14:03 +0300
commit2a7aa481eaf81a71e5c5682974fffe1aa1fc6202 (patch)
tree4df2f855b4235490e9b63f89927784fd4ea3220a /libs/libcurl/src/url.c
parentdf32d54d3b04bd5b4cfdc550b0d8b01fc12a7c15 (diff)
libs/libcurl: update to 7.60
Diffstat (limited to 'libs/libcurl/src/url.c')
-rw-r--r--libs/libcurl/src/url.c380
1 files changed, 180 insertions, 200 deletions
diff --git a/libs/libcurl/src/url.c b/libs/libcurl/src/url.c
index 47f69c9f14..701f83ab3b 100644
--- a/libs/libcurl/src/url.c
+++ b/libs/libcurl/src/url.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -55,9 +55,7 @@
#error "We can't compile without socket() support!"
#endif
-#ifdef HAVE_LIMITS_H
#include <limits.h>
-#endif
#ifdef USE_LIBIDN2
#include <idn2.h>
@@ -127,10 +125,6 @@ bool curl_win32_idn_to_ascii(const char *in, char **out);
#include "curl_memory.h"
#include "memdebug.h"
-/* Local static prototypes */
-static struct connectdata *
-find_oldest_idle_connection_in_bundle(struct Curl_easy *data,
- struct connectbundle *bundle);
static void conn_free(struct connectdata *conn);
static void free_fixed_hostname(struct hostname *host);
static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke);
@@ -196,8 +190,11 @@ static const struct Curl_handler * const protocols[] = {
&Curl_handler_tftp,
#endif
-#ifdef USE_LIBSSH2
+#if defined(USE_LIBSSH2) || defined(USE_LIBSSH)
&Curl_handler_scp,
+#endif
+
+#if defined(USE_LIBSSH2) || defined(USE_LIBSSH)
&Curl_handler_sftp,
#endif
@@ -294,6 +291,8 @@ void Curl_freeset(struct Curl_easy *data)
data->change.url_alloc = FALSE;
}
data->change.url = NULL;
+
+ Curl_mime_cleanpart(&data->set.mimepost);
}
/*
@@ -383,8 +382,6 @@ CURLcode Curl_close(struct Curl_easy *data)
Curl_http2_cleanup_dependencies(data);
Curl_convert_close(data);
- Curl_mime_cleanpart(&data->set.mimepost);
-
/* No longer a dirty share, if it exists */
if(data->share) {
Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
@@ -403,8 +400,9 @@ CURLcode Curl_close(struct Curl_easy *data)
* Initialize the UserDefined fields within a Curl_easy.
* This may be safely called on a new or existing Curl_easy.
*/
-CURLcode Curl_init_userdefined(struct UserDefined *set)
+CURLcode Curl_init_userdefined(struct Curl_easy *data)
{
+ struct UserDefined *set = &data->set;
CURLcode result = CURLE_OK;
set->out = stdout; /* default output to stdout */
@@ -454,6 +452,8 @@ CURLcode Curl_init_userdefined(struct UserDefined *set)
/* make libcurl quiet by default: */
set->hide_progress = TRUE; /* CURLOPT_NOPROGRESS changes these */
+ Curl_mime_initpart(&set->mimepost, data);
+
/*
* libcurl 7.10 introduced SSL verification *by default*! This needs to be
* switched off unless wanted.
@@ -488,25 +488,33 @@ CURLcode Curl_init_userdefined(struct UserDefined *set)
set->socks5_gssapi_nec = FALSE;
#endif
- /* This is our preferred CA cert bundle/path since install time */
+ /* Set the default CA cert bundle/path detected/specified at build time.
+ *
+ * If Schannel (WinSSL) is the selected SSL backend then these locations
+ * are ignored. We allow setting CA location for schannel only when
+ * explicitly specified by the user via CURLOPT_CAINFO / --cacert.
+ */
+ if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL) {
#if defined(CURL_CA_BUNDLE)
- result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_ORIG], CURL_CA_BUNDLE);
- if(result)
- return result;
+ result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_ORIG], CURL_CA_BUNDLE);
+ if(result)
+ return result;
- result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_PROXY], CURL_CA_BUNDLE);
- if(result)
- return result;
+ result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_PROXY],
+ CURL_CA_BUNDLE);
+ if(result)
+ return result;
#endif
#if defined(CURL_CA_PATH)
- result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_ORIG], CURL_CA_PATH);
- if(result)
- return result;
+ result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_ORIG], CURL_CA_PATH);
+ if(result)
+ return result;
- result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_PROXY], CURL_CA_PATH);
- if(result)
- return result;
+ result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_PROXY], CURL_CA_PATH);
+ if(result)
+ return result;
#endif
+ }
set->wildcard_enabled = FALSE;
set->chunk_bgn = ZERO_NULL;
@@ -527,6 +535,7 @@ CURLcode Curl_init_userdefined(struct UserDefined *set)
set->expect_100_timeout = 1000L; /* Wait for a second by default. */
set->sep_headers = TRUE; /* separated header lists by default */
set->buffer_size = READBUFFER_SIZE;
+ set->happy_eyeballs_timeout = CURL_HET_DEFAULT;
Curl_http2_init_userset(set);
return result;
@@ -570,15 +579,13 @@ CURLcode Curl_open(struct Curl_easy **curl)
result = CURLE_OUT_OF_MEMORY;
}
else {
- Curl_mime_initpart(&data->set.mimepost, data);
-
data->state.headerbuff = malloc(HEADERSIZE);
if(!data->state.headerbuff) {
DEBUGF(fprintf(stderr, "Error: malloc of headerbuff failed\n"));
result = CURLE_OUT_OF_MEMORY;
}
else {
- result = Curl_init_userdefined(&data->set);
+ result = Curl_init_userdefined(data);
data->state.headersize = HEADERSIZE;
Curl_convert_init(data);
@@ -716,6 +723,9 @@ static void conn_free(struct connectdata *conn)
Curl_safefree(conn->unix_domain_socket);
#endif
+#ifdef USE_SSL
+ Curl_safefree(conn->ssl_extra);
+#endif
free(conn); /* free all the connection oriented data */
}
@@ -770,7 +780,7 @@ CURLcode Curl_disconnect(struct connectdata *conn, bool dead_connection)
/* unlink ourselves! */
infof(data, "Closing connection %ld\n", conn->connection_id);
- Curl_conncache_remove_conn(data->state.conn_cache, conn);
+ Curl_conncache_remove_conn(conn, TRUE);
free_fixed_hostname(&conn->host);
free_fixed_hostname(&conn->conn_to_host);
@@ -936,56 +946,17 @@ proxy_info_matches(const struct proxy_info* data,
return FALSE;
}
-
/*
- * This function finds the connection in the connection
- * bundle that has been unused for the longest time.
+ * This function checks if the given connection is dead and extracts it from
+ * the connection cache if so.
*
- * Returns the pointer to the oldest idle connection, or NULL if none was
- * found.
- */
-static struct connectdata *
-find_oldest_idle_connection_in_bundle(struct Curl_easy *data,
- struct connectbundle *bundle)
-{
- struct curl_llist_element *curr;
- timediff_t highscore = -1;
- timediff_t score;
- struct curltime now;
- struct connectdata *conn_candidate = NULL;
- struct connectdata *conn;
-
- (void)data;
-
- now = Curl_now();
-
- curr = bundle->conn_list.head;
- while(curr) {
- conn = curr->ptr;
-
- if(!conn->inuse) {
- /* Set higher score for the age passed since the connection was used */
- score = Curl_timediff(now, conn->now);
-
- if(score > highscore) {
- highscore = score;
- conn_candidate = conn;
- }
- }
- curr = curr->next;
- }
-
- return conn_candidate;
-}
-
-/*
- * This function checks if given connection is dead and disconnects if so.
- * (That also removes it from the connection cache.)
+ * When this is called as a Curl_conncache_foreach() callback, the connection
+ * cache lock is held!
*
- * Returns TRUE if the connection actually was dead and disconnected.
+ * Returns TRUE if the connection was dead and extracted.
*/
-static bool disconnect_if_dead(struct connectdata *conn,
- struct Curl_easy *data)
+static bool extract_if_dead(struct connectdata *conn,
+ struct Curl_easy *data)
{
size_t pipeLen = conn->send_pipe.size + conn->recv_pipe.size;
if(!pipeLen && !conn->inuse) {
@@ -1010,25 +981,30 @@ static bool disconnect_if_dead(struct connectdata *conn,
if(dead) {
conn->data = data;
infof(data, "Connection %ld seems to be dead!\n", conn->connection_id);
-
- /* disconnect resources */
- Curl_disconnect(conn, /* dead_connection */TRUE);
+ Curl_conncache_remove_conn(conn, FALSE);
return TRUE;
}
}
return FALSE;
}
+struct prunedead {
+ struct Curl_easy *data;
+ struct connectdata *extracted;
+};
+
/*
- * Wrapper to use disconnect_if_dead() function in Curl_conncache_foreach()
+ * Wrapper to use extract_if_dead() function in Curl_conncache_foreach()
*
- * Returns always 0.
*/
-static int call_disconnect_if_dead(struct connectdata *conn,
- void *param)
+static int call_extract_if_dead(struct connectdata *conn, void *param)
{
- struct Curl_easy* data = (struct Curl_easy*)param;
- disconnect_if_dead(conn, data);
+ struct prunedead *p = (struct prunedead *)param;
+ if(extract_if_dead(conn, p->data)) {
+ /* stop the iteration here, pass back the connection that was extracted */
+ p->extracted = conn;
+ return 1;
+ }
return 0; /* continue iteration */
}
@@ -1043,8 +1019,14 @@ static void prune_dead_connections(struct Curl_easy *data)
time_t elapsed = Curl_timediff(now, data->state.conn_cache->last_cleanup);
if(elapsed >= 1000L) {
- Curl_conncache_foreach(data, data->state.conn_cache, data,
- call_disconnect_if_dead);
+ struct prunedead prune;
+ prune.data = data;
+ prune.extracted = NULL;
+ while(Curl_conncache_foreach(data, data->state.conn_cache, &prune,
+ call_extract_if_dead)) {
+ /* disconnect it */
+ (void)Curl_disconnect(prune.extracted, /* dead_connection */TRUE);
+ }
data->state.conn_cache->last_cleanup = now;
}
}
@@ -1099,8 +1081,8 @@ ConnectionExists(struct Curl_easy *data,
Curl_pipeline_site_blacklisted(data, needle))
canpipe &= ~ CURLPIPE_HTTP1;
- /* Look up the bundle with all the connections to this
- particular host */
+ /* Look up the bundle with all the connections to this particular host.
+ Locks the connection cache, beware of early returns! */
bundle = Curl_conncache_find_bundle(needle, data->state.conn_cache);
if(bundle) {
/* Max pipe length is zero (unlimited) for multiplexed connections */
@@ -1123,6 +1105,7 @@ ConnectionExists(struct Curl_easy *data,
if((bundle->multiuse == BUNDLE_UNKNOWN) && data->set.pipewait) {
infof(data, "Server doesn't support multi-use yet, wait\n");
*waitpipe = TRUE;
+ Curl_conncache_unlock(needle);
return FALSE; /* no re-use */
}
@@ -1154,8 +1137,11 @@ ConnectionExists(struct Curl_easy *data,
check = curr->ptr;
curr = curr->next;
- if(disconnect_if_dead(check, data))
+ if(extract_if_dead(check, data)) {
+ /* disconnect it */
+ (void)Curl_disconnect(check, /* dead_connection */TRUE);
continue;
+ }
pipeLen = check->send_pipe.size + check->recv_pipe.size;
@@ -1286,6 +1272,11 @@ ConnectionExists(struct Curl_easy *data,
already in use so we skip it */
continue;
+ if((check->inuse) && (check->data->multi != needle->data->multi))
+ /* this could be subject for pipeline/multiplex use, but only
+ if they belong to the same multi handle */
+ continue;
+
if(needle->localdev || needle->localport) {
/* If we are bound to a specific local end (IP+port), we must not
re-use a random other one, although if we didn't ask for a
@@ -1472,9 +1463,13 @@ ConnectionExists(struct Curl_easy *data,
}
if(chosen) {
+ /* mark it as used before releasing the lock */
+ chosen->inuse = TRUE;
+ Curl_conncache_unlock(needle);
*usethis = chosen;
return TRUE; /* yes, we found one to use! */
}
+ Curl_conncache_unlock(needle);
if(foundPendingCandidate && data->set.pipewait) {
infof(data,
@@ -1793,38 +1788,27 @@ static void llist_dtor(void *user, void *element)
*/
static struct connectdata *allocate_conn(struct Curl_easy *data)
{
- struct connectdata *conn;
- size_t connsize = sizeof(struct connectdata);
-
-#ifdef USE_SSL
-/* SSLBK_MAX_ALIGN: The max byte alignment a CPU would use */
-#define SSLBK_MAX_ALIGN 32
- /* The SSL backend-specific data (ssl_backend_data) objects are allocated as
- part of connectdata at the end. To ensure suitable alignment we will
- assume a maximum of SSLBK_MAX_ALIGN for alignment. Since calloc returns a
- pointer suitably aligned for any variable this will ensure the
- ssl_backend_data array has proper alignment, even if that alignment turns
- out to be less than SSLBK_MAX_ALIGN. */
- size_t paddingsize = sizeof(struct connectdata) % SSLBK_MAX_ALIGN;
- size_t alignsize = paddingsize ? (SSLBK_MAX_ALIGN - paddingsize) : 0;
- size_t sslbksize = Curl_ssl->sizeof_ssl_backend_data;
- connsize += alignsize + (4 * sslbksize);
-#endif
-
- conn = calloc(1, connsize);
+ struct connectdata *conn = calloc(1, sizeof(struct connectdata));
if(!conn)
return NULL;
#ifdef USE_SSL
- /* Point to the ssl_backend_data objects at the end of connectdata.
+ /* The SSL backend-specific data (ssl_backend_data) objects are allocated as
+ a separate array to ensure suitable alignment.
Note that these backend pointers can be swapped by vtls (eg ssl backend
data becomes proxy backend data). */
{
- char *end = (char *)conn + connsize;
- conn->ssl[0].backend = ((void *)(end - (4 * sslbksize)));
- conn->ssl[1].backend = ((void *)(end - (3 * sslbksize)));
- conn->proxy_ssl[0].backend = ((void *)(end - (2 * sslbksize)));
- conn->proxy_ssl[1].backend = ((void *)(end - (1 * sslbksize)));
+ size_t sslsize = Curl_ssl->sizeof_ssl_backend_data;
+ char *ssl = calloc(4, sslsize);
+ if(!ssl) {
+ free(conn);
+ return NULL;
+ }
+ conn->ssl_extra = ssl;
+ conn->ssl[0].backend = (void *)ssl;
+ conn->ssl[1].backend = (void *)(ssl + sslsize);
+ conn->proxy_ssl[0].backend = (void *)(ssl + 2 * sslsize);
+ conn->proxy_ssl[1].backend = (void *)(ssl + 3 * sslsize);
}
#endif
@@ -1953,6 +1937,9 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
free(conn->master_buffer);
free(conn->localdev);
+#ifdef USE_SSL
+ free(conn->ssl_extra);
+#endif
free(conn);
return NULL;
}
@@ -2054,7 +2041,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
((('a' <= (str)[0] && (str)[0] <= 'z') || \
('A' <= (str)[0] && (str)[0] <= 'Z')) && \
((str)[1] == ':' || (str)[1] == '|') && \
- ((str)[2] == '/' || (str)[2] == 0))
+ ((str)[2] == '/' || (str)[2] == '\\' || (str)[2] == 0))
/* Don't mistake a drive letter for a scheme if the default protocol is file.
curld --proto-default file c:/foo/bar.txt */
@@ -2088,15 +2075,6 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
return CURLE_URL_MALFORMAT;
}
- if(url_has_scheme && path[0] == '/' && path[1] == '/' &&
- path[2] == '/' && path[3] == '/') {
- /* This appears to be a UNC string (usually indicating a SMB share).
- * We don't do SMB in file: URLs. (TODO?)
- */
- failf(data, "SMB shares are not supported in file: URLs.");
- return CURLE_URL_MALFORMAT;
- }
-
/* Extra handling URLs with an authority component (i.e. that start with
* "file://")
*
@@ -2135,25 +2113,6 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
ptr += 9; /* now points to the slash after the host */
}
- /*
- * RFC 8089, Appendix D, Section D.1, says:
- *
- * > In a POSIX file system, the root of the file system is represented
- * > as a directory with a zero-length name, usually written as "/"; the
- * > presence of this root in a file URI can be taken as given by the
- * > initial slash in the "path-absolute" rule.
- *
- * i.e. the first slash is part of the path.
- *
- * However in RFC 1738 the "/" between the host (or port) and the
- * URL-path was NOT part of the URL-path. Any agent that followed the
- * older spec strictly, and wanted to refer to a file with an absolute
- * path, would have included a second slash. So if there are two
- * slashes, swallow one.
- */
- if('/' == ptr[1]) /* note: the only way ptr[0]!='/' is if ptr[1]==':' */
- ptr++;
-
/* This cannot be done with strcpy, as the memory chunks overlap! */
memmove(path, ptr, strlen(ptr) + 1);
}
@@ -2595,7 +2554,15 @@ static bool check_noproxy(const char *name, const char *no_proxy)
/* NO_PROXY was specified and it wasn't just an asterisk */
no_proxy_len = strlen(no_proxy);
- endptr = strchr(name, ':');
+ if(name[0] == '[') {
+ /* IPv6 numerical address */
+ endptr = strchr(name, ']');
+ if(!endptr)
+ return FALSE;
+ name++;
+ }
+ else
+ endptr = strchr(name, ':');
if(endptr)
namelen = endptr - name;
else
@@ -2703,13 +2670,20 @@ static char *detect_proxy(struct connectdata *conn)
prox = curl_getenv(proxy_env);
}
- if(prox)
+ envp = proxy_env;
+ if(prox) {
proxy = prox; /* use this */
+ }
else {
- proxy = curl_getenv("all_proxy"); /* default proxy to use */
- if(!proxy)
- proxy = curl_getenv("ALL_PROXY");
+ envp = (char *)"all_proxy";
+ proxy = curl_getenv(envp); /* default proxy to use */
+ if(!proxy) {
+ envp = (char *)"ALL_PROXY";
+ proxy = curl_getenv(envp);
+ }
}
+ if(proxy)
+ infof(conn->data, "Uses proxy env variable %s == '%s'\n", envp, proxy);
return proxy;
}
@@ -2766,7 +2740,7 @@ static CURLcode parse_proxy(struct Curl_easy *data,
proxyptr = proxy; /* No xxx:// head: It's a HTTP proxy */
#ifdef USE_SSL
- if(!Curl_ssl->support_https_proxy)
+ if(!(Curl_ssl->supports & SSLSUPP_HTTPS_PROXY))
#endif
if(proxytype == CURLPROXY_HTTPS) {
failf(data, "Unsupported proxy \'%s\', libcurl is built without the "
@@ -2994,9 +2968,15 @@ static CURLcode create_conn_helper_init_proxy(struct connectdata *conn)
}
if(!data->set.str[STRING_NOPROXY]) {
- no_proxy = curl_getenv("no_proxy");
- if(!no_proxy)
- no_proxy = curl_getenv("NO_PROXY");
+ 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(conn->data, "Uses proxy env variable %s == '%s'\n", p, no_proxy);
+ }
}
if(check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY] ?
@@ -3439,7 +3419,7 @@ static CURLcode parse_remote_port(struct Curl_easy *data,
* stripped off. It would be better to work directly from the original
* URL and simply replace the port part of it.
*/
- url = aprintf("%s://%s%s%s:%hu%s%s%s", conn->given->scheme,
+ url = aprintf("%s://%s%s%s:%d%s%s%s", conn->given->scheme,
conn->bits.ipv6_ip?"[":"", conn->host.name,
conn->bits.ipv6_ip?"]":"", conn->remote_port,
data->state.slash_removed?"/":"", data->state.path,
@@ -3634,6 +3614,7 @@ static CURLcode parse_connect_to_host_port(struct Curl_easy *data,
/* detect and extract RFC6874-style IPv6-addresses */
if(*hostptr == '[') {
+#ifdef ENABLE_IPV6
char *ptr = ++hostptr; /* advance beyond the initial bracket */
while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':') || (*ptr == '.')))
ptr++;
@@ -3657,6 +3638,11 @@ static CURLcode parse_connect_to_host_port(struct Curl_easy *data,
* hostptr first, but I can't see anything wrong with that as no host
* name nor a numeric can legally start with a bracket.
*/
+#else
+ failf(data, "Use of IPv6 in *_CONNECT_TO without IPv6 support built-in!");
+ free(host_dup);
+ return CURLE_NOT_BUILT_IN;
+#endif
}
/* Get port number off server.com:1080 */
@@ -4132,7 +4118,7 @@ static CURLcode create_conn(struct Curl_easy *data,
*************************************************************/
if(prot_missing) {
/* We're guessing prefixes here and if we're told to use a proxy or if
- we're gonna follow a Location: later or... then we need the protocol
+ we're going to follow a Location: later or... then we need the protocol
part added so that we have a valid URL. */
char *reurl;
char *ch_lower;
@@ -4410,20 +4396,21 @@ static CURLcode create_conn(struct Curl_easy *data,
else
reuse = ConnectionExists(data, conn, &conn_temp, &force_reuse, &waitpipe);
- /* If we found a reusable connection, we may still want to
- open a new connection if we are pipelining. */
+ /* If we found a reusable connection that is now marked as in use, we may
+ still want to open a new connection if we are pipelining. */
if(reuse && !force_reuse && IsPipeliningPossible(data, conn_temp)) {
size_t pipelen = conn_temp->send_pipe.size + conn_temp->recv_pipe.size;
if(pipelen > 0) {
infof(data, "Found connection %ld, with requests in the pipe (%zu)\n",
conn_temp->connection_id, pipelen);
- if(conn_temp->bundle->num_connections < max_host_connections &&
- data->state.conn_cache->num_connections < max_total_connections) {
+ if(Curl_conncache_bundle_size(conn_temp) < max_host_connections &&
+ Curl_conncache_size(data) < max_total_connections) {
/* We want a new connection anyway */
reuse = FALSE;
infof(data, "We can reuse, but we want a new connection anyway\n");
+ Curl_conncache_return_conn(conn_temp);
}
}
}
@@ -4435,9 +4422,10 @@ static CURLcode create_conn(struct Curl_easy *data,
* just allocated before we can move along and use the previously
* existing one.
*/
- conn_temp->inuse = TRUE; /* mark this as being in use so that no other
- handle in a multi stack may nick it */
reuse_conn(conn, conn_temp);
+#ifdef USE_SSL
+ free(conn->ssl_extra);
+#endif
free(conn); /* we don't need this anymore */
conn = conn_temp;
*in_connect = conn;
@@ -4453,7 +4441,6 @@ static CURLcode create_conn(struct Curl_easy *data,
/* 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
connections we are allowed to open. */
- struct connectbundle *bundle = NULL;
if(conn->handler->flags & PROTOPT_ALPN_NPN) {
/* The protocol wants it, so set the bits if enabled in the easy handle
@@ -4468,35 +4455,42 @@ static CURLcode create_conn(struct Curl_easy *data,
/* There is a connection that *might* become usable for pipelining
"soon", and we wait for that */
connections_available = FALSE;
- else
- bundle = Curl_conncache_find_bundle(conn, data->state.conn_cache);
-
- if(max_host_connections > 0 && bundle &&
- (bundle->num_connections >= max_host_connections)) {
- struct connectdata *conn_candidate;
-
- /* The bundle is full. Let's see if we can kill a connection. */
- conn_candidate = find_oldest_idle_connection_in_bundle(data, bundle);
-
- if(conn_candidate) {
- /* Set the connection's owner correctly, then kill it */
- conn_candidate->data = data;
- (void)Curl_disconnect(conn_candidate, /* dead_connection */ FALSE);
- }
- else {
- infof(data, "No more connections allowed to host: %d\n",
- max_host_connections);
- connections_available = FALSE;
+ else {
+ /* this gets a lock on the conncache */
+ struct connectbundle *bundle =
+ Curl_conncache_find_bundle(conn, data->state.conn_cache);
+
+ if(max_host_connections > 0 && bundle &&
+ (bundle->num_connections >= max_host_connections)) {
+ struct connectdata *conn_candidate;
+
+ /* The bundle is full. Extract the oldest connection. */
+ conn_candidate = Curl_conncache_extract_bundle(data, bundle);
+ Curl_conncache_unlock(conn);
+
+ if(conn_candidate) {
+ /* Set the connection's owner correctly, then kill it */
+ conn_candidate->data = data;
+ (void)Curl_disconnect(conn_candidate, /* dead_connection */ FALSE);
+ }
+ else {
+ infof(data, "No more connections allowed to host: %d\n",
+ max_host_connections);
+ connections_available = FALSE;
+ }
}
+ else
+ Curl_conncache_unlock(conn);
+
}
if(connections_available &&
(max_total_connections > 0) &&
- (data->state.conn_cache->num_connections >= max_total_connections)) {
+ (Curl_conncache_size(data) >= max_total_connections)) {
struct connectdata *conn_candidate;
/* The cache is full. Let's see if we can kill a connection. */
- conn_candidate = Curl_conncache_oldest_idle(data);
+ conn_candidate = Curl_conncache_extract_oldest(data);
if(conn_candidate) {
/* Set the connection's owner correctly, then kill it */
@@ -4519,6 +4513,9 @@ static CURLcode create_conn(struct Curl_easy *data,
goto out;
}
else {
+ /* Mark the connection as used, before we add it */
+ conn->inuse = TRUE;
+
/*
* This is a brand new connection, so let's store it in the connection
* cache of ours!
@@ -4546,9 +4543,6 @@ static CURLcode create_conn(struct Curl_easy *data,
#endif
}
- /* Mark the connection as used */
- conn->inuse = TRUE;
-
/* Setup and init stuff before DO starts, in preparing for the transfer. */
Curl_init_do(data, conn);
@@ -4648,22 +4642,8 @@ CURLcode Curl_setup_conn(struct connectdata *conn,
Curl_verboseconnect(conn);
}
- conn->now = Curl_now(); /* time this *after* the connect is done, we
- set this here perhaps a second time */
-
-#ifdef __EMX__
- /*
- * This check is quite a hack. We're calling _fsetmode to fix the problem
- * with fwrite converting newline characters (you get mangled text files,
- * and corrupted binary files when you download to stdout and redirect it to
- * a file).
- */
-
- if((data->set.out)->_handle == NULL) {
- _fsetmode(stdout, "b");
- }
-#endif
-
+ conn->now = Curl_now(); /* time this *after* the connect is done, we set
+ this here perhaps a second time */
return result;
}