Newer
Older
/* Within the constraint of the login string */
if(psep >= login + len)
psep = NULL;
}
/* Attempt to find the options separator */
osep = strchr(login, ';');
/* Within the constraint of the login string */
if(osep >= login + len)
osep = NULL;
}
/* Calculate the portion lengths */
ulen = (psep ?
(size_t)(osep && psep > osep ? osep - login : psep - login) :
(osep ? (size_t)(osep - login) : len));
plen = (psep ?
(osep && osep > psep ? (size_t)(osep - psep) :
(size_t)(login + len - psep)) - 1 : 0);
olen = (osep ?
(psep && psep > osep ? (size_t)(psep - osep) :
(size_t)(login + len - osep)) - 1 : 0);
/* Allocate the user portion buffer */
if(userp && ulen) {
ubuf = malloc(ulen + 1);
if(!ubuf)
result = CURLE_OUT_OF_MEMORY;
}
/* Allocate the password portion buffer */
if(!result && passwdp && plen) {
pbuf = malloc(plen + 1);
result = CURLE_OUT_OF_MEMORY;
/* Allocate the options portion buffer */
if(!result && optionsp && olen) {
obuf = malloc(olen + 1);
result = CURLE_OUT_OF_MEMORY;
if(!result) {
/* Store the user portion if necessary */
if(ubuf) {
memcpy(ubuf, login, ulen);
ubuf[ulen] = '\0';
Curl_safefree(*userp);
*userp = ubuf;
/* Store the password portion if necessary */
if(pbuf) {
memcpy(pbuf, psep + 1, plen);
pbuf[plen] = '\0';
Curl_safefree(*passwdp);
*passwdp = pbuf;
/* Store the options portion if necessary */
if(obuf) {
memcpy(obuf, osep + 1, olen);
obuf[olen] = '\0';
Curl_safefree(*optionsp);
*optionsp = obuf;
}
}
return result;
/*************************************************************
* Figure out the remote port number and fix it in the URL
*
* No matter if we use a proxy or not, we have to figure out the remote
* port number of various reasons.
*
* To be able to detect port number flawlessly, we must not confuse them
* IPv6-specified addresses in the [0::1] style. (RFC2732)
*
* The conn->host.name is currently [user:passwd@]host[:port] where host
* could be a hostname, IPv4 address or IPv6 address.
*
* The port number embedded in the URL is replaced, if necessary.
*************************************************************/
static CURLcode parse_remote_port(struct SessionHandle *data,
struct connectdata *conn)
{
char *portptr;
char endbracket;
Daniel Stenberg
committed
/* Note that at this point, the IPv6 address cannot contain any scope
Daniel Stenberg
committed
suffix as that has already been removed in the parseurlandfillconn()
Daniel Stenberg
committed
function */
if((1 == sscanf(conn->host.name, "[%*45[0123456789abcdefABCDEF:.]%c",
&endbracket)) &&
(']' == endbracket)) {
/* this is a RFC2732-style specified IP-address */
conn->bits.ipv6_ip = TRUE;
conn->host.name++; /* skip over the starting bracket */
portptr = strchr(conn->host.name, ']');
if(portptr) {
*portptr++ = '\0'; /* zero terminate, killing the bracket */
if(':' != *portptr)
portptr = NULL; /* no port number available */
}
else {
#ifdef ENABLE_IPV6
struct in6_addr in6;
if(Curl_inet_pton(AF_INET6, conn->host.name, &in6) > 0) {
/* This is a numerical IPv6 address, meaning this is a wrongly formatted
URL */
failf(data, "IPv6 numerical address used in URL without brackets");
return CURLE_URL_MALFORMAT;
}
#endif
portptr = strrchr(conn->host.name, ':');
if(data->set.use_port && data->state.allow_port) {
/* if set, we use this and ignore the port possibly given in the URL */
conn->remote_port = (unsigned short)data->set.use_port;
if(portptr)
*portptr = '\0'; /* cut off the name there anyway - if there was a port
number - since the port number is to be ignored! */
if(conn->bits.httpproxy) {
/* we need to create new URL with the new port number */
char *url;
char type[12]="";
if(conn->bits.type_set)
snprintf(type, sizeof(type), ";type=%c",
data->set.prefer_ascii?'A':
(data->set.ftp_list_only?'D':'I'));
* This synthesized URL isn't always right--suffixes like ;type=A are
* stripped off. It would be better to work directly from the original
* URL and simply replace the port part of it.
url = aprintf("%s://%s%s%s:%hu%s%s%s", conn->given->scheme,
Daniel Stenberg
committed
conn->bits.ipv6_ip?"[":"", conn->host.name,
conn->bits.ipv6_ip?"]":"", conn->remote_port,
data->state.slash_removed?"/":"", data->state.path,
type);
if(!url)
return CURLE_OUT_OF_MEMORY;
if(data->change.url_alloc) {
Curl_safefree(data->change.url);
data->change.url_alloc = FALSE;
}
data->change.url = url;
data->change.url_alloc = TRUE;
}
}
else if(portptr) {
/* no CURLOPT_PORT given, extract the one from the URL */
char *rest;
long port;
port=strtol(portptr+1, &rest, 10); /* Port number must be decimal */
if((port < 0) || (port > 0xffff)) {
/* Single unix standard says port numbers are 16 bits long */
failf(data, "Port number out of range");
return CURLE_URL_MALFORMAT;
}
else if(rest != &portptr[1]) {
*portptr = '\0'; /* cut off the name there */
/* Browser behavior adaptation. If there's a colon with no digits after,
just cut off the name there which makes us ignore the colon and just
use the default port. Firefox and Chrome both do that. */
*portptr = '\0';
/* only if remote_port was not already parsed off the URL we use the
default port number */
if(conn->remote_port < 0)
conn->remote_port = (unsigned short)conn->given->defport;
return CURLE_OK;
}
/*
* Override the login details from the URL with that in the CURLOPT_USERPWD
* option or a .netrc file, if applicable.
static CURLcode override_login(struct SessionHandle *data,
struct connectdata *conn,
char **userp, char **passwdp, char **optionsp)
if(data->set.str[STRING_USERNAME]) {
free(*userp);
*userp = strdup(data->set.str[STRING_USERNAME]);
if(!*userp)
return CURLE_OUT_OF_MEMORY;
}
if(data->set.str[STRING_PASSWORD]) {
free(*passwdp);
*passwdp = strdup(data->set.str[STRING_PASSWORD]);
if(!*passwdp)
return CURLE_OUT_OF_MEMORY;
}
if(data->set.str[STRING_OPTIONS]) {
free(*optionsp);
*optionsp = strdup(data->set.str[STRING_OPTIONS]);
if(!*optionsp)
return CURLE_OUT_OF_MEMORY;
}
conn->bits.netrc = FALSE;
if(data->set.use_netrc != CURL_NETRC_IGNORED) {
int ret = Curl_parsenetrc(conn->host.name,
userp, passwdp,
data->set.str[STRING_NETRC_FILE]);
if(ret > 0) {
infof(data, "Couldn't find host %s in the "
DOT_CHAR "netrc file; using defaults\n",
conn->host.name);
}
return CURLE_OUT_OF_MEMORY;
}
else {
/* set bits.netrc TRUE to remember that we got the name from a .netrc
file, so that it is safe to use even if we followed a Location: to a
different host or similar. */
conn->bits.netrc = TRUE;
conn->bits.user_passwd = TRUE; /* enable user+password */
}
}
return CURLE_OK;
}
/*
* Set the login details so they're available in the connection
static CURLcode set_login(struct connectdata *conn,
const char *user, const char *passwd,
const char *options)
CURLcode result = CURLE_OK;
/* If our protocol needs a password and we have none, use the defaults */
if((conn->handler->flags & PROTOPT_NEEDSPWD) && !conn->bits.user_passwd) {
/* Store the default user */
conn->user = strdup(CURL_DEFAULT_USER);
/* Store the default password */
if(conn->user)
conn->passwd = strdup(CURL_DEFAULT_PASSWORD);
else
conn->passwd = NULL;
/* This is the default password, so DON'T set conn->bits.user_passwd */
}
else {
/* Store the user, zero-length if not set */
conn->user = strdup(user);
/* Store the password (only if user is present), zero-length if not set */
if(conn->user)
conn->passwd = strdup(passwd);
else
conn->passwd = NULL;
if(!conn->user || !conn->passwd)
result = CURLE_OUT_OF_MEMORY;
/* Store the options, null if not set */
if(!result && options[0]) {
conn->options = strdup(options);
if(!conn->options)
result = CURLE_OUT_OF_MEMORY;
}
return result;
}
5306
5307
5308
5309
5310
5311
5312
5313
5314
5315
5316
5317
5318
5319
5320
5321
5322
5323
5324
5325
5326
5327
5328
5329
5330
5331
5332
5333
5334
5335
5336
5337
5338
5339
5340
5341
5342
5343
5344
5345
5346
5347
5348
5349
5350
5351
5352
5353
5354
5355
5356
5357
5358
5359
5360
5361
5362
5363
5364
5365
5366
5367
5368
5369
5370
5371
5372
5373
5374
5375
5376
5377
5378
5379
5380
5381
5382
5383
5384
5385
5386
5387
5388
5389
5390
5391
5392
5393
5394
5395
5396
5397
5398
5399
5400
5401
5402
5403
5404
5405
5406
5407
5408
5409
5410
5411
5412
5413
5414
5415
5416
5417
5418
5419
5420
5421
5422
5423
5424
5425
5426
5427
5428
5429
5430
5431
5432
5433
5434
5435
5436
5437
5438
5439
5440
5441
5442
5443
5444
5445
5446
5447
5448
5449
5450
5451
5452
5453
5454
5455
5456
5457
5458
5459
5460
5461
5462
5463
5464
5465
5466
5467
5468
5469
5470
5471
5472
5473
5474
5475
5476
5477
5478
5479
5480
5481
5482
5483
5484
5485
5486
5487
5488
5489
5490
5491
5492
5493
5494
5495
5496
5497
5498
5499
5500
5501
5502
5503
5504
5505
5506
5507
5508
5509
5510
5511
5512
5513
/*
* Parses a "host:port" string to connect to.
* The hostname and the port may be empty; in this case, NULL is returned for
* the hostname and -1 for the port.
*/
static CURLcode parse_connect_to_host_port(struct SessionHandle *data,
const char *host,
char **hostname_result,
int *port_result)
{
char *host_dup;
char *hostptr;
char *host_portno;
char *portptr;
int port = -1;
*hostname_result = NULL;
*port_result = -1;
if(!host || !*host)
return CURLE_OK;
host_dup = strdup(host);
if(!host_dup)
return CURLE_OUT_OF_MEMORY;
hostptr = host_dup;
/* start scanning for port number at this point */
portptr = hostptr;
/* detect and extract RFC6874-style IPv6-addresses */
if(*hostptr == '[') {
char *ptr = ++hostptr; /* advance beyond the initial bracket */
while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':') || (*ptr == '.')))
ptr++;
if(*ptr == '%') {
/* There might be a zone identifier */
if(strncmp("%25", ptr, 3))
infof(data, "Please URL encode %% as %%25, see RFC 6874.\n");
ptr++;
/* Allow unreserved characters as defined in RFC 3986 */
while(*ptr && (ISALPHA(*ptr) || ISXDIGIT(*ptr) || (*ptr == '-') ||
(*ptr == '.') || (*ptr == '_') || (*ptr == '~')))
ptr++;
}
if(*ptr == ']')
/* yeps, it ended nicely with a bracket as well */
*ptr++ = '\0';
else
infof(data, "Invalid IPv6 address format\n");
portptr = ptr;
/* Note that if this didn't end with a bracket, we still advanced the
* hostptr 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 server.com:1080 */
host_portno = strchr(portptr, ':');
if(host_portno) {
char *endp = NULL;
*host_portno = '\0'; /* cut off number from host name */
host_portno++;
if(*host_portno) {
long portparse = strtol(host_portno, &endp, 10);
if((endp && *endp) || (portparse < 0) || (portparse > 65535)) {
infof(data, "No valid port number in connect to host string (%s)\n",
host_portno);
hostptr = NULL;
port = -1;
}
else
port = (int)portparse; /* we know it will fit */
}
}
/* now, clone the cleaned host name */
if(hostptr) {
*hostname_result = strdup(hostptr);
if(!*hostname_result) {
free(host_dup);
return CURLE_OUT_OF_MEMORY;
}
}
*port_result = port;
free(host_dup);
return CURLE_OK;
}
/*
* Parses one "connect to" string in the form:
* "HOST:PORT:CONNECT-TO-HOST:CONNECT-TO-PORT".
*/
static CURLcode parse_connect_to_string(struct SessionHandle *data,
struct connectdata *conn,
const char *conn_to_host,
char **host_result,
int *port_result)
{
CURLcode result = CURLE_OK;
const char *ptr = conn_to_host;
int host_match = FALSE;
int port_match = FALSE;
if(*ptr == ':') {
/* an empty hostname always matches */
host_match = TRUE;
ptr++;
}
else {
/* check whether the URL's hostname matches */
size_t hostname_to_match_len;
char *hostname_to_match = aprintf("%s%s%s",
conn->bits.ipv6_ip ? "[" : "",
conn->host.name,
conn->bits.ipv6_ip ? "]" : "");
if(!hostname_to_match)
return CURLE_OUT_OF_MEMORY;
hostname_to_match_len = strlen(hostname_to_match);
host_match = curl_strnequal(ptr, hostname_to_match, hostname_to_match_len);
free(hostname_to_match);
ptr += hostname_to_match_len;
host_match = host_match && *ptr == ':';
ptr++;
}
if(host_match) {
if(*ptr == ':') {
/* an empty port always matches */
port_match = TRUE;
ptr++;
}
else {
/* check whether the URL's port matches */
char *ptr_next = strchr(ptr, ':');
if(ptr_next) {
char *endp = NULL;
long port_to_match = strtol(ptr, &endp, 10);
if((endp == ptr_next) && (port_to_match == conn->remote_port)) {
port_match = TRUE;
ptr = ptr_next + 1;
}
}
}
}
if(host_match && port_match) {
/* parse the hostname and port to connect to */
result = parse_connect_to_host_port(data, ptr, host_result, port_result);
}
return result;
}
/*
* Processes all strings in the "connect to" slist, and uses the "connect
* to host" and "connect to port" of the first string that matches.
*/
static CURLcode parse_connect_to_slist(struct SessionHandle *data,
struct connectdata *conn,
struct curl_slist *conn_to_host)
{
CURLcode result = CURLE_OK;
char *host = NULL;
int port = 0;
while(conn_to_host && !host) {
result = parse_connect_to_string(data, conn, conn_to_host->data,
&host, &port);
if(result)
return result;
if(host && *host) {
bool ipv6host;
conn->conn_to_host.rawalloc = host;
conn->conn_to_host.name = host;
conn->bits.conn_to_host = TRUE;
ipv6host = strchr(host, ':') != NULL;
infof(data, "Connecting to hostname: %s%s%s\n",
ipv6host ? "[" : "", host, ipv6host ? "]" : "");
}
else {
/* no "connect to host" */
conn->bits.conn_to_host = FALSE;
free(host);
}
if(port >= 0) {
conn->conn_to_port = port;
conn->bits.conn_to_port = TRUE;
infof(data, "Connecting to port: %d\n", port);
}
else {
/* no "connect to port" */
conn->bits.conn_to_port = FALSE;
}
conn_to_host = conn_to_host->next;
}
return result;
}
/*************************************************************
* Resolve the address of the server or proxy
*************************************************************/
static CURLcode resolve_server(struct SessionHandle *data,
struct connectdata *conn,
bool *async)
{
CURLcode result=CURLE_OK;
long timeout_ms = Curl_timeleft(data, NULL, TRUE);
/*************************************************************
* Resolve the name of the server or proxy
*************************************************************/
if(conn->bits.reuse)
/* We're reusing the connection - no need to resolve anything, and
fix_hostname() was called already in create_conn() for the re-use
case. */
Daniel Stenberg
committed
*async = FALSE;
else {
/* this is a fresh connect */
int rc;
struct Curl_dns_entry *hostaddr;
#ifdef USE_UNIX_SOCKETS
if(data->set.str[STRING_UNIX_SOCKET_PATH]) {
/* Unix domain sockets are local. The host gets ignored, just use the
* specified domain socket address. Do not cache "DNS entries". There is
* no DNS involved and we already have the filesystem path available */
const char *path = data->set.str[STRING_UNIX_SOCKET_PATH];
hostaddr = calloc(1, sizeof(struct Curl_dns_entry));
if(!hostaddr)
result = CURLE_OUT_OF_MEMORY;
else if((hostaddr->addr = Curl_unix2addr(path)) != NULL)
hostaddr->inuse++;
else {
/* Long paths are not supported for now */
if(strlen(path) >= sizeof(((struct sockaddr_un *)0)->sun_path)) {
failf(data, "Unix socket path too long: '%s'", path);
result = CURLE_COULDNT_RESOLVE_HOST;
}
else
result = CURLE_OUT_OF_MEMORY;
free(hostaddr);
hostaddr = NULL;
}
}
else
#endif
if(!conn->proxy.name || !*conn->proxy.name) {
struct hostname *connhost;
if(conn->bits.conn_to_host)
connhost = &conn->conn_to_host;
else
connhost = &conn->host;
/* If not connecting via a proxy, extract the port from the URL, if it is
* there, thus overriding any defaults that might have been set above. */
if(conn->bits.conn_to_port)
conn->port = conn->conn_to_port;
else
conn->port = conn->remote_port; /* it is the same port */
/* Resolve target host right on */
rc = Curl_resolv_timeout(conn, connhost->name, (int)conn->port,
if(rc == CURLRESOLV_PENDING)
*async = TRUE;
else if(rc == CURLRESOLV_TIMEDOUT)
result = CURLE_OPERATION_TIMEDOUT;
else if(!hostaddr) {
failf(data, "Couldn't resolve host '%s'", connhost->dispname);
result = CURLE_COULDNT_RESOLVE_HOST;
/* don't return yet, we need to clean up the timeout first */
}
}
else {
/* This is a proxy that hasn't been resolved yet. */
/* resolve proxy */
rc = Curl_resolv_timeout(conn, conn->proxy.name, (int)conn->port,
if(rc == CURLRESOLV_PENDING)
*async = TRUE;
else if(rc == CURLRESOLV_TIMEDOUT)
result = CURLE_OPERATION_TIMEDOUT;
else if(!hostaddr) {
failf(data, "Couldn't resolve proxy '%s'", conn->proxy.dispname);
result = CURLE_COULDNT_RESOLVE_PROXY;
/* don't return yet, we need to clean up the timeout first */
}
}
Daniel Stenberg
committed
DEBUGASSERT(conn->dns_entry == NULL);
conn->dns_entry = hostaddr;
}
return result;
}
/*
* Cleanup the connection just allocated before we can move along and use the
* previously existing one. All relevant data is copied over and old_conn is
* ready for freeing once this function returns.
*/
static void reuse_conn(struct connectdata *old_conn,
struct connectdata *conn)
{
free_fixed_hostname(&old_conn->proxy);
Markus Elfring
committed
free(old_conn->proxy.rawalloc);
5629
5630
5631
5632
5633
5634
5635
5636
5637
5638
5639
5640
5641
5642
5643
5644
5645
5646
5647
5648
5649
5650
5651
5652
5653
5654
5655
5656
5657
5658
5659
/* free the SSL config struct from this connection struct as this was
allocated in vain and is targeted for destruction */
Curl_free_ssl_config(&old_conn->ssl_config);
conn->data = old_conn->data;
/* get the user+password information from the old_conn struct since it may
* be new for this request even when we re-use an existing connection */
conn->bits.user_passwd = old_conn->bits.user_passwd;
if(conn->bits.user_passwd) {
/* use the new user name and password though */
Curl_safefree(conn->user);
Curl_safefree(conn->passwd);
conn->user = old_conn->user;
conn->passwd = old_conn->passwd;
old_conn->user = NULL;
old_conn->passwd = NULL;
}
conn->bits.proxy_user_passwd = old_conn->bits.proxy_user_passwd;
if(conn->bits.proxy_user_passwd) {
/* use the new proxy user name and proxy password though */
Curl_safefree(conn->proxyuser);
Curl_safefree(conn->proxypasswd);
conn->proxyuser = old_conn->proxyuser;
conn->proxypasswd = old_conn->proxypasswd;
old_conn->proxyuser = NULL;
old_conn->proxypasswd = NULL;
}
/* host can change, when doing keepalive with a proxy or if the case is
different this time etc */
free_fixed_hostname(&conn->host);
free_fixed_hostname(&conn->conn_to_host);
Curl_safefree(conn->host.rawalloc);
Curl_safefree(conn->conn_to_host.rawalloc);
conn->host=old_conn->host;
conn->bits.conn_to_host = old_conn->bits.conn_to_host;
conn->conn_to_host = old_conn->conn_to_host;
conn->bits.conn_to_port = old_conn->bits.conn_to_port;
conn->conn_to_port = old_conn->conn_to_port;
/* persist connection info in session handle */
Curl_persistconninfo(conn);
conn_reset_all_postponed_data(old_conn); /* free buffers */
conn_reset_all_postponed_data(conn); /* reset unprocessed data */
/* re-use init */
conn->bits.reuse = TRUE; /* yes, we're re-using here */
Curl_safefree(old_conn->user);
Curl_safefree(old_conn->passwd);
Curl_safefree(old_conn->proxyuser);
Curl_safefree(old_conn->proxypasswd);
Curl_safefree(old_conn->localdev);
Curl_llist_destroy(old_conn->send_pipe, NULL);
Curl_llist_destroy(old_conn->recv_pipe, NULL);
old_conn->send_pipe = NULL;
old_conn->recv_pipe = NULL;
Curl_safefree(old_conn->master_buffer);
}
/**
* create_conn() 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
Daniel Stenberg
committed
* @param async is set TRUE when an async DNS resolution is pending
*
* *NOTE* this function assigns the conn->data pointer!
*/
static CURLcode create_conn(struct SessionHandle *data,
struct connectdata **in_connect,
bool *async)
{
CURLcode result = CURLE_OK;
struct connectdata *conn;
struct connectdata *conn_temp = NULL;
size_t urllen;
char *user = NULL;
char *passwd = NULL;
char *options = NULL;
bool reuse;
char *proxy = NULL;
bool prot_missing = FALSE;
bool force_reuse = FALSE;
size_t max_host_connections = Curl_multi_max_host_connections(data->multi);
size_t max_total_connections = Curl_multi_max_total_connections(data->multi);
*async = FALSE;
Daniel Stenberg
committed
/*************************************************************
* Check input data
*************************************************************/
if(!data->change.url) {
result = CURLE_URL_MALFORMAT;
goto out;
}
/* 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. */
if(!conn) {
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;
/* 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;
/*
* We malloc() the buffers below urllen+2 to make room for 2 possibilities:
* 1 - an extra terminating zero
* 2 - an extra slash (in case a syntax like "www.host.com?moo" is used)
*/
Curl_safefree(data->state.pathbuffer);
data->state.pathbuffer = malloc(urllen+2);
if(NULL == data->state.pathbuffer) {
result = CURLE_OUT_OF_MEMORY; /* really bad error */
goto out;
}
Daniel Stenberg
committed
data->state.path = data->state.pathbuffer;
conn->host.rawalloc = malloc(urllen+2);
if(NULL == conn->host.rawalloc) {
Curl_safefree(data->state.pathbuffer);
data->state.path = NULL;
result = CURLE_OUT_OF_MEMORY;
goto out;
conn->host.name = conn->host.rawalloc;
conn->host.name[0] = 0;
user = strdup("");
passwd = strdup("");
options = strdup("");
if(!user || !passwd || !options) {
result = CURLE_OUT_OF_MEMORY;
goto out;
}
result = parseurlandfillconn(data, conn, &prot_missing, &user, &passwd,
&options);
Daniel Stenberg
committed
/*************************************************************
* No protocol part in URL was used, add it!
*************************************************************/
if(prot_missing) {
Daniel Stenberg
committed
/* 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;
char *ch_lower;
Daniel Stenberg
committed
Daniel Stenberg
committed
reurl = aprintf("%s://%s", conn->handler->scheme, data->change.url);
Daniel Stenberg
committed
if(!reurl) {
result = CURLE_OUT_OF_MEMORY;
goto out;
Daniel Stenberg
committed
}
/* Change protocol prefix to lower-case */
for(ch_lower = reurl; *ch_lower != ':'; ch_lower++)
*ch_lower = (char)TOLOWER(*ch_lower);
if(data->change.url_alloc) {
Curl_safefree(data->change.url);
data->change.url_alloc = FALSE;
}
Daniel Stenberg
committed
data->change.url = reurl;
data->change.url_alloc = TRUE; /* free this later */
}
/*************************************************************
* If the protocol can't handle url query strings, then cut
*************************************************************/
if((conn->given->flags&PROTOPT_NOURLQUERY)) {
char *path_q_sep = strchr(conn->data->state.path, '?');
if(path_q_sep) {
/* according to rfc3986, allow the query (?foo=bar)
also on protocols that can't handle it.
cut the string-part after '?'
*/
/* terminate the string */
path_q_sep[0] = 0;
}
}
if(data->set.str[STRING_BEARER]) {
conn->oauth_bearer = strdup(data->set.str[STRING_BEARER]);
if(!conn->oauth_bearer) {
result = CURLE_OUT_OF_MEMORY;
goto out;
Daniel Stenberg
committed
#ifndef CURL_DISABLE_PROXY
/*************************************************************
* Extract the user and password from the authentication string
*************************************************************/
if(conn->bits.proxy_user_passwd) {
result = parse_proxy_auth(data, conn);
}
/*************************************************************
* Detect what (if any) proxy to use
*************************************************************/
Daniel Stenberg
committed
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");
result = CURLE_OUT_OF_MEMORY;
goto out;
}
}
Daniel Stenberg
committed
if(data->set.str[STRING_NOPROXY] &&
check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY])) {
Markus Elfring
committed
free(proxy); /* proxy is in exception list */
proxy = NULL;
Daniel Stenberg
committed
}
Daniel Stenberg
committed
else if(!proxy)
proxy = detect_proxy(conn);
#ifdef USE_UNIX_SOCKETS
if(proxy && data->set.str[STRING_UNIX_SOCKET_PATH]) {
free(proxy); /* Unix domain sockets cannot be proxied, so disable it */
proxy = NULL;
}
#endif
if(proxy && (!*proxy || (conn->handler->flags & PROTOPT_NONETWORK))) {
free(proxy); /* Don't bother with an empty proxy string or if the
protocol doesn't work with network */
proxy = NULL;
}
/***********************************************************************
* If this is supposed to use a proxy, we need to figure out the proxy host
* name, proxy type and port number, 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);
free(proxy); /* parse_proxy copies the proxy string */
proxy = NULL;
if((conn->proxytype == CURLPROXY_HTTP) ||
(conn->proxytype == CURLPROXY_HTTP_1_0)) {
#ifdef CURL_DISABLE_HTTP
/* asking for a HTTP proxy is a bit funny when HTTP is disabled... */
result = CURLE_UNSUPPORTED_PROTOCOL;
goto out;
#else
/* force this connection's protocol to become HTTP if not already
compatible - if it isn't tunneling through */
if(!(conn->handler->protocol & PROTO_FAMILY_HTTP) &&
!conn->bits.tunnel_proxy)
conn->handler = &Curl_handler_http;
Daniel Stenberg
committed
conn->bits.httpproxy = TRUE;
#endif
Daniel Stenberg
committed
}
conn->bits.httpproxy = FALSE; /* not a HTTP proxy */
conn->bits.tunnel_proxy = FALSE; /* no tunneling if not HTTP */
}
Daniel Stenberg
committed
conn->bits.proxy = TRUE;
}
else {
Daniel Stenberg
committed
/* we aren't using the proxy after all... */
conn->bits.proxy = FALSE;
conn->bits.httpproxy = FALSE;
conn->bits.proxy_user_passwd = FALSE;
conn->bits.tunnel_proxy = FALSE;
Daniel Stenberg
committed
}
#endif /* CURL_DISABLE_PROXY */
/*************************************************************
* 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;
/*************************************************************
* Figure out the remote port number and fix it in the URL
*************************************************************/
result = parse_remote_port(data, conn);
/* Check for overridden login details and set them accordingly so they
they are known when protocol->setup_connection is called! */
result = override_login(data, conn, &user, &passwd, &options);
result = set_login(conn, user, passwd, options);
/*************************************************************
* 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);
if(result)
goto out;
/*************************************************************
* IDN-fix the hostnames
*************************************************************/
fix_hostname(data, conn, &conn->host);
if(conn->bits.conn_to_host)
fix_hostname(data, conn, &conn->conn_to_host);
if(conn->proxy.name && *conn->proxy.name)
fix_hostname(data, conn, &conn->proxy);
/*************************************************************
* Check whether the host and the "connect to host" are equal.
* Do this after the hostnames have been IDN-fixed .