Канонизация URL-адресов в нижний регистр
Я хочу написать модуль HTTP, который преобразует URL-адреса в нижний регистр.Моя первая попытка игнорировала международные наборы символов и прекрасно работает:
// Convert URL virtual path to lowercase
string lowercase = context.Request.FilePath.ToLowerInvariant();
// If anything changed then issue 301 Permanent Redirect
if (!lowercase.Equals(context.Request.FilePath, StringComparison.Ordinal))
{
context.Response.RedirectPermanent(...lowercase URL...);
}
Тест Турции (международные культуры):
Но как насчет культур, отличных от en-US?Я сослался на Turkey Test , чтобы придумать тестовый URL:
http://example.com/Iıİi
Этот маленький коварный драгоценный камень разрушает любое представление о том, что преобразование регистра в URL-адресах просто!Его строчные и прописные версии, соответственно, следующие:
http://example.com/ııii
http://example.com/IIİİ
Для преобразования регистра для работы с турецкими URL-адресами мне сначала пришлось установить текущую культуру ASP.NET на турецкий язык:
<system.web>
<globalization culture="tr-TR" />
</system.web>
Затем мне пришлось изменить свой код, чтобы использовать текущую культуру для преобразования регистра:
// Convert URL virtual path to lowercase
string lowercase = context.Request.FilePath.ToLower(CultureInfo.CurrentCulture);
// If anything changed then issue 301 Permanent Redirect
if (!lowercase.Equals(context.Request.FilePath, StringComparison.Ordinal))
{
context.Response.RedirectPermanent(...);
}
Но подождите!Будет ли StringComparison.Ordinal
все еще работать?Или я должен использовать StringComparison.CurrentCulture
?Я действительно не уверен ни в одном!
Имена файлов: он получает НАМНОГО ХОРОШО!
Даже если вышеперечисленное работает, используя текущую культуру для конверсий случаев ломает NTFS файловая система!Допустим, у меня есть статический файл с именем Iıİi.html
:
http://example.com/Iıİi.html
Несмотря на то, что файловая система Windows нечувствительна к регистру, она не использует языковую культуру.Преобразование вышеуказанного URL-адреса в нижний регистр приводит к значению 404 Not Found, поскольку файловая система не считает два имени равными:
http://example.com/ııii.html
Правильно ли преобразован регистр имен файлов?КТО ЗНАЕТ?!
В статье MSDN, Рекомендации по использованию строк в .NET Framework , есть примечание (примерно в середине статьи):
Примечание: Строковое поведение файловой системы, разделов и значений реестра и переменных среды лучше всего представлено в виде StringComparison.OrdinalIgnoreCase.
А? Лучше всего представлено ??? Это лучшее, что мы можем сделать в C #?Итак, каково правильное преобразование регистра в файловую систему? Кто знает? !!? Все, что мы можем сказать, - это то, что сравнение строк с использованием приведенного выше кода, вероятно, будет работать МОСТЕ времени.
Резюме: два преобразования: статические / динамические URL-адреса
- Итак, мы видели, что статические URL --- URL-адреса, имеющие путь к файлу, который соответствует реальному каталогу / файлу в файловой системе - должны использовать неизвестное преобразование, котороетолько «лучше всего представлен»
StringComparison.OrdinalIgnoreCase
.И, пожалуйста, обратите внимание, что метода string.ToLowerOrdinal()
нет, поэтому очень трудно точно определить, какой именно перевод прецедентов соответствует сравнению строки OrdinalIgnoreCase
.Использование string.ToLowerInvariant()
, вероятно, является лучшим выбором, но это нарушает языковую культуру. - С другой стороны, динамические URL-адреса --- URL-адреса с путем к файлу, который не соответствует реальному файлуна диске (который отображается в вашем приложении) --- может использовать
string.ToLower(CultureInfo.CurrentCulture)
, но это нарушает сопоставление файловой системы, и несколько неясно, какие существуют крайние случаи, которые могут нарушить эту стратегию.
Таким образомПохоже, что преобразование сначала требует определения того, является ли URL-адрес статическим или динамическим, прежде чем выбрать один из двух методов преобразования.Для статических URL существует неопределенность, как изменить регистр, не нарушая файловую систему Windows.Для динамических URL-адресов сомнительно, что преобразование регистра с использованием культуры аналогично нарушит URL-адрес.
Вот так!У кого-нибудь есть решение этой проблемы?Или мне просто закрыть глаза и притвориться, что все в ASCII?