- uses: actions/checkout@v4
- - run: cmake -B build -DCMAKE_UNITY_BUILD=ON -DCURL_WERROR=ON ${{ matrix.build.generate }}
+ - run: cmake -B build -DCMAKE_UNITY_BUILD=ON -DCURL_WERROR=ON -DUSE_APPLE_IDN=ON ${{ matrix.build.generate }}
name: 'cmake generate'
- run: cmake --build build --parallel 3
endif()
endif()
+if(APPLE)
+ option(USE_APPLE_IDN "Use Apple built-in IDN support" OFF)
+ if(USE_APPLE_IDN)
+ cmake_push_check_state()
+ set(CMAKE_REQUIRED_LIBRARIES "icucore")
+ check_symbol_exists("uidna_openUTS46" "unicode/uidna.h" HAVE_APPLE_IDN)
+ cmake_pop_check_state()
+ if(HAVE_APPLE_IDN)
+ list(APPEND CURL_LIBS "icucore")
+ else()
+ set(USE_APPLE_IDN OFF)
+ endif()
+ endif()
+endif()
+
#libpsl
option(CURL_USE_LIBPSL "Use libPSL" ON)
mark_as_advanced(CURL_USE_LIBPSL)
_add_if("brotli" HAVE_BROTLI)
_add_if("zstd" HAVE_ZSTD)
_add_if("AsynchDNS" USE_ARES OR USE_THREADS_POSIX OR USE_THREADS_WIN32)
- _add_if("IDN" HAVE_LIBIDN2 OR USE_WIN32_IDN)
+ _add_if("IDN" HAVE_LIBIDN2 OR USE_WIN32_IDN OR USE_APPLE_IDN)
_add_if("Largefile" (SIZEOF_CURL_OFF_T GREATER 4) AND
((SIZEOF_OFF_T GREATER 4) OR USE_WIN32_LARGE_FILES))
_add_if("SSPI" USE_WINDOWS_SSPI)
1.3 struct lifreq
1.4 Better and more sharing
1.5 get rid of PATH_MAX
- 1.6 native IDN support on macOS
1.8 CURLOPT_RESOLVE for any port number
1.9 Cache negative name resolves
1.10 auto-detect proxy
there we need libssh2 to properly tell us when we pass in a too small buffer
and its current API (as of libssh2 1.2.7) does not.
-1.6 native IDN support on macOS
-
- On recent macOS versions, the getaddrinfo() function itself has built-in IDN
- support. By setting the AI_CANONNAME flag, the function will return the
- encoded name in the ai_canonname struct field in the returned information.
- This could be used by curl on macOS when built without a separate IDN library
- and an IDN host name is used in a URL.
-
- See initial work in https://github.com/curl/curl/pull/5371
-
1.8 CURLOPT_RESOLVE for any port number
This option allows applications to set a replacement IP address for a given
/* to enable Windows IDN */
#cmakedefine USE_WIN32_IDN 1
+/* to enable Apple IDN */
+#cmakedefine USE_APPLE_IDN 1
+
/* Define to 1 to enable websocket support. */
#cmakedefine USE_WEBSOCKETS 1
/* ---------------------------------------------------------------- */
-#if defined(HAVE_LIBIDN2) && defined(HAVE_IDN2_H) && !defined(USE_WIN32_IDN)
+#if defined(HAVE_LIBIDN2) && defined(HAVE_IDN2_H) && \
+ !defined(USE_WIN32_IDN) && !defined(USE_APPLE_IDN)
/* The lib and header are present */
#define USE_LIBIDN2
#endif
-#if defined(USE_LIBIDN2) && defined(USE_WIN32_IDN)
-#error "Both libidn2 and WinIDN are enabled, choose one."
+#if defined(USE_LIBIDN2) && (defined(USE_WIN32_IDN) || defined(USE_APPLE_IDN))
+#error "libidn2 cannot be enabled with WinIDN or AppleIDN, choose one."
#endif
#define LIBIDN_REQUIRED_VERSION "0.4.1"
#include "curl_memory.h"
#include "memdebug.h"
+/* for macOS and iOS targets */
+#if defined(USE_APPLE_IDN)
+#include <unicode/uidna.h>
+
+static CURLcode mac_idn_to_ascii(const char *in, char **out)
+{
+ UErrorCode err = U_ZERO_ERROR;
+ UIDNA* idna = uidna_openUTS46(UIDNA_CHECK_BIDI, &err);
+ if(U_FAILURE(err)) {
+ return CURLE_OUT_OF_MEMORY;
+ }
+ else {
+ UIDNAInfo info = UIDNA_INFO_INITIALIZER;
+ char buffer[256] = {0};
+ (void)uidna_nameToASCII_UTF8(idna, in, -1, buffer,
+ sizeof(buffer), &info, &err);
+ uidna_close(idna);
+ if(U_FAILURE(err)) {
+ return CURLE_URL_MALFORMAT;
+ }
+ else {
+ *out = strdup(buffer);
+ if(*out)
+ return CURLE_OK;
+ else
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+}
+
+static CURLcode mac_ascii_to_idn(const char *in, char **out)
+{
+ UErrorCode err = U_ZERO_ERROR;
+ UIDNA* idna = uidna_openUTS46(UIDNA_CHECK_BIDI, &err);
+ if(U_FAILURE(err)) {
+ return CURLE_OUT_OF_MEMORY;
+ }
+ else {
+ UIDNAInfo info = UIDNA_INFO_INITIALIZER;
+ char buffer[256] = {0};
+ (void)uidna_nameToUnicodeUTF8(idna, in, -1, buffer,
+ sizeof(buffer), &info, &err);
+ uidna_close(idna);
+ if(U_FAILURE(err)) {
+ return CURLE_URL_MALFORMAT;
+ }
+ else {
+ *out = strdup(buffer);
+ if(*out)
+ return CURLE_OK;
+ else
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+}
+#endif
+
#ifdef USE_WIN32_IDN
/* using Windows kernel32 and normaliz libraries. */
result = CURLE_NOT_BUILT_IN;
#elif defined(USE_WIN32_IDN)
result = win32_idn_to_ascii(input, &decoded);
+#elif defined(USE_APPLE_IDN)
+ result = mac_idn_to_ascii(input, &decoded);
#endif
if(!result)
*output = decoded;
CURLcode result = win32_ascii_to_idn(puny, &enc);
if(result)
return result;
+#elif defined(USE_APPLE_IDN)
+ CURLcode result = mac_ascii_to_idn(puny, &enc);
+ if(result)
+ return result;
#endif
*output = enc;
return CURLE_OK;
bool Curl_is_ASCII_name(const char *hostname);
CURLcode Curl_idnconvert_hostname(struct hostname *host);
-#if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN)
+#if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN) || defined(USE_APPLE_IDN)
#define USE_IDN
void Curl_free_idnconverted_hostname(struct hostname *host);
CURLcode Curl_idn_decode(const char *input, char **output);
src[i++] = idn_version;
#elif defined(USE_WIN32_IDN)
src[i++] = (char *)"WinIDN";
+#elif defined(USE_APPLE_IDN)
+ src[i++] = (char *)"AppleIDN";
#endif
#ifdef USE_LIBPSL
!defined(CURL_DISABLE_HTTP)
FEATURE("HTTPS-proxy", https_proxy_present, CURL_VERSION_HTTPS_PROXY),
#endif
-#if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN)
+#if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN) || defined(USE_APPLE_IDN)
FEATURE("IDN", idn_present, CURL_VERSION_IDN),
#endif
#ifdef USE_IPV6
*/
#include "test.h"
-#if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN)
+#if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN) || defined(USE_APPLE_IDN)
#define USE_IDN
#endif