123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378 |
-
- #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
- #include "curl_printf.h"
- #include "curl_memory.h"
- #include "memdebug.h"
- #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) {
- 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)) {
- 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) && !info.errors) {
- *out = strdup(buffer);
- if(*out)
- return CURLE_OK;
- else
- return CURLE_OUT_OF_MEMORY;
- }
- }
- }
- else
- return iconv_result;
- }
- return CURLE_URL_MALFORMAT;
- }
- static CURLcode mac_ascii_to_idn(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_UNICODE, &err);
- if(!U_FAILURE(err)) {
- UIDNAInfo info = UIDNA_INFO_INITIALIZER;
- char buffer[MAX_HOST_LENGTH] = {0};
- (void)uidna_nameToUnicodeUTF8(idna, in, -1, 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;
- }
- }
- }
- return CURLE_URL_MALFORMAT;
- }
- #endif
- #ifdef USE_WIN32_IDN
- #if (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x600) && \
- (!defined(WINVER) || WINVER < 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
- static CURLcode win32_idn_to_ascii(const char *in, char **out)
- {
- wchar_t *in_w = curlx_convert_UTF8_to_wchar(in);
- *out = NULL;
- if(in_w) {
- wchar_t punycode[IDN_MAX_LENGTH];
- int chars = IdnToAscii(0, in_w, (int)(wcslen(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)
- return CURLE_OUT_OF_MEMORY;
- }
- else
- return CURLE_OUT_OF_MEMORY;
- }
- else
- return CURLE_URL_MALFORMAT;
- }
- else
- return CURLE_URL_MALFORMAT;
- return CURLE_OK;
- }
- static CURLcode win32_ascii_to_idn(const char *in, char **output)
- {
- char *out = NULL;
- wchar_t *in_w = curlx_convert_UTF8_to_wchar(in);
- if(in_w) {
- WCHAR idn[IDN_MAX_LENGTH];
- int chars = IdnToUnicode(0, in_w, (int)(wcslen(in_w) + 1), idn,
- IDN_MAX_LENGTH);
- if(chars) {
-
- char *mstr = curlx_convert_wchar_to_UTF8(idn);
- if(mstr) {
- out = strdup(mstr);
- curlx_unicodefree(mstr);
- if(!out)
- return CURLE_OUT_OF_MEMORY;
- }
- }
- else
- return CURLE_URL_MALFORMAT;
- }
- else
- return CURLE_URL_MALFORMAT;
- *output = out;
- return CURLE_OK;
- }
- #endif
- bool Curl_is_ASCII_name(const char *hostname)
- {
-
- const unsigned char *ch = (const unsigned char *)hostname;
- if(!hostname)
- return TRUE;
- while(*ch) {
- if(*ch++ & 0x80)
- return FALSE;
- }
- return TRUE;
- }
- #ifdef USE_IDN
- static CURLcode idn_decode(const char *input, char **output)
- {
- char *decoded = NULL;
- CURLcode result = CURLE_OK;
- #ifdef USE_LIBIDN2
- if(idn2_check_version(IDN2_VERSION)) {
- int flags = IDN2_NFC_INPUT
- #if IDN2_VERSION_NUMBER >= 0x00140000
-
- | IDN2_NONTRANSITIONAL
- #endif
- ;
- int rc = IDN2_LOOKUP(input, &decoded, flags);
- if(rc != IDN2_OK)
-
- rc = IDN2_LOOKUP(input, &decoded, IDN2_TRANSITIONAL);
- if(rc != IDN2_OK)
- result = CURLE_URL_MALFORMAT;
- }
- else
-
- 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;
- return result;
- }
- static CURLcode idn_encode(const char *puny, char **output)
- {
- char *enc = NULL;
- #ifdef USE_LIBIDN2
- int rc = idn2_to_unicode_8z8z(puny, &enc, 0);
- if(rc != IDNA_SUCCESS)
- return rc == IDNA_MALLOC_ERROR ? CURLE_OUT_OF_MEMORY : CURLE_URL_MALFORMAT;
- #elif defined(USE_WIN32_IDN)
- 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;
- }
- CURLcode Curl_idn_decode(const char *input, char **output)
- {
- char *d = NULL;
- CURLcode result = idn_decode(input, &d);
- #ifdef USE_LIBIDN2
- if(!result) {
- char *c = strdup(d);
- idn2_free(d);
- if(c)
- d = c;
- else
- result = CURLE_OUT_OF_MEMORY;
- }
- #endif
- if(!result)
- *output = d;
- return result;
- }
- CURLcode Curl_idn_encode(const char *puny, char **output)
- {
- char *d = NULL;
- CURLcode result = idn_encode(puny, &d);
- #ifdef USE_LIBIDN2
- if(!result) {
- char *c = strdup(d);
- idn2_free(d);
- if(c)
- d = c;
- else
- result = CURLE_OUT_OF_MEMORY;
- }
- #endif
- if(!result)
- *output = d;
- return result;
- }
- void Curl_free_idnconverted_hostname(struct hostname *host)
- {
- Curl_safefree(host->encalloc);
- }
- #endif
- CURLcode Curl_idnconvert_hostname(struct hostname *host)
- {
-
- host->dispname = host->name;
- #ifdef USE_IDN
-
- if(!Curl_is_ASCII_name(host->name)) {
- char *decoded;
- CURLcode result = Curl_idn_decode(host->name, &decoded);
- if(result)
- return result;
-
- host->name = host->encalloc = decoded;
- }
- #endif
- return CURLE_OK;
- }
|