]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
url.c: code/comment cleanup around conn creation
authorStefan Eissing <stefan@eissing.org>
Wed, 28 Jan 2026 16:20:57 +0000 (17:20 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Thu, 5 Feb 2026 16:21:53 +0000 (17:21 +0100)
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

lib/url.c

index b0d5c1ab3925a14a1139b3020687780739061b84..fac8cea732b04896e737473148facb8d161d33c5 100644 (file)
--- a/lib/url.c
+++ b/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
- * detect if there already is one that has all the significant details
- * exactly the same and thus should be used instead.
+ * Given a transfer and a prototype connection (needle),
+ * find and attach an existing connection that matches.
  *
- * If there is a match, this function returns TRUE - and has marked the
- * connection as 'in-use'. It must later be called with ConnectionDone() to
- * return back to 'idle' (unused) state.
- *
- * The force_reuse flag is set if the connection must be used.
+ * Return TRUE if an existing connection was attached.
+ * `waitpipe` is TRUE if no existing connection matched, but there
+ * might be suitable one in the near future (common cause: multiplexing
+ * capability has not been determined yet, e.g. ALPN handshake).
  */
-static bool ConnectionExists(struct Curl_easy *data,
-                             struct connectdata *needle,
-                             struct connectdata **usethis,
-                             bool *force_reuse,
-                             bool *waitpipe)
+static bool url_attach_existing(struct Curl_easy *data,
+                                struct connectdata *needle,
+                                bool *waitpipe)
 {
   struct url_conn_match match;
   bool result;
 
+  DEBUGASSERT(!data->conn);
   memset(&match, 0, sizeof(match));
   match.data = data;
   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
    * is no matching connection then, yet. */
-  *usethis = match.found;
-  *force_reuse = (bool)match.force_reuse;
   *waitpipe = (bool)match.wait_pipe;
   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
- * previously `existing` one for `data`. All relevant info is copied over
- * and `temp` is freed.
+ * Adjust reused connection settings to the transfer/needle.
  */
-static void reuse_conn(struct Curl_easy *data,
-                       struct connectdata *temp,
-                       struct connectdata *existing)
+static void url_conn_reuse_adjust(struct Curl_easy *data,
+                                  struct connectdata *needle)
 {
-  /* get the user+password information from the temp struct since it may
-   * be new for this request even when we reuse an existing connection */
-  if(temp->user) {
+  struct connectdata *conn = data->conn;
+
+  /* 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 */
-    curlx_free(existing->user);
-    curlx_free(existing->passwd);
-    existing->user = temp->user;
-    existing->passwd = temp->passwd;
-    temp->user = NULL;
-    temp->passwd = NULL;
+    curlx_free(conn->user);
+    curlx_free(conn->passwd);
+    conn->user = needle->user;
+    conn->passwd = needle->passwd;
+    needle->user = NULL;
+    needle->passwd = NULL;
   }
 
 #ifndef CURL_DISABLE_PROXY
-  existing->bits.proxy_user_passwd = temp->bits.proxy_user_passwd;
-  if(existing->bits.proxy_user_passwd) {
+  conn->bits.proxy_user_passwd = needle->bits.proxy_user_passwd;
+  if(conn->bits.proxy_user_passwd) {
     /* use the new proxy username and proxy password though */
-    curlx_free(existing->http_proxy.user);
-    curlx_free(existing->socks_proxy.user);
-    curlx_free(existing->http_proxy.passwd);
-    curlx_free(existing->socks_proxy.passwd);
-    existing->http_proxy.user = temp->http_proxy.user;
-    existing->socks_proxy.user = temp->socks_proxy.user;
-    existing->http_proxy.passwd = temp->http_proxy.passwd;
-    existing->socks_proxy.passwd = temp->socks_proxy.passwd;
-    temp->http_proxy.user = NULL;
-    temp->socks_proxy.user = NULL;
-    temp->http_proxy.passwd = NULL;
-    temp->socks_proxy.passwd = NULL;
+    curlx_free(conn->http_proxy.user);
+    curlx_free(conn->socks_proxy.user);
+    curlx_free(conn->http_proxy.passwd);
+    curlx_free(conn->socks_proxy.passwd);
+    conn->http_proxy.user = needle->http_proxy.user;
+    conn->socks_proxy.user = needle->socks_proxy.user;
+    conn->http_proxy.passwd = needle->http_proxy.passwd;
+    conn->socks_proxy.passwd = needle->socks_proxy.passwd;
+    needle->http_proxy.user = NULL;
+    needle->socks_proxy.user = NULL;
+    needle->http_proxy.passwd = NULL;
+    needle->socks_proxy.passwd = NULL;
   }
 #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
    *   that use the same proxy on this connection.
    * - we have a "connect-to" setting that may redirect the hostname of
-   *   a new request to the same remote endpoint of an existing conn.
-   *   We want to reuse an existing conn to the remote endpoint.
+   *   a new request to the same remote endpoint of an conn conn.
+   *   We want to reuse an conn conn to the remote endpoint.
    * Since connection reuse does not match on conn->host necessarily, we
-   * switch `existing` conn to `temp` conn'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?
+   * switch conn to needle's host settings.
    */
-  url_move_hostname(&existing->host, &temp->host);
-  url_move_hostname(&existing->conn_to_host, &temp->conn_to_host);
+  url_move_hostname(&conn->host, &needle->host);
+  url_move_hostname(&conn->conn_to_host, &needle->conn_to_host);
 
-  existing->conn_to_port = temp->conn_to_port;
-  existing->remote_port = temp->remote_port;
-  curlx_free(existing->hostname_resolve);
-  existing->hostname_resolve = temp->hostname_resolve;
-  temp->hostname_resolve = NULL;
-
-  /* reuse init */
-  existing->bits.reuse = TRUE; /* yes, we are reusing here */
-
-  Curl_conn_free(data, temp);
+  conn->conn_to_port = needle->conn_to_port;
+  conn->remote_port = needle->remote_port;
+  curlx_free(conn->hostname_resolve);
+  conn->hostname_resolve = needle->hostname_resolve;
+  needle->hostname_resolve = NULL;
 }
 
 static void conn_meta_freeentry(void *p)
@@ -3195,35 +3181,11 @@ static void conn_meta_freeentry(void *p)
   DEBUGASSERT(p == NULL);
 }
 
-/**
- * create_conn() sets up a new connectdata struct, or reuses an already
- * 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)
+static CURLcode url_create_needle(struct Curl_easy *data,
+                                  struct connectdata **pneedle)
 {
+  struct connectdata *needle = NULL;
   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
@@ -3237,37 +3199,31 @@ static CURLcode create_conn(struct Curl_easy *data,
      parts for checking against the already present connections. In order
      to not have to modify everything at once, we allocate a temporary
      connection data struct and fill in for comparison purposes. */
-  conn = allocate_conn(data);
-
-  if(!conn) {
+  needle = allocate_conn(data);
+  if(!needle) {
     result = CURLE_OUT_OF_MEMORY;
     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 */
-  Curl_hash_init(&conn->meta_hash, 23,
+  Curl_hash_init(&needle->meta_hash, 23,
                  Curl_hash_str, curlx_str_key_compare, conn_meta_freeentry);
 
-  result = parseurlandfillconn(data, conn);
+  result = parseurlandfillconn(data, needle);
   if(result)
     goto out;
 
   if(data->set.str[STRING_SASL_AUTHZID]) {
-    conn->sasl_authzid = curlx_strdup(data->set.str[STRING_SASL_AUTHZID]);
-    if(!conn->sasl_authzid) {
+    needle->sasl_authzid = curlx_strdup(data->set.str[STRING_SASL_AUTHZID]);
+    if(!needle->sasl_authzid) {
       result = CURLE_OUT_OF_MEMORY;
       goto out;
     }
   }
 
   if(data->set.str[STRING_BEARER]) {
-    conn->oauth_bearer = curlx_strdup(data->set.str[STRING_BEARER]);
-    if(!conn->oauth_bearer) {
+    needle->oauth_bearer = curlx_strdup(data->set.str[STRING_BEARER]);
+    if(!needle->oauth_bearer) {
       result = CURLE_OUT_OF_MEMORY;
       goto out;
     }
@@ -3275,20 +3231,20 @@ static CURLcode create_conn(struct Curl_easy *data,
 
 #ifdef USE_UNIX_SOCKETS
   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]);
-    if(!conn->unix_domain_socket) {
+    if(!needle->unix_domain_socket) {
       result = CURLE_OUT_OF_MEMORY;
       goto out;
     }
-    conn->bits.abstract_unix_socket = data->set.abstract_unix_socket;
+    needle->bits.abstract_unix_socket = data->set.abstract_unix_socket;
   }
 #endif
 
   /* After the Unix socket init but before the proxy vars are used, parse and
      initialize the proxy vars */
 #ifndef CURL_DISABLE_PROXY
-  result = create_conn_helper_init_proxy(data, conn);
+  result = create_conn_helper_init_proxy(data, needle);
   if(result)
     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
    * the tunnel_proxy bit.
    *************************************************************/
-  if((conn->given->flags & PROTOPT_SSL) && conn->bits.httpproxy)
-    conn->bits.tunnel_proxy = TRUE;
+  if((needle->given->flags & PROTOPT_SSL) && needle->bits.httpproxy)
+    needle->bits.tunnel_proxy = TRUE;
 #endif
 
   /*************************************************************
    * 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)
     goto out;
 
   /* Check for overridden login details and set them accordingly so that
      they are known when protocol->setup_connection is called! */
-  result = override_login(data, conn);
+  result = override_login(data, needle);
   if(result)
     goto out;
 
-  result = set_login(data, conn); /* default credentials */
+  result = set_login(data, needle); /* default credentials */
   if(result)
     goto out;
 
@@ -3321,7 +3277,7 @@ static CURLcode create_conn(struct Curl_easy *data,
    * Process the "connect to" linked list of hostname/port mappings.
    * 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)
     goto out;
 
@@ -3329,38 +3285,39 @@ static CURLcode create_conn(struct Curl_easy *data,
    * IDN-convert the proxy hostnames
    *************************************************************/
 #ifndef CURL_DISABLE_PROXY
-  if(conn->bits.httpproxy) {
-    result = Curl_idnconvert_hostname(&conn->http_proxy.host);
+  if(needle->bits.httpproxy) {
+    result = Curl_idnconvert_hostname(&needle->http_proxy.host);
     if(result)
-      return result;
+      goto out;
   }
-  if(conn->bits.socksproxy) {
-    result = Curl_idnconvert_hostname(&conn->socks_proxy.host);
+  if(needle->bits.socksproxy) {
+    result = Curl_idnconvert_hostname(&needle->socks_proxy.host);
     if(result)
-      return result;
+      goto out;
   }
 #endif
-  if(conn->bits.conn_to_host) {
-    result = Curl_idnconvert_hostname(&conn->conn_to_host);
+  if(needle->bits.conn_to_host) {
+    result = Curl_idnconvert_hostname(&needle->conn_to_host);
     if(result)
-      return result;
+      goto out;
   }
 
   /*************************************************************
    * Check whether the host and the "connect to host" are equal.
    * Do this after the hostnames have been IDN-converted.
    *************************************************************/
-  if(conn->bits.conn_to_host &&
-     curl_strequal(conn->conn_to_host.name, conn->host.name)) {
-    conn->bits.conn_to_host = FALSE;
+  if(needle->bits.conn_to_host &&
+     curl_strequal(needle->conn_to_host.name, needle->host.name)) {
+    needle->bits.conn_to_host = FALSE;
   }
 
   /*************************************************************
    * Check whether the port and the "connect to port" are equal.
    * 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) {
-    conn->bits.conn_to_port = FALSE;
+  if(needle->bits.conn_to_port &&
+     needle->conn_to_port == needle->remote_port) {
+    needle->bits.conn_to_port = FALSE;
   }
 
 #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,
    * we set the tunnel_proxy bit.
    *************************************************************/
-  if((conn->bits.conn_to_host || conn->bits.conn_to_port) &&
-     conn->bits.httpproxy)
-    conn->bits.tunnel_proxy = TRUE;
+  if((needle->bits.conn_to_host || needle->bits.conn_to_port) &&
+     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.
    *************************************************************/
-  result = setup_connection_internals(data, conn);
+  result = setup_connection_internals(data, needle);
+  if(result)
+    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
    ***********************************************************************/
 #ifndef CURL_DISABLE_FILE
-  if(conn->scheme->flags & PROTOPT_NONETWORK) {
+  if(needle->scheme->flags & PROTOPT_NONETWORK) {
     bool done;
     /* this is supposed to be the connect function so we better at least check
        that the file is present here! */
-    DEBUGASSERT(conn->scheme->run->connect_it);
-    data->info.conn_scheme = conn->scheme->name;
+    DEBUGASSERT(needle->scheme->run->connect_it);
+    data->info.conn_scheme = needle->scheme->name;
     /* conn_protocol can only provide "old" protocols */
-    data->info.conn_protocol = (conn->scheme->protocol) & CURLPROTO_MASK;
-    result = conn->scheme->run->connect_it(data, &done);
+    data->info.conn_protocol = (needle->scheme->protocol) & CURLPROTO_MASK;
+    result = needle->scheme->run->connect_it(data, &done);
     if(result)
       goto out;
 
     /* Setup a "faked" transfer that will do nothing */
-    Curl_attach_connection(data, conn);
-    result = Curl_cpool_add(data, conn);
+    Curl_attach_connection(data, needle);
+    needle = NULL;
+    result = Curl_cpool_add(data, data->conn);
     if(!result) {
       /* Setup whatever necessary for a resumed transfer */
       result = setup_range(data);
       if(!result) {
         Curl_xfer_setup_nop(data);
-        result = Curl_init_do(data, conn);
+        result = Curl_init_do(data, data->conn);
       }
     }
 
     if(result) {
-      DEBUGASSERT(conn->scheme->run->done);
+      DEBUGASSERT(data->conn->scheme->run->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;
   }
 #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 */
   result = Curl_ssl_easy_config_complete(data);
   if(result)
     goto out;
 
+  /* Get rid of any dead connections so limit are easier kept. */
   Curl_cpool_prune_dead(data);
 
   /*************************************************************
-   * Check the current list of connections to see if we can
-   * reuse an already existing one or if we have to create a
-   * new one.
+   * Reuse of existing connection is not allowed when
+   * - connect_only is set or
+   * - 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);
-  DEBUGASSERT(conn->passwd);
-
-  /* reuse_fresh is TRUE if we are told to use a new connection by force, but
-     we only acknowledge this option if this is not a reused connection
-     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) &&
+  if(data->conn) {
+    /* We attached an existing connection for this transfer. Copy
+     * over transfer specific properties over from needle. */
+    struct connectdata *conn = data->conn;
+    VERBOSE(bool tls_upgraded = (!(needle->given->flags & PROTOPT_SSL) &&
                                  Curl_conn_is_ssl(conn, FIRSTSOCKET)));
 
-    reuse_conn(data, conn, existing);
-    conn = existing;
-    *in_connect = conn;
+    conn->bits.reuse = TRUE;
+    url_conn_reuse_adjust(data, needle);
 
 #ifndef CURL_DISABLE_PROXY
     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
        be able to do that if we have reached the limit of how many
        connections we are allowed to open. */
-    DEBUGF(infof(data, "new connection, bits.close=%d", conn->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;
-    }
+    DEBUGF(infof(data, "new connection, bits.close=%d", needle->bits.close));
 
     if(waitpipe) {
       /* There is a connection that *might* become usable for multiplexing
          "soon", and we wait for that */
       infof(data, "Waiting on connection to negotiate possible multiplexing.");
-      connections_available = FALSE;
+      result = CURLE_NO_CONNECTION_AVAILABLE;
+      goto out;
     }
     else {
-      switch(Curl_cpool_check_limits(data, conn)) {
+      switch(Curl_cpool_check_limits(data, needle)) {
       case CPOOL_LIMIT_DEST:
         infof(data, "No more connections allowed to host");
-        connections_available = FALSE;
-        break;
+        result = CURLE_NO_CONNECTION_AVAILABLE;
+        goto out;
       case CPOOL_LIMIT_TOTAL:
         if(data->master_mid != UINT32_MAX)
           CURL_TRC_M(data, "Allowing sub-requests (like DoH) to override "
@@ -3511,7 +3498,8 @@ static CURLcode create_conn(struct Curl_easy *data,
         else {
           infof(data, "No connections available, total of %zu reached.",
                 data->multi->max_total_connections);
-          connections_available = FALSE;
+          result = CURLE_NO_CONNECTION_AVAILABLE;
+          goto out;
         }
         break;
       default:
@@ -3519,29 +3507,20 @@ static CURLcode create_conn(struct Curl_easy *data,
       }
     }
 
-    if(!connections_available) {
-      Curl_conn_free(data, conn);
-      *in_connect = NULL;
-
-      result = CURLE_NO_CONNECTION_AVAILABLE;
+    /* Convert needle into a full connection by filling in all the
+     * remaining parts like the cloned SSL configuration. */
+    result = Curl_ssl_conn_config_init(data, needle);
+    if(result) {
+      DEBUGF(curl_mfprintf(stderr, "Error: init connection ssl config\n"));
       goto out;
     }
-    else {
-      /*
-       * This is a brand new connection, so let's store it in the connection
-       * 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;
-      }
+    /* attach it and no longer own it */
+    Curl_attach_connection(data, needle);
+    needle = NULL;
 
-      Curl_attach_connection(data, conn);
-      result = Curl_cpool_add(data, conn);
-      if(result)
-        goto out;
-    }
+    result = Curl_cpool_add(data, data->conn);
+    if(result)
+      goto out;
 
 #ifdef USE_NTLM
     /* 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. */
-  result = Curl_init_do(data, conn);
+  result = Curl_init_do(data, data->conn);
   if(result)
     goto out;
 
-  /*
-   * Setup whatever necessary for a resumed transfer
-   */
+  /* Setup whatever necessary for a resumed transfer */
   result = setup_range(data);
   if(result)
     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 */
-  data->info.conn_scheme = conn->scheme->name;
+  data->info.conn_scheme = data->conn->scheme->name;
   /* 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 =
 #ifdef CURL_DISABLE_PROXY
     0
 #else
-    conn->bits.proxy
+    data->conn->bits.proxy
 #endif
     ;
 
-  /* Everything general done, inform filters that they need
-   * to prepare for a data transfer. */
+  /* Lastly, inform connection filters that a new transfer is attached */
   result = Curl_conn_ev_data_setup(data);
 
 out:
+  if(needle)
+    Curl_conn_free(data, needle);
+  DEBUGASSERT(result || data->conn);
   return result;
 }
 
@@ -3636,7 +3606,6 @@ CURLcode Curl_connect(struct Curl_easy *data,
 {
   CURLcode result;
   struct connectdata *conn;
-  bool reused = FALSE;
 
   *asyncp = FALSE; /* assume synchronous resolves by default */
   *protocol_done = FALSE;
@@ -3644,8 +3613,9 @@ CURLcode Curl_connect(struct Curl_easy *data,
   /* Set the request to virgin state based on transfer settings */
   Curl_req_hard_reset(&data->req, data);
 
-  /* call the stuff that needs to be called */
-  result = create_conn(data, &conn, &reused);
+  /* Get or create a connection for the transfer. */
+  result = url_find_or_create_conn(data);
+  conn = data->conn;
 
   if(result == CURLE_NO_CONNECTION_AVAILABLE) {
     DEBUGASSERT(!conn);
@@ -3655,7 +3625,7 @@ CURLcode Curl_connect(struct Curl_easy *data,
   if(!result) {
     DEBUGASSERT(conn);
     Curl_pgrsTime(data, TIMER_POSTQUEUE);
-    if(reused) {
+    if(conn->bits.reuse) {
       if(conn->attached_xfers > 1)
         /* multiplexed */
         *protocol_done = TRUE;