aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDan Fandrich <dan@coneharvesters.com>2007-08-03 22:46:59 +0000
committerDan Fandrich <dan@coneharvesters.com>2007-08-03 22:46:59 +0000
commit0d3d84e3ffcaa6118cc4f33c5f2d6c9166d60662 (patch)
tree840e3159383847a460ba027e84d08695c52b9977 /lib
parente789a3802cd454b9b37fb40ef2f04244db4831ee (diff)
Refactored CreateConnection() somewhat to reduce its length by splitting
it into a few new functions. Fixed a few leaks in out of memory conditions, including for test case 231.
Diffstat (limited to 'lib')
-rw-r--r--lib/url.c947
1 files changed, 509 insertions, 438 deletions
diff --git a/lib/url.c b/lib/url.c
index e184c2b09..ba48da8eb 100644
--- 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;
- }
+/****************************************************************
+* 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(CURLE_OK == res) {
- conn->bits.proxy_user_passwd = TRUE; /* enable it */
- atsign = strdup(atsign+1); /* the right side of the @-letter */
+#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;
- if(atsign) {
- free(proxy); /* free the former proxy string */
- proxy = proxyptr = atsign; /* now use this instead */
- }
- else
- res = CURLE_OUT_OF_MEMORY;
- }
+ /* Now, build <protocol>_proxy and check for such a one to use */
+ while(*protop)
+ *envp++ = (char)tolower((int)*protop++);
- if(res) {
- free(proxy); /* free the allocated proxy string */
- return res;
- }
+ /* 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);
}
- }
- /* 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;
+ if(prox && *prox) { /* don't count "" strings */
+ proxy = prox; /* use this */
}
- /* 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.
- */
- }
+ 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);
- /* 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->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 */
+
+ 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
+ *************************************************************/
+
+ 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;
- /* now, clone the cleaned proxy host name */
- conn->proxy.rawalloc = strdup(proxyptr);
- conn->proxy.name = conn->proxy.rawalloc;
+ /* Free the old buffer */
+ Curl_safefree(data->reqdata.pathbuffer);
- free(proxy);
+ /*
+ * 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 */