Открыть список
Как стать автором
Обновить

Национальные доменные имена: из 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. Так же буду рад интересным дополнениям по теме.
Теги:C++IDNIDNAUNICODEASCIIASCPunycodeICANN
Хабы: Чулан
Всего голосов 11: ↑7 и ↓4 +3
Просмотры1.1K

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

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

Похожие публикации

Разработчик C++
от 290 000 до 300 000 ₽ВГТМосква
Senior C++ / JS Developer
от 200 000 до 300 000 ₽ZennoLabМожно удаленно
Python / C++ разработчик
от 150 000 до 230 000 ₽Wunder FundМожно удаленно
Senior C++ Engineer
до 230 000 ₽ItivitiСанкт-Петербург
Senior C++/Qt разработчик
от 120 000 до 200 000 ₽ROGIIНовосибирск

Лучшие публикации за сутки