summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2022-12-26 10:58:37 +0100
committerDaniel Stenberg <daniel@haxx.se>2022-12-26 23:29:23 +0100
commit901392cbb7939f43b7e7ed2b39135b45416a2714 (patch)
treefd74a1a6370ba56fcd76cd15cb052d352fbcb076 /lib
parentcf174810db32c362775349e9afe5543c0e9cc18b (diff)
downloadcurl-901392cbb7939f43b7e7ed2b39135b45416a2714.tar.gz
urlapi: add CURLU_PUNYCODE
Allows curl_url_get() get the punycode version of host names for the host name and URL parts. Extend test 1560 to verify. Closes #10109
Diffstat (limited to 'lib')
-rw-r--r--lib/idn.c30
-rw-r--r--lib/idn.h8
-rw-r--r--lib/strerror.c3
-rw-r--r--lib/urlapi.c28
4 files changed, 56 insertions, 13 deletions
diff --git a/lib/idn.c b/lib/idn.c
index 6255221ae..758900bdd 100644
--- a/lib/idn.c
+++ b/lib/idn.c
@@ -116,7 +116,7 @@ bool Curl_is_ASCII_name(const char *hostname)
* Curl_idn_decode() returns an allocated IDN decoded string if it was
* possible. NULL on error.
*/
-static char *Curl_idn_decode(const char *input)
+static char *idn_decode(const char *input)
{
char *decoded = NULL;
#ifdef USE_LIBIDN2
@@ -144,24 +144,29 @@ static char *Curl_idn_decode(const char *input)
return decoded;
}
+char *Curl_idn_decode(const char *input)
+{
+ char *d = idn_decode(input);
+#ifdef USE_LIBIDN2
+ if(d) {
+ char *c = strdup(d);
+ idn2_free(d);
+ d = c;
+ }
+#endif
+ return d;
+}
+
/*
* Frees data allocated by idnconvert_hostname()
*/
void Curl_free_idnconverted_hostname(struct hostname *host)
{
-#if defined(USE_LIBIDN2)
if(host->encalloc) {
- idn2_free(host->encalloc); /* must be freed with idn2_free() since this was
- allocated by libidn */
+ /* must be freed with idn2_free() if allocated by libidn */
+ Curl_idn_free(host->encalloc);
host->encalloc = NULL;
}
-#elif defined(USE_WIN32_IDN)
- free(host->encalloc); /* must be freed with free() since this was
- allocated by Curl_win32_idn_to_ascii */
- host->encalloc = NULL;
-#else
- (void)host;
-#endif
}
#endif /* USE_IDN */
@@ -177,7 +182,7 @@ CURLcode Curl_idnconvert_hostname(struct hostname *host)
#ifdef USE_IDN
/* Check name for non-ASCII and convert hostname if we can */
if(!Curl_is_ASCII_name(host->name)) {
- char *decoded = Curl_idn_decode(host->name);
+ char *decoded = idn_decode(host->name);
if(decoded) {
/* successful */
host->encalloc = decoded;
@@ -190,4 +195,3 @@ CURLcode Curl_idnconvert_hostname(struct hostname *host)
#endif
return CURLE_OK;
}
-
diff --git a/lib/idn.h b/lib/idn.h
index 2d04efcdf..c7adf97e6 100644
--- a/lib/idn.h
+++ b/lib/idn.h
@@ -32,7 +32,15 @@ CURLcode Curl_idnconvert_hostname(struct hostname *host);
#if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN)
#define USE_IDN
void Curl_free_idnconverted_hostname(struct hostname *host);
+char *Curl_idn_decode(const char *input);
+#ifdef USE_LIBIDN2
+#define Curl_idn_free(x) idn2_free(x)
+#else
+#define Curl_idn_free(x) free(x)
+#endif
+
#else
#define Curl_free_idnconverted_hostname(x)
+#define Curl_idn_decode(x) NULL
#endif
#endif /* HEADER_CURL_IDN_H */
diff --git a/lib/strerror.c b/lib/strerror.c
index b9a51e26b..3d7193509 100644
--- a/lib/strerror.c
+++ b/lib/strerror.c
@@ -550,6 +550,9 @@ curl_url_strerror(CURLUcode error)
case CURLUE_BAD_USER:
return "Bad user";
+ case CURLUE_LACKS_IDN:
+ return "libcurl lacks IDN support";
+
case CURLUE_LAST:
break;
}
diff --git a/lib/urlapi.c b/lib/urlapi.c
index b96af35ad..29238c7e3 100644
--- a/lib/urlapi.c
+++ b/lib/urlapi.c
@@ -33,6 +33,7 @@
#include "inet_pton.h"
#include "inet_ntop.h"
#include "strdup.h"
+#include "idn.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -1379,6 +1380,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
char portbuf[7];
bool urldecode = (flags & CURLU_URLDECODE)?1:0;
bool urlencode = (flags & CURLU_URLENCODE)?1:0;
+ bool punycode = FALSE;
bool plusdecode = FALSE;
(void)flags;
if(!u)
@@ -1408,6 +1410,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
case CURLUPART_HOST:
ptr = u->host;
ifmissing = CURLUE_NO_HOST;
+ punycode = (flags & CURLU_PUNYCODE)?1:0;
break;
case CURLUPART_ZONEID:
ptr = u->zoneid;
@@ -1460,6 +1463,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
char *options = u->options;
char *port = u->port;
char *allochost = NULL;
+ punycode = (flags & CURLU_PUNYCODE)?1:0;
if(u->scheme && strcasecompare("file", u->scheme)) {
url = aprintf("file://%s%s%s",
u->path,
@@ -1514,6 +1518,17 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
if(!allochost)
return CURLUE_OUT_OF_MEMORY;
}
+ else if(punycode) {
+ if(!Curl_is_ASCII_name(u->host)) {
+#ifndef USE_IDN
+ return CURLUE_LACKS_IDN;
+#else
+ allochost = Curl_idn_decode(u->host);
+ if(!allochost)
+ return CURLUE_OUT_OF_MEMORY;
+#endif
+ }
+ }
else {
/* only encode '%' in output host name */
char *host = u->host;
@@ -1611,6 +1626,19 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
free(*part);
*part = Curl_dyn_ptr(&enc);
}
+ else if(punycode) {
+ if(!Curl_is_ASCII_name(u->host)) {
+#ifndef USE_IDN
+ return CURLUE_LACKS_IDN;
+#else
+ char *allochost = Curl_idn_decode(*part);
+ if(!allochost)
+ return CURLUE_OUT_OF_MEMORY;
+ free(*part);
+ *part = allochost;
+#endif
+ }
+ }
return CURLUE_OK;
}