From 4b9f8e766d0c4d989b0188a6dfd3c667e49a93a9 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 27 Apr 2004 13:56:23 +0000 Subject: [PATCH] Made host name and proxy name get stored in a 'struct hostname' and set all things up to work with encoded host names internally, as well as keeping 'display names' to show in debug messages. IDN resolves work for me now using ipv6, ipv4 and ares resolving. Even cookies on IDN sites seem to do right. --- lib/connect.c | 4 +- lib/ftp.c | 6 +- lib/hostares.c | 4 +- lib/hostthre.c | 4 +- lib/http.c | 9 +- lib/http_negotiate.c | 4 +- lib/ldap.c | 4 +- lib/ssluse.c | 22 ++-- lib/transfer.c | 2 +- lib/url.c | 255 +++++++++++++++++++++++-------------------- lib/urldata.h | 23 ++-- 11 files changed, 180 insertions(+), 157 deletions(-) diff --git a/lib/connect.c b/lib/connect.c index e55464cdf..c7dee3ce2 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -479,7 +479,7 @@ CURLcode Curl_is_connected(struct connectdata *conn, else if(1 != rc) { int error = Curl_ourerrno(); failf(data, "Failed connect to %s:%d; %s", - conn->hostname, conn->port, Curl_strerror(conn,error)); + conn->host.name, conn->port, Curl_strerror(conn,error)); return CURLE_COULDNT_CONNECT; } /* @@ -576,7 +576,7 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */ } } - hostname = data->change.proxy?conn->proxyhost:conn->hostname; + hostname = data->change.proxy?conn->proxy.name:conn->host.name; infof(data, "About to connect() to %s port %d\n", hostname, port); diff --git a/lib/ftp.c b/lib/ftp.c index 6333bb422..17632044b 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -489,7 +489,7 @@ CURLcode Curl_ftp_connect(struct connectdata *conn) if (data->set.tunnel_thru_httpproxy) { /* We want "seamless" FTP operations through HTTP proxy tunnel */ result = Curl_ConnectHTTPProxyTunnel(conn, FIRSTSOCKET, - conn->hostname, conn->remote_port); + conn->host.name, conn->remote_port); if(CURLE_OK != result) return result; } @@ -1619,7 +1619,7 @@ CURLcode ftp_use_pasv(struct connectdata *conn, newport = num; /* we should use the same host we already are connected to */ - newhostp = conn->hostname; + newhostp = conn->host.name; } } else @@ -1641,7 +1641,7 @@ CURLcode ftp_use_pasv(struct connectdata *conn, * We don't want to rely on a former host lookup that might've expired * now, instead we remake the lookup here and now! */ - rc = Curl_resolv(conn, conn->proxyhost, conn->port, &addr); + rc = Curl_resolv(conn, conn->proxy.name, conn->port, &addr); if(rc == CURLRESOLV_PENDING) rc = Curl_wait_for_resolv(conn, &addr); diff --git a/lib/hostares.c b/lib/hostares.c index d2ea98ea0..35640d5b7 100644 --- a/lib/hostares.c +++ b/lib/hostares.c @@ -233,11 +233,11 @@ CURLcode Curl_wait_for_resolv(struct connectdata *conn, if(!conn->async.dns) { /* a name was not resolved */ if((timeout < 0) || (conn->async.status == ARES_ETIMEOUT)) { - failf(data, "Resolving host timed out: %s", conn->hostname); + failf(data, "Resolving host timed out: %s", conn->host.name); rc = CURLE_OPERATION_TIMEDOUT; } else if(conn->async.done) { - failf(data, "Could not resolve host: %s (%s)", conn->hostname, + failf(data, "Could not resolve host: %s (%s)", conn->host.name, ares_strerror(conn->async.status)); rc = CURLE_COULDNT_RESOLVE_HOST; } diff --git a/lib/hostthre.c b/lib/hostthre.c index 6f2182e03..b6c04c1af 100644 --- a/lib/hostthre.c +++ b/lib/hostthre.c @@ -375,12 +375,12 @@ CURLcode Curl_wait_for_resolv(struct connectdata *conn, if (!conn->async.dns) { /* a name was not resolved */ if (td->thread_status == (DWORD)-1 || conn->async.status == NO_DATA) { - failf(data, "Resolving host timed out: %s", conn->hostname); + failf(data, "Resolving host timed out: %s", conn->host.name); rc = CURLE_OPERATION_TIMEDOUT; } else if(conn->async.done) { failf(data, "Could not resolve host: %s; %s", - conn->hostname, Curl_strerror(conn,conn->async.status)); + conn->host.name, Curl_strerror(conn,conn->async.status)); rc = CURLE_COULDNT_RESOLVE_HOST; } else diff --git a/lib/http.c b/lib/http.c index 4cc813e98..4c517eb0e 100644 --- a/lib/http.c +++ b/lib/http.c @@ -253,7 +253,7 @@ static CURLcode http_auth_headers(struct connectdata *conn, host due to a location-follow, we do some weirdo checks here */ if(!data->state.this_is_a_follow || !data->state.auth_host || - curl_strequal(data->state.auth_host, TRUE_HOSTNAME(conn)) || + curl_strequal(data->state.auth_host, conn->host.name) || data->set.http_disable_hostname_check_before_authentication) { /* Send proxy authentication header if needed */ @@ -1113,7 +1113,8 @@ CURLcode Curl_http_connect(struct connectdata *conn) /* either HTTPS over proxy, OR explicitly asked for a tunnel */ result = Curl_ConnectHTTPProxyTunnel(conn, FIRSTSOCKET, - TRUE_HOSTNAME(conn), conn->remote_port); + conn->host.name, + conn->remote_port); if(CURLE_OK != result) return result; } @@ -1132,7 +1133,7 @@ CURLcode Curl_http_connect(struct connectdata *conn) /* Free to avoid leaking memory on multiple requests*/ free(data->state.auth_host); - data->state.auth_host = strdup(TRUE_HOSTNAME(conn)); + data->state.auth_host = strdup(conn->host.name); } return CURLE_OK; @@ -1219,7 +1220,7 @@ CURLcode Curl_http(struct connectdata *conn) struct HTTP *http; struct Cookie *co=NULL; /* no cookies from start */ char *ppath = conn->path; - char *host = TRUE_HOSTNAME(conn); + char *host = conn->host.name; const char *te = ""; /* tranfer-encoding */ char *ptr; char *request; diff --git a/lib/http_negotiate.c b/lib/http_negotiate.c index 2dc09eed3..df0d6ab84 100644 --- a/lib/http_negotiate.c +++ b/lib/http_negotiate.c @@ -71,10 +71,10 @@ get_gss_name(struct connectdata *conn, gss_name_t *server) else service = "http"; - token.length = strlen(service) + 1 + strlen(conn->hostname) + 1; + token.length = strlen(service) + 1 + strlen(conn->host.name) + 1; if (token.length + 1 > sizeof(name)) return EMSGSIZE; - sprintf(name, "%s@%s", service, conn->hostname); + sprintf(name, "%s@%s", service, conn->host.name); token.value = (void *) name; major_status = gss_import_name(&minor_status, diff --git a/lib/ldap.c b/lib/ldap.c index cb2ba0101..6e755f44e 100644 --- a/lib/ldap.c +++ b/lib/ldap.c @@ -196,10 +196,10 @@ CURLcode Curl_ldap(struct connectdata *conn) DYNA_GET_FUNCTION(void (*)(void *), ldap_memfree); DYNA_GET_FUNCTION(void (*)(void *, int), ber_free); - server = ldap_init(conn->hostname, conn->port); + server = ldap_init(conn->host.name, conn->port); if (server == NULL) { failf(data, "LDAP: Cannot connect to %s:%d", - conn->hostname, conn->port); + conn->host.name, conn->port); status = CURLE_COULDNT_CONNECT; } else { diff --git a/lib/ssluse.c b/lib/ssluse.c index 55888c08b..fa8a9fc80 100644 --- a/lib/ssluse.c +++ b/lib/ssluse.c @@ -544,7 +544,7 @@ static int Get_SSL_Session(struct connectdata *conn, if(!check->sessionid) /* not session ID means blank entry */ continue; - if(curl_strequal(conn->hostname, check->name) && + if(curl_strequal(conn->host.name, check->name) && (conn->remote_port == check->remote_port) && Curl_ssl_config_matches(&conn->ssl_config, &check->ssl_config)) { /* yes, we have a session ID! */ @@ -662,7 +662,7 @@ static int Store_SSL_Session(struct connectdata *conn, /* now init the session struct wisely */ store->sessionid = ssl_sessionid; store->age = data->state.sessionage; /* set current age */ - store->name = strdup(conn->hostname); /* clone host name */ + store->name = strdup(conn->host.name); /* clone host name */ store->remote_port = conn->remote_port; /* port number */ Curl_clone_ssl_config(&conn->ssl_config, &store->ssl_config); @@ -796,13 +796,13 @@ static CURLcode verifyhost(struct connectdata *conn, #ifdef ENABLE_IPV6 if(conn->bits.ipv6_ip && - Curl_inet_pton(AF_INET6, conn->hostname, &addr)) { + Curl_inet_pton(AF_INET6, conn->host.name, &addr)) { target = GEN_IPADD; addrlen = sizeof(struct in6_addr); } else #endif - if(Curl_inet_pton(AF_INET, conn->hostname, &addr)) { + if(Curl_inet_pton(AF_INET, conn->host.name, &addr)) { target = GEN_IPADD; addrlen = sizeof(struct in_addr); } @@ -818,8 +818,8 @@ static CURLcode verifyhost(struct connectdata *conn, int i; if(GEN_DNS == target) { - hostlen = (int)strlen(conn->hostname); - domain = strchr(conn->hostname, '.'); + hostlen = (int)strlen(conn->host.name); + domain = strchr(conn->host.name, '.'); if(domain) domainlen = (int)strlen(domain); } @@ -843,7 +843,7 @@ static CURLcode verifyhost(struct connectdata *conn, case GEN_DNS: /* name comparison */ /* Is this an exact match? */ if((hostlen == altlen) && - curl_strnequal(conn->hostname, altptr, hostlen)) + curl_strnequal(conn->host.name, altptr, hostlen)) matched = TRUE; /* Is this a wildcard match? */ @@ -867,7 +867,7 @@ static CURLcode verifyhost(struct connectdata *conn, if(matched) /* an alternative name matched the server hostname */ - infof(data, "\t subjectAltName: %s matched\n", conn->hostname); + infof(data, "\t subjectAltName: %s matched\n", conn->host.name); else { bool obtain=FALSE; if(X509_NAME_get_text_by_NID(X509_get_subject_name(server_cert), @@ -889,15 +889,15 @@ static CURLcode verifyhost(struct connectdata *conn, obtain = TRUE; if(obtain) { - if(!cert_hostcheck(peer_CN, conn->hostname)) { + if(!cert_hostcheck(peer_CN, conn->host.name)) { if(data->set.ssl.verifyhost > 1) { failf(data, "SSL: certificate subject name '%s' does not match " - "target host name '%s'", peer_CN, conn->hostname); + "target host name '%s'", peer_CN, conn->host.name); return CURLE_SSL_PEER_CERTIFICATE; } else infof(data, "\t common name: %s (does not match '%s')\n", - peer_CN, conn->hostname); + peer_CN, conn->host.name); } else infof(data, "\t common name: %s (matched)\n", peer_CN); diff --git a/lib/transfer.c b/lib/transfer.c index c46ed3061..3df1f1fd0 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -805,7 +805,7 @@ CURLcode Curl_readwrite(struct connectdata *conn, /* If there is a custom-set Host: name, use it here, or else use real peer host name. */ conn->allocptr.cookiehost? - conn->allocptr.cookiehost:conn->hostname, + conn->allocptr.cookiehost:conn->host.name, conn->path); Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); } diff --git a/lib/url.c b/lib/url.c index 695d374bf..38beb89a2 100644 --- a/lib/url.c +++ b/lib/url.c @@ -149,10 +149,6 @@ static unsigned int ConnectionStore(struct SessionHandle *data, struct connectdata *conn); static bool safe_strequal(char* str1, char* str2); -#ifdef USE_LIBIDN -static bool is_ASCII_name(const char *hostname); -#endif - #ifndef USE_ARES /* not for Win32, unless it is cygwin not for ares builds */ @@ -1369,10 +1365,17 @@ CURLcode Curl_disconnect(struct connectdata *conn) Curl_safefree(conn->proto.generic); Curl_safefree(conn->newurl); Curl_safefree(conn->pathbuffer); /* the URL path buffer */ - Curl_safefree(conn->namebuffer); /* the URL host name buffer */ -#ifdef USE_LIBIDN - Curl_safefree(conn->ace_hostname); -#endif + + Curl_safefree(conn->host.rawalloc); /* host name buffer */ + Curl_safefree(conn->proxy.rawalloc); /* proxy name buffer */ + if(conn->host.encalloc) + (free)(conn->host.encalloc); /* encoded host name buffer, must be freed + with free() since this was allocated by + libidn */ + if(conn->proxy.encalloc) + (free)(conn->proxy.encalloc); /* encoded proxy name buffer, must be freed + with free() since this was allocated by + libidn */ Curl_SSL_Close(conn); /* close possibly still open sockets */ @@ -1394,7 +1397,7 @@ CURLcode Curl_disconnect(struct connectdata *conn) Curl_safefree(conn->allocptr.cookie); Curl_safefree(conn->allocptr.host); Curl_safefree(conn->allocptr.cookiehost); - Curl_safefree(conn->proxyhost); + #if defined(USE_ARES) || defined(USE_THREADING_GETHOSTBYNAME) || \ defined(USE_THREADING_GETADDRINFO) /* possible left-overs from the async name resolve */ @@ -1473,7 +1476,7 @@ ConnectionExists(struct SessionHandle *data, continue; if(strequal(needle->protostr, check->protostr) && - strequal(TRUE_HOSTNAME(needle), TRUE_HOSTNAME(check)) && + strequal(needle->host.name, check->host.name) && (needle->remote_port == check->remote_port) ) { if(needle->protocol & PROT_SSL) { /* This is SSL, verify that we're using the same @@ -1500,7 +1503,7 @@ ConnectionExists(struct SessionHandle *data, else { /* The requested needle connection is using a proxy, is the checked one using the same? */ if(check->bits.httpproxy && - strequal(needle->proxyhost, check->proxyhost) && + strequal(needle->proxy.name, check->proxy.name) && needle->port == check->port) { /* This is the same proxy connection, use it! */ match = TRUE; @@ -1763,7 +1766,7 @@ static int handleSock5Proxy(const char *proxy_name, #ifndef ENABLE_IPV6 struct Curl_dns_entry *dns; Curl_addrinfo *hp=NULL; - int rc = Curl_resolv(conn, TRUE_HOSTNAME(conn), conn->remote_port, &dns); + int rc = Curl_resolv(conn, conn->host.name, conn->remote_port, &dns); if(rc == CURLRESOLV_ERROR) return 1; @@ -1788,7 +1791,7 @@ static int handleSock5Proxy(const char *proxy_name, } else { failf(conn->data, "Failed to resolve \"%s\" for SOCKS5 connect.", - conn->hostname); + conn->host.name); return 1; } #else @@ -1906,7 +1909,7 @@ static void verboseconnect(struct connectdata *conn) host = Curl_inet_ntop(AF_INET, &in, addrbuf, sizeof(addrbuf)); #endif infof(data, "Connected to %s (%s) port %d\n", - conn->bits.httpproxy?conn->proxyhost:conn->hostname, + conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname, host?host:"", conn->port); } @@ -1950,6 +1953,50 @@ CURLcode Curl_protocol_connect(struct connectdata *conn) return result; /* pass back status */ } +/* + * Helpers for IDNA convertions. + */ +#ifdef USE_LIBIDN +static bool is_ASCII_name (const char *hostname) +{ + const unsigned char *ch = (const unsigned char*)hostname; + + while (*ch) { + if (*ch++ & 0x80) + return FALSE; + } + return TRUE; +} +#endif + +static void fix_hostname(struct connectdata *conn, struct hostname *host) +{ + /* set the name we use to display the host name */ + conn->host.dispname = conn->host.name; + +#ifdef USE_LIBIDN + /************************************************************* + * Check name for non-ASCII and convert hostname to ACE form. + *************************************************************/ + if (!is_ASCII_name(host->name)) { + char *ace_hostname = NULL; + struct SessionHandle *data = conn->data; + int rc = idna_to_ascii_lz(host->name, &ace_hostname, 0); + infof (data, "Input domain encoded as `%s'\n", + stringprep_locale_charset ()); + if (rc != IDNA_SUCCESS) + infof(data, "Failed to convert %s to ACE; IDNA error %d\n", + host->name, rc); + else { + host->encalloc = ace_hostname; + /* change the name pointer to point to the encoded hostname */ + host->name = host->encalloc; + } + } +#endif +} + + /** * CreateConnection() sets up a new connectdata struct, or re-uses an already * existing one, and resolves host name. @@ -2075,10 +2122,10 @@ static CURLcode CreateConnection(struct SessionHandle *data, return CURLE_OUT_OF_MEMORY; /* really bad error */ conn->path = conn->pathbuffer; - conn->namebuffer=(char *)malloc(urllen); - if(NULL == conn->namebuffer) + conn->host.rawalloc=(char *)malloc(urllen); + if(NULL == conn->host.rawalloc) return CURLE_OUT_OF_MEMORY; - conn->hostname = conn->namebuffer; + conn->host.name = conn->host.rawalloc; /************************************************************* * Parse the URL. @@ -2139,9 +2186,9 @@ static CURLcode CreateConnection(struct SessionHandle *data, strcpy(conn->protostr, "file"); /* store protocol string lowercase */ } else { - /* Set default host and default path */ - strcpy(conn->namebuffer, "curl.haxx.se"); + /* Set default path */ strcpy(conn->path, "/"); + /* We need to search for '/' OR '?' - whichever comes first after host * name but before the path. We need to change that to handle things like * http://example.com?param= (notice the missing '/'). Later we'll insert @@ -2150,14 +2197,14 @@ static CURLcode CreateConnection(struct SessionHandle *data, if (2 > sscanf(data->change.url, "%64[^\n:]://%[^\n/?]%[^\n]", conn->protostr, - conn->namebuffer, conn->path)) { + conn->host.name, conn->path)) { /* * The URL was badly formatted, let's try the browser-style _without_ * protocol specified like 'http://'. */ if((1 > sscanf(data->change.url, "%[^\n/?]%[^\n]", - conn->namebuffer, conn->path)) ) { + conn->host.name, conn->path)) ) { /* * We couldn't even get this format. */ @@ -2173,21 +2220,21 @@ static CURLcode CreateConnection(struct SessionHandle *data, /* Note: if you add a new protocol, please update the list in * lib/version.c too! */ - if(checkprefix("GOPHER", conn->namebuffer)) + if(checkprefix("GOPHER", conn->host.name)) strcpy(conn->protostr, "gopher"); #ifdef USE_SSLEAY - else if(checkprefix("HTTPS", conn->namebuffer)) + else if(checkprefix("HTTPS", conn->host.name)) strcpy(conn->protostr, "https"); - else if(checkprefix("FTPS", conn->namebuffer)) + else if(checkprefix("FTPS", conn->host.name)) strcpy(conn->protostr, "ftps"); #endif /* USE_SSLEAY */ - else if(checkprefix("FTP", conn->namebuffer)) + else if(checkprefix("FTP", conn->host.name)) strcpy(conn->protostr, "ftp"); - else if(checkprefix("TELNET", conn->namebuffer)) + else if(checkprefix("TELNET", conn->host.name)) strcpy(conn->protostr, "telnet"); - else if (checkprefix("DICT", conn->namebuffer)) + else if (checkprefix("DICT", conn->host.name)) strcpy(conn->protostr, "DICT"); - else if (checkprefix("LDAP", conn->namebuffer)) + else if (checkprefix("LDAP", conn->host.name)) strcpy(conn->protostr, "LDAP"); else { strcpy(conn->protostr, "http"); @@ -2212,7 +2259,7 @@ static CURLcode CreateConnection(struct SessionHandle *data, /* * So if the URL was A://B/C, * conn->protostr is A - * conn->namebuffer is B + * conn->host.name is B * conn->path is /C */ @@ -2275,15 +2322,15 @@ static CURLcode CreateConnection(struct SessionHandle *data, nope=no_proxy?strtok_r(no_proxy, ", ", &no_proxy_tok_buf):NULL; while(nope) { unsigned int namelen; - char *endptr = strchr(conn->hostname, ':'); + char *endptr = strchr(conn->host.name, ':'); if(endptr) - namelen=endptr-conn->hostname; + namelen=endptr-conn->host.name; else - namelen=strlen(conn->hostname); + namelen=strlen(conn->host.name); if(strlen(nope) <= namelen) { char *checkn= - conn->hostname + namelen - strlen(nope); + conn->host.name + namelen - strlen(nope); if(checkprefix(nope, checkn)) { /* no proxy for this host! */ break; @@ -2546,7 +2593,7 @@ static CURLcode CreateConnection(struct SessionHandle *data, * we'll try to get now! */ type=strstr(conn->path, ";type="); if(!type) { - type=strstr(conn->namebuffer, ";type="); + type=strstr(conn->host.rawalloc, ";type="); } if(type) { char command; @@ -2655,23 +2702,23 @@ static CURLcode CreateConnection(struct SessionHandle *data, * To be able to detect port number flawlessly, we must not confuse them * IPv6-specified addresses in the [0::1] style. (RFC2732) * - * The conn->hostname is currently [user:passwd@]host[:port] where host + * The conn->host.name is currently [user:passwd@]host[:port] where host * could be a hostname, IPv4 address or IPv6 address. *************************************************************/ - if((1 == sscanf(conn->hostname, "[%*39[0-9a-fA-F:.]%c", &endbracket)) && + if((1 == sscanf(conn->host.name, "[%*39[0-9a-fA-F:.]%c", &endbracket)) && (']' == endbracket)) { /* this is a RFC2732-style specified IP-address */ conn->bits.ipv6_ip = TRUE; - conn->hostname++; /* pass the starting bracket */ - tmp = strchr(conn->hostname, ']'); + conn->host.name++; /* pass the starting bracket */ + tmp = strchr(conn->host.name, ']'); *tmp = 0; /* zero terminate */ tmp++; /* pass the ending bracket */ if(':' != *tmp) tmp = NULL; /* no port number available */ } else - tmp = strrchr(conn->hostname, ':'); + tmp = strrchr(conn->host.name, ':'); if (tmp) { char *rest; @@ -2740,7 +2787,8 @@ static CURLcode CreateConnection(struct SessionHandle *data, } /* now, clone the cleaned proxy host name */ - conn->proxyhost = strdup(proxyptr); + conn->proxy.rawalloc = strdup(proxyptr); + conn->proxy.name = conn->proxy.rawalloc; free(proxydup); /* free the duplicate pointer and not the modified */ } @@ -2753,7 +2801,7 @@ static CURLcode CreateConnection(struct SessionHandle *data, * Inputs: data->set.userpwd (CURLOPT_USERPWD) * data->set.fpasswd (CURLOPT_PASSWDFUNCTION) * data->set.use_netrc (CURLOPT_NETRC) - * conn->hostname + * conn->host.name * netrc file * hard-coded defaults * @@ -2761,11 +2809,11 @@ static CURLcode CreateConnection(struct SessionHandle *data, * conn->bits.user_passwd - non-zero if non-default passwords exist * conn->user - non-zero length if defined * conn->passwd - ditto - * conn->hostname - remove user name and password + * conn->host.name - remove user name and password */ /* At this point, we're hoping all the other special cases have - * been taken care of, so conn->hostname is at most + * been taken care of, so conn->host.name is at most * [user[:password]]@]hostname * * We need somewhere to put the embedded details, so do that first. @@ -2778,12 +2826,12 @@ static CURLcode CreateConnection(struct SessionHandle *data, /* This is a FTP or HTTP URL, we will now try to extract the possible * user+password pair in a string like: * ftp://user:password@ftp.my.site:8021/README */ - char *ptr=strchr(conn->hostname, '@'); - char *userpass = conn->hostname; + char *ptr=strchr(conn->host.name, '@'); + char *userpass = conn->host.name; if(ptr != NULL) { /* there's a user+password given here, to the left of the @ */ - conn->hostname = ++ptr; + conn->host.name = ++ptr; /* So the hostname is sane. Only bother interpreting the * results if we could care. It could still be wasted @@ -2844,11 +2892,11 @@ static CURLcode CreateConnection(struct SessionHandle *data, } if (data->set.use_netrc != CURL_NETRC_IGNORED) { - if(Curl_parsenetrc(conn->hostname, + if(Curl_parsenetrc(conn->host.name, user, passwd, data->set.netrc_file)) { infof(data, "Couldn't find host %s in the .netrc file, using defaults\n", - conn->hostname); + conn->host.name); } else conn->bits.user_passwd = 1; /* enable user+password */ @@ -2898,8 +2946,8 @@ static CURLcode CreateConnection(struct SessionHandle *data, */ struct connectdata *old_conn = conn; - if(old_conn->proxyhost) - free(old_conn->proxyhost); + if(old_conn->proxy.rawalloc) + free(old_conn->proxy.rawalloc); /* free the SSL config struct from this connection struct as this was allocated in vain and is targeted for destruction */ @@ -2915,13 +2963,12 @@ static CURLcode CreateConnection(struct SessionHandle *data, /* get the newly set value, not the old one */ conn->bits.no_body = old_conn->bits.no_body; - free(conn->namebuffer); /* free the newly allocated name buffer */ - conn->namebuffer = old_conn->namebuffer; /* use the old one */ - conn->hostname = old_conn->hostname; -#ifdef USE_LIBIDN - Curl_safefree(conn->ace_hostname); - conn->ace_hostname = old_conn->ace_hostname; -#endif + free(conn->host.rawalloc); /* free the newly allocated name buffer */ + conn->host.rawalloc = old_conn->host.rawalloc; /* use the old one */ + conn->host.name = old_conn->host.name; + + conn->host.encalloc = old_conn->host.encalloc; /* use the old one */ + conn->host.dispname = old_conn->host.dispname; free(conn->pathbuffer); /* free the newly allocated path pointer */ conn->pathbuffer = old_conn->pathbuffer; /* use the old one */ @@ -3056,35 +3103,45 @@ static CURLcode CreateConnection(struct SessionHandle *data, conn->connect_addr = NULL; /* we don't connect now so we don't have any fresh connect_addr struct to point to */ } - else if(!data->change.proxy || !*data->change.proxy) { - /* 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. */ - conn->port = conn->remote_port; /* it is the same port */ - - /* Resolve target host right on */ - rc = Curl_resolv(conn, TRUE_HOSTNAME(conn), conn->port, &hostaddr); - if(rc == CURLRESOLV_PENDING) - *async = TRUE; - - else if(!hostaddr) { - failf(data, "Couldn't resolve host '%s'", conn->hostname); - 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. */ + /* this is a fresh connect */ - /* resolve proxy */ - rc = Curl_resolv(conn, conn->proxyhost, conn->port, &hostaddr); + /* set a pointer to the hostname we display */ + fix_hostname(conn, &conn->host); - if(rc == CURLRESOLV_PENDING) - *async = TRUE; + if(!data->change.proxy || !*data->change.proxy) { + /* 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. */ + conn->port = conn->remote_port; /* it is the same port */ - else if(!hostaddr) { - failf(data, "Couldn't resolve proxy '%s'", conn->proxyhost); - result = CURLE_COULDNT_RESOLVE_PROXY; - /* don't return yet, we need to clean up the timeout first */ + /* Resolve target host right on */ + rc = Curl_resolv(conn, conn->host.name, conn->port, &hostaddr); + if(rc == CURLRESOLV_PENDING) + *async = TRUE; + + else if(!hostaddr) { + failf(data, "Couldn't resolve host '%s'", conn->host.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. */ + + /* IDN check */ + fix_hostname(conn, &conn->proxy); + + /* resolve proxy */ + rc = Curl_resolv(conn, conn->proxy.name, conn->port, &hostaddr); + + if(rc == CURLRESOLV_PENDING) + *async = TRUE; + + 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 */ + } } } *addr = hostaddr; @@ -3150,25 +3207,6 @@ static CURLcode SetupConnection(struct connectdata *conn, a file:// transfer */ return result; -#ifdef USE_LIBIDN - /************************************************************* - * Check name for non-ASCII and convert hostname to ACE form. - *************************************************************/ - - if(!conn->bits.reuse && conn->remote_port) { - const char *host = conn->hostname; - char *ace_hostname; - - if (!is_ASCII_name(host)) { - int rc = idna_to_ascii_lz (host, &ace_hostname, 0); - if (rc == IDNA_SUCCESS) - conn->ace_hostname = ace_hostname; - else - infof(data, "Failed to convert %s to ACE; IDNA error %d\n", host, rc); - } - } -#endif - /************************************************************* * Send user-agent to HTTP proxies even if the target protocol * isn't HTTP. @@ -3502,18 +3540,3 @@ void Curl_free_ssl_config(struct ssl_config_data* sslc) free(sslc->random_file); } -/* - * Helpers for IDNA convertions. - */ -#ifdef USE_LIBIDN -static bool is_ASCII_name (const char *hostname) -{ - const unsigned char *ch = (const unsigned char*)hostname; - - while (*ch) { - if (*ch++ > 0x80) - return FALSE; - } - return TRUE; -} -#endif diff --git a/lib/urldata.h b/lib/urldata.h index 1912bcf0f..19e83ca4f 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -304,6 +304,13 @@ struct ConnectBits { bool no_body; /* CURLOPT_NO_BODY (or similar) was set */ }; +struct hostname { + char *rawalloc; /* allocated "raw" version of the name */ + char *encalloc; /* allocated IDN-encoded version of the name */ + char *name; /* name to use internally, might be encoded, might be raw */ + char *dispname; /* name to display, as 'name' might be encoded */ +}; + /* * This struct is all the previously local variables from Curl_perform() moved * to struct to allow the function to return and get re-invoked better without @@ -428,16 +435,10 @@ struct connectdata { struct sockaddr_in serv_addr; #endif char protostr[64]; /* store the protocol string in this buffer */ - char *namebuffer; /* allocated buffer to store the hostname in */ - char *hostname; /* hostname to use, as parsed from url. points to - somewhere within the namebuffer[] area */ -#ifdef USE_LIBIDN - char *ace_hostname; /* hostname possibly converted to ACE form */ -#define TRUE_HOSTNAME(conn) \ - (conn->ace_hostname ? conn->ace_hostname : conn->hostname) -#else -#define TRUE_HOSTNAME(conn) conn->hostname -#endif + + struct hostname host; + struct hostname proxy; + char *pathbuffer;/* allocated buffer to store the URL's path part in */ char *path; /* path to use, points to somewhere within the pathbuffer area */ @@ -456,8 +457,6 @@ struct connectdata { this syntax. */ curl_off_t resume_from; /* continue [ftp] transfer from here */ - char *proxyhost; /* name of the http proxy host */ - char *user; /* user name string, allocated */ char *passwd; /* password string, allocated */