Refactored CreateConnection() somewhat to reduce its length by splitting
authorDan Fandrich <dan@coneharvesters.com>
Fri, 3 Aug 2007 22:46:59 +0000 (22:46 +0000)
committerDan Fandrich <dan@coneharvesters.com>
Fri, 3 Aug 2007 22:46:59 +0000 (22:46 +0000)
it into a few new functions.
Fixed a few leaks in out of memory conditions, including for test case 231.

lib/url.c

index e184c2b..ba48da8 100644 (file)
--- a/lib/url.c
+++ b/lib/url.c
@@ -2888,345 +2888,13 @@ static CURLcode setup_range(struct SessionHandle *data)
   return CURLE_OK;
 }
 
-/**
- * CreateConnection() sets up a new connectdata struct, or re-uses an already
- * existing one, and resolves host name.
- *
- * 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 addr is set to the new dns entry for this connection. If this
- *        connection is re-used it will be NULL.
- * @param async is set TRUE/FALSE depending on the nature of this lookup
- * @return CURLcode
- * @see SetupConnection()
- *
- * *NOTE* this function assigns the conn->data pointer!
- */
 
-static CURLcode CreateConnection(struct SessionHandle *data,
-                                 struct connectdata **in_connect,
-                                 struct Curl_dns_entry **addr,
-                                 bool *async)
+/***************************************************************
+* Setup connection internals specific to the requested protocol
+***************************************************************/
+static CURLcode setup_connection_internals(struct SessionHandle *data,
+                                          struct connectdata *conn)
 {
-
-  char *tmp;
-  CURLcode result=CURLE_OK;
-  struct connectdata *conn;
-  struct connectdata *conn_temp = NULL;
-  size_t urllen;
-  struct Curl_dns_entry *hostaddr;
-#if defined(HAVE_ALARM) && !defined(USE_ARES)
-  unsigned int prev_alarm=0;
-#endif
-  char endbracket;
-  char user[MAX_CURL_USER_LENGTH];
-  char passwd[MAX_CURL_PASSWORD_LENGTH];
-  int rc;
-  bool reuse;
-  char *proxy = NULL;
-
-#ifndef USE_ARES
-#ifdef SIGALRM
-#ifdef HAVE_SIGACTION
-  struct sigaction keep_sigact;   /* store the old struct here */
-  bool keep_copysig=FALSE;        /* did copy it? */
-#else
-#ifdef HAVE_SIGNAL
-  void (*keep_sigact)(int);       /* store the old handler here */
-#endif /* HAVE_SIGNAL */
-#endif /* HAVE_SIGACTION */
-#endif /* SIGALRM */
-#endif /* USE_ARES */
-
-  *addr = NULL; /* nothing yet */
-  *async = FALSE;
-
-  /*************************************************************
-   * Check input data
-   *************************************************************/
-
-  if(!data->change.url)
-    return CURLE_URL_MALFORMAT;
-
-  /* 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
-     connection data struct and fill in for comparison purposes. */
-
-  conn = (struct connectdata *)calloc(1, sizeof(struct connectdata));
-  if(!conn) {
-    *in_connect = NULL; /* clear the pointer */
-    return CURLE_OUT_OF_MEMORY;
-  }
-  /* 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;
-
-  /* and we setup a few fields in case we end up actually using this struct */
-
-  conn->data = data; /* Setup the association between this connection
-                        and the SessionHandle */
-
-  conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD;     /* no file descriptor */
-  conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
-  conn->connectindex = -1;    /* no index */
-
-  conn->proxytype = data->set.proxytype; /* type */
-  conn->bits.proxy = (bool)(data->set.str[STRING_PROXY] &&
-                            *data->set.str[STRING_PROXY]);
-  conn->bits.httpproxy = (bool)(conn->bits.proxy
-                                && (conn->proxytype == CURLPROXY_HTTP));
-
-
-  /* Default protocol-independent behavior doesn't support persistent
-     connections, so we set this to force-close. Protocols that support
-     this need to set this to FALSE in their "curl_do" functions. */
-  conn->bits.close = TRUE;
-
-  conn->readchannel_inuse = FALSE;
-  conn->writechannel_inuse = FALSE;
-
-  conn->read_pos = 0;
-  conn->buf_len = 0;
-
-  /* Store creation time to help future close decision making */
-  conn->created = Curl_tvnow();
-
-  conn->bits.user_passwd = (bool)(NULL != data->set.str[STRING_USERPWD]);
-  conn->bits.proxy_user_passwd = (bool)(NULL != data->set.str[STRING_PROXYUSERPWD]);
-  conn->bits.no_body = data->set.opt_no_body;
-  conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy;
-  conn->bits.ftp_use_epsv = data->set.ftp_use_epsv;
-  conn->bits.ftp_use_eprt = data->set.ftp_use_eprt;
-
-  if (data->multi && Curl_multi_canPipeline(data->multi) &&
-      !conn->master_buffer) {
-    /* Allocate master_buffer to be used for pipelining */
-    conn->master_buffer = calloc(BUFSIZE, sizeof (char));
-    if (!conn->master_buffer)
-      return CURLE_OUT_OF_MEMORY;
-  }
-
-  /* Initialize the pipeline lists */
-  conn->send_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
-  conn->recv_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
-  if (!conn->send_pipe || !conn->recv_pipe)
-    return CURLE_OUT_OF_MEMORY;
-
-  /* This initing continues below, see the comment "Continue connectdata
-   * initialization here" */
-
-  /***********************************************************
-   * We need to allocate memory to store the path in. We get the size of the
-   * full URL to be sure, and we need to make it at least 256 bytes since
-   * other parts of the code will rely on this fact
-   ***********************************************************/
-#define LEAST_PATH_ALLOC 256
-  urllen=strlen(data->change.url);
-  if(urllen < LEAST_PATH_ALLOC)
-    urllen=LEAST_PATH_ALLOC;
-
-  /* Free the old buffer */
-  Curl_safefree(data->reqdata.pathbuffer);
-
-  /*
-   * We malloc() the buffers below urllen+2 to make room for to possibilities:
-   * 1 - an extra terminating zero
-   * 2 - an extra slash (in case a syntax like "www.host.com?moo" is used)
-   */
-
-  data->reqdata.pathbuffer=(char *)malloc(urllen+2);
-  if(NULL == data->reqdata.pathbuffer)
-    return CURLE_OUT_OF_MEMORY; /* really bad error */
-  data->reqdata.path = data->reqdata.pathbuffer;
-
-  conn->host.rawalloc=(char *)malloc(urllen+2);
-  if(NULL == conn->host.rawalloc)
-    return CURLE_OUT_OF_MEMORY;
-
-  conn->host.name = conn->host.rawalloc;
-  conn->host.name[0] = 0;
-
-  result = ParseURLAndFillConnection(data, conn);
-  if (result != CURLE_OK) {
-      return result;
-  }
-
-  /*************************************************************
-   * Take care of proxy authentication stuff
-   *************************************************************/
-  if(conn->bits.proxy_user_passwd) {
-    char proxyuser[MAX_CURL_USER_LENGTH]="";
-    char proxypasswd[MAX_CURL_PASSWORD_LENGTH]="";
-
-    sscanf(data->set.str[STRING_PROXYUSERPWD],
-           "%" MAX_CURL_USER_LENGTH_TXT "[^:]:"
-           "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^\n]",
-           proxyuser, proxypasswd);
-
-    conn->proxyuser = curl_easy_unescape(data, proxyuser, 0, NULL);
-    if(!conn->proxyuser)
-      return CURLE_OUT_OF_MEMORY;
-
-    conn->proxypasswd = curl_easy_unescape(data, proxypasswd, 0, NULL);
-    if(!conn->proxypasswd)
-      return CURLE_OUT_OF_MEMORY;
-  }
-
-  if (data->set.str[STRING_PROXY]) {
-    proxy = strdup(data->set.str[STRING_PROXY]);
-    /* if global proxy is set, this is it */
-    if(NULL == proxy) {
-      failf(data, "memory shortage");
-      return CURLE_OUT_OF_MEMORY;
-    }
-  }
-  /* proxy must be freed later unless NULL */
-
-#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.
-   *************************************************************/
-  if(!proxy) {
-    /* 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 don't exist.
-     */
-    char *no_proxy=NULL;
-    char *no_proxy_tok_buf;
-    char proxy_env[128];
-
-    no_proxy=curl_getenv("no_proxy");
-    if(!no_proxy)
-      no_proxy=curl_getenv("NO_PROXY");
-
-    if(!no_proxy || !strequal("*", no_proxy)) {
-      /* NO_PROXY wasn't specified or it wasn't just an asterisk */
-      char *nope;
-
-      nope=no_proxy?strtok_r(no_proxy, ", ", &no_proxy_tok_buf):NULL;
-      while(nope) {
-        size_t namelen;
-        char *endptr = strchr(conn->host.name, ':');
-        if(endptr)
-          namelen=endptr-conn->host.name;
-        else
-          namelen=strlen(conn->host.name);
-
-        if(strlen(nope) <= namelen) {
-          char *checkn=
-            conn->host.name + namelen - strlen(nope);
-          if(checkprefix(nope, checkn)) {
-            /* no proxy for this host! */
-            break;
-          }
-        }
-        nope=strtok_r(NULL, ", ", &no_proxy_tok_buf);
-      }
-      if(!nope) {
-        /* It was not listed as without proxy */
-        char *protop = conn->protostr;
-        char *envp = proxy_env;
-        char *prox;
-
-        /* Now, build <protocol>_proxy and check for such a one to use */
-        while(*protop)
-          *envp++ = (char)tolower((int)*protop++);
-
-        /* append _proxy */
-        strcpy(envp, "_proxy");
-
-        /* read the protocol proxy: */
-        prox=curl_getenv(proxy_env);
-
-        /*
-         * We don't 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(!prox && !strequal("http_proxy", proxy_env)) {
-          /* There was no lowercase variable, try the uppercase version: */
-          for(envp = proxy_env; *envp; envp++)
-            *envp = (char)toupper((int)*envp);
-          prox=curl_getenv(proxy_env);
-        }
-
-        if(prox && *prox) { /* don't count "" strings */
-          proxy = prox; /* use this */
-        }
-        else {
-          proxy = curl_getenv("all_proxy"); /* default proxy to use */
-          if(!proxy)
-            proxy=curl_getenv("ALL_PROXY");
-        }
-
-        if(proxy && *proxy) {
-          long bits = conn->protocol & (PROT_HTTPS|PROT_SSL|PROT_MISSING);
-
-          if(conn->proxytype == CURLPROXY_HTTP) {
-            /* force this connection's protocol to become HTTP */
-            conn->protocol = PROT_HTTP | bits;
-            conn->bits.httpproxy = TRUE;
-          }
-        }
-      } /* if (!nope) - it wasn't specified non-proxy */
-    } /* NO_PROXY wasn't specified or '*' */
-    if(no_proxy)
-      free(no_proxy);
-  } /* if not using proxy */
-#endif /* CURL_DISABLE_HTTP */
-
-  /*************************************************************
-   * No protocol part in URL was used, add it!
-   *************************************************************/
-  if(conn->protocol&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
-       part added so that we have a valid URL. */
-    char *reurl;
-
-    reurl = aprintf("%s://%s", conn->protostr, data->change.url);
-
-    if(!reurl) {
-      Curl_safefree(proxy);
-      return CURLE_OUT_OF_MEMORY;
-    }
-
-    data->change.url = reurl;
-    data->change.url_alloc = TRUE; /* free this later */
-    conn->protocol &= ~PROT_MISSING; /* switch that one off again */
-  }
-
-  /*************************************************************
-   * Setup internals depending on protocol
-   *************************************************************/
-
   conn->socktype = SOCK_STREAM; /* most of them are TCP streams */
 
   if (strequal(conn->protostr, "HTTP")) {
@@ -3244,6 +2912,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
     return CURLE_UNSUPPORTED_PROTOCOL;
 #endif
   }
+
   else if (strequal(conn->protostr, "HTTPS")) {
 #if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)
 
@@ -3264,6 +2933,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
     return CURLE_UNSUPPORTED_PROTOCOL;
 #endif /* !USE_SSL */
   }
+
   else if(strequal(conn->protostr, "FTP") ||
           strequal(conn->protostr, "FTPS")) {
 
@@ -3344,6 +3014,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
     return CURLE_UNSUPPORTED_PROTOCOL;
 #endif
   }
+
   else if(strequal(conn->protostr, "TELNET")) {
 #ifndef CURL_DISABLE_TELNET
     /* telnet testing factory */
@@ -3359,6 +3030,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
     return CURLE_UNSUPPORTED_PROTOCOL;
 #endif
   }
+
   else if (strequal(conn->protostr, "DICT")) {
 #ifndef CURL_DISABLE_DICT
     conn->protocol |= PROT_DICT;
@@ -3373,6 +3045,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
     return CURLE_UNSUPPORTED_PROTOCOL;
 #endif
   }
+
   else if (strequal(conn->protostr, "LDAP")) {
 #ifndef CURL_DISABLE_LDAP
     conn->protocol |= PROT_LDAP;
@@ -3387,6 +3060,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
     return CURLE_UNSUPPORTED_PROTOCOL;
 #endif
   }
+
   else if (strequal(conn->protostr, "FILE")) {
 #ifndef CURL_DISABLE_FILE
     conn->protocol |= PROT_FILE;
@@ -3399,6 +3073,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
     return CURLE_UNSUPPORTED_PROTOCOL;
 #endif
   }
+
   else if (strequal(conn->protostr, "TFTP")) {
 #ifndef CURL_DISABLE_TFTP
     char *type;
@@ -3438,6 +3113,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
     return CURLE_UNSUPPORTED_PROTOCOL;
 #endif
   }
+
   else if (strequal(conn->protostr, "SCP")) {
 #ifdef USE_LIBSSH2
     conn->port = PORT_SSH;
@@ -3455,6 +3131,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
     return CURLE_UNSUPPORTED_PROTOCOL;
 #endif
   }
+
   else if (strequal(conn->protostr, "SFTP")) {
 #ifdef USE_LIBSSH2
     conn->port = PORT_SSH;
@@ -3472,128 +3149,520 @@ static CURLcode CreateConnection(struct SessionHandle *data,
     return CURLE_UNSUPPORTED_PROTOCOL;
 #endif
   }
+
   else {
     /* We fell through all checks and thus we don't support the specified
        protocol */
     failf(data, "Unsupported protocol: %s", conn->protostr);
     return CURLE_UNSUPPORTED_PROTOCOL;
   }
+  return CURLE_OK;
+}
 
-  if(proxy && *proxy) {
-    /* If this is supposed to use a proxy, we need to figure out the proxy
-       host name name, so that we can re-use an existing connection
-       that may exist registered to the same proxy host. */
-
-    char *prox_portno;
-    char *endofprot;
-
-    /* We use 'proxyptr' to point to the proxy name from now on... */
-    char *proxyptr=proxy;
-    char *portptr;
-    char *atsign;
-
-    /* We do the proxy host string parsing here. We want the host name and the
-     * port name. Accept a protocol:// prefix, even though it should just be
-     * ignored.
-     */
-
-    /* Skip the protocol part if present */
-    endofprot=strstr(proxyptr, "://");
-    if(endofprot)
-      proxyptr = endofprot+3;
-
-    /* Is there a username and password given in this proxy url? */
-    atsign = strchr(proxyptr, '@');
-    if(atsign) {
-      char proxyuser[MAX_CURL_USER_LENGTH];
-      char proxypasswd[MAX_CURL_PASSWORD_LENGTH];
-      proxypasswd[0] = 0;
-
-      if(1 <= sscanf(proxyptr,
-                     "%" MAX_CURL_USER_LENGTH_TXT"[^:]:"
-                     "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]",
-                     proxyuser, proxypasswd)) {
-        CURLcode res = CURLE_OK;
-
-        /* found user and password, rip them out.  note that we are
-           unescaping them, as there is otherwise no way to have a
-           username or password with reserved characters like ':' in
-           them. */
-        Curl_safefree(conn->proxyuser);
-        conn->proxyuser = curl_easy_unescape(data, proxyuser, 0, NULL);
-
-        if(!conn->proxyuser)
-          res = CURLE_OUT_OF_MEMORY;
-        else {
-          Curl_safefree(conn->proxypasswd);
-          conn->proxypasswd = curl_easy_unescape(data, proxypasswd, 0, NULL);
-
-          if(!conn->proxypasswd)
-            res = CURLE_OUT_OF_MEMORY;
-        }
-
-        if(CURLE_OK == res) {
-          conn->bits.proxy_user_passwd = TRUE; /* enable it */
-          atsign = strdup(atsign+1); /* the right side of the @-letter */
+/****************************************************************
+* 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 *detect_proxy(struct connectdata *conn)
+{
+  char *proxy = NULL;
 
-          if(atsign) {
-            free(proxy); /* free the former proxy string */
-            proxy = proxyptr = atsign; /* now use this instead */
-          }
-          else
-            res = CURLE_OUT_OF_MEMORY;
-        }
-
-        if(res) {
-          free(proxy); /* free the allocated proxy string */
-          return res;
-        }
+#ifndef CURL_DISABLE_HTTP
+  /* 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 don't exist.
+   */
+  char *no_proxy=NULL;
+  char *no_proxy_tok_buf;
+  char proxy_env[128];
+
+  no_proxy=curl_getenv("no_proxy");
+  if(!no_proxy)
+    no_proxy=curl_getenv("NO_PROXY");
+
+  if(!no_proxy || !strequal("*", no_proxy)) {
+    /* NO_PROXY wasn't specified or it wasn't just an asterisk */
+    char *nope;
+
+    nope=no_proxy?strtok_r(no_proxy, ", ", &no_proxy_tok_buf):NULL;
+    while(nope) {
+      size_t namelen;
+      char *endptr = strchr(conn->host.name, ':');
+      if(endptr)
+       namelen=endptr-conn->host.name;
+      else
+       namelen=strlen(conn->host.name);
+
+      if(strlen(nope) <= namelen) {
+       char *checkn=
+         conn->host.name + namelen - strlen(nope);
+       if(checkprefix(nope, checkn)) {
+         /* no proxy for this host! */
+         break;
+       }
       }
+      nope=strtok_r(NULL, ", ", &no_proxy_tok_buf);
     }
+    if(!nope) {
+      /* It was not listed as without proxy */
+      char *protop = conn->protostr;
+      char *envp = proxy_env;
+      char *prox;
 
-    /* start scanning for port number at this point */
-    portptr = proxyptr;
-
-    /* detect and extract RFC2732-style IPv6-addresses */
-    if(*proxyptr == '[') {
-      char *ptr = ++proxyptr; /* advance beyond the initial bracket */
-      while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':')))
-        ptr++;
-      if(*ptr == ']') {
-        /* yeps, it ended nicely with a bracket as well */
-        *ptr = 0;
-        portptr = ptr+1;
-      }
-      /* Note that if this didn't end with a bracket, we still advanced the
-       * proxyptr first, but I can't see anything wrong with that as no host
-       * name nor a numeric can legally start with a bracket.
+      /* Now, build <protocol>_proxy and check for such a one to use */
+      while(*protop)
+       *envp++ = (char)tolower((int)*protop++);
+
+      /* append _proxy */
+      strcpy(envp, "_proxy");
+
+      /* read the protocol proxy: */
+      prox=curl_getenv(proxy_env);
+
+      /*
+       * We don't 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(!prox && !strequal("http_proxy", proxy_env)) {
+       /* There was no lowercase variable, try the uppercase version: */
+       for(envp = proxy_env; *envp; envp++)
+         *envp = (char)toupper((int)*envp);
+       prox=curl_getenv(proxy_env);
+      }
+
+      if(prox && *prox) { /* don't count "" strings */
+       proxy = prox; /* use this */
+      }
+      else {
+       proxy = curl_getenv("all_proxy"); /* default proxy to use */
+       if(!proxy)
+         proxy=curl_getenv("ALL_PROXY");
+      }
+
+      if(proxy && *proxy) {
+       long bits = conn->protocol & (PROT_HTTPS|PROT_SSL|PROT_MISSING);
+
+       if(conn->proxytype == CURLPROXY_HTTP) {
+         /* force this connection's protocol to become HTTP */
+         conn->protocol = PROT_HTTP | bits;
+         conn->bits.httpproxy = TRUE;
+       }
+      }
+    } /* if (!nope) - it wasn't specified non-proxy */
+  } /* NO_PROXY wasn't specified or '*' */
+  if(no_proxy)
+    free(no_proxy);
+#endif /* CURL_DISABLE_HTTP */
+
+  return proxy;
+}
+
+/* If this is supposed to use a proxy, we need to figure out the proxy
+ * host name, so that we can re-use an existing connection
+ * that may exist registered to the same proxy host.
+ * proxy will be freed before this function returns.
+ */
+static CURLcode parse_proxy(struct SessionHandle *data,
+                            struct connectdata *conn, char *proxy)
+{
+  char *prox_portno;
+  char *endofprot;
+
+  /* We use 'proxyptr' to point to the proxy name from now on... */
+  char *proxyptr=proxy;
+  char *portptr;
+  char *atsign;
+
+  /* We do the proxy host string parsing here. We want the host name and the
+   * port name. Accept a protocol:// prefix, even though it should just be
+   * ignored.
+   */
+
+  /* Skip the protocol part if present */
+  endofprot=strstr(proxyptr, "://");
+  if(endofprot)
+    proxyptr = endofprot+3;
+
+  /* Is there a username and password given in this proxy url? */
+  atsign = strchr(proxyptr, '@');
+  if(atsign) {
+    char proxyuser[MAX_CURL_USER_LENGTH];
+    char proxypasswd[MAX_CURL_PASSWORD_LENGTH];
+    proxypasswd[0] = 0;
+
+    if(1 <= sscanf(proxyptr,
+                  "%" MAX_CURL_USER_LENGTH_TXT"[^:]:"
+                  "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]",
+                  proxyuser, proxypasswd)) {
+      CURLcode res = CURLE_OK;
+
+      /* found user and password, rip them out.  note that we are
+        unescaping them, as there is otherwise no way to have a
+        username or password with reserved characters like ':' in
+        them. */
+      Curl_safefree(conn->proxyuser);
+      conn->proxyuser = curl_easy_unescape(data, proxyuser, 0, NULL);
+
+      if(!conn->proxyuser)
+       res = CURLE_OUT_OF_MEMORY;
+      else {
+       Curl_safefree(conn->proxypasswd);
+       conn->proxypasswd = curl_easy_unescape(data, proxypasswd, 0, NULL);
 
-    /* Get port number off proxy.server.com:1080 */
-    prox_portno = strchr(portptr, ':');
-    if (prox_portno) {
-      *prox_portno = 0x0; /* cut off number from host name */
-      prox_portno ++;
-      /* now set the local port number */
-      conn->port = atoi(prox_portno);
+       if(!conn->proxypasswd)
+         res = CURLE_OUT_OF_MEMORY;
+      }
+
+      if(CURLE_OK == res) {
+       conn->bits.proxy_user_passwd = TRUE; /* enable it */
+       atsign = strdup(atsign+1); /* the right side of the @-letter */
+
+       if(atsign) {
+         free(proxy); /* free the former proxy string */
+         proxy = proxyptr = atsign; /* now use this instead */
+       }
+       else
+         res = CURLE_OUT_OF_MEMORY;
+      }
+
+      if(res) {
+       free(proxy); /* free the allocated proxy string */
+       return res;
+      }
     }
-    else if(data->set.proxyport) {
-      /* None given in the proxy string, then get the default one if it is
-         given */
-      conn->port = data->set.proxyport;
+  }
+
+  /* start scanning for port number at this point */
+  portptr = proxyptr;
+
+  /* detect and extract RFC2732-style IPv6-addresses */
+  if(*proxyptr == '[') {
+    char *ptr = ++proxyptr; /* advance beyond the initial bracket */
+    while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':')))
+      ptr++;
+    if(*ptr == ']') {
+      /* yeps, it ended nicely with a bracket as well */
+      *ptr = 0;
+      portptr = ptr+1;
     }
+    /* Note that if this didn't end with a bracket, we still advanced the
+     * proxyptr first, but I can't see anything wrong with that as no host
+     * name nor a numeric can legally start with a bracket.
+     */
+  }
+
+  /* Get port number off proxy.server.com:1080 */
+  prox_portno = strchr(portptr, ':');
+  if (prox_portno) {
+    *prox_portno = 0x0; /* cut off number from host name */
+    prox_portno ++;
+    /* now set the local port number */
+    conn->port = atoi(prox_portno);
+  }
+  else if(data->set.proxyport) {
+    /* None given in the proxy string, then get the default one if it is
+       given */
+    conn->port = data->set.proxyport;
+  }
+
+  /* now, clone the cleaned proxy host name */
+  conn->proxy.rawalloc = strdup(proxyptr);
+  conn->proxy.name = conn->proxy.rawalloc;
+
+  free(proxy);
+  if(!conn->proxy.rawalloc)
+    return CURLE_OUT_OF_MEMORY;
+
+  return CURLE_OK;
+}
+
+/* Extract the user and password from the authentication string */
+static CURLcode parse_proxy_auth(struct SessionHandle *data, struct connectdata *conn)
+{
+  char proxyuser[MAX_CURL_USER_LENGTH]="";
+  char proxypasswd[MAX_CURL_PASSWORD_LENGTH]="";
+
+  sscanf(data->set.str[STRING_PROXYUSERPWD],
+        "%" MAX_CURL_USER_LENGTH_TXT "[^:]:"
+        "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^\n]",
+        proxyuser, proxypasswd);
+
+  conn->proxyuser = curl_easy_unescape(data, proxyuser, 0, NULL);
+  if(!conn->proxyuser)
+    return CURLE_OUT_OF_MEMORY;
+
+  conn->proxypasswd = curl_easy_unescape(data, proxypasswd, 0, NULL);
+  if(!conn->proxypasswd)
+    return CURLE_OUT_OF_MEMORY;
+
+  return CURLE_OK;
+}
+
+/**
+ * CreateConnection() sets up a new connectdata struct, or re-uses an already
+ * existing one, and resolves host name.
+ *
+ * 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 addr is set to the new dns entry for this connection. If this
+ *        connection is re-used it will be NULL.
+ * @param async is set TRUE/FALSE depending on the nature of this lookup
+ * @return CURLcode
+ * @see SetupConnection()
+ *
+ * *NOTE* this function assigns the conn->data pointer!
+ */
+
+static CURLcode CreateConnection(struct SessionHandle *data,
+                                 struct connectdata **in_connect,
+                                 struct Curl_dns_entry **addr,
+                                 bool *async)
+{
+
+  char *tmp;
+  CURLcode result=CURLE_OK;
+  struct connectdata *conn;
+  struct connectdata *conn_temp = NULL;
+  size_t urllen;
+  struct Curl_dns_entry *hostaddr;
+#if defined(HAVE_ALARM) && !defined(USE_ARES)
+  unsigned int prev_alarm=0;
+#endif
+  char endbracket;
+  char user[MAX_CURL_USER_LENGTH];
+  char passwd[MAX_CURL_PASSWORD_LENGTH];
+  int rc;
+  bool reuse;
+  char *proxy = NULL;
+
+#ifndef USE_ARES
+#ifdef SIGALRM
+#ifdef HAVE_SIGACTION
+  struct sigaction keep_sigact;   /* store the old struct here */
+  bool keep_copysig=FALSE;        /* did copy it? */
+#else
+#ifdef HAVE_SIGNAL
+  void (*keep_sigact)(int);       /* store the old handler here */
+#endif /* HAVE_SIGNAL */
+#endif /* HAVE_SIGACTION */
+#endif /* SIGALRM */
+#endif /* USE_ARES */
+
+  *addr = NULL; /* nothing yet */
+  *async = FALSE;
+
+  /*************************************************************
+   * Check input data
+   *************************************************************/
 
-    /* now, clone the cleaned proxy host name */
-    conn->proxy.rawalloc = strdup(proxyptr);
-    conn->proxy.name = conn->proxy.rawalloc;
+  if(!data->change.url)
+    return CURLE_URL_MALFORMAT;
+
+  /* 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
+     connection data struct and fill in for comparison purposes. */
+
+  conn = (struct connectdata *)calloc(1, sizeof(struct connectdata));
+  if(!conn) {
+    *in_connect = NULL; /* clear the pointer */
+    return CURLE_OUT_OF_MEMORY;
+  }
+  /* 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;
 
-    free(proxy);
+  /* and we setup a few fields in case we end up actually using this struct */
+
+  conn->data = data; /* Setup the association between this connection
+                        and the SessionHandle */
+
+  conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD;     /* no file descriptor */
+  conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
+  conn->connectindex = -1;    /* no index */
+
+  conn->proxytype = data->set.proxytype; /* type */
+  conn->bits.proxy = (bool)(data->set.str[STRING_PROXY] &&
+                            *data->set.str[STRING_PROXY]);
+  conn->bits.httpproxy = (bool)(conn->bits.proxy
+                                && (conn->proxytype == CURLPROXY_HTTP));
+
+
+  /* Default protocol-independent behavior doesn't support persistent
+     connections, so we set this to force-close. Protocols that support
+     this need to set this to FALSE in their "curl_do" functions. */
+  conn->bits.close = TRUE;
+
+  conn->readchannel_inuse = FALSE;
+  conn->writechannel_inuse = FALSE;
+
+  conn->read_pos = 0;
+  conn->buf_len = 0;
+
+  /* Store creation time to help future close decision making */
+  conn->created = Curl_tvnow();
+
+  conn->bits.user_passwd = (bool)(NULL != data->set.str[STRING_USERPWD]);
+  conn->bits.proxy_user_passwd = (bool)(NULL != data->set.str[STRING_PROXYUSERPWD]);
+  conn->bits.no_body = data->set.opt_no_body;
+  conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy;
+  conn->bits.ftp_use_epsv = data->set.ftp_use_epsv;
+  conn->bits.ftp_use_eprt = data->set.ftp_use_eprt;
+
+  if (data->multi && Curl_multi_canPipeline(data->multi) &&
+      !conn->master_buffer) {
+    /* Allocate master_buffer to be used for pipelining */
+    conn->master_buffer = calloc(BUFSIZE, sizeof (char));
+    if (!conn->master_buffer)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  /* Initialize the pipeline lists */
+  conn->send_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
+  conn->recv_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
+  if (!conn->send_pipe || !conn->recv_pipe)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* This initing continues below, see the comment "Continue connectdata
+   * initialization here" */
+
+  /***********************************************************
+   * We need to allocate memory to store the path in. We get the size of the
+   * full URL to be sure, and we need to make it at least 256 bytes since
+   * other parts of the code will rely on this fact
+   ***********************************************************/
+#define LEAST_PATH_ALLOC 256
+  urllen=strlen(data->change.url);
+  if(urllen < LEAST_PATH_ALLOC)
+    urllen=LEAST_PATH_ALLOC;
+
+  /* Free the old buffer */
+  Curl_safefree(data->reqdata.pathbuffer);
+
+  /*
+   * We malloc() the buffers below urllen+2 to make room for to possibilities:
+   * 1 - an extra terminating zero
+   * 2 - an extra slash (in case a syntax like "www.host.com?moo" is used)
+   */
+
+  data->reqdata.pathbuffer=(char *)malloc(urllen+2);
+  if(NULL == data->reqdata.pathbuffer)
+    return CURLE_OUT_OF_MEMORY; /* really bad error */
+  data->reqdata.path = data->reqdata.pathbuffer;
+
+  conn->host.rawalloc=(char *)malloc(urllen+2);
+  if(NULL == conn->host.rawalloc)
+    return CURLE_OUT_OF_MEMORY;
+
+  conn->host.name = conn->host.rawalloc;
+  conn->host.name[0] = 0;
+
+  result = ParseURLAndFillConnection(data, conn);
+  if (result != CURLE_OK) {
+      return result;
+  }
+
+  /*************************************************************
+   * Take care of proxy authentication stuff
+   *************************************************************/
+  if(conn->bits.proxy_user_passwd) {
+    result = parse_proxy_auth(data, conn);
+    if (result != CURLE_OK)
+       return result;
+  }
+
+  /*************************************************************
+   * Detect what (if any) proxy to use
+   *************************************************************/
+  if (data->set.str[STRING_PROXY]) {
+    proxy = strdup(data->set.str[STRING_PROXY]);
+    /* if global proxy is set, this is it */
+    if(NULL == proxy) {
+      failf(data, "memory shortage");
+      return CURLE_OUT_OF_MEMORY;
+    }
+  }
+
+  if (!proxy)
+    proxy = detect_proxy(conn);
+  if (proxy && !*proxy) {
+    free(proxy);  /* Don't bother with an empty proxy string */
     proxy = NULL;
-    if(!conn->proxy.rawalloc)
+  }
+  /* proxy must be freed later unless NULL */
+
+  /*************************************************************
+   * No protocol part in URL was used, add it!
+   *************************************************************/
+  if(conn->protocol&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
+       part added so that we have a valid URL. */
+    char *reurl;
+
+    reurl = aprintf("%s://%s", conn->protostr, data->change.url);
+
+    if(!reurl) {
+      Curl_safefree(proxy);
       return CURLE_OUT_OF_MEMORY;
+    }
+
+    data->change.url = reurl;
+    data->change.url_alloc = TRUE; /* free this later */
+    conn->protocol &= ~PROT_MISSING; /* switch that one off again */
   }
 
+  /*************************************************************
+   * Setup internals depending on protocol
+   *************************************************************/
+  result = setup_connection_internals(data, conn);
+  if (result != CURLE_OK) {
+    Curl_safefree(proxy);
+    return result;
+  }
+
+
+  /***********************************************************************
+   * If this is supposed to use a proxy, we need to figure out the proxy
+   * host name, so that we can re-use an existing connection
+   * that may exist registered to the same proxy host.
+   ***********************************************************************/
+  if (proxy) {
+    result = parse_proxy(data, conn, proxy);
+    /* parse_proxy has freed the proxy string, so don't try to use it again */
+    proxy = NULL;
+    if (result != CURLE_OK)
+      return result;
+  }
+
+
   /***********************************************************************
    * file: is a special case in that it doesn't need a network connection
    ***********************************************************************/
@@ -3611,8 +3680,10 @@ static CURLcode CreateConnection(struct SessionHandle *data,
       ConnectionStore(data, conn);
 
       result = setup_range(data);
-      if(result)
+      if(result) {
+        Curl_file_done(conn, result, FALSE);
         return result;
+      }
 
       result = Curl_setup_transfer(conn, -1, -1, FALSE,
                                    NULL, /* no download */