aboutsummaryrefslogtreecommitdiffstats
path: root/lib/url.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/url.c')
-rw-r--r--lib/url.c160
1 files changed, 95 insertions, 65 deletions
diff --git a/lib/url.c b/lib/url.c
index 0d5a13f9..7839dfa7 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -127,7 +127,7 @@ bool curl_win32_idn_to_ascii(const char *in, char **out);
#include "memdebug.h"
static void conn_free(struct connectdata *conn);
-static void free_fixed_hostname(struct hostname *host);
+static void free_idnconverted_hostname(struct hostname *host);
static unsigned int get_protocol_family(unsigned int protocol);
/* Some parts of the code (e.g. chunked encoding) assume this buffer has at
@@ -570,7 +570,7 @@ CURLcode Curl_open(struct Curl_easy **curl)
data->magic = CURLEASY_MAGIC_NUMBER;
- result = Curl_resolver_init(&data->state.resolver);
+ result = Curl_resolver_init(data, &data->state.resolver);
if(result) {
DEBUGF(fprintf(stderr, "Error: resolver_init failed\n"));
free(data);
@@ -708,6 +708,7 @@ static void conn_free(struct connectdata *conn)
Curl_safefree(conn->trailer);
Curl_safefree(conn->host.rawalloc); /* host name buffer */
Curl_safefree(conn->conn_to_host.rawalloc); /* host name buffer */
+ Curl_safefree(conn->hostname_resolve);
Curl_safefree(conn->secondaryhostname);
Curl_safefree(conn->http_proxy.host.rawalloc); /* http proxy name buffer */
Curl_safefree(conn->socks_proxy.host.rawalloc); /* socks proxy name buffer */
@@ -788,10 +789,10 @@ CURLcode Curl_disconnect(struct Curl_easy *data,
infof(data, "Closing connection %ld\n", conn->connection_id);
Curl_conncache_remove_conn(conn, TRUE);
- free_fixed_hostname(&conn->host);
- free_fixed_hostname(&conn->conn_to_host);
- free_fixed_hostname(&conn->http_proxy.host);
- free_fixed_hostname(&conn->socks_proxy.host);
+ free_idnconverted_hostname(&conn->host);
+ free_idnconverted_hostname(&conn->conn_to_host);
+ free_idnconverted_hostname(&conn->http_proxy.host);
+ free_idnconverted_hostname(&conn->socks_proxy.host);
DEBUGASSERT(conn->data == data);
/* this assumes that the pointer is still there after the connection was
@@ -1679,11 +1680,23 @@ static bool is_ASCII_name(const char *hostname)
}
/*
- * Perform any necessary IDN conversion of hostname
+ * Strip single trailing dot in the hostname,
+ * primarily for SNI and http host header.
*/
-static CURLcode fix_hostname(struct connectdata *conn, struct hostname *host)
+static void strip_trailing_dot(struct hostname *host)
{
size_t len;
+ len = strlen(host->name);
+ if(len && (host->name[len-1] == '.'))
+ host->name[len-1] = 0;
+}
+
+/*
+ * Perform any necessary IDN conversion of hostname
+ */
+static CURLcode idnconvert_hostname(struct connectdata *conn,
+ struct hostname *host)
+{
struct Curl_easy *data = conn->data;
#ifndef USE_LIBIDN2
@@ -1696,12 +1709,6 @@ static CURLcode fix_hostname(struct connectdata *conn, struct hostname *host)
/* set the name we use to display the host name */
host->dispname = host->name;
- len = strlen(host->name);
- if(len && (host->name[len-1] == '.'))
- /* strip off a single trailing dot if present, primarily for SNI but
- there's no use for it */
- host->name[len-1] = 0;
-
/* Check name for non-ASCII and convert hostname to ACE form if we can */
if(!is_ASCII_name(host->name)) {
#ifdef USE_LIBIDN2
@@ -1756,9 +1763,9 @@ static CURLcode fix_hostname(struct connectdata *conn, struct hostname *host)
}
/*
- * Frees data allocated by fix_hostname()
+ * Frees data allocated by idnconvert_hostname()
*/
-static void free_fixed_hostname(struct hostname *host)
+static void free_idnconverted_hostname(struct hostname *host)
{
#if defined(USE_LIBIDN2)
if(host->encalloc) {
@@ -2026,7 +2033,13 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
Curl_up_free(data); /* cleanup previous leftovers first */
/* parse the URL */
- uh = data->state.uh = curl_url();
+ if(data->set.uh) {
+ uh = data->set.uh;
+ }
+ else {
+ uh = data->state.uh = curl_url();
+ }
+
if(!uh)
return CURLE_OUT_OF_MEMORY;
@@ -2043,14 +2056,18 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
data->change.url_alloc = TRUE;
}
- uc = curl_url_set(uh, CURLUPART_URL, data->change.url,
+ if(!data->set.uh) {
+ uc = curl_url_set(uh, CURLUPART_URL, data->change.url,
CURLU_GUESS_SCHEME |
CURLU_NON_SUPPORT_SCHEME |
(data->set.disallow_username_in_url ?
CURLU_DISALLOW_USER : 0) |
(data->set.path_as_is ? CURLU_PATH_AS_IS : 0));
- if(uc)
- return Curl_uc_to_curlcode(uc);
+ if(uc) {
+ DEBUGF(infof(data, "curl_url_set rejected %s\n", data->change.url));
+ return Curl_uc_to_curlcode(uc);
+ }
+ }
uc = curl_url_get(uh, CURLUPART_SCHEME, &data->state.up.scheme, 0);
if(uc)
@@ -2191,6 +2208,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
return CURLE_OK;
}
+
/*
* If we're doing a resumed transfer, we need to setup our stuff
* properly.
@@ -2979,7 +2997,7 @@ static CURLcode parse_remote_port(struct Curl_easy *data,
char portbuf[16];
CURLUcode uc;
conn->remote_port = (unsigned short)data->set.use_port;
- snprintf(portbuf, sizeof(portbuf), "%u", conn->remote_port);
+ msnprintf(portbuf, sizeof(portbuf), "%u", conn->remote_port);
uc = curl_url_set(data->state.uh, CURLUPART_PORT, portbuf, 0);
if(uc)
return CURLE_OUT_OF_MEMORY;
@@ -2999,6 +3017,20 @@ static CURLcode override_login(struct Curl_easy *data,
bool user_changed = FALSE;
bool passwd_changed = FALSE;
CURLUcode uc;
+
+ if(data->set.use_netrc == CURL_NETRC_REQUIRED && conn->bits.user_passwd) {
+ /* ignore user+password in the URL */
+ if(*userp) {
+ Curl_safefree(*userp);
+ user_changed = TRUE;
+ }
+ if(*passwdp) {
+ Curl_safefree(*passwdp);
+ passwd_changed = TRUE;
+ }
+ conn->bits.user_passwd = FALSE; /* disable user+password */
+ }
+
if(data->set.str[STRING_USERNAME]) {
free(*userp);
*userp = strdup(data->set.str[STRING_USERNAME]);
@@ -3025,16 +3057,15 @@ static CURLcode override_login(struct Curl_easy *data,
}
conn->bits.netrc = FALSE;
- if(data->set.use_netrc != CURL_NETRC_IGNORED) {
- char *nuser = NULL;
- char *npasswd = NULL;
+ if(data->set.use_netrc != CURL_NETRC_IGNORED &&
+ (!*userp || !**userp || !*passwdp || !**passwdp)) {
+ bool netrc_user_changed = FALSE;
+ bool netrc_passwd_changed = FALSE;
int ret;
- if(data->set.use_netrc == CURL_NETRC_OPTIONAL)
- nuser = *userp; /* to separate otherwise identical machines */
-
ret = Curl_parsenetrc(conn->host.name,
- &nuser, &npasswd,
+ userp, passwdp,
+ &netrc_user_changed, &netrc_passwd_changed,
data->set.str[STRING_NETRC_FILE]);
if(ret > 0) {
infof(data, "Couldn't find host %s in the "
@@ -3051,31 +3082,11 @@ static CURLcode override_login(struct Curl_easy *data,
conn->bits.netrc = TRUE;
conn->bits.user_passwd = TRUE; /* enable user+password */
- if(data->set.use_netrc == CURL_NETRC_OPTIONAL) {
- /* prefer credentials outside netrc */
- if(nuser && !*userp) {
- free(*userp);
- *userp = nuser;
- user_changed = TRUE;
- }
- if(npasswd && !*passwdp) {
- free(*passwdp);
- *passwdp = npasswd;
- passwd_changed = TRUE;
- }
+ if(netrc_user_changed) {
+ user_changed = TRUE;
}
- else {
- /* prefer netrc credentials */
- if(nuser) {
- free(*userp);
- *userp = nuser;
- user_changed = TRUE;
- }
- if(npasswd) {
- free(*passwdp);
- *passwdp = npasswd;
- passwd_changed = TRUE;
- }
+ if(netrc_passwd_changed) {
+ passwd_changed = TRUE;
}
}
}
@@ -3369,7 +3380,7 @@ static CURLcode resolve_server(struct Curl_easy *data,
*************************************************************/
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
+ idnconvert_hostname() was called already in create_conn() for the re-use
case. */
*async = FALSE;
@@ -3424,7 +3435,10 @@ static CURLcode resolve_server(struct Curl_easy *data,
conn->port = conn->remote_port;
/* Resolve target host right on */
- rc = Curl_resolv_timeout(conn, connhost->name, (int)conn->port,
+ conn->hostname_resolve = strdup(connhost->name);
+ if(!conn->hostname_resolve)
+ return CURLE_OUT_OF_MEMORY;
+ rc = Curl_resolv_timeout(conn, conn->hostname_resolve, (int)conn->port,
&hostaddr, timeout_ms);
if(rc == CURLRESOLV_PENDING)
*async = TRUE;
@@ -3445,7 +3459,10 @@ static CURLcode resolve_server(struct Curl_easy *data,
&conn->socks_proxy.host : &conn->http_proxy.host;
/* resolve proxy */
- rc = Curl_resolv_timeout(conn, host->name, (int)conn->port,
+ conn->hostname_resolve = strdup(host->name);
+ if(!conn->hostname_resolve)
+ return CURLE_OUT_OF_MEMORY;
+ rc = Curl_resolv_timeout(conn, conn->hostname_resolve, (int)conn->port,
&hostaddr, timeout_ms);
if(rc == CURLRESOLV_PENDING)
@@ -3475,8 +3492,8 @@ static CURLcode resolve_server(struct Curl_easy *data,
static void reuse_conn(struct connectdata *old_conn,
struct connectdata *conn)
{
- free_fixed_hostname(&old_conn->http_proxy.host);
- free_fixed_hostname(&old_conn->socks_proxy.host);
+ free_idnconverted_hostname(&old_conn->http_proxy.host);
+ free_idnconverted_hostname(&old_conn->socks_proxy.host);
free(old_conn->http_proxy.host.rawalloc);
free(old_conn->socks_proxy.host.rawalloc);
@@ -3520,14 +3537,18 @@ static void reuse_conn(struct connectdata *old_conn,
/* 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);
+ free_idnconverted_hostname(&conn->host);
+ free_idnconverted_hostname(&conn->conn_to_host);
Curl_safefree(conn->host.rawalloc);
Curl_safefree(conn->conn_to_host.rawalloc);
conn->host = old_conn->host;
conn->conn_to_host = old_conn->conn_to_host;
conn->conn_to_port = old_conn->conn_to_port;
conn->remote_port = old_conn->remote_port;
+ Curl_safefree(conn->hostname_resolve);
+
+ conn->hostname_resolve = old_conn->hostname_resolve;
+ old_conn->hostname_resolve = NULL;
/* persist connection info in session handle */
Curl_persistconninfo(conn);
@@ -3677,30 +3698,30 @@ static CURLcode create_conn(struct Curl_easy *data,
goto out;
/*************************************************************
- * IDN-fix the hostnames
+ * IDN-convert the hostnames
*************************************************************/
- result = fix_hostname(conn, &conn->host);
+ result = idnconvert_hostname(conn, &conn->host);
if(result)
goto out;
if(conn->bits.conn_to_host) {
- result = fix_hostname(conn, &conn->conn_to_host);
+ result = idnconvert_hostname(conn, &conn->conn_to_host);
if(result)
goto out;
}
if(conn->bits.httpproxy) {
- result = fix_hostname(conn, &conn->http_proxy.host);
+ result = idnconvert_hostname(conn, &conn->http_proxy.host);
if(result)
goto out;
}
if(conn->bits.socksproxy) {
- result = fix_hostname(conn, &conn->socks_proxy.host);
+ result = idnconvert_hostname(conn, &conn->socks_proxy.host);
if(result)
goto out;
}
/*************************************************************
* Check whether the host and the "connect to host" are equal.
- * Do this after the hostnames have been IDN-fixed.
+ * Do this after the hostnames have been IDN-converted.
*************************************************************/
if(conn->bits.conn_to_host &&
strcasecompare(conn->conn_to_host.name, conn->host.name)) {
@@ -4028,6 +4049,15 @@ static CURLcode create_conn(struct Curl_easy *data,
*************************************************************/
result = resolve_server(data, conn, async);
+ /* Strip trailing dots. resolve_server copied the name. */
+ strip_trailing_dot(&conn->host);
+ if(conn->bits.httpproxy)
+ strip_trailing_dot(&conn->http_proxy.host);
+ if(conn->bits.socksproxy)
+ strip_trailing_dot(&conn->socks_proxy.host);
+ if(conn->bits.conn_to_host)
+ strip_trailing_dot(&conn->conn_to_host);
+
out:
return result;
}