Newer
Older
/* possible free the old one */
if(data->change.url_alloc) {
Curl_safefree(data->change.url);
data->change.url_alloc = FALSE;
}
infof(data, "Rebuilt URL to: %s\n", reurl);
data->change.url = reurl;
data->change.url_alloc = TRUE; /* free this later */
Daniel Stenberg
committed
}
/*
* Parse the login details from the URL and strip them out of
* the host name
*/
result = parse_url_login(data, conn, userp, passwdp, optionsp);
if(result != CURLE_OK)
return result;
if(conn->host.name[0] == '[') {
Daniel Stenberg
committed
/* This looks like an IPv6 address literal. See if there is an address
scope if there is no location header */
char *percent = strchr(conn->host.name, '%');
unsigned int identifier_offset = 3;
Daniel Stenberg
committed
char *endp;
unsigned long scope;
if(strncmp("%25", percent, 3) != 0) {
infof(data,
"Please URL encode %% as %%25, see RFC 6874.\n");
identifier_offset = 1;
}
scope = strtoul(percent + identifier_offset, &endp, 10);
if(*endp == ']') {
/* The address scope was well formed. Knock it out of the
hostname. */
memmove(percent, endp, strlen(endp)+1);
conn->scope = (unsigned int)scope;
}
else {
/* Zone identifier is not numeric */
#if defined(HAVE_NET_IF_H) && defined(IFNAMSIZ) && defined(HAVE_IF_NAMETOINDEX)
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
char ifname[IFNAMSIZ + 2];
char *square_bracket;
unsigned int scopeidx = 0;
strncpy(ifname, percent + identifier_offset, IFNAMSIZ + 2);
/* Ensure nullbyte termination */
ifname[IFNAMSIZ + 1] = '\0';
square_bracket = strchr(ifname, ']');
if(square_bracket) {
/* Remove ']' */
*square_bracket = '\0';
scopeidx = if_nametoindex(ifname);
if(scopeidx == 0) {
infof(data, "Invalid network interface: %s; %s\n", ifname,
strerror(errno));
}
}
if(scopeidx > 0) {
/* Remove zone identifier from hostname */
memmove(percent,
percent + identifier_offset + strlen(ifname),
identifier_offset + strlen(ifname));
conn->scope = scopeidx;
}
else
#endif /* HAVE_NET_IF_H && IFNAMSIZ */
infof(data, "Invalid IPv6 address format\n");
Daniel Stenberg
committed
}
}
Claes Jakobsson
committed
if(data->set.scope)
Daniel Stenberg
committed
/* Override any scope that was set above. */
conn->scope = data->set.scope;
Claes Jakobsson
committed
/* Remove the fragment part of the path. Per RFC 2396, this is always the
last part of the URI. We are looking for the first '#' so that we deal
gracefully with non conformant URI such as http://example.com#foo#bar. */
Claes Jakobsson
committed
fragment = strchr(path, '#');
Claes Jakobsson
committed
*fragment = 0;
/* we know the path part ended with a fragment, so we know the full URL
string does too and we need to cut it off from there so it isn't used
over proxy */
fragment = strchr(data->change.url, '#');
if(fragment)
*fragment = 0;
}
Claes Jakobsson
committed
* So if the URL was A://B/C#D,
Daniel Stenberg
committed
* protop is A
* conn->host.name is B
Daniel Stenberg
committed
* data->state.path is /C
*/
Daniel Stenberg
committed
Daniel Stenberg
committed
return findprotocol(data, conn, protop);
}
/*
* If we're doing a resumed transfer, we need to setup our stuff
* properly.
*/
Daniel Stenberg
committed
static CURLcode setup_range(struct SessionHandle *data)
{
Daniel Stenberg
committed
struct UrlState *s = &data->state;
s->resume_from = data->set.set_resume_from;
if(s->resume_from || data->set.str[STRING_SET_RANGE]) {
if(s->rangestringalloc)
free(s->range);
if(s->resume_from)
s->range = aprintf("%" CURL_FORMAT_CURL_OFF_TU "-", s->resume_from);
Daniel Stenberg
committed
else
Daniel Stenberg
committed
s->range = strdup(data->set.str[STRING_SET_RANGE]);
Daniel Stenberg
committed
s->rangestringalloc = (s->range)?TRUE:FALSE;
Daniel Stenberg
committed
Daniel Stenberg
committed
if(!s->range)
Daniel Stenberg
committed
return CURLE_OUT_OF_MEMORY;
/* tell ourselves to fetch this range */
Daniel Stenberg
committed
s->use_range = TRUE; /* enable range download */
Daniel Stenberg
committed
}
else
Daniel Stenberg
committed
s->use_range = FALSE; /* disable range download */
Daniel Stenberg
committed
return CURLE_OK;
}
/*
* setup_connection_internals() -
*
* Setup connection internals specific to the requested protocol in the
* SessionHandle. This is inited and setup before the connection is made but
* is about the particular protocol that is to be used.
*
* This MUST get called after proxy magic has been figured out.
*/
Daniel Stenberg
committed
static CURLcode setup_connection_internals(struct connectdata *conn)
{
Patrick Monnerat
committed
const struct Curl_handler * p;
CURLcode result;
struct SessionHandle *data = conn->data;
/* in some case in the multi state-machine, we go back to the CONNECT state
and then a second (or third or...) call to this function will be made
without doing a DISCONNECT or DONE in between (since the connection is
yet in place) and therefore this function needs to first make sure
there's no lingering previous data allocated. */
Curl_free_request_state(data);
memset(&data->req, 0, sizeof(struct SingleRequest));
data->req.maxdownload = -1;
conn->socktype = SOCK_STREAM; /* most of them are TCP streams */
Daniel Stenberg
committed
/* Perform setup complement if some. */
p = conn->handler;
Daniel Stenberg
committed
if(p->setup_connection) {
result = (*p->setup_connection)(conn);
Daniel Stenberg
committed
if(result != CURLE_OK)
return result;
Daniel Stenberg
committed
p = conn->handler; /* May have changed. */
}
Daniel Stenberg
committed
if(conn->port < 0)
/* we check for -1 here since if proxy was detected already, this
was very likely already set to the proxy port */
conn->port = p->defport;
/* only if remote_port was not already parsed off the URL we use the
default port number */
conn->remote_port = (unsigned short)conn->given->defport;
Daniel Stenberg
committed
return CURLE_OK;
}
/*
* Curl_free_request_state() should free temp data that was allocated in the
* SessionHandle for this single request.
*/
void Curl_free_request_state(struct SessionHandle *data)
Curl_safefree(data->req.protop);
}
Daniel Stenberg
committed
#ifndef CURL_DISABLE_PROXY
Daniel Stenberg
committed
4200
4201
4202
4203
4204
4205
4206
4207
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
4231
/****************************************************************
* Checks if the host is in the noproxy list. returns true if it matches
* and therefore the proxy should NOT be used.
****************************************************************/
static bool check_noproxy(const char* name, const char* no_proxy)
{
/* 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)
*/
size_t tok_start;
size_t tok_end;
const char* separator = ", ";
size_t no_proxy_len;
size_t namelen;
char *endptr;
if(no_proxy && no_proxy[0]) {
if(Curl_raw_equal("*", no_proxy)) {
return TRUE;
}
/* NO_PROXY was specified and it wasn't just an asterisk */
no_proxy_len = strlen(no_proxy);
endptr = strchr(name, ':');
if(endptr)
namelen = endptr - name;
else
namelen = strlen(name);
for(tok_start = 0; tok_start < no_proxy_len; tok_start = tok_end + 1) {
while(tok_start < no_proxy_len &&
strchr(separator, no_proxy[tok_start]) != NULL) {
Daniel Stenberg
committed
/* Look for the beginning of the token. */
++tok_start;
}
if(tok_start == no_proxy_len)
break; /* It was all trailing separator chars, no more tokens. */
for(tok_end = tok_start; tok_end < no_proxy_len &&
strchr(separator, no_proxy[tok_end]) == NULL; ++tok_end)
Daniel Stenberg
committed
/* Look for the end of the token. */
Daniel Stenberg
committed
/* To match previous behaviour, where it was necessary to specify
* ".local.com" to prevent matching "notlocal.com", we will leave
* the '.' off.
*/
if(no_proxy[tok_start] == '.')
++tok_start;
if((tok_end - tok_start) <= namelen) {
/* Match the last part of the name to the domain we are checking. */
const char *checkn = name + namelen - (tok_end - tok_start);
if(Curl_raw_nequal(no_proxy + tok_start, checkn,
tok_end - tok_start)) {
Daniel Stenberg
committed
if((tok_end - tok_start) == namelen || *(checkn - 1) == '.') {
/* We either have an exact match, or the previous character is a .
* so it is within the same domain, so no proxy for this host.
*/
return TRUE;
}
}
} /* if((tok_end - tok_start) <= namelen) */
} /* for(tok_start = 0; tok_start < no_proxy_len;
Daniel Stenberg
committed
tok_start = tok_end + 1) */
} /* NO_PROXY was specified and it wasn't just an asterisk */
return FALSE;
}
/****************************************************************
* 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;
Daniel Stenberg
committed
4283
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
4301
4302
4303
4304
4305
4306
4307
#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 proxy_env[128];
no_proxy=curl_getenv("no_proxy");
if(!no_proxy)
no_proxy=curl_getenv("NO_PROXY");
Daniel Stenberg
committed
if(!check_noproxy(conn->host.name, no_proxy)) {
/* It was not listed as without proxy */
Daniel Stenberg
committed
const char *protop = conn->handler->scheme;
Daniel Stenberg
committed
char *envp = proxy_env;
char *prox;
Daniel Stenberg
committed
/* Now, build <protocol>_proxy and check for such a one to use */
while(*protop)
*envp++ = (char)tolower((int)*protop++);
Daniel Stenberg
committed
/* append _proxy */
strcpy(envp, "_proxy");
Daniel Stenberg
committed
/* read the protocol proxy: */
prox=curl_getenv(proxy_env);
Daniel Stenberg
committed
/*
* 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 && !Curl_raw_equal("http_proxy", proxy_env)) {
/* There was no lowercase variable, try the uppercase version: */
Curl_strntoupper(proxy_env, proxy_env, sizeof(proxy_env));
prox=curl_getenv(proxy_env);
}
Daniel Stenberg
committed
proxy = prox; /* use this */
else {
proxy = curl_getenv("all_proxy"); /* default proxy to use */
if(!proxy)
proxy=curl_getenv("ALL_PROXY");
}
} /* if(!check_noproxy(conn->host.name, no_proxy)) - it wasn't specified
non-proxy */
if(no_proxy)
free(no_proxy);
#else /* !CURL_DISABLE_HTTP */
(void)conn;
#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;
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
*/
/* Parse the protocol part if present */
endofprot = strstr(proxy, "://");
proxyptr = endofprot+3;
if(checkprefix("socks5h", proxy))
conn->proxytype = CURLPROXY_SOCKS5_HOSTNAME;
else if(checkprefix("socks5", proxy))
conn->proxytype = CURLPROXY_SOCKS5;
else if(checkprefix("socks4a", proxy))
conn->proxytype = CURLPROXY_SOCKS4A;
else if(checkprefix("socks4", proxy) || checkprefix("socks", proxy))
conn->proxytype = CURLPROXY_SOCKS4;
/* Any other xxx:// : change to http proxy */
}
else
proxyptr = proxy; /* No xxx:// head: It's a HTTP proxy */
/* Is there a username and password given in this proxy url? */
atsign = strchr(proxyptr, '@');
if(atsign) {
CURLcode res = CURLE_OK;
char *proxyuser = NULL;
char *proxypasswd = NULL;
res = parse_login_details(proxyptr, atsign - proxyptr,
&proxyuser, &proxypasswd, NULL);
if(!res) {
/* 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);
if(proxyuser && strlen(proxyuser) < MAX_CURL_USER_LENGTH)
conn->proxyuser = curl_easy_unescape(data, proxyuser, 0, NULL);
else
conn->proxyuser = strdup("");
if(!conn->proxyuser)
res = CURLE_OUT_OF_MEMORY;
else {
Curl_safefree(conn->proxypasswd);
if(proxypasswd && strlen(proxypasswd) < MAX_CURL_PASSWORD_LENGTH)
conn->proxypasswd = curl_easy_unescape(data, proxypasswd, 0, NULL);
else
conn->proxypasswd = strdup("");
if(!conn->proxypasswd)
res = CURLE_OUT_OF_MEMORY;
}
conn->bits.proxy_user_passwd = TRUE; /* enable it */
atsign++; /* the right side of the @-letter */
proxyptr = atsign; /* now use this instead */
}
Curl_safefree(proxyuser);
Curl_safefree(proxypasswd);
if(res)
return res;
}
/* start scanning for port number at this point */
portptr = proxyptr;
/* detect and extract RFC6874-style IPv6-addresses */
if(*proxyptr == '[') {
char *ptr = ++proxyptr; /* 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 unresered characters as defined in RFC 3986 */
while(*ptr && (ISALPHA(*ptr) || ISXDIGIT(*ptr) || (*ptr == '-') ||
(*ptr == '.') || (*ptr == '_') || (*ptr == '~')))
ptr++;
}
/* yeps, it ended nicely with a bracket as well */
*ptr++ = 0;
infof(data, "Invalid IPv6 address format\n");
portptr = ptr;
/* 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, ':');
Daniel Stenberg
committed
if(prox_portno) {
*prox_portno = 0x0; /* cut off number from host name */
prox_portno ++;
/* now set the local port number */
}
Daniel Stenberg
committed
else {
/* If the first character in the proxy string is a slash, fail
immediately. The following code will otherwise clear the string which
will lead to code running as if no proxy was set! */
return CURLE_COULDNT_RESOLVE_PROXY;
Daniel Stenberg
committed
/* without a port number after the host name, some people seem to use
a slash so we strip everything from the first slash */
atsign = strchr(proxyptr, '/');
Daniel Stenberg
committed
*atsign = 0x0; /* cut off path part from host name */
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;
if(!conn->proxy.rawalloc)
return CURLE_OUT_OF_MEMORY;
return CURLE_OK;
}
/*
* Extract the user and password from the authentication string
*/
Daniel Stenberg
committed
static CURLcode parse_proxy_auth(struct SessionHandle *data,
struct connectdata *conn)
{
char proxyuser[MAX_CURL_USER_LENGTH]="";
char proxypasswd[MAX_CURL_PASSWORD_LENGTH]="";
Daniel Stenberg
committed
if(data->set.str[STRING_PROXYUSERNAME] != NULL) {
Daniel Stenberg
committed
strncpy(proxyuser, data->set.str[STRING_PROXYUSERNAME],
MAX_CURL_USER_LENGTH);
Daniel Stenberg
committed
proxyuser[MAX_CURL_USER_LENGTH-1] = '\0'; /*To be on safe side*/
}
if(data->set.str[STRING_PROXYPASSWORD] != NULL) {
strncpy(proxypasswd, data->set.str[STRING_PROXYPASSWORD],
MAX_CURL_PASSWORD_LENGTH);
proxypasswd[MAX_CURL_PASSWORD_LENGTH-1] = '\0'; /*To be on safe side*/
}
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;
}
Daniel Stenberg
committed
#endif /* CURL_DISABLE_PROXY */
* parse_url_login()
*
* Parse the login details (user name, password and options) from the URL and
* strip them out of the host name
*
* Inputs: data->set.use_netrc (CURLOPT_NETRC)
* conn->host.name
*
* Outputs: (almost :- all currently undefined)
* conn->bits.user_passwd - non-zero if non-default passwords exist
* user - non-zero length if defined
* passwd - non-zero length if defined
* options - non-zero length if defined
* conn->host.name - remove user name and password
*/
static CURLcode parse_url_login(struct SessionHandle *data,
struct connectdata *conn,
char **user, char **passwd, char **options)
{
CURLcode result = CURLE_OK;
char *userp = NULL;
char *passwdp = NULL;
char *optionsp = NULL;
/* At this point, we're hoping all the other special cases have
* been taken care of, so conn->host.name is at most
* [user[:password][;options]]@]hostname
*
* We need somewhere to put the embedded details, so do that first.
*/
char *ptr = strchr(conn->host.name, '@');
char *login = conn->host.name;
DEBUGASSERT(!**user);
DEBUGASSERT(!**passwd);
DEBUGASSERT(!**options);
if(!ptr)
goto out;
/* We will now try to extract the
* possible login information in a string like:
* ftp://user:password@ftp.my.site:8021/README */
conn->host.name = ++ptr;
/* So the hostname is sane. Only bother interpreting the
* results if we could care. It could still be wasted
* work because it might be overtaken by the programmatically
* set user/passwd, but doing that first adds more cases here :-(
*/
if(data->set.use_netrc == CURL_NETRC_REQUIRED)
goto out;
Daniel Stenberg
committed
/* We could use the login information in the URL so extract it */
result = parse_login_details(login, ptr - login - 1,
&userp, &passwdp, &optionsp);
if(result != CURLE_OK)
goto out;
if(userp) {
char *newname;
/* We have a user in the URL */
conn->bits.userpwd_in_url = TRUE;
conn->bits.user_passwd = TRUE; /* enable user+password */
/* Decode the user */
newname = curl_easy_unescape(data, userp, 0, NULL);
if(!newname) {
result = CURLE_OUT_OF_MEMORY;
goto out;
}
free(*user);
*user = newname;
if(passwdp) {
/* We have a password in the URL so decode it */
char *newpasswd = curl_easy_unescape(data, passwdp, 0, NULL);
if(!newpasswd) {
result = CURLE_OUT_OF_MEMORY;
goto out;
}
free(*passwd);
*passwd = newpasswd;
if(optionsp) {
/* We have an options list in the URL so decode it */
char *newoptions = curl_easy_unescape(data, optionsp, 0, NULL);
if(!newoptions) {
result = CURLE_OUT_OF_MEMORY;
goto out;
free(*options);
*options = newoptions;
out:
Curl_safefree(userp);
Curl_safefree(passwdp);
Curl_safefree(optionsp);
return result;
}
4661
4662
4663
4664
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
4686
4687
4688
4689
4690
/*
* parse_login_details()
*
* This is used to parse a login string for user name, password and options in
* the following formats:
*
* user
* user:password
* user:password;options
* user;options
* user;options:password
* :password
* :password;options
* ;options
* ;options:password
*
* Parameters:
*
* login [in] - The login string.
* len [in] - The length of the login string.
* userp [in/out] - The address where a pointer to newly allocated memory
* holding the user will be stored upon completion.
* passdwp [in/out] - The address where a pointer to newly allocated memory
* holding the password will be stored upon completion.
* optionsp [in/out] - The address where a pointer to newly allocated memory
* holding the options will be stored upon completion.
*
* Returns CURLE_OK on success.
*/
static CURLcode parse_login_details(const char *login, const size_t len,
char **userp, char **passwdp,
char **optionsp)
CURLcode result = CURLE_OK;
char *ubuf = NULL;
char *pbuf = NULL;
char *obuf = NULL;
const char *psep = NULL;
const char *osep = NULL;
size_t ulen;
size_t plen;
size_t olen;
/* Attempt to find the password separator */
psep = strchr(login, ':');
/* 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);
if(!pbuf) {
Curl_safefree(ubuf);
result = CURLE_OUT_OF_MEMORY;
/* Allocate the options portion buffer */
if(!result && optionsp && olen) {
obuf = malloc(olen + 1);
if(!obuf) {
Curl_safefree(pbuf);
Curl_safefree(ubuf);
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';
}
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);
}
else if(ret < 0 ) {
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;