Uri.IdnHost长主机的奇怪行为



Uri.IdnHost不适用于长主机。这是正常行为吗?如何解决这个问题?

void checkIDN(string urlString)
{
var uri = new Uri(urlString);
Console.WriteLine($"{uri.Host,-40} ---> {uri.IdnHost}");
}
checkIDN("https://единая-дата-объединения-застройщиков.рф");
checkIDN("https://единая-дата-объединения-застройщико.рф");
checkIDN("https://единая-дата-объединения-застройщик.рф");
checkIDN("https://единая-дата-объединения-застройщи.рф");
checkIDN("https://единая-дата-объединения-застройщ.рф");
checkIDN("https://единая-дата-объединения-застрой.рф");
checkIDN("https://единая-дата-объединения-застро.рф");

作为参考,您的代码会产生以下结果:

;xn---------5cdbacgvcedib5aejbw8dkbql3czamp4tlfqa.xn-p1ai

;xn--------5dbacgvcedib5aejb7fkbp1cyalp6eqa.xn--p1ai

请注意,只要部件在"之前;。рф"在主机名中超过31个字符-它将按预期停止工作。

根据RFC,域名最多可以包含256个字符,每个标签(标签用点分隔)最多可以包含63个字符。不过,对于IDN名称,我们不应该直接计算字符数,而应该计算已转换名称中的字符数。

然而,根据我在.NET源代码中找到的这段代码,如果标签包含unicode字符,它只会将每个unicode字符计数为2:

count++;
if (*newPos > 0xFF)
count++; // counts for two octets

然后它进行检查:

if (... (labelHasUnicode ? count + 4 : count) > 63 ...)
{
return false;
}

长话短说——它不认为你的域名是有效的,因为它认为标签长度要求被违反了。如果它不是一个有效的域名,则无需将其转换为IDN。你可以通过运行来验证它是否认为它是一个有效的域名

Uri.CheckHostName("единая-дата-объединения-застройщиков.рф");

这返回"0";未知";而对于有效域名,它将返回"0";Dns";。

我可能会错过一些东西,但我不同意这一点,因为如果我们转换一个标签";";,我们将得到这个字符串:

XN------5CDBACGLLCEEIB7AFJBDUX5CKBTLD7C3AQP8USA0OQA

它包含51个字符,所以不违反要求,所以整个东西是一个有效的域名。

我会在.NET bug跟踪器中提交一个bug来描述这个问题,也许他们可以更好地澄清。

作为一种变通方法,您可以使用IdnMMapping类:

static void checkIDN(string urlString) {
var uri = new Uri(urlString);
var m = new IdnMapping();
var idn = m.GetAscii(uri.Host);
Console.WriteLine($"{uri.Host,-40} ---> {idn}");
}

这个类不进行任何检查,只是将字符串转换为IDN。

最新更新