diff options
Diffstat (limited to 'lib/url.c')
| -rw-r--r-- | lib/url.c | 160 |
1 files changed, 95 insertions, 65 deletions
@@ -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; } |
