idn: support non-UTF-8 input under AppleIDN

This aligns the behaviour with libidn2 and the curl documentation.

Closes #14431
This commit is contained in:
Bo Anderson 2024-08-07 03:14:57 +01:00 committed by Daniel Stenberg
parent 07843d8167
commit a35687831f
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
5 changed files with 57 additions and 18 deletions

View File

@ -980,7 +980,7 @@ if(APPLE)
check_symbol_exists("uidna_openUTS46" "unicode/uidna.h" HAVE_APPLE_IDN)
cmake_pop_check_state()
if(HAVE_APPLE_IDN)
list(APPEND CURL_LIBS "icucore")
list(APPEND CURL_LIBS "icucore" "iconv")
else()
set(USE_APPLE_IDN OFF)
endif()

View File

@ -2780,7 +2780,7 @@ case $host_os in
AC_DEFINE(USE_APPLE_IDN, 1, [if AppleIDN])
AC_SUBST(USE_APPLE_IDN, [1])
AC_SUBST([IDN_ENABLED], [1])
LIBS="-licucore $LIBS"
LIBS="-licucore -liconv $LIBS"
)
])
;;

View File

@ -530,7 +530,7 @@ problems may have been fixed or changed somewhat since this was written.
11.7 AppleIDN test failures
Test 1034 and 1035 fail on macOS when built to use AppleIDN.
Test 1035 fail on macOS when built to use AppleIDN.
See https://github.com/curl/curl/issues/14176

View File

@ -53,30 +53,70 @@
/* for macOS and iOS targets */
#if defined(USE_APPLE_IDN)
#include <unicode/uidna.h>
#include <iconv.h>
#include <langinfo.h>
#define MAX_HOST_LENGTH 512
static CURLcode iconv_to_utf8(const char *in, size_t inlen,
char **out, size_t *outlen)
{
iconv_t cd = iconv_open("UTF-8", nl_langinfo(CODESET));
if(cd != (iconv_t)-1) {
size_t iconv_outlen = *outlen;
char *iconv_in = (char *)in;
size_t iconv_inlen = inlen;
size_t iconv_result = iconv(cd, &iconv_in, &iconv_inlen,
out, &iconv_outlen);
*outlen -= iconv_outlen;
iconv_close(cd);
if(iconv_result == (size_t)-1) {
if(errno == ENOMEM)
return CURLE_OUT_OF_MEMORY;
else
return CURLE_URL_MALFORMAT;
}
return CURLE_OK;
}
else {
if(errno == ENOMEM)
return CURLE_OUT_OF_MEMORY;
else
return CURLE_FAILED_INIT;
}
}
static CURLcode mac_idn_to_ascii(const char *in, char **out)
{
size_t inlen = strlen(in);
if(inlen < MAX_HOST_LENGTH) {
UErrorCode err = U_ZERO_ERROR;
UIDNA* idna = uidna_openUTS46(
UIDNA_CHECK_BIDI|UIDNA_NONTRANSITIONAL_TO_ASCII, &err);
if(!U_FAILURE(err)) {
UIDNAInfo info = UIDNA_INFO_INITIALIZER;
char buffer[MAX_HOST_LENGTH] = {0};
(void)uidna_nameToASCII_UTF8(idna, in, -1, buffer,
sizeof(buffer) - 1, &info, &err);
uidna_close(idna);
char iconv_buffer[MAX_HOST_LENGTH] = {0};
char *iconv_outptr = iconv_buffer;
size_t iconv_outlen = sizeof(iconv_buffer);
CURLcode iconv_result = iconv_to_utf8(in, inlen,
&iconv_outptr, &iconv_outlen);
if(!iconv_result) {
UErrorCode err = U_ZERO_ERROR;
UIDNA* idna = uidna_openUTS46(
UIDNA_CHECK_BIDI|UIDNA_NONTRANSITIONAL_TO_ASCII, &err);
if(!U_FAILURE(err)) {
*out = strdup(buffer);
if(*out)
return CURLE_OK;
else
return CURLE_OUT_OF_MEMORY;
UIDNAInfo info = UIDNA_INFO_INITIALIZER;
char buffer[MAX_HOST_LENGTH] = {0};
(void)uidna_nameToASCII_UTF8(idna, iconv_buffer, (int)iconv_outlen,
buffer, sizeof(buffer) - 1, &info, &err);
uidna_close(idna);
if(!U_FAILURE(err)) {
*out = strdup(buffer);
if(*out)
return CURLE_OK;
else
return CURLE_OUT_OF_MEMORY;
}
}
}
else
return iconv_result;
}
return CURLE_URL_MALFORMAT;
}

View File

@ -94,7 +94,6 @@
313
%endif
%if AppleIDN
1034
1035
%endif
%if WinIDN