123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- /***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at https://curl.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * SPDX-License-Identifier: curl
- *
- ***************************************************************************/
- /*
- * IDN conversions
- */
- #include "curl_setup.h"
- #include "urldata.h"
- #include "idn.h"
- #include "sendf.h"
- #include "curl_multibyte.h"
- #include "warnless.h"
- #ifdef USE_LIBIDN2
- #include <idn2.h>
- #if defined(WIN32) && defined(UNICODE)
- #define IDN2_LOOKUP(name, host, flags) \
- idn2_lookup_u8((const uint8_t *)name, (uint8_t **)host, flags)
- #else
- #define IDN2_LOOKUP(name, host, flags) \
- idn2_lookup_ul((const char *)name, (char **)host, flags)
- #endif
- #endif /* USE_LIBIDN2 */
- /* The last 3 #include files should be in this order */
- #include "curl_printf.h"
- #include "curl_memory.h"
- #include "memdebug.h"
- #ifdef USE_WIN32_IDN
- /* using Windows kernel32 and normaliz libraries. */
- #if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x600
- WINBASEAPI int WINAPI IdnToAscii(DWORD dwFlags,
- const WCHAR *lpUnicodeCharStr,
- int cchUnicodeChar,
- WCHAR *lpASCIICharStr,
- int cchASCIIChar);
- WINBASEAPI int WINAPI IdnToUnicode(DWORD dwFlags,
- const WCHAR *lpASCIICharStr,
- int cchASCIIChar,
- WCHAR *lpUnicodeCharStr,
- int cchUnicodeChar);
- #endif
- #define IDN_MAX_LENGTH 255
- bool Curl_win32_idn_to_ascii(const char *in, char **out)
- {
- bool success = FALSE;
- wchar_t *in_w = curlx_convert_UTF8_to_wchar(in);
- if(in_w) {
- wchar_t punycode[IDN_MAX_LENGTH];
- int chars = IdnToAscii(0, in_w, -1, punycode, IDN_MAX_LENGTH);
- curlx_unicodefree(in_w);
- if(chars) {
- char *mstr = curlx_convert_wchar_to_UTF8(punycode);
- if(mstr) {
- *out = strdup(mstr);
- curlx_unicodefree(mstr);
- if(*out)
- success = TRUE;
- }
- }
- }
- return success;
- }
- #endif /* USE_WIN32_IDN */
- /*
- * Helpers for IDNA conversions.
- */
- bool Curl_is_ASCII_name(const char *hostname)
- {
- /* get an UNSIGNED local version of the pointer */
- const unsigned char *ch = (const unsigned char *)hostname;
- if(!hostname) /* bad input, consider it ASCII! */
- return TRUE;
- while(*ch) {
- if(*ch++ & 0x80)
- return FALSE;
- }
- return TRUE;
- }
- #ifdef USE_IDN
- /*
- * Curl_idn_decode() returns an allocated IDN decoded string if it was
- * possible. NULL on error.
- */
- static char *idn_decode(const char *input)
- {
- char *decoded = NULL;
- #ifdef USE_LIBIDN2
- if(idn2_check_version(IDN2_VERSION)) {
- int flags = IDN2_NFC_INPUT
- #if IDN2_VERSION_NUMBER >= 0x00140000
- /* IDN2_NFC_INPUT: Normalize input string using normalization form C.
- IDN2_NONTRANSITIONAL: Perform Unicode TR46 non-transitional
- processing. */
- | IDN2_NONTRANSITIONAL
- #endif
- ;
- int rc = IDN2_LOOKUP(input, &decoded, flags);
- if(rc != IDN2_OK)
- /* fallback to TR46 Transitional mode for better IDNA2003
- compatibility */
- rc = IDN2_LOOKUP(input, &decoded, IDN2_TRANSITIONAL);
- if(rc != IDN2_OK)
- decoded = NULL;
- }
- #elif defined(USE_WIN32_IDN)
- if(!Curl_win32_idn_to_ascii(input, &decoded))
- decoded = NULL;
- #endif
- 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(host->encalloc) {
- /* must be freed with idn2_free() if allocated by libidn */
- Curl_idn_free(host->encalloc);
- host->encalloc = NULL;
- }
- }
- #endif /* USE_IDN */
- /*
- * Perform any necessary IDN conversion of hostname
- */
- CURLcode Curl_idnconvert_hostname(struct hostname *host)
- {
- /* set the name we use to display the host name */
- host->dispname = host->name;
- #ifdef USE_IDN
- /* Check name for non-ASCII and convert hostname if we can */
- if(!Curl_is_ASCII_name(host->name)) {
- char *decoded = idn_decode(host->name);
- if(decoded) {
- if(!*decoded) {
- /* zero length is a bad host name */
- Curl_idn_free(decoded);
- return CURLE_URL_MALFORMAT;
- }
- /* successful */
- host->encalloc = decoded;
- /* change the name pointer to point to the encoded hostname */
- host->name = host->encalloc;
- }
- else
- return CURLE_URL_MALFORMAT;
- }
- #endif
- return CURLE_OK;
- }
|