Национальные доменные имена: из ASCII-формата в IDN и обратно

    Если встанет необходимость работать с национальными доменными именами, то для большинства случаев приходящий от клиента формат «xn—abrakatabra.com» будет достаточным. Но бывают случаи, когда необходимо работать с доменными именами в их национальном представлении, т.е. «пример.com».

    В данной статье рассмотрены программные реализации кодировки национальных доменных имен из ASCII- формата в IDN и обратно средствами MS VisualStudio и библиотеки ICU.


    История.
    Если вы уже слышали аббревиатуру IDN, то следующие четыре абзаца можно смело пропускать.

    Исторически для представления доменных имен в Интернете использовались символы ASCII кодировки: “A-z”, “0-9”, “-”. С развитием Интернета символов стало не хватать (точнее коротких и удобных имен) и ICANN заявило о необходимости расширения знаков представления доменных имен за счет использования национальных алфавитов (представлены в Unicode).

    IDN — (англ. Internationalized Domain Names — Интернационализованные Доменные Имена) — это доменные имена, которые содержат символы национальных алфавитов. Например, «сайт.com».

    Многочисленные обсуждения на немногочисленных форумах, посвященных IDN, сводятся к двум мнениям: «офигеть – дайте две!» и «нас пытаются — мягко говоря — обмануть». Второе основано на специфике реализации данной технологии.

    Новые символы – это хорошо закодированные старые :)

    По сути, IDN – это удобная и красивая обертка для длинного и неудобного набора символов. На стороне клиента осуществляется кодировка национальных символов в допустимые символы ASCII, которые и являются доменным именем. Если в адресную строку ввести «пример.испытание», то она перекодируется в «xn--e1afmkfd.xn--80akhbyknj4f». Для этого используется кодировка из семейства ASCII – совместимых кодировок (ACE) – Punycode, применяемая в настоящее время в системе многоязычных доменных имен. Алгоритм кодирования Punycode достаточно прост и подробно описан в RFC-3492 (там же он реализован на C).

    Какие средства кодировки и перекодировки в нашем распоряжении?

    1. Средства Microsoft.

    В VisualStudio в пространстве имен System.Globalization реализован класс IdnMapping, среди методов которого можно найти в частности такие — GetAscii и GetUnicode, которые и осуществляют перекодировку в соответствии со стандартами IDNA. Не класс, а мечта – проще некуда:

    using namespace System::Globalization;
    using System::String;

    String^ s1 = "привет.пример";
    String^ s;

    IdnMapping idn;

    s = idn.GetAscii(s1, 0, s1->Length);
    System::Console::WriteLine(s);

    String^ s2 = "xn--b1agh1afp.xn--e1afmkfd";

    s = idn.GetUnicode(s2, 0, s2->Length);
    System::Console::WriteLine(s);

    Результат:
    xn--b1agh1afp.xn--e1afmkfd
    привет.пример


    Для этих же целей у мелкомягких есть две API функции IdnToAscii и IdnToUnicode. К сожалению, Minimum supported client – Windows Vista. Очень жаль. Пример использования функция можно найти на их сайте.

    2. Средства ICU (International Components for Unicode). ICU — это С/С++ и Java open source библиотеки, в которых реализованы поддержка и возможности «Unicode and Globalization». В этой библиотеке реализованы следующие функции преобразования доменных имен:

    int32_t uidna_toUnicode / uidna_toAscii (const UChar *src, int32_t srcLength, UChar *dest, int32_t destCapacity, int32_t options, UParseError *parseError, UErrorCode *status)

    — используется для преобразований ASCII to IDN / IDN to ASCII простых имен (составных частей доменного имени). Например, «www.example.com» состоит из трех частей – «www», «example», «com».

    int32_t uidna_IDNToUnicode / uidna_IDNToASCII(const UChar *src, int32_t srcLength, UChar *dest, int32_t destCapacity, int32_t options, UParseError *parseError, UErrorCode *status)

    — используется для преобразований ASCII to IDN / IDN to ASCII полных доменных имен. Например, «www.example.com».

    Параметры:
    src – указатель на входную строку, которую необходимо преобразовать.
    srcLength – длина src. Если src – си строка, то можно задать -1.
    dest – указатель на строк, куда будет записана преобразованная строка.
    destCapacity – размер dest.
    Options – бит опций. Может принимать одно из следующих значений:
    • UIDNA_DEFAULT – по умолчанию. В случае ошибки возвращает U_UNASSIGNED_ERROR.
    • UIDNA_ALLOW_UNASSIGNED – если данный флаг установлен, то считается, что не назначенные элементы кода в строке ввода представлены в кодировке Unicode.
    • UIDNA_USE_STD3_RULES – синтаксис доменного имени должен удовлетворять стандартам STD3 ASCII. В случае ошибки возвращает U_IDNA_STD3_ASCII_RULES_ERROR.

    parseError – указатель на структуру UParseError. Можно задать нулем.
    status – код ошибки.

    Возвращаемое значение – длина преобразованной строки. Для избежания переполнения, необходимо сравнить с destCapacity.

    #include "unicode/utypes.h"
    #include "unicode/parseerr.h"
    #include "unicode/uidna.h"

    wchar_t* s1 = L"пример.прием";
    wchar_t pPunycode[MAX_PATH];
    UErrorCode status = U_ZERO_ERROR;

    int32_t i = uidna_IDNToASCII(s1, -1, pPunycode, MAX_PATH, UIDNA_USE_STD3_RULES, NULL, &status);

    if(status == U_IDNA_STD3_ASCII_RULES_ERROR)
    wprintf(L"Error");


    wchar_t* s2 = L"xn--e1afmkfd.xn--e1afnjf";
    wchar_t pUnicode[MAX_PATH];
    UErrorCode status = U_ZERO_ERROR;

    int32_t i = uidna_IDNToUnicode(s2, -1, pUnicode, MAX_PATH, UIDNA_ALLOW_UNASSIGNED, NULL, &status);

    if(status == U_IDNA_STD3_ASCII_RULES_ERROR)
    wprintf(L"Error")


    Результаты аналогичны предыдущему примеру.

    Перед использованием библиотеку нужно собрать. По порядку (для MS VS):

    1. Выбираем последний релиз (у меня — ICU4C 4.4 2010-03-17) здесь.
    2. Скачиваем сорцы.
    3. Настраиваем переменную окружения PATH: “\bin\”
    4. Открываем солюшн: “\source\allinone\allinone.sln”
    5. Build-> Batch Build...-> Select All-> Rebuild.
    6. Build->Rebuild Solution.

    Если не собралось, открываем “\Readme.html ->How To Build And Install ICU и сверяемся. Если собралось без ошибок – пользуем.

    P.s. Любым замечаниям и поправкам буду рад.
    Pp.s. Так же буду рад интересным дополнениям по теме.

    Комментарии 4

      +1
      > средствами MS VisualStudio
      необходимо подключать библиотеки MS VS или это в какой-то версии .NET Framework сделано? :)
        0
        В .NET Framework 2.0 и выше…

        Второй вариант подходит? :)
        0
        offtopic
        Чего только не придумают ради обратной совместимости…
        Почему бы не перейти сразу на UTF-16?
        А так же на IPv6 и 64bit :)
          0
          В .NET Framework 2.0 и выше…

          Второй вариант подходит? :)

          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

          Самое читаемое