RFC 3986 | URI — Унифицированный идентификатор ресурса: общий синтаксис

Аннотация

Унифицированный идентификатор ресурса (URI) — это компактная последовательность символов, которая идентифицирует абстрактный или физический ресурс. В этой спецификации определяется общий синтаксис URI и процесс разрешения ссылок URI, которые могут быть в относительной форме, а также рекомендации и соображения безопасности по использованию URI в Интернете. Синтаксис URI определяет грамматику, которая является надмножеством всех допустимых URI, позволяя реализации анализировать общие компоненты ссылки на URI, не зная специфических для схемы требований каждого возможного идентификатора. Эта спецификация не определяет генеративную грамматику для URI; эта задача выполняется отдельными спецификациями каждой схемы URI.

Скачать оригинальную версию документа на английском языке RFC 3986 PDF

Оглавление

1. Введение
1.1. Обзор URI
1.1.1. Общий синтаксис
1.1.2. Примеры
1.1.3. URI, URL и URN
1.2. Особенности дизайна
1.2.1. Транскрипция
1.2.2. Отделение идентификации от взаимодействия
1.2.3. Иерархические идентификаторы
1.3. Синтаксическая нотация
2. Символы
2.1. Процент-Кодирование
2.2. Зарезервированные символы
2.3. Незарезервированные символы
2.4. Когда кодировать или декодировать
2.5. Идентификация данных
3. Синтаксические компоненты
3.1. Схема
3.2. Основание
3.2.1. Информация о пользователе
3.2.2. Хост
3.2.3. Порт
3.3. Путь
3.4. Запрос
3.5. Фрагмент
4. Использование
4.1. Ссылка на URI
4.2. Относительная ссылка
4.3. Абсолютный URI
4.4. Ссылка на тот же документ
4.5. Суффикс ссылка
5. Справочное разрешение
5.1. Установление базового URI
5.1.1. Базовый URI, встроенный в контент
5.1.2. Базовый URI от инкапсулирующего объекта
5.1.3. Базовый URI из URI получения
5.1.4. Базовый URI по умолчанию
5.2. Относительное разрешение
5.2.1. Предварительный анализ базового URI
5.2.2. Преобразование ссылок
5.2.3. Cлияние путей
5.2.4. Удаление точечных сегментов
5.3. Компонент перекомпоновки
5.4. Примеры разрешения ссылок
5.4.1. Нормальные примеры
5.4.2. Ненормальные примеры
6. Нормализация и сравнение
6.1. Эквивалентность
6.2. Лестница сравнения
6.2.1. Простое сравнение строк
6.2.2. Синтаксическая нормализация
6.2.2.1. Нормализация случая
6.2.2.2. Нормализация кодирования процентов
6.2.2.3. Нормализация сегмента пути
6.2.3. Нормализация на основе схемы
6.2.4. Основанная на протоколе нормализация
7. Вопросы безопасности
7.1. Надежность и последовательность
7.2. Вредоносная Конструкция
7.3. Back-End транскодирование
7.4. Редкие форматы IP-адресов
7.5. Конфиденциальная информация
7.6. Семантические атаки
8. Соображения IANA
9. Благодарности
10. Ссылки
10.1. Нормативные ссылки
10.2. Информационные ссылки
A. Собранный ABNF для URI
B. Разбор ссылки на URI с помощью регулярного выражения
C. Разграничение URI в контексте
D. Отличия от RFC 2396
D.1. Дополнения
D.2. Изменения
Индекс
Адреса авторов
Полное авторское право

1. Введение

Унифицированный идентификатор ресурса (URI) обеспечивает простое и расширяемое средство для идентификации ресурса. Эта спецификация синтаксиса и семантики URI получена из концепций, представленных глобальной информационной инициативой World Wide Web, чье использование этих идентификаторов датируется 1990 годом и описано в «Универсальных идентификаторах ресурсов в WWW» [RFC1630 #]. Синтаксис разработан с учетом рекомендаций, изложенных в «Функциональных рекомендациях для локаторов интернет-ресурсов» [RFC1736 #] и «Функциональных требованиях к унифицированным именам ресурсов» [RFC1737 #].

Этот документ устарел [RFC2396 #], который объединил «Унифицированные указатели ресурсов» [RFC1738 #] и «Относительные унифицированные указатели ресурсов» [RFC1808 #], чтобы определить единый общий синтаксис для всех URI. Он устарел [RFC2732 #], который ввел синтаксис для адреса IPv6. Он исключает части RFC 1738, которые определяли конкретный синтаксис отдельных схем URI; эти части будут обновлены как отдельные документы. Процесс регистрации новых схем URI определяется отдельно [BCP35]. Рекомендации для разработчиков новых схем URI можно найти в [RFC2718 #]. Все существенные изменения по сравнению с RFC 2396 отмечены в Приложении D.

В данной спецификации используются термины «символ» и «набор кодированных символов» в соответствии с определениями, приведенными в [BCP19], и «кодировка символов» вместо того, что [BCP19] называется «кодировкой».

1.1. Обзор URI

URI характеризуются следующим образом:

Унифицированный (единообразный) (uniform)

Равномерность дает несколько преимуществ. Это позволяет использовать разные типы идентификаторов ресурсов в одном контексте, даже если механизмы доступа к этим ресурсам могут различаться. Это позволяет получить единообразную семантическую интерпретацию общих синтаксических соглашений для различных типов идентификаторов ресурсов. Это позволяет вводить новые типы идентификаторов ресурсов, не влияя на то, как используются существующие идентификаторы. Это позволяет идентификаторам многократно использоваться во многих различных контекстах, что позволяет новым приложениям или протоколам использовать уже существующий, большой и широко используемый набор идентификаторов ресурсов.

Ресурс (resource)

Эта спецификация не ограничивает область действия ресурса; скорее, термин «ресурс» используется в общем смысле для того, что может быть идентифицировано посредством URI. Знакомые примеры включают электронный документ, изображение, источник информации с постоянной целью (например, «отчет о погоде в Лос-Анджелесе на сегодня»), услугу (например, шлюз HTTP-SMS) и набор других ресурсов. Ресурс не обязательно доступен через Интернет; например, люди, корпорации и книги в библиотеке также могут быть ресурсами. Аналогично, абстрактные понятия могут быть ресурсами, такими как операторы и операнды математического уравнения, типы отношений (например, «родитель» или «сотрудник») или числовые значения (например, ноль, один и бесконечность).

Идентификатор (identifier)

Идентификатор воплощает информацию, необходимую для того, чтобы отличить то, что идентифицируется, от всех других вещей в пределах его области идентификации. Наше использование терминов «идентифицировать» и «идентификация» относится к этой цели, заключающейся в различении одного ресурса от всех других ресурсов, независимо от того, как эта цель достигается (например, по имени, адресу или контексту). Эти термины не следует принимать за допущение, что идентификатор определяет или воплощает идентичность того, на что ссылаются, хотя это может иметь место для некоторых идентификаторов. Не следует также предполагать, что система, использующая URI, будет обращаться к идентифицированному ресурсу: во многих случаях URI используются для обозначения ресурсов без какого-либо намерения получить к ним доступ. Аналогично, идентифицированный «один» ресурс может не быть единичным по своей природе (например, ресурс может быть именованным набором или отображением, которое изменяется во времени).

URI является идентификатором, состоящим из последовательности символов, соответствующих правилу синтаксиса с именем <URI> в Разделе 3. Он обеспечивает единообразную идентификацию ресурсов с помощью отдельно определенного расширяемого набора схем именования (Раздел 3.1). То, как эта идентификация выполнена, назначена или включена, делегируется каждой спецификации схемы.

Эта спецификация не накладывает никаких ограничений на природу ресурса, причины, по которым приложение может ссылаться на ресурс, или типы систем, которые могут использовать URI для идентификации ресурсов. Эта спецификация не требует, чтобы URI продолжал идентифицировать один и тот же ресурс с течением времени, хотя это является общей целью всех схем URI. Тем не менее, ничто в этой спецификации не препятствует приложению ограничивать себя определенными типами ресурсов или подмножеством URI, которые поддерживают характеристики, требуемые этим приложением.

URI имеют глобальную область видимости и интерпретируются последовательно независимо от контекста, хотя результат такой интерпретации может быть связан с контекстом конечного пользователя. Например, «http://localhost/» имеет одинаковую интерпретацию для каждого пользователя этой ссылки, даже если сетевой интерфейс, соответствующий «localhost», может отличаться для каждого конечного пользователя: интерпретация не зависит от доступа. Однако действие, выполненное на основе этой ссылки, будет иметь место в отношении контекста конечного пользователя, что подразумевает, что действие, предназначенное для ссылки на глобально уникальную вещь, должно использовать URI, который отличает этот ресурс от всех других вещей. URI, которые идентифицируются в отношении локального контекста конечного пользователя, должны использоваться только в том случае, если сам контекст является определяющим аспектом ресурса, например, когда интерактивное справочное руководство ссылается на файл в файловой системе конечного пользователя (например, «file:///etc/hosts»).

1.1.1. Общий синтаксис

Каждый URI начинается с имени схемы, как определено в разделе 3.1, которое относится к спецификации для назначения идентификаторов в этой схеме. Таким образом, синтаксис URI является интегрированной и расширяемой системой именования, в которой спецификация каждой схемы может дополнительно ограничивать синтаксис и семантику идентификаторов, использующих эту схему.

Эта спецификация определяет те элементы синтаксиса URI, которые требуются для всех схем URI или являются общими для многих схем URI. Таким образом, он определяет синтаксис и семантику, необходимые для реализации независимого от схемы механизма синтаксического анализа ссылок на URI, с помощью которого зависимая от схемы обработка URI может быть отложена до тех пор, пока не понадобится зависимая от схемы семантика. Аналогично, протоколы и форматы данных, которые используют ссылки URI, могут ссылаться на эту спецификацию как определение диапазона синтаксиса, разрешенного для всех URI, включая те схемы, которые еще не определены. Это отделяет эволюцию схем идентификации от эволюции протоколов, форматов данных и реализаций, которые используют URI.

Синтаксический анализатор (Parser) общего URI-синтаксиса может анализировать любую ссылку на URI в ее основные компоненты. Как только схема определена, дальнейший синтаксический анализ схемы может быть выполнен для компонентов. Другими словами «общий синтаксис» (generic syntax) URI является расширенным набором синтаксиса всех схем URI.

1.1.2. Примеры

В следующих примерах URI иллюстрируют несколько схем и вариантов URI в их общих синтаксических компонентах:

ftp://ftp.is.co.za/rfc/rfc1808.txt
http://www.ietf.org/rfc/rfc2396.txt
ldap://[2001:db8::7]/c=GB?objectClass?one
mailto:John.Doe@example.com
news:comp.infosystems.www.servers.unix
tel:+1-816-555-1212
telnet://192.0.2.16:80/
urn:oasis:names:specification:docbook:dtd:xml:4.1.2

1.1.3. URI, URL и URN

URI может быть далее классифицирован как локатор, имя или оба. Термин «Унифицированный указатель ресурса» (URL) относится к подмножеству URI, которые, помимо идентификации ресурса, предоставляют средства для определения местоположения ресурса путем описания его основного механизма доступа (например, его «местоположения» в сети). Термин «Унифицированное имя ресурса» (URN) исторически использовался для ссылки на оба URI в схеме «URN» [RFC2141 #], которые должны оставаться глобально уникальными и постоянными, даже когда ресурс перестает существовать или становится недоступным, и к любому другому URI со свойствами имени.

Отдельная схема не должна классифицироваться как «имя» или «локатор». Экземпляры URI из любой данной схемы могут иметь характеристики имен или локаторов или обоих, часто в зависимости от настойчивости и осторожности при назначении идентификаторов органом по присвоению имен, а не от какого-либо качества схемы. В будущих спецификациях и соответствующей документации следует использовать общий термин «URI», а не более ограничительные термины «URL» и «URN» [RFC3305 #].

1.2. Особенности дизайна

1.2.1. Транскрипция

Синтаксис URI был разработан с глобальной «транскрипцией» в качестве одного из основных соображений. URI — это последовательность «символов» (characters) из очень ограниченного набора: буквы основного латинского алфавита, цифры и несколько специальных символов. URI может быть представлен различными способами; например, чернила на бумаге, пиксели на экране или последовательность октетов кодирования символов. Интерпретация URI зависит только от используемых символов, а не от того, как эти символы представлены в сетевом протоколе.

Цель транскрипции может быть описана простым сценарием. Представьте себе двух коллег, Сэма и Ким, которые сидят в пабе на международной конференции и обмениваются исследовательскими идеями. Сэм спрашивает Ким о месте, чтобы получить больше информации, поэтому Ким пишет URI для исследовательского сайта на салфетке. Вернувшись домой, Сэм достает салфетку и вводит URI в компьютер, который затем получает информацию, на которую ссылалась Ким.

Есть несколько конструктивных соображений, выявленных сценарием:

  • URI — это последовательность символов, которая не всегда представляется как последовательность октетов.
  • URI может транскрибироваться из не сетевого источника и, таким образом, должен состоять из символов, которые наиболее вероятно могут быть введены в компьютер, в пределах ограничений, наложенных клавиатурами (и связанными устройствами ввода) для разных языков и локалей.
  • Люди часто запоминают URI, и людям легче запомнить URI, если он состоит из значимых или знакомых компонентов.

Эти конструктивные соображения не всегда совпадают. Например, часто бывает так, что наиболее значимое имя для компонента URI требует символов, которые нельзя ввести в некоторых системах. Возможность транскрибировать идентификатор ресурса с одного носителя на другой считалась более важной, чем URI, состоящий из наиболее значимых компонентов.

В локальном или региональном контексте и с улучшением технологии пользователи могут извлечь выгоду из возможности использовать более широкий диапазон символов; такое использование не определено этой спецификацией. Кодированные в процентах октеты (раздел 2.1) могут использоваться в URI для представления символов вне диапазона набора кодированных символов US-ASCII, если это представление разрешено схемой или элементом протокола, в котором имеется ссылка на URI. Такое определение должно определять кодировку символов, используемую для сопоставления этих символов с октетами до того, как они будут кодироваться в процентах для URI.

1.2.2. Отделение идентификации от взаимодействия

Распространенным заблуждением URI является то, что они используются только для ссылки на доступные ресурсы. Сам URI обеспечивает только идентификацию; доступ к ресурсу не гарантируется и не подразумевается наличием URI. Вместо этого любая операция, связанная со ссылкой на URI, определяется элементом протокола, атрибутом формата данных или текстом на естественном языке, в котором она появляется.

Учитывая URI, система может попытаться выполнить множество операций над ресурсом, которые могут характеризоваться такими словами, как «доступ», «обновление», «замена» или «поиск атрибутов». Такие операции определяются протоколами, которые используют URI, а не этой спецификацией. Однако мы используем несколько общих терминов для описания общих операций с URI. «Разрешение» URI — это процесс определения механизма доступа и соответствующих параметров, необходимых для разыменования URI; это разрешение может потребовать нескольких итераций. Использовать этот механизм доступа для выполнения действия над ресурсом URI — это «разыменовать» (dereference) URI.

Когда URI используются в информационно-поисковых системах для идентификации источников информации, наиболее распространенной формой разыменования URI является «поиск» (retrieval): использование URI для извлечения представления связанного с ним ресурса. «Представление» (representation) представляет собой последовательность октетов вместе с метаданными представления, описывающими эти октеты, которые составляют запись состояния ресурса в момент, когда представление генерируется. Поиск достигается с помощью процесса, который может включать в себя использование URI в качестве ключа кэша для проверки локально кэшированного представления, разрешение URI для определения подходящего механизма доступа (если есть) и разыменование URI для применения поисковой операции. В зависимости от протоколов, используемых для поиска, может быть предоставлена дополнительная информация о ресурсе (метаданные ресурса) и его связи с другими ресурсами.

Ссылки URI в системах поиска информации предназначены для позднего связывания: результат доступа обычно определяется, когда к нему осуществляется доступ, и может изменяться во времени или из-за других аспектов взаимодействия. Эти ссылки созданы для использования в будущем: то, что идентифицируется, это не какой-то конкретный результат, который был получен в прошлом, а скорее некоторая характеристика, которая, как ожидается, будет верна для будущих результатов. В таких случаях ресурс, на который ссылается URI, фактически представляет собой «сходство» (sameness) характеристик, наблюдаемых с течением времени, возможно, объясненных дополнительными комментариями или утверждениями, сделанными поставщиком ресурса.

Хотя многие схемы URI названы в честь протоколов, это не означает, что использование этих URI приведет к доступу к ресурсу через указанный протокол. URI часто используются просто для идентификации. Даже когда URI используется для получения представления ресурса, такой доступ может осуществляться через шлюзы, прокси-серверы, кэши и службы разрешения имен, которые не зависят от протокола, связанного с именем схемы. Для разрешения некоторых URI может потребоваться использование более одного протокола (например, DNS и HTTP обычно используются для доступа к серверу происхождения «http» URI, когда представление не найдено в локальном кэше).

1.2.3. Иерархические идентификаторы

Синтаксис URI организован иерархически, а компоненты перечислены в порядке убывания значимости слева направо. Для некоторых схем URI видимая иерархия ограничена самой схемой: все, что находится после разделителя компонентов схемы («:»), считается непрозрачным для обработки URI. Другие схемы URI делают иерархию явной и видимой для общих алгоритмов синтаксического анализа.

Общий синтаксис использует символы косой черты («/»), вопросительного знака («?») И знака числа («#») для разделения компонентов, которые важны для иерархической (hierarchical) интерпретации идентификатора универсального синтаксического анализатора. В дополнение к содействию удобочитаемости таких идентификаторов посредством последовательного использования знакомого синтаксиса, это унифицированное представление иерархии по схемам именования позволяет делать независимые от схемы ссылки относительно этой иерархии.

Часто бывает, что группа или «дерево» документов построено для общей цели, когда подавляющее большинство ссылок на URI в этих документах указывают на ресурсы внутри дерева, а не за его пределами. Точно так же документы, расположенные на определенном сайте, гораздо чаще ссылаются на другие ресурсы на этом сайте, чем на ресурсы на удаленных сайтах. Относительная ссылка на URI позволяет деревьям документов быть частично независимыми от их местоположения и схемы доступа. Например, один и тот же набор гипертекстовых документов может быть одновременно доступен и проходим через каждую из схем «file», «http» и «ftp», если документы ссылаются друг на друга с относительными ссылками. Кроме того, такие деревья документов можно перемещать в целом без изменения каких-либо относительных ссылок.

Относительная ссылка (раздел 4.2) ссылается на ресурс, описывая разницу в иерархическом пространстве имен между ссылочным контекстом и целевым URI. Алгоритм разрешения ссылок, представленный в разделе 5, определяет, как такая ссылка преобразуется в целевой URI. Поскольку относительные ссылки могут использоваться только в контексте иерархического URI, разработчики новых схем URI должны использовать синтаксис, согласующийся с иерархическими компонентами общего синтаксиса, если нет веских причин запретить относительные ссылки в этой схеме.

ПРИМЕЧАНИЕ. Предыдущие спецификации использовали термины «частичный URI» и «относительный URI» для обозначения относительных ссылок на URI. Эти ссылки не содержат ссылок на URI, эта спецификация просто называет их относительными ссылками.

Все ссылки на URI анализируются общими синтаксическими анализаторами, когда они используются. Однако, поскольку иерархическая обработка не влияет на абсолютный URI, используемый в ссылке, если только он не содержит один или несколько точечных сегментов (полные сегменты пути «.» или «..», как описано в разделе 3.3), спецификации схемы URI могут определить непрозрачные идентификаторы, запретив использование символов косой черты, символов вопросительного знака и URI «scheme:.» и «scheme:..»

1.3. Синтаксическая нотация

Эта спецификация использует «Расширенную нотацию Бэкуса-Наура — Augmented Backus-Naur Form» (ABNF) из [RFC2234 #], включая следующие основные правила синтаксиса ABNF, определенные этой спецификацией: ALPHA (буквы), CR (возврат каретки), DIGIT (десятичные цифры), DQUOTE (двойной цитата), HEXDIG (шестнадцатеричные цифры), LF (перевод строки) и SP (пробел). Полный синтаксис URI собран в Приложении А.

2. Символы

Синтаксис URI обеспечивает метод кодирования данных, предположительно, для идентификации ресурса в виде последовательности символов. Символы URI, в свою очередь, часто кодируются как октеты для транспорта или представления. Эта спецификация не требует какой-либо конкретной кодировки символов для отображения между символами URI и октетами, используемыми для хранения или передачи этих символов. Когда URI появляется в элементе протокола, кодировка символов определяется этим протоколом; без такого определения предполагается, что URI находится в той же кодировке символов, что и окружающий текст.

Нотация ABNF определяет свои терминальные значения как неотрицательные целые числа (кодовые точки) на основе набора кодированных символов US-ASCII [ASCII]. Поскольку URI — это последовательность символов, мы должны инвертировать это отношение, чтобы понять синтаксис URI. Поэтому целочисленные значения, используемые ABNF, должны быть сопоставлены с соответствующими им символами через US-ASCII, чтобы завершить правила синтаксиса.

URI состоит из ограниченного набора символов, состоящего из цифр, букв и нескольких графических символов. Зарезервированное подмножество этих символов может использоваться для разграничения компонентов синтаксиса в URI, в то время как оставшиеся символы, включая как незарезервированный набор, так и те зарезервированные символы, не выступающие в качестве разделителей, определяют идентификационные данные каждого компонента.

2.1. Процент-Кодирование

Механизм «кодирования процентов» (percent-encoding) используется для представления октета данных в компоненте, когда соответствующий символ этого октета находится за пределами разрешенного набора или используется в качестве разделителя или внутри компонента. Процитированный в процентах октет кодируется как символьный триплет, состоящий из символа процента «%», за которым следуют две шестнадцатеричные цифры, представляющие числовое значение этого октета. Например, «%20» — это кодировка процента для двоичного октета «00100000» (ABNF: %x20), который в US-ASCII соответствует пробелу (SP). Раздел 2.4 описывает, когда применяется процентное кодирование и декодирование.

pct-encoded = "%" HEXDIG HEXDIG

Шестнадцатеричные цифры в верхнем регистре от «A» до «F» эквивалентны строчным цифрам от «a» до «f» соответственно. Если два URI отличаются только в случае шестнадцатеричных цифр, используемых в октетах с кодированием в процентах, они эквивалентны. Для обеспечения согласованности производители и нормализаторы URI должны использовать шестнадцатеричные цифры в верхнем регистре для всех процентных кодировок.

2.2. Зарезервированные символы

URI включают компоненты и подкомпоненты, которые разделены символами в «зарезервированном» наборе. Эти символы называются «зарезервированными», потому что они могут (или не могут) быть определены как разделители общим синтаксисом, каждым синтаксисом, специфичным для схемы, или специфичным для реализации синтаксисом алгоритма разыменования URI. Если данные для компонента URI будут конфликтовать с назначением зарезервированного символа в качестве разделителя, то конфликтующие данные должны быть закодированы в процентах до формирования URI.

reserved = gen-delims / sub-delims
gen-delims = ":"   "/"   "?"   "#"   "["   "]"   "@"
sub-delims = "!"   "$"   "&"   "’"   "("   ")"   "*"   "+"   ","   ";"   "="

Цель зарезервированных символов — предоставить набор символов-разделителей, которые можно отличить от других данных в URI. URI, которые отличаются заменой зарезервированного символа соответствующим октетом в процентах, не эквивалентны. Процентное кодирование зарезервированного символа или декодирование процентного кодированного октета, который соответствует зарезервированному символу, изменит то, как URI интерпретируется большинством приложений. Таким образом, символы в зарезервированном наборе защищены от нормализации и поэтому безопасны для использования алгоритмами, специфичными для схемы и производителя, для разграничения подкомпонентов данных в URI.

«Подмножество зарезервированных символов» (gen-delims) используется в качестве разделителей общих компонентов URI, описанных в разделе 3. Синтаксическое правило ABNF компонента не будет напрямую использовать имена зарезервированных или gen-delims правил; вместо этого каждое правило синтаксиса перечисляет символы, разрешенные в этом компоненте (то есть не ограничивая его), и любые из тех символов, которые также находятся в зарезервированном наборе, «зарезервированы» для использования в качестве разделителей подкомпонентов в компоненте. Только самые распространенные подкомпоненты определены этой спецификацией; другие подкомпоненты могут быть определены спецификацией схемы URI или специфичным для реализации синтаксисом алгоритма разыменования URI, при условии, что такие подкомпоненты ограничены символами в зарезервированном наборе, разрешенном в этом компоненте.

Приложения, производящие URI, должны кодировать октеты данных в процентах, которые соответствуют символам в зарезервированном наборе, если только эти символы специально не разрешены схемой URI для представления данных в этом компоненте. Если зарезервированный символ найден в компоненте URI, и для этого символа не известна роль разграничения, он должен интерпретироваться как представляющий октет данных, соответствующий кодировке этого символа в US-ASCII.

2.3. Незарезервированные символы

Символы, которые разрешены в URI, но не имеют зарезервированной цели, называются «незарезервированными» (unreserved). К ним относятся прописные и строчные буквы, десятичные цифры, дефис, точка, подчеркивание и тильда.

unreserved = ALPHA  DIGIT  "-"  "."  "_"  "~"

URI, которые отличаются заменой незарезервированного символа на соответствующий октет US-ASCII, закодированный в процентах, эквивалентны: они идентифицируют один и тот же ресурс. Однако реализации сравнения URI не всегда выполняют нормализацию перед сравнением (см. Раздел 6). Для согласованности, октеты в процентах в диапазонах ALPHA (% 41-% 5A  и % 61-% 7A), DIGIT (% 30-% 39), дефис (% 2D), период (% 2E), подчеркивание (% 5F), или тильда (% 7E) не должна создаваться производителями URI и, если она найдена в URI, должна быть декодирована в соответствующие им незарезервированные символы нормализаторами URI.

2.4. Когда кодировать или декодировать

При нормальных обстоятельствах единственное время, когда октеты в URI кодируются в процентах, это во время процесса создания URI из его составных частей. Это когда реализация определяет, какие из зарезервированных символов должны использоваться в качестве разделителей подкомпонентов, а какие можно безопасно использовать в качестве данных. После создания URI всегда находится в процентно-кодированной форме.

При разыменовании URI компоненты и подкомпоненты, имеющие значение для процесса разыменования для конкретной схемы (если есть), должны быть проанализированы и разделены, прежде чем октеты в этих компонентах, закодированные в процентах, могут быть безопасно декодированы, так как в противном случае данные могут быть ошибочно приняты за компонент разделители. Единственное исключение — октеты с кодированием в процентах, соответствующие символам в незарезервированном наборе, которые могут быть декодированы в любое время. Например, октет, соответствующий символу тильды («~»), часто кодируется как «% 7E» в более старых реализациях обработки URI; «% 7E» можно заменить на «~» без изменения его интерпретации.

Поскольку символ процента («%») служит индикатором для октетов, закодированных в процентах, он должен быть закодирован в процентах как «% 25» для того, чтобы этот октет использовался в качестве данных в URI. Реализации не должны кодировать или декодировать проценты одну и ту же строку более одного раза, так как декодирование уже декодированной строки может привести к неверному истолкованию октета данных процента как начала кодирования процента, или наоборот, в случае кодирования процента уже процентная строка.

2.5. Идентификация данных

Символы URI предоставляют идентифицирующие данные для каждого из компонентов URI, выступая в качестве внешнего интерфейса для идентификации между системами. Хотя наличие и характер производственного интерфейса URI скрыт от клиентов, использующих его URI (и, следовательно, выходит за рамки требований к функциональной совместимости, определенных в этой спецификации), он часто является источником путаницы и ошибок при интерпретации проблемы символа URI. Разработчики должны знать, что в создании и передаче URI участвуют несколько кодировок символов:

  • локальное имя и кодировка данных (local name and data encoding)
  • кодировка открытого интерфейса (public interface encoding)
  • кодировка символов URI (URI character encoding)
  • кодировка формата данных (data format encoding)
  • кодировка протокола (protocol encoding)

Локальные имена, такие как имена файловых систем, хранятся с локальной кодировкой символов. Приложения, создающие URI (например, серверы происхождения — origin servers), обычно используют локальную кодировку в качестве основы для создания значимых имен. Производитель URI преобразует локальную кодировку в кодировку, подходящую для общедоступного интерфейса, а затем преобразует кодировку общедоступного интерфейса в ограниченный набор символов URI (зарезервированное, незарезервированное и процентное кодирование). Эти символы, в свою очередь, кодируются как октеты для использования в качестве ссылки в формате данных (например, кодировке документа), и такие форматы данных часто впоследствии кодируются для передачи по интернет-протоколам.

Для большинства систем незарезервированный символ, появляющийся в компоненте URI, интерпретируется как представляющий октет данных, соответствующий кодировке этого символа в US-ASCII. Потребители URI предполагают, что буква «X» соответствует октету «01011000», и даже если это предположение неверно, его создание не повредит. Система, которая внутренне предоставляет идентификаторы в форме другой кодировки символов, например EBCDIC, обычно выполняет преобразование символов текстовых идентификаторов в UTF-8 [STD63] (или некоторый другой расширенный набор кодировки символов US-ASCII) во внутренней интерфейс, тем самым предоставляя более значимые идентификаторы, чем те, которые являются результатом простого кодирования процентов оригинальных октетов.

Например, рассмотрим информационную службу, которая предоставляет данные, хранящиеся локально с использованием файловой системы на основе EBCDIC, клиентам в Интернете через HTTP-сервер. Когда автор создает файл с именем «Laguna Beach» в этой файловой системе, ожидается, что URI «http», соответствующий этому ресурсу, будет содержать значимую строку «Laguna% 20Beach». Однако если этот сервер создает URI с использованием слишком упрощенного сопоставления необработанных октетов, то результатом будет URI, содержащий «%D3%81%87%A4%95%81@%C2%85%81%83%88«, Внутренний интерфейс транскодирования устраняет эту проблему путем транскодирования локального имени в расширенный набор US-ASCII до создания URI. Естественно, для правильной интерпретации входящего URI на таком интерфейсе требуется, чтобы октеты с кодированием в процентах были декодированы (например, от «%20» до SP), прежде чем обратное транскодирование будет применено для получения локального имени.

В некоторых случаях внутренний интерфейс между компонентом URI и идентифицирующими данными, которыми он был создан для представления, гораздо менее прямой, чем перевод кодировки символов. Например, части URI могут отражать запрос к не-ASCII-данным или числовые координаты на карте. Аналогично, схема URI может определять компоненты с дополнительными требованиями к кодированию, которые применяются до формирования компонента и создания URI.

Когда новая схема URI определяет компонент, который представляет текстовые данные, состоящие из символов из универсального набора символов [UCS], данные должны сначала быть закодированы как октеты в соответствии с кодировкой символов UTF-8 [STD63]; тогда только те октеты, которые не соответствуют символам в незарезервированном наборе, должны кодироваться в процентах. Например, символ A будет представлен как «A», символ LATIN CAPITAL LETTER A WITH GRAVE будет представлен как «%C3%80«, а символ KATAKANA LETTER A будет представлен как «%E3%82%A2«.

3. Синтаксические компоненты

Общий синтаксис URI состоит из иерархической последовательности пяти компонентов:

URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]

hier-part = "//" authority path-abempty (авторитетный путь)
/ path-absolute (абсолютный путь)
/ path-rootless (путь без корней)
/ path-empty (пустой путь)

Компоненты схемы и пути являются обязательными, хотя путь может быть пустым (без символов). При наличии прав доступа путь должен быть либо пустым, либо начинаться с символа косой черты («/»). Если права доступа отсутствуют, путь не может начинаться с двух символов косой черты («//»). Эти ограничения приводят к пяти различным правилам ABNF для пути (раздел 3.3), только одно из которых будет соответствовать любой заданной ссылке URI.

Ниже приведены два примера URI и их составные части:

Два примера URI и их составные части
Два примера URI и их составные части

3.1. Схема

Каждый URI начинается с имени схемы, которое ссылается на спецификацию для назначения идентификаторов в этой схеме. Таким образом, синтаксис URI является интегрированной и расширяемой системой именования, в которой спецификация каждой схемы может дополнительно ограничивать синтаксис и семантику идентификаторов, использующих эту схему.

Имена схем состоят из последовательности символов, начинающихся с буквы и сопровождаемых любой комбинацией букв, цифр, плюса («+»), точки («.») или дефиса («-«). Хотя схемы нечувствительны к регистру, каноническая форма написана строчными буквами, и документы, в которых указаны схемы, должны делать это строчными буквами. Реализация должна принимать заглавные буквы как эквивалентные строчным в именах схем (например, разрешать «HTTP», а также «http») ради надежности, но должна обеспечивать только строчные имена схем для согласованности.

scheme = ALPHA *( ALPHA / DIGIT / «+» / «-» / «.» )

Индивидуальные схемы не указаны в этом документе. Процесс регистрации новых схем URI определяется отдельно [BCP35]. Реестр схем поддерживает соответствие между именами схем и их спецификациями. Рекомендации для разработчиков новых схем URI можно найти в [RFC2718 #]. Спецификации схемы URI должны определять свой собственный синтаксис, чтобы все строки, соответствующие их специфичному для схемы синтаксису, также соответствовали грамматике <absolute-URI>, как описано в разделе 4.3.

При представлении с URI, который нарушает одно или несколько ограничений, специфичных для схемы, процесс разрешения, специфичный для схемы, должен помечать ссылку как ошибку, а не игнорировать неиспользуемые части; это уменьшает количество эквивалентных URI и помогает обнаружить злоупотребления общим синтаксисом, что может указывать на то, что URI был создан для введения пользователя в заблуждение (раздел 7.6).

3.2. Основание

Многие схемы URI включают в себя иерархический элемент, который именуют как «основание«, так что управление пространством имен, определенным оставшейся частью URI, делегируется этому основанию (которое, в свою очередь, может делегировать его далее). Общий синтаксис предоставляет общие средства для разграничения оснований на основе зарегистрированного имени или адреса сервера, а также необязательного порта и информации о пользователе.

Компонент основания (authority component) должен начинаться с двойной косой черты («//») и завершается следующей косой чертой («/»), знаком вопроса («?»), знаком знака числа («#») или концом URI.

authority = [ userinfo «@» ] host [ «:» port ]

Производителям и нормализаторам URI следует опустить разделитель двоеточия «:», который отделяет хост от порта, если компонент порта пуст. Некоторые схемы не допускают подкомпоненты userinfo и/или порта.

Если URI содержит компонент основания, то компонент пути должен быть либо пустым, либо начинаться с символа косой черты («/»). Не проверяющие синтаксические анализаторы (те, которые просто разделяют ссылку на URI на ее основные компоненты) часто будут игнорировать субкомпонентную структуру оснований, рассматривая ее как непрозрачную строку от двойной косой черты до первого завершающего разделителя, до тех пор, пока не будет разыменована ссылка на URI.

3.2.1. Информация о пользователе

Подкомпонент «userinfo» может состоять из имени пользователя и, необязательно, специфической для схемы информации о том, как получить авторизацию для доступа к ресурсу. За информацией о пользователе, если она имеется, следует коммерческий знак («@»), который отделяет ее от хоста.

userinfo = *( unreserved / pct-encoded / sub-delims / «:» )

Использование формата «user: password» в поле userinfo не рекомендуется. Приложения не должны отображать в виде открытого текста любые данные после первого символа двоеточия («:»), найденного в подкомпоненте «userinfo», если только данные после двоеточия не являются пустой строкой (без указания пароля). Приложения могут выбрать игнорирование или отклонение таких данных, когда они получены как часть ссылки, и должны отклонить хранение таких данных в незашифрованном виде. Передача аутентификационной информации в виде открытого текста оказалась угрозой безопасности почти во всех случаях, когда она использовалась.

Приложения, которые отображают URI для обратной связи с пользователем, например, в графическом просмотре гипертекста, должны отображать информацию о пользователе способом, отличным от остальной части URI, когда это возможно. Такой рендеринг поможет пользователю в случаях, когда информация о пользователе была введена в заблуждение, чтобы выглядеть как доверенное доменное имя (Раздел 7.6).

3.2.2. Хост

Подкомпонент «хоста» из основания идентифицируется литералом IP, заключенным в квадратные скобки, адресом IPv4 в точечно-десятичной форме или зарегистрированным именем. Подкомпонент хоста нечувствителен к регистру. Наличие субкомпонента хоста в URI не означает, что схема требует доступа к данному хосту в Интернете. Во многих случаях синтаксис хоста используется только для повторного использования существующего процесса регистрации, созданного и развернутого для DNS, что позволяет получить глобально уникальное имя без затрат на развертывание другого реестра. Однако такое использование сопряжено со своими расходами: право собственности на доменное имя может со временем меняться по причинам, не ожидаемым производителем URI. В других случаях данные в компоненте хоста идентифицируют зарегистрированное имя, которое не имеет ничего общего с интернет-хостом. Мы используем имя «хост» для правила ABNF, потому что это его наиболее распространенная цель, а не единственная цель.

host = IP-literal / IPv4address / reg-name

Правило синтаксиса для хоста неоднозначно, потому что оно не полностью различает IPv4-адрес и имя-регистра. Чтобы устранить неоднозначность синтаксиса, мы применяем алгоритм «first-match-wins»: если хост соответствует правилу для IPv4-адреса, то он должен рассматриваться как литерал адреса IPv4, а не как reg-name. Хотя хост не учитывает регистр, производители и нормализаторы должны использовать строчные буквы для зарегистрированных имен и шестнадцатеричные адреса для единообразия, в то время как только заглавные буквы используются для кодирования процентов.

Хост, идентифицируемый литеральным адресом Интернет-протокола версии 6 [RFC3513 #] или новее, различается заключением литерала IP в квадратные скобки («[» и «]»). Это единственное место, где разрешены символы в квадратных скобках в синтаксисе URI. В ожидании будущих пока еще не определенных форматов буквенных IP-адресов реализация может использовать необязательный флаг версии, чтобы явно указывать такой формат, а не полагаться на эвристическое определение.

IP-literal = «[» ( IPv6address / IPvFuture ) «]»

IPvFuture = «v» 1*HEXDIG «.» 1*( unreserved / sub-delims / «:» )

Флаг версии не указывает версию IP; скорее это указывает на будущие версии буквального формата. Таким образом, реализации не должны предоставлять флаг версии для существующих форм буквенных адресов IPv4 и IPv6, описанных ниже. Если URI, содержащий IP-литерал, начинающийся с «v» (без учета регистра), указывающий на наличие флага версии, разыменовывается приложением, которое не знает значения этого флага версии, тогда приложение должно вернуть соответствующую ошибку для «адресного механизма не поддерживается» (address mechanism not supported).

Хост, идентифицируемый литеральным адресом IPv6, представлен в квадратных скобках без флага предыдущей версии. ABNF, предоставленный здесь, является переводом текстового определения буквального адреса IPv6, предоставленного в [RFC3513 #]. Этот синтаксис не поддерживает идентификаторы зоны адресации в области IPv6.

128-битный адрес IPv6 делится на восемь 16-битных частей. Каждый фрагмент представлен численно в шестнадцатеричном формате без учета регистра, используя от одной до четырех шестнадцатеричных цифр (допускаются начальные нули). Восемь закодированных частей даны самыми значимыми первыми, разделенными двоеточиями По выбору, наименее значимые две части могут быть представлены в текстовом формате адреса IPv4. Последовательность из одного или нескольких последовательных 16-битных фрагментов с нулевым значением в адресе может быть исключена, пропуская все их цифры и оставляя ровно два последовательных двоеточия на своем месте для обозначения исключения.

IPv6address =                6( h16 ":" ) ls32
/                       "::" 5( h16 ":" ) ls32
/               [ h16 ] "::" 4( h16 ":" ) ls32
/ [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
/ [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
/ [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32
/ [ *4( h16 ":" ) h16 ] "::" ls32
/ [ *5( h16 ":" ) h16 ] "::" h16
/ [ *6( h16 ":" ) h16 ] "::"

ls32 = ( h16 ":" h16 ) / IPv4address; (наименее значимый 32-битный адрес)

h16 = 1*4HEXDIG; (16 бит адреса представлены в шестнадцатеричном формате)

«ls32» — это наименее значимый 32-битный адрес

«h16» — это 16 бит адреса представлены в шестнадцатеричном формате

Хост, идентифицируемый литеральным адресом IPv4, представлен в десятично-точечной нотации (последовательность из четырех десятичных чисел в диапазоне от 0 до 255, разделенных «.»), Как описано в [RFC1123 #] со ссылкой на [RFC0952 #]. Обратите внимание, что другие формы точечной нотации могут интерпретироваться на некоторых платформах, как описано в разделе 7.4, но эта грамматика допускает только точечно-десятичную форму из четырех октетов. («десятичный октет» — dec-octet)

IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet

dec-octet = DIGIT ; 0-9
/ %x31-39 DIGIT ; 10-99
/ "1" 2DIGIT ; 100-199
/ "2" %x30-34 DIGIT ; 200-249
/ "25" %x30-35 ; 250-255

Хост, идентифицируемый «зарегистрированным именем» (registered name), представляет собой последовательность символов, обычно предназначенную для поиска в локально определенном реестре хоста или имени службы, хотя для семантики, специфичной для схемы URI, может потребоваться использование определенного реестра (или таблицы фиксированных имен). Наиболее распространенным механизмом регистрации имен является система доменных имен (DNS). Зарегистрированное имя, предназначенное для поиска в DNS, использует синтаксис, определенный в Разделе 3.5 [RFC1034 #] и Разделе 2.1 [RFC1123 #]. Такое имя состоит из последовательности меток домена, разделенных символом «.», Каждая метка домена начинается и заканчивается буквенно-цифровым символом и, возможно, также содержит символы «-». За самой правой доменной меткой полного доменного имени в DNS может следовать одно «.» и должно быть, если необходимо различать полное доменное имя и какой-либо локальный домен.

reg-name = *( unreserved / pct-encoded / sub-delims )

Если схема URI определяет значение по умолчанию для хоста, то это значение по умолчанию применяется, когда подкомпонент хоста не определен или когда зарегистрированное имя пусто (нулевая длина). Например, схема URI «file» определена таким образом, что никакие права доступа, пустой хост и «localhost» не означают машину конечного пользователя, тогда как схема «http» считает отсутствующие права доступа или пустой хост недействительными.

Эта спецификация не требует конкретной технологии поиска зарегистрированных имен и, следовательно, не ограничивает синтаксис reg-name сверх того, что необходимо для совместимости. Вместо этого он делегирует вопрос о соответствии синтаксиса зарегистрированного имени операционной системе каждого приложения, выполняющего разрешение URI, и эта операционная система решает, что она позволит для идентификации хоста. Реализация разрешения URI может использовать DNS, таблицы хостов, желтые страницы, NetInfo, WINS или любую другую систему для поиска зарегистрированных имен. Однако для имен URI, имеющих глобальную область видимости, необходима глобальная система именования, такая как полные доменные имена DNS. Производители URI должны использовать имена, соответствующие синтаксису DNS, даже если использование DNS не является очевидным, и должны ограничивать эти имена длиной не более 255 символов.

Синтаксис reg-name позволяет кодировать октеты в процентах, чтобы представлять зарегистрированные имена, не входящие в ASCII, единообразным способом, независимым от базовой технологии разрешения имен. Символы, не входящие в ASCII, должны сначала кодироваться в соответствии с UTF-8 [STD63], а затем каждый октет соответствующей последовательности UTF-8 должен кодироваться в процентах для представления в виде символов URI. Приложения, производящие URI, не должны использовать процентное кодирование в хосте, если оно не используется для представления последовательности символов UTF-8. Если зарегистрированное имя не в формате ASCII представляет собой интернационализированное доменное имя, предназначенное для разрешения через DNS, имя должно быть преобразовано в кодировку IDNA [RFC3490 #] до поиска имени. Производители URI должны предоставить эти зарегистрированные имена в кодировке IDNA, а не в процентном кодировании, если они хотят максимизировать совместимость с устаревшими распознавателями URI.

3.2.3. Порт

Подкомпонент «порт» из основания обозначается необязательным номером порта в десятичном формате после хоста и отделяется от него одним двоеточием («:»).

port = *DIGIT

Схема может определять порт по умолчанию. Например, схема «http» определяет порт по умолчанию «80», соответствующий его зарезервированному номеру порта TCP. Тип порта, обозначенный номером порта (например, TCP, UDP, SCTP), определяется схемой URI. Производителям и нормализаторам URI следует опустить компонент порта и его разделитель «:», если порт пуст или если его значение будет таким же, как и для значения по умолчанию схемы.

3.3. Путь

Компонент пути содержит данные, обычно организованные в иерархической форме, которые наряду с данными в неиерархическом компоненте запросов (раздел 3.4) служат для идентификации ресурса в рамках схемы URI и основания по присвоению имен (если таковые имеются). Путь завершается первым знаком вопроса («?») или знаком числа («#») или концом URI.

Если URI содержит компонент основания, то компонент пути должен быть либо пустым, либо начинаться с символа косой черты («/»). Если URI не содержит компонента основания, путь не может начинаться с двух символов косой черты («//»). Кроме того, ссылка на URI (раздел 4.1) может быть ссылкой на относительный путь, и в этом случае первый «сегмент» (segment) пути не может содержать двоеточие («:»). ABNF требует пяти отдельных правил для устранения неоднозначности этих случаев, только одно из которых будет соответствовать подстроке пути в данной ссылке URI. Мы используем общий термин «компонент пути» для описания подстроки URI, сопоставленной синтаксическим анализатором с одним из этих правил.

path         = path-abempty ; begins with "/" or is empty
/ path-absolute ; begins with "/" but not "//"
/ path-noscheme ; begins with a non-colon segment
/ path-rootless ; begins with a segment
/ path-empty ; zero characters

path-abempty  = *( "/" segment )
path-absolute = "/" [ segment-nz *( "/" segment ) ]
path-noscheme = segment-nz-nc *( "/" segment )
path-rootless = segment-nz *( "/" segment )
path-empty    = 0<pchar>

segment       = *pchar
segment-nz    = 1*pchar
segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
; non-zero-length segment without any colon ":"

pchar        = unreserved / pct-encoded / sub-delims / ":" / "@"

Путь состоит из последовательности сегментов пути, разделенных символом косой черты («/»). Путь всегда определяется для URI, хотя указанный путь может быть пустым (нулевой длины). Использование символа косой черты для обозначения иерархии требуется только в том случае, если в качестве контекста для относительных ссылок будет использоваться URI. Например, URI <mailto:fred@example.com>; имеет путь «fred@example.com», а URI <foo://info.example.com?fred>; имеет пустой путь.

Путь сегментов «.» и «..», также известный как «точечные сегменты» (dot-segments), определены для относительной ссылки в иерархии имен путей. Они предназначены для использования в начале ссылки на относительный путь (раздел 4.2) для указания относительного положения в иерархическом дереве имен. Это похоже на их роль в структурах файловых каталогов некоторых операционных систем для указания текущего каталога и родительского каталога соответственно. Однако, в отличие от файловой системы, эти точечные сегменты интерпретируются только в иерархии путей URI и удаляются как часть процесса разрешения (раздел 5.2).

Помимо точечных сегментов в иерархических путях, сегмент пути считается непрозрачным по общему синтаксису. Приложения, генерирующие URI, часто используют зарезервированные символы, разрешенные в сегменте, для разграничения подкомпонентов, специфичных для схемы или обработчика разыменования. Например, зарезервированные символы точки с запятой («;») и равенства («=») часто используются для разделения параметров и значений параметров, применимых к этому сегменту. Запятая («,») зарезервированный символ часто используется для аналогичных целей. Например, один производитель URI может использовать сегмент, такой как «name;v=1.1«, чтобы указать ссылку на версию 1.1 «name», тогда как другой может использовать сегмент, такой как «name,1.1«, чтобы указать то же самое. Типы параметров могут быть определены семантикой, специфичной для схемы, но в большинстве случаев синтаксис параметра является специфическим для реализации алгоритма разыменования URI.

3.4. Запрос

Компонент запроса содержит неиерархические данные, которые наряду с данными в компоненте пути (раздел 3.3) служат для идентификации ресурса в рамках схемы URI и основания по присвоению имен (если таковые имеются). Компонент запроса обозначается символом первого вопросительного знака («?») И оканчивается символом знака числа («#») или концом URI.

query = *( pchar / "/" / "?" )

Косая черта («/») и знак вопроса («?») Могут представлять данные в компоненте запроса. Помните, что некоторые старые, ошибочные реализации могут некорректно обрабатывать такие данные, когда они используются в качестве базового URI для относительных ссылок (раздел 5.1), очевидно, потому что они не могут отличить данные запроса от данных пути при поиске иерархических разделителей. Однако, поскольку компоненты запроса часто используются для передачи идентифицирующей информации в виде пар «ключ = значение» («key=value»), а одно часто используемое значение является ссылкой на другой URI, иногда для удобства использования лучше избегать процентного кодирования этих символов.

3.5. Фрагмент

Компонент идентификатора фрагмента URI позволяет косвенно идентифицировать вторичный ресурс посредством ссылки на первичный ресурс и дополнительной идентифицирующей информации. Идентифицированный вторичный ресурс может быть некоторой частью или подмножеством первичного ресурса, некоторым представлением представлений первичного ресурса или некоторым другим ресурсом, определенным или описанным этими представлениями. Компонент идентификатора фрагмента указывается присутствием символа знака числа («#») и заканчивается концом URI.

fragment = *( pchar / "/" / "?" )

Семантика идентификатора фрагмента определяется набором представлений, которые могут возникнуть в результате действия поиска на первичном ресурсе. Таким образом, формат и разрешение фрагмента зависят от типа носителя [RFC2046] потенциально извлеченного представления, даже если такое извлечение выполняется только в том случае, если URI разыменовывается. Если такого представления не существует, то семантика фрагмента считается неизвестной и фактически не ограничена. Семантика идентификатора фрагмента не зависит от схемы URI и, следовательно, не может быть переопределена спецификациями схемы.

Отдельные типы мультимедиа могут определять свои собственные ограничения или структуры в синтаксисе идентификатора фрагмента для указания различных типов подмножеств, представлений или внешних ссылок, которые можно идентифицировать как вторичные ресурсы по этому типу мультимедиа. Если первичный ресурс имеет несколько представлений, как это часто бывает для ресурсов, представление которых выбирается на основе атрибутов запроса поиска (например, согласование содержимого), то все, что идентифицировано фрагментом, должно быть согласованным во всех этих представлениях. Каждое представление должно либо определять фрагмент так, чтобы оно соответствовало одному и тому же вторичному ресурсу, независимо от того, как оно представлено, либо должно оставлять фрагмент неопределенным (т.е. не найденным).

Как и в случае любого URI, использование компонента идентификатора фрагмента не означает, что будет выполнено действие поиска. URI с идентификатором фрагмента может использоваться для ссылки на вторичный ресурс без какого-либо указания на то, что первичный ресурс доступен или когда-либо будет доступен.

Идентификаторы фрагментов играют особую роль в системах поиска информации в качестве основной формы косвенных ссылок на стороне клиента, позволяя автору конкретно идентифицировать аспекты существующего ресурса, которые только косвенно предоставляются владельцем ресурса. Как таковой, идентификатор фрагмента не используется в специфичной для схемы обработке URI; вместо этого идентификатор фрагмента отделяется от остальной части URI до разыменования, и, таким образом, идентифицирующая информация в самом фрагменте разыменовывается исключительно пользовательским агентом, независимо от схемы URI. Хотя эта отдельная обработка часто воспринимается как потеря информации, особенно для точного перенаправления ссылок, когда ресурсы перемещаются с течением времени, она также служит для того, чтобы поставщики информации не могли отказывать авторам ссылок в избирательном доступе к информации внутри ресурса. Косвенные ссылки также обеспечивают дополнительную гибкость и расширяемость для систем, которые используют URI, поскольку новые типы носителей легче определить и развернуть, чем новые схемы идентификации.

Символы косой черты («/») и вопросительного знака («?») могут представлять данные в идентификаторе фрагмента. Помните, что некоторые более старые ошибочные реализации могут некорректно обрабатывать эти данные, когда они используются в качестве базового URI для относительных ссылок (раздел 5.1).

4. Использование

Когда приложения делают ссылку на URI, они не всегда используют полную форму ссылки, определенную правилом синтаксиса «URI». Чтобы сэкономить пространство и использовать преимущества иерархической локализации, многие элементы интернет-протокола и форматы медиа-типов позволяют сокращать URI, тогда как другие ограничивают синтаксис конкретной формой URI. Мы определяем наиболее распространенные формы эталонного синтаксиса в этой спецификации, потому что они влияют и зависят от структуры общего синтаксиса, требующего единого алгоритма синтаксического анализа для последовательной интерпретации.

4.1. Ссылка на URI

«URI-ссылка» используется для обозначения наиболее распространенного использования идентификатора ресурса.

URI-reference = URI / relative-ref

URI-ссылка — это либо URI, либо относительная ссылка. Если префикс URI-ссылки не соответствует синтаксису схемы, за которой следует разделитель двоеточий, тогда URI-ссылка является относительной ссылкой.

URI-ссылка обычно сначала разбирается на пять компонентов URI, чтобы определить, какие компоненты присутствуют и является ли ссылка относительной. Затем каждый компонент анализируется на предмет его частей и их проверки. ABNF URI-ссылки вместе с правилом устранения неоднозначности «first-match-wins» достаточно для определения проверяющего синтаксического анализатора для общего синтаксиса. Читатели, знакомые с регулярными выражениями, должны увидеть в Приложении B пример не проверяющего анализатора URI-ссылок, который будет принимать любую заданную строку и извлекать компоненты URI.

4.2. Относительная ссылка

Относительная ссылка использует преимущества иерархического синтаксиса (раздел 1.2.3) для выражения ссылки URI относительно пространства имен другого иерархического URI.

relative-ref = relative-part [ "?" query ] [ "#" fragment ]

relative-part = "//" authority path-abempty
/ path-absolute
/ path-noscheme
/ path-empty

URI, на который ссылается относительная ссылка, также известная как целевой URI, получается путем применения алгоритма эталонного разрешения из Раздела 5.

Относительная ссылка, которая начинается с двух символов косой черты «//», называется ссылкой на «сетевой путь» (network-path); такие ссылки используются редко. Относительная ссылка, которая начинается с одного символа косой черты «/», называется ссылкой абсолютного пути. Относительная ссылка, которая не начинается с символа косой черты, называется ссылкой на относительный путь.

Сегмент пути, который содержит символ двоеточия «:» (например, «this:that»), нельзя использовать в качестве первого сегмента ссылки на относительный путь, так как он будет ошибочно принят за имя схемы. Такому сегменту должен предшествовать точечный сегмент (например, «./this:that»), чтобы сделать ссылку на относительный путь.

4.3. Абсолютный URI

Некоторые элементы протокола допускают только «абсолютную» форму URI без идентификатора фрагмента. Например, определение базового URI для последующего использования относительными ссылками требует правила синтаксиса «абсолютного URI» (absolute-URI), которое не допускает фрагмент.

absolute-URI = scheme ":" hier-part [ "?" query ]

Спецификации схемы URI должны определять свой собственный синтаксис, чтобы все строки, соответствующие их специфичному для схемы синтаксису, также соответствовали грамматике <absolute-URI>. Спецификации схемы не будут определять синтаксис или использование идентификатора фрагмента, независимо от его применимости к ресурсам, идентифицируемым посредством этой схемы, поскольку идентификация фрагмента ортогональна определению схемы. Однако рекомендуется, чтобы спецификации схемы включали в себя широкий спектр примеров, в том числе примеры, которые показывают использование URI схемы с идентификаторами фрагментов, когда такое использование целесообразно.

4.4. Ссылка на тот же документ

Когда ссылка URI ссылается на URI, который, кроме своего фрагмента (если есть), идентичен базовому URI (раздел 5.1), эта ссылка называется ссылкой на «тот же документ» (same-document). Наиболее частыми примерами ссылок на один и тот же документ являются относительные ссылки, которые пусты или содержат только разделитель знака числа («#»), за которым следует идентификатор фрагмента.

Когда ссылка на тот же документ разыменовывается для действия поиска, цель этой ссылки определяется как находящаяся в той же сущности (представление, документ или сообщение), что и ссылка; следовательно, разыменование не должно приводить к новому поисковому действию.
Нормализация базовых и целевых URI перед их сравнением, как описано в разделах 6.2.2 и 6.2.3, разрешена, но редко выполняется на практике.

Нормализация может увеличить набор ссылок на один и тот же документ, что может быть полезно для некоторых приложений кэширования. Таким образом, авторы ссылок не должны предполагать, что слегка отличающийся, хотя и эквивалентный, ссылочный URI будет (или не будет) интерпретироваться как ссылка на один и тот же документ какой-либо данной заявкой.

4.5. Суффикс ссылка

Синтаксис URI разработан для однозначной ссылки на ресурсы и расширяемости через схему URI. Однако по мере того, как идентификация и использование URI стали обычным явлением, традиционные средства массовой информации (телевидение, радио, газеты, рекламные щиты и т. д.) Все чаще используют «суффикс» URI в качестве справочного материала, состоящий только из авторитетных частей и частей пути URI, таких как как

www.w3.org/Addressing/

или просто зарегистрированное имя DNS самостоятельно. Такие ссылки в первую очередь предназначены для интерпретации человеком, а не для машин, при условии, что основанная на контексте эвристика достаточна для завершения URI (например, большинство зарегистрированных имен, начинающихся с «www«, вероятно, имеют префикс URI «http://«). Хотя нет стандартного набора эвристик для устранения неоднозначности суффикса URI, многие клиентские реализации позволяют вводить их пользователю и разрешать эвристически.

Хотя такая практика использования ссылок на суффиксы является обычной, ее следует по возможности избегать и никогда не следует использовать в ситуациях, когда ожидаются долгосрочные ссылки. Вышеупомянутая эвристика будет меняться со временем, особенно когда новая схема URI становится популярной, и часто некорректна, когда используется вне контекста. Кроме того, они могут привести к проблемам безопасности, аналогичным тем, которые описаны в [RFC1535 #].

Поскольку суффикс URI имеет тот же синтаксис, что и ссылка на относительный путь, ссылка на суффикс не может использоваться в тех случаях, когда ожидается относительная ссылка. В результате ссылки на суффиксы ограничены местами, где нет определенного базового URI, такими как диалоговые окна и автономные рекламные объявления.

5. Справочное разрешение

В этом разделе описывается процесс разрешения ссылки URI в контексте, который допускает относительные ссылки, так что в результате получается строка, соответствующая правилу синтаксиса <URI> Раздела 3.

5.1. Установление базового URI

Термин «относительный» подразумевает, что существует «базовый URI», к которому применяется относительная ссылка. Помимо ссылок только для фрагментов (раздел 4.4), относительные ссылки могут использоваться только тогда, когда известен базовый URI. Базовый URI должен быть установлен синтаксическим анализатором до анализа ссылок URI, которые могут быть относительными. Базовый URI должен соответствовать синтаксическому правилу <absolute-URI> (раздел 4.3). Если базовый URI получен из ссылки на URI, то эта ссылка должна быть преобразована в абсолютную форму и удалена из любого фрагмента компонента перед его использованием в качестве базового URI.

Базовый URI ссылки может быть установлен одним из четырех способов, обсуждаемых ниже в порядке приоритета. Порядок приоритета можно представить в терминах слоев, где наиболее определенный базовый URI имеет наивысший приоритет. Это можно визуализировать графически следующим образом:

Порядок приоритета можно представить в терминах слоев, где наиболее определенный базовый URI имеет наивысший приоритет
Порядок приоритета можно представить в терминах слоев, где наиболее определенный базовый URI имеет наивысший приоритет

5.1.1. Базовый URI, встроенный в контент

В определенных типах мультимедиа базовый URI для относительных ссылок может быть встроен в сам контент, так что он может быть легко получен синтаксическим анализатором. Это может быть полезно для описательных документов, таких как оглавления, которые могут быть переданы другим через протоколы, отличные от их обычного поискового контекста (например, электронная почта или новости USENET).

В объем данной спецификации не входит указание того, как для каждого типа мультимедиа может быть встроен базовый URI. Соответствующий синтаксис, если он доступен, описывается спецификацией формата данных, связанной с каждым типом носителя.

5.1.2. Базовый URI от инкапсулирующего объекта

Если базовый URI не внедрен, базовый URI определяется контекстом извлечения представления. Для документа, который вложен в другую сущность, такую как сообщение или архив, контекст извлечения является этой сущностью. Таким образом, базовый URI по умолчанию для представления является базовым URI объекта, в который инкапсулировано представление.

Механизм для встраивания базового URI в типы контейнеров MIME (например, сообщения и составные типы) определяется в MHTML [RFC2557 #]. Протоколы, которые не используют синтаксис заголовка сообщения MIME, но допускают включение метаданных некоторой формы в сообщения, могут определять свой собственный синтаксис для определения базового URI как части сообщения.

5.1.3. Базовый URI из URI получения

Если базовый URI не внедрен и представление не инкапсулировано в какой-либо другой сущности, то, если URI использовался для извлечения представления, этот URI должен рассматриваться как базовый URI. Обратите внимание, что если получение было результатом перенаправленного запроса, последний использованный URI (то есть URI, который привел к фактическому извлечению представления) является базовым URI.

5.1.4. Базовый URI по умолчанию

Если ни одно из условий, описанных выше, не применимо, то базовый URI определяется контекстом приложения. Поскольку это определение обязательно зависит от приложения, отказ определить базовый URI с помощью одного из других методов может привести к тому, что один и тот же контент по-разному интерпретируется различными типами приложений.

Отправитель представления, содержащего относительные ссылки, отвечает за обеспечение возможности установки базового URI для этих ссылок. Помимо ссылок только для фрагментов, относительные ссылки могут надежно использоваться только в ситуациях, когда базовый URI четко определен.

5.2. Относительное разрешение

В этом разделе описывается алгоритм для преобразования ссылки URI, которая может относиться к данному базовому URI, в анализируемые компоненты цели ссылки. Затем компоненты могут быть перекомпонованы, как описано в разделе 5.3, для формирования целевого URI. Этот алгоритм обеспечивает точные результаты, которые можно использовать для проверки выходных данных других реализаций. Приложения могут реализовывать относительное эталонное разрешение, используя некоторый другой алгоритм, при условии, что результаты соответствуют тому, что будет дано этим.

5.2.1. Предварительный анализ базового URI

Базовый URI (базовый) устанавливается в соответствии с процедурой, описанной в разделе 5.1, и разбивается на пять основных компонентов, описанных в разделе 3. Обратите внимание, что в базовом URI должен присутствовать только компонент схемы; другие компоненты могут быть пустыми или неопределенными. Компонент не определен, если связанный с ним разделитель не отображается в ссылке URI; компонент пути никогда не является неопределенным, хотя он может быть пустым.

Нормализация базового URI, как описано в разделах 6.2.2 и 6.2.3, является необязательной. Ссылка на URI должна быть преобразована в целевой URI, прежде чем ее можно будет нормализовать.

5.2.2. Преобразование ссылок

Для каждой ссылки URI («R» — URI reference) следующий псевдокод описывает алгоритм для преобразования R в его целевой URI («T» — target URI):

Ссылка на URI разбирается на пять компонентов URI

(R.scheme, R.authority, R.path, R.query, R.fragment) = parse(R);

Схема, основание, путь, запрос, фрагмент

Не строгий синтаксический анализатор может игнорировать схему в ссылке, если она идентична схеме базового URI.

if ((not strict) and (R.scheme == Base.scheme)) then
  undefine(R.scheme);
endif;
if defined(R.scheme) then
  T.scheme = R.scheme;
  T.authority = R.authority;
  T.path = remove_dot_segments(R.path);
  T.query = R.query;
else
  if defined(R.authority) then
    T.authority = R.authority;
    T.path = remove_dot_segments(R.path);
    T.query = R.query;
  else
    if (R.path == "") then
    T.path = Base.path;
      if defined(R.query) then
        T.query = R.query;
      else
        T.query = Base.query;
      endif;
    else
      if (R.path starts-with "/") then
        T.path = remove_dot_segments(R.path);
      else
        T.path = merge(Base.path, R.path);
        T.path = remove_dot_segments(T.path);
      endif;
      T.query = R.query;
    endif;
    T.authority = Base.authority;
  endif;
  T.scheme = Base.scheme;
endif;

T.fragment = R.fragment;

5.2.3. Слияние путей

Приведенный выше псевдокод относится к процедуре «слияния» (merge) для объединения ссылки относительного пути с путем базового URI. Это достигается следующим образом:

  • Если базовый URI имеет определенный компонент основания и пустой путь, тогда вернуть строку, состоящую из «/», соединенную с путем ссылки; иначе,
  • вернуть строку, состоящую из компонента пути ссылки, добавленного ко всем, кроме последнего сегмента пути базового URI (т.е. исключая любые символы после крайнего правого «/» в пути базового URI, или исключая весь путь базового URI, если он не содержит символов «/»).

5.2.4. Удалить точечные сегменты

Псевдокод также ссылается на подпрограмму «remove_dot_segments» для интерпретации и удаления специального «.» и «..» завершить сегменты пути по указанному пути. Это делается после того, как путь извлекается из ссылки независимо от того, был ли путь относительным или нет, чтобы удалить любые недопустимые или посторонние точечные сегменты до формирования целевого URI. Хотя существует много способов выполнить этот процесс удаления, мы описываем простой метод с использованием двух строковых буферов.

1. Входной буфер инициализируется с добавленными теперь компонентами пути, а выходной буфер инициализируется пустой строкой.

2. Пока входной буфер не пустой, выполните цикл следующим образом:

  • A. Если входной буфер начинается с префикса «../» или «./», то удалите этот префикс из входного буфера; иначе,
  • B. Если входной буфер начинается с префикса «/./» или «/.», Где «.» является полным сегментом пути, затем замените этот префикс на «/» во входном буфере; иначе,
  • C. Если входной буфер начинается с префикса «/../» или «/..», где «..» — полный сегмент пути, то замените этот префикс на «/» во входном буфере и удалите последний сегмент и его предшествующий «/» (если есть) из буфера вывода; иначе,
  • D. Если входной буфер состоит только из «.» или «..», затем удалите это из буфера ввода; иначе,
  • E. Переместите первый сегмент пути во входном буфере в конец выходного буфера, включая начальный символ «/» (если есть) и любые последующие символы до, но не включая следующий символ «/» или конец входного буфера.

3. Наконец, выходной буфер возвращается как результат remove_dot_segments.

Обратите внимание, что точечные сегменты предназначены для использования в ссылках URI для выражения идентификатора относительно иерархии имен в базовом URI. Алгоритм remove_dot_segments учитывает эту иерархию, удаляя лишние точечные сегменты, а не рассматривая их как ошибку или оставляя их для неверной интерпретации реализациями разыменования.

Далее показано, как вышеуказанные шаги применяются для двух примеров объединенных путей, показывая состояние двух буферов после каждого шага.

Два примера объединенных путей - состояние двух буферов после каждого шага
Два примера объединенных путей — состояние двух буферов после каждого шага

В некоторых приложениях может оказаться более эффективным реализовать алгоритм remove_dot_segments с использованием двух стеков сегментов, а не строк.

Примечание. Помните, что некоторые более старые ошибочные реализации не смогут отделить компонент запроса ссылки от его компонента пути до объединения базового и ссылочного путей, что приведет к ошибке взаимодействия, если компонент запроса содержит строки «/../» или « /./».

5.3. Компонент перекомпоновки

Проанализированные компоненты URI могут быть перекомпонованы для получения соответствующей строки ссылки на URI. Используя псевдокод, это будет:

result = ""
if defined(scheme) then
   append scheme to result;
   append ":" to result;
endif;
if defined(authority) then
   append "//" to result;
   append authority to result;
endif;
append path to result;
if defined(query) then
   append "?" to result;
   append query to result;
endif;
if defined(fragment) then
   append "#" to result;
   append fragment to result;
endif;
return result;

Обратите внимание, что мы тщательно сохраняем различие между компонентом, который не определен, что означает, что его разделитель отсутствовал в ссылке, и компонентом, который является пустым, что означает, что разделитель присутствовал и за ним сразу следовал следующий разделитель компонента или конец ссылки.

5.4. Примеры разрешения ссылок

В представлении с четко определенным базовым URI

http://a/b/c/d;p?q

относительная ссылка преобразуется в целевой URI следующим образом.

5.4.1. Нормальные примеры

"g:h"     = "g:h"
"g"       = "http://a/b/c/g"
"./g"     = "http://a/b/c/g"
"g/"      = "http://a/b/c/g/"
"/g"      = "http://a/g"
"//g"     = "http://g"
"?y"      = "http://a/b/c/d;p?y"
"g?y"     = "http://a/b/c/g?y"
"#s"      = "http://a/b/c/d;p?q#s"
"g#s"     = "http://a/b/c/g#s"
"g?y#s"   = "http://a/b/c/g?y#s"
";x"      = "http://a/b/c/;x"
"g;x"     = "http://a/b/c/g;x"
"g;x?y#s" = "http://a/b/c/g;x?y#s"
""        = "http://a/b/c/d;p?q"
"."       = "http://a/b/c/"
"./"      = "http://a/b/c/"
".."      = "http://a/b/"
"../"     = "http://a/b/"
"../g"    = "http://a/b/g"
"../.."   = "http://a/"
"../../"  = "http://a/"
"../../g" = "http://a/g"

5.4.2. Ненормальные примеры

Хотя следующие ненормальные примеры маловероятны в обычной практике, все анализаторы URI должны быть способны разрешать их последовательно. Каждый пример использует ту же базу, что и выше.

Синтаксические анализаторы должны быть осторожны при обработке случаев, когда в ссылке на относительный путь больше сегментов «..», чем в базовом URI-уровне. Обратите внимание, что синтаксис «..» не может использоваться для изменения компонента полномочий URI.

"../../../g"    = "http://a/g"
"../../../../g" = "http://a/g"

Аналогично, парсеры (семантические анализаторы) должны удалить точечные сегменты «.» и «..», когда они являются полными компонентами пути, но не когда они являются только частью сегмента.

"/./g"  = "http://a/g"
"/../g" = "http://a/g"
"g."    = "http://a/b/c/g."
".g"    = "http://a/b/c/.g"
"g.."   = "http://a/b/c/g.."
"..g"   = "http://a/b/c/..g"

Менее вероятны случаи, когда относительная ссылка использует ненужные или бессмысленные формы «.» и «..» завершить сегменты пути.

"./../g"     = "http://a/b/g"
"./g/."      = "http://a/b/c/g/"
"g/./h"      = "http://a/b/c/g/h"
"g/../h"     = "http://a/b/c/h"
"g;x=1/./y"  = "http://a/b/c/g;x=1/y"
"g;x=1/../y" = "http://a/b/c/y"

Некоторым приложениям не удается отделить компоненты запроса и / или фрагмента ссылки от компонента пути перед тем, как объединить его с базовым путем и удалить точечные сегменты. Эта ошибка редко замечается, так как типичное использование фрагмента никогда не включает символ иерархии («/»), а компонент запроса обычно не используется в относительных ссылках.

"g?y/./x"  = "http://a/b/c/g?y/./x"
"g?y/../x" = "http://a/b/c/g?y/../x"
"g#s/./x"  = "http://a/b/c/g#s/./x"
"g#s/../x" = "http://a/b/c/g#s/../x"

Некоторые синтаксические анализаторы позволяют имени схемы присутствовать в относительной ссылке, если оно совпадает с базовой схемой URI. Это считается пробелом в предыдущих спецификациях частичного URI [RFC1630 #]. Следует избегать его использования, но допускается обратная совместимость.

"http:g" = "http:g"         ; для строгих парсеров
         / "http://a/b/c/g" ; для обратной совместимости

6. Нормализация и сравнение

Одной из наиболее распространенных операций над URI является простое сравнение: определяется, эквивалентны ли два URI, без использования URI для доступа к их соответствующим ресурсам. Сравнение выполняется каждый раз, когда к кэшу ответов обращаются, браузер проверяет его историю, чтобы окрасить ссылку, или анализатор XML обрабатывает теги в пространстве имен. Обширная нормализация перед сравнением URI часто используется пауками и механизмами индексирования для сокращения пространства поиска или для уменьшения дублирования действий запроса и хранения ответов.

Сравнение URI выполняется для определенной цели. Протоколы или реализации, которые сравнивают URI для различных целей, часто будут подвергаться различным компромиссным решениям в отношении того, сколько усилий следует потратить на сокращение псевдонимов идентификаторов. В этом разделе описываются различные методы, которые можно использовать для сравнения URI, компромиссов между ними и типов приложений, которые могут их использовать.

6.1. Эквивалентность

Поскольку URI существуют для идентификации ресурсов, предположительно их следует считать эквивалентными, когда они идентифицируют один и тот же ресурс. Однако это определение эквивалентности не имеет большого практического применения, так как реализация не может сравнивать два ресурса, если у них нет полного знания или контроля над ними. По этой причине определение эквивалентности или разности URI основано на сравнении строк, возможно, дополненном ссылкой на дополнительные правила, предоставляемые определениями схемы URI. Мы используем термины «разные» и «эквивалентные» для описания возможных результатов таких сравнений, но существует множество зависимых от приложения версий эквивалентности.

Даже если можно определить, что два URI эквивалентны, сравнения URI недостаточно, чтобы определить, идентифицируют ли два URI разные ресурсы. Например, владелец двух разных доменных имен может решить обслуживать один и тот же ресурс из обоих, что приведет к двум разным URI. Таким образом, методы сравнения предназначены для минимизации ложных срабатываний, при этом строго избегая ложных срабатываний.

При тестировании на эквивалентность приложения не должны напрямую сравнивать относительные ссылки; ссылки должны быть преобразованы в их соответствующие целевые URI перед сравнением. Когда сравниваются URI, чтобы выбрать (или избежать) сетевое действие, такое как получение представления, компоненты сравнения (если таковые имеются) должны быть исключены из сравнения.

6.2. Лестница сравнения

На практике используются различные методы для проверки эквивалентности URI. Эти методы попадают в диапазон, отличающийся объемом требуемой обработки и степенью снижения вероятности ложных негативов. Как отмечено выше, ложные негативы не могут быть устранены. На практике их вероятность может быть уменьшена, но это сокращение требует большей обработки и не является экономически эффективным для всех приложений.

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

6.2.1. Простое сравнение строк

Если два URI идентичны, если рассматривать их как символьные строки, то можно с уверенностью заключить, что они эквивалентны. Этот тип теста эквивалентности имеет очень низкую вычислительную стоимость и широко используется в различных приложениях, особенно в области синтаксического анализа.

Тестирование строк на эквивалентность требует некоторых основных мер предосторожности. Эту процедуру часто называют сравнением «бит за битом» или «байт за байтом», что может вводить в заблуждение. Тестирование строк на равенство обычно основано на парном сравнении символов, составляющих строки, начиная с первой и продолжая, пока обе строки не будут исчерпаны и все символы не будут найдены равными, пока пара символов не сравнится неравномерно, или пока один из строк исчерпан раньше других.

Это сравнение символов требует, чтобы каждая пара символов была помещена в сопоставимую форму. Например, если один URI будет сохранен в байтовом массиве в кодировке EBCDIC, а второй — в объекте Java String (UTF-16), сравнение по битам, примененное наивно, приведет к ошибкам. Лучше говорить о равенстве на символьно-символьной основе, а не на побайтной или побитовой основе. С практической точки зрения, посимвольное сравнение должно быть выполнено код за кодом после преобразования в обычную кодировку символов.

Ложные негативы вызваны производством и использованием псевдонимов URI. Ненужные псевдонимы могут быть уменьшены, независимо от способа сравнения, путем последовательного предоставления ссылок URI в уже нормализованной форме (то есть форме, идентичной той, которая будет получена после применения нормализации, как описано ниже).

Протоколы и форматы данных часто ограничивают некоторые сравнения URI простым сравнением строк, основываясь на теории, что люди и реализации будут, в своих собственных интересах, последовательны в предоставлении ссылок URI или, по крайней мере, достаточно последовательны, чтобы свести на нет любую эффективность, которая может быть получена от дальнейшей нормализации.

6.2.2. Синтаксическая нормализация

Реализации могут использовать логику, основанную на определениях, предоставленных этой спецификацией, чтобы уменьшить вероятность ложных негативов. Эта обработка умеренно дороже, чем сравнение строки символ-символ. Например, приложение, использующее этот подход, может разумно считать следующие два URI эквивалентными:

example://a/b/c/%7Bfoo%7D
eXAMPLE://a/./b/../b/%63/%7bfoo%7d

Агенты веб-пользователей, такие как браузеры, обычно применяют этот тип нормализации URI при определении доступности кэшированного ответа. Нормализация на основе синтаксиса включает в себя такие методы, как нормализация регистра, нормализация кодирования процентов и удаление точечных сегментов.

6.2.2.1. Нормализация случая

Для всех URI шестнадцатеричные цифры в триплете кодирования процентов (например, «%3a» против «%3A») нечувствительны к регистру и, следовательно, должны быть нормализованы для использования заглавных букв для цифр A-F.

Когда URI использует компоненты общего синтаксиса, всегда применяются правила эквивалентности синтаксиса компонентов; а именно, что схема и хост не чувствительны к регистру и поэтому должны быть нормализованы к строчным. Например, URI <HTTP://www.EXAMPLE.com/> эквивалентен <http://www.example.com/>. Предполагается, что другие компоненты общего синтаксиса чувствительны к регистру, если в схеме не указано иное (см. Раздел 6.2.3).

6.2.2.2. Нормализация кодирования процентов

Механизм процентного кодирования (раздел 2.1) является частым источником расхождений среди идентичных идентификаторов URI. В дополнение к проблеме нормализации случая, отмеченной выше, некоторые производители URI кодируют проценты октетов, которые не требуют кодирования процентов, в результате чего идентификаторы URI эквивалентны их некодированным аналогам. Эти URI должны быть нормализованы путем декодирования любого кодированного в процентах октета, который соответствует незарезервированному символу, как описано в разделе 2.3.

6.2.2.3. Нормализация сегмента пути

Полный путь сегментов «.» и «..» предназначены только для использования в относительных ссылках (раздел 4.1) и удаляются как часть процесса разрешения ссылок (раздел 5.2). Однако некоторые развернутые реализации ошибочно предполагают, что разрешение ссылки не является необходимым, когда ссылка уже является URI, и, таким образом, не удаляют точечные сегменты, когда они встречаются в не относительных путях. Нормализаторы URI должны удалять точечные сегменты, применяя к пути алгоритм remove_dot_segments, как описано в разделе 5.2.4.

6.2.3. Нормализация на основе схемы

Синтаксис и семантика URI варьируются от схемы к схеме, как описано в определяющей спецификации для каждой схемы. Реализации могут использовать правила, специфичные для схемы, при дальнейшей стоимости обработки, чтобы уменьшить вероятность ложных негативов. Например, поскольку схема «http» использует компонент полномочий, имеет порт по умолчанию «80» и определяет пустой путь, эквивалентный «/», следующие четыре URI эквивалентны:

http://example.com
http://example.com/
http://example.com:/
http://example.com:80/

В общем, URI, который использует общий синтаксис для оснований с пустым путем, должен быть нормализован к пути «/». Аналогичным образом, явный «:port«, для которого порт пуст или используется по умолчанию для схемы, эквивалентен тому, где порт и его разделитель «:» исключены, и, следовательно, должен быть удален путем нормализации на основе схемы. Например, второй URI выше является нормальной формой для схемы «http».

Другой случай, когда нормализация варьируется в зависимости от схемы, заключается в обработке пустого компонента оснований или подкомпонента пустого хоста. Для многих спецификаций схемы пустое основание или хост считается ошибкой; для других он считается эквивалентным «localhost» или хосту конечного пользователя. Когда схема определяет значение по умолчанию для основания и желательна ссылка на URI для этого значения по умолчанию, ссылка должна быть нормализована до пустого основания для единообразия, краткости и интернационализации. Однако, если подкомпоненты userinfo или port не являются пустыми, то хост должен быть указан явно, даже если он соответствует значению по умолчанию.

Нормализация не должна удалять разделители, когда связанный с ними компонент пуст, если только на это нет лицензии согласно спецификации схемы. Например, URI «http://example.com/?» нельзя считать эквивалентным любому из приведенных выше примеров. Аналогично, наличие или отсутствие разделителей в подкомпоненте userinfo обычно имеет большое значение для его интерпретации. Компонент фрагмента не подлежит какой-либо основанной на схеме нормализации; таким образом, два URI, которые отличаются только суффиксом «#», считаются разными независимо от схемы.

Некоторые схемы определяют дополнительные подкомпоненты, которые состоят из нечувствительных к регистру данных, давая неявную лицензию нормализаторам для преобразования этих данных в общий регистр (например, все строчные буквы). Например, схемы URI, которые определяют подкомпонент пути для содержания имени хоста в Интернете, например, схему URI «mailto«, приводят к тому, что этот подкомпонент нечувствителен к регистру и, следовательно, подлежит нормализации регистра (например, «mailto:Joe@Example.COM«). COM «эквивалентен» mailto: Joe@example.com «, хотя общий синтаксис считает, что компонент пути чувствителен к регистру).

Возможны другие специфичные для схемы нормализации.

6.2.4. Основанная на протоколе нормализация

Существенные усилия по сокращению числа ложных негативов часто являются экономически эффективными для веб-пауков. Следовательно, они реализуют еще более агрессивные методы сравнения URI. Например, если они наблюдают, что такой URI, как

http://example.com/data

перенаправляет на URI, отличающийся только конечной косой чертой

http://example.com/data/

они, вероятно, будут рассматривать их как эквивалент в будущем. Этот вид техники подходит только тогда, когда эквивалентность четко указывается как результатом доступа к ресурсам, так и общими соглашениями алгоритма разыменования их схемы (в этом случае использование перенаправления серверами происхождения HTTP, чтобы избежать проблем с относительными ссылками).

7. Вопросы безопасности

URI сам по себе не представляет угрозы безопасности. Тем не менее, поскольку URI часто используются для предоставления компактного набора инструкций для доступа к сетевым ресурсам, необходимо позаботиться о том, чтобы правильно интерпретировать данные в URI, чтобы эти данные не вызывали непреднамеренный доступ и не включали данные, которые не должны быть открытым текстом

7.1. Надежность и последовательность

Нет гарантии, что после использования URI для извлечения информации та же информация будет извлечена этим URI в будущем. Также нет никакой гарантии, что информация, которую можно извлечь через этот URI в будущем, будет заметно похожа на ту, что была получена в прошлом. Синтаксис URI не ограничивает то, как данная схема или орган выделяет свое пространство имен или поддерживает его с течением времени. Такие гарантии могут быть получены только от лица (лиц), контролирующих это пространство имен и рассматриваемый ресурс. Конкретная схема URI может определять дополнительную семантику, например постоянство имени, если эта семантика требуется от всех органов именования для этой схемы.

7.2. Вредоносная Конструкция

Иногда можно сконструировать URI так, чтобы попытка выполнить, казалось бы, безвредную идемпотентную операцию, такую ​​как получение представления, фактически привела к возможному повреждению удаленной операции. Небезопасный URI обычно создается путем указания номера порта, отличного от зарезервированного для рассматриваемого сетевого протокола. Клиент невольно связывается с сайтом, на котором запущена другая служба протокола, и данные в URI содержат инструкции, которые при интерпретации в соответствии с этим другим протоколом вызывают непредвиденную операцию. Частым примером такого злоупотребления является использование основанной на протоколе схемы с компонентом порта «25», тем самым вводя в заблуждение программное обеспечение агента пользователя при отправке непреднамеренного или олицетворяющего сообщения через SMTP-сервер.

Приложения должны предотвращать разыменование URI, который задает номер порта TCP в диапазоне «общеизвестный порт» (0–1023), если только не используется протокол для разыменования того, что URI совместим с протоколом, ожидаемым на этом общеизвестном порту. Хотя IANA поддерживает реестр известных портов, приложения должны устанавливать такие ограничения, настраиваемые пользователем, чтобы избежать предотвращения развертывания новых служб.

Когда URI содержит октеты в процентах, которые соответствуют разделителям для данного протокола разрешения или разыменования (например, символы CR и LF для протокола TELNET), эти кодировки процента не должны декодироваться перед передачей по этому протоколу. Передача кодировки процентов, которая может нарушать протокол, менее вредна, чем возможность интерпретировать декодированные октеты как дополнительные операции или параметры, возможно, вызывая неожиданную и, возможно, вредную удаленную операцию.

7.3. Back-End транскодирование

При разыменовании URI данные внутри него часто анализируются как пользовательским агентом, так и одним или несколькими серверами. Например, типичный пользовательский HTTP-агент будет анализировать URI по пяти основным компонентам, получать доступ к серверу основания и отправлять ему данные в пределах оснований, пути и запросов. Типичный сервер будет принимать эту информацию, разбирать путь на сегменты и запрос на пары «ключ/значение«, а затем вызывать специфичные для реализации обработчики для ответа на запрос. В результате общей проблемой безопасности для серверных реализаций, которые обрабатывают URI, либо в целом, либо в виде отдельных компонентов, является правильная интерпретация данных октетов, представленных символами и процентными кодировками в этом URI.

Кодированные в процентах октеты должны быть декодированы в некоторый момент в процессе разыменования. Приложения должны разбивать URI на его компоненты и подкомпоненты до декодирования октетов, так как в противном случае декодированные октеты могут быть ошибочно приняты за разделители. Проверки безопасности данных в URI должны применяться после декодирования октетов. Однако обратите внимание, что процентное кодирование «%00» (NUL) может потребовать специальной обработки и должно быть отклонено, если приложение не ожидает получения необработанных данных внутри компонента.

Особую осторожность следует проявлять, когда в процессе интерпретации пути URI используется внутренняя файловая система или связанные системные функции. Файловые системы обычно назначают рабочее значение специальным символам, таким как символы «/», «\», «:», «[«, and «]», и специальным именам устройств, таким как «.», «..», «…», «aux», «lpt» и т. д. В некоторых случаях простое тестирование на наличие такого имени приведет к приостановке или вызову несвязанными системными вызовами операционной системы, что приведет к серьезным проблемам безопасности в отношении отказа обслуживания и непреднамеренной передачи данных. Для этой спецификации было бы невозможно перечислить все такие значимые символы и имена устройств. Разработчики должны изучить зарезервированные имена и символы для типов устройств хранения, которые могут быть подключены к их приложениям, и соответствующим образом ограничить использование данных, полученных из компонентов URI.

7.4. Редкие форматы IP-адресов

Хотя синтаксис URI для IPv4-адреса допускает только общую десятичную форму адресного литерала IPv4, многие реализации, обрабатывающие URI, используют системные подпрограммы, такие как gethostbyname () и inet_aton (), для перевода строкового литерала в фактический IP-адрес. К сожалению, такие системные подпрограммы часто позволяют и обрабатывают гораздо больший набор форматов, чем описано в разделе 3.2.2.

Например, многие реализации допускают пунктирные формы трех чисел, причем последняя часть интерпретируется как 16-битная величина и помещается в самые правые два байта сетевого адреса (например, сеть класса B). Аналогично, пунктирная форма из двух чисел означает, что последняя часть интерпретируется как 24-разрядная величина и помещается в самые правые три байта сетевого адреса (класс A), а одно число (без точек) интерпретируется как 32-разрядное количество и хранится непосредственно в сетевом адресе. В дополнение к путанице, некоторые реализации позволяют интерпретировать каждую пунктирную часть как десятичную, восьмеричную или шестнадцатеричную, как указано в языке Си (т. е. ведущий «0x» или «0X» подразумевает шестнадцатеричное; начальный «0» означает восьмеричное; в противном случае число означает интерпретируется как десятичный).

Эти дополнительные форматы IP-адресов не допускаются в синтаксисе URI из-за различий между реализациями платформы. Однако они могут стать проблемой безопасности, если приложение пытается фильтровать доступ к ресурсам на основе IP-адреса в строковом литеральном формате. Если эта фильтрация выполняется, литералы должны быть преобразованы в числовую форму и отфильтрованы на основе числового значения, а не по префиксу или суффиксу строковой формы.

7.5. Конфиденциальная информация

Производители URI не должны предоставлять URI, который содержит имя пользователя или пароль, которые должны быть секретными. URI часто отображаются браузерами, хранятся в виде текстовых закладок и регистрируются в истории пользовательских агентов и посреднических приложениях (прокси). Пароль, появляющийся в компоненте userinfo, устарел и должен рассматриваться как ошибка (или просто игнорироваться), за исключением тех редких случаев, когда параметр ‘password’ должен быть общедоступным.

7.6. Семантические атаки

Поскольку подкомпонент userinfo редко используется и появляется перед хостом в компоненте оснований, его можно использовать для создания URI, предназначенного для введения в заблуждение человека-пользователя, путем идентификации одного (доверенного) органа именования, в то же время фактически идентифицируя различные полномочия, скрытые за шум. Например

ftp://cnn.example.com&story=breaking_news@10.0.0.1/top_story.htm

пользователь может предположить, что хост — это «cnn.example.com», тогда как на самом деле это «10 .0.0.1». Обратите внимание, что вводящий в заблуждение подкомпонент userinfo может быть намного длиннее, чем в приведенном выше примере.

Вводящий в заблуждение URI, такой как приведенный выше, представляет собой атаку на предвзятые представления пользователя о значении URI, а не на саму программу. Пользовательские агенты могут уменьшить воздействие таких атак, различая различные компоненты URI, когда они отображаются, например, используя другой цвет или тон для визуализации информации о пользователе, если таковая имеется, хотя панацея отсутствует. Более подробную информацию о семантических атаках на основе URI можно найти в [Siedzik].

8. Соображения IANA

Имена схем URI, как определено в <scheme> в разделе 3.1, образуют зарегистрированное пространство имен, которым управляет IANA в соответствии с процедурами, определенными в [BCP35]. Никакие действия IANA не требуются этим документом.

9. Благодарности

Эта спецификация основана на RFC 2396 [RFC2396 #], RFC 1808 [RFC1808 #] и RFC 1738 [RFC1738 #]; подтверждения в этих документах все еще применяются. Он также включает обновление (с исправлениями) литералов IPv6 в синтаксисе хоста, как это определено Робертом М. Хинденом (Robert M. Hinden), Брайаном Э. Карпентером (Brian E. Carpenter) и Ларри Масинтером (Larry Masinter) в [RFC2732 #]. Кроме того, материалы Жизля Ааса (Gisle Aas), Риз Аншульц (Reese Anschultz), Даниэля Барклая (Daniel Barclay), Тима Брея (Tim Bray), Майка Брауна (Mike Brown), Роба Кэмерона (Rob Cameron), Джереми Кэрролла (Jeremy Carroll), Дана Коннолли (Dan Connolly), Адама М. Костелло (Adam M. Costello), Джона Коуэна (John Cowan), Джейсона Даймонда (Jason Diamond), Мартина Дюрста (Martin Duerst), Стефана Эйссинга (Stefan Eissing), Клайва Д.В. Перо (Clive D.W. Feather), Эл Гилман (Al Gilman), Тони Хаммонд (Tony Hammond), Эллиот Гарольд (Elliotte Harold), Пэт Хейс (Pat Hayes), Генри Хольцман (Henry Holtzman), Ян Б. Джекобс (Ian B. Jacobs), Майкл Кей (Michael Kay), Джон К. Кленсин (John C. Klensin), Грэм Клайн (Graham Klyne), Дэн Кон (Dan Kohn), Брюс Лилли (Bruce Lilly), Эндрю Мейн (Andrew Main), Дэйв Макалпин (Dave McAlpin), Ира Макдональд (Ira McDonald), Майкл Меллинг (Michael Mealling), Рэй Меркерт (Ray Merkert), Стивен Поллей (Stephen Pollei), Джулиан Решке (Julian Reschke), Томас Рокицки (Tomas Rokicki), Майлз Сабин (Miles Sabin), Кай Шецль (Kai Schaetzl), Марк Томсон (Mark Thomson), Рональд Чалаер (Ronald Tschalaer), Норм Уолш (Norm Walsh), Марк Уорн (Marc Warne), Стюарт Уильямс (Stuart Williams) и Генри Зонгаро (Henry Zongaro) c благодарностью отмечены.

10. Ссылки

10.1. Нормативные ссылки

[ASCII] American National Standards Institute, «Coded Character Set — 7-bit American Standard Code for Information Interchange», ANSI X3.4, 1986.

[RFC2234] Crocker, D. and P. Overell, «Augmented BNF for Syntax Specifications: ABNF», RFC 2234, November 1997.

[STD63] Yergeau, F., «UTF-8, a transformation format of ISO 10646», STD 63, RFC 3629, November 2003.

[UCS] International Organization for Standardization, «Information Technology — Universal Multiple-Octet Coded Character Set (UCS)», ISO/IEC 10646:2003, December 2003.

10.2. Информационные ссылки

[BCP19] Freed, N. and J. Postel, «IANA Charset Registration Procedures», BCP 19, RFC 2978, October 2000.

[BCP35] Petke, R. and I. King, «Registration Procedures for URL Scheme Names», BCP 35, RFC 2717, November 1999.

[RFC0952] Harrenstien, K., Stahl, M., and E. Feinler, «DoD Internet host table specification», RFC 952, October 1985.

[RFC1034] Mockapetris, P., «Domain names — concepts and facilities», STD 13, RFC 1034, November 1987.

[RFC1123] Braden, R., «Requirements for Internet Hosts — Application and Support», STD 3, RFC 1123, October 1989.

[RFC1535] Gavron, E., «A Security Problem and Proposed Correction With Widely Deployed DNS Software», RFC 1535, October 1993.

[RFC1630] Berners-Lee, T., «Universal Resource Identifiers in WWW: A Unifying Syntax for the Expression of Names and Addresses of Objects on the Network as used in the World-Wide Web», RFC 1630, June 1994.

[RFC1736] Kunze, J., «Functional Recommendations for Internet Resource Locators», RFC 1736, February 1995.

[RFC1737] Sollins, K. and L. Masinter, «Functional Requirements for Uniform Resource Names», RFC 1737, December 1994.

[RFC1738] Berners-Lee, T., Masinter, L., and M. McCahill, «Uniform Resource Locators (URL)», RFC 1738, December 1994.

[RFC1808] Fielding, R., «Relative Uniform Resource Locators», RFC 1808, June 1995.

[RFC2046] Freed, N. and N. Borenstein, «Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types», RFC 2046, November 1996.

[RFC2141] Moats, R., «URN Syntax», RFC 2141, May 1997.

[RFC2396] Berners-Lee, T., Fielding, R., and L. Masinter, «Uniform Resource Identifiers (URI): Generic Syntax», RFC 2396, August 1998.

[RFC2518] Goland, Y., Whitehead, E., Faizi, A., Carter, S., and D. Jensen, «HTTP Extensions for Distributed Authoring — WEBDAV», RFC 2518, February 1999.

[RFC2557] Palme, J., Hopmann, A., and N. Shelness, «MIME Encapsulation of Aggregate Documents, such as HTML (MHTML)», RFC 2557, March 1999.

[RFC2718] Masinter, L., Alvestrand, H., Zigmond, D., and R. Petke, «Guidelines for new URL Schemes», RFC 2718, November 1999.

[RFC2732] Hinden, R., Carpenter, B., and L. Masinter, «Format for Literal IPv6 Addresses in URL’s», RFC 2732, December 1999.

[RFC3305] Mealling, M. and R. Denenberg, «Report from the Joint W3C/IETF URI Planning Interest Group: Uniform Resource Identifiers (URIs), URLs, and Uniform Resource Names (URNs): Clarifications and Recommendations», RFC 3305, August 2002.

[RFC3490] Faltstrom, P., Hoffman, P., and A. Costello, «Internationalizing Domain Names in Applications (IDNA)», RFC 3490, March 2003.

[RFC3513] Hinden, R. and S. Deering, «Internet Protocol Version 6 (IPv6) Addressing Architecture», RFC 3513, April 2003.

[Siedzik] Siedzik, R., «Semantic Attacks: What’s in a URL?», April 2001, <http://www.giac.org/practical/gsec/Richard_Siedzik_GSEC.pdf>.

A. Собранный ABNF для URI

URI            = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
hier-part      = "//" authority path-abempty
               / path-absolute
               / path-rootless
               / path-empty
URI-reference  = URI / relative-ref
absolute-URI   = scheme ":" hier-part [ "?" query ]
relative-ref   = relative-part [ "?" query ] [ "#" fragment ]
relative-part  = "//" authority path-abempty
               / path-absolute
               / path-noscheme
               / path-empty
scheme        = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
authority     = [ userinfo "@" ] host [ ":" port ]
userinfo      = *( unreserved / pct-encoded / sub-delims / ":" )
host          = IP-literal / IPv4address / reg-name
port          = *DIGIT
IP-literal    = "[" ( IPv6address / IPvFuture ) "]"
IPvFuture     = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
IPv6address   = 6( h16 ":" ) ls32
              / "::" 5( h16 ":" ) ls32
              / [ h16 ] "::" 4( h16 ":" ) ls32
              / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
              / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
              / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32
              / [ *4( h16 ":" ) h16 ] "::" ls32
              / [ *5( h16 ":" ) h16 ] "::" h16
              / [ *6( h16 ":" ) h16 ] "::"
h16           = 1*4HEXDIG
ls32          = ( h16 ":" h16 ) / IPv4address
IPv4address   = dec-octet "." dec-octet "." dec-octet "." dec-octet

dec-octet     = DIGIT ; 0-9
              / %x31-39 DIGIT ; 10-99
              / "1" 2DIGIT ; 100-199
              / "2" %x30-34 DIGIT ; 200-249
              / "25" %x30-35 ; 250-255
reg-name      = *( unreserved / pct-encoded / sub-delims )
path          = path-abempty ; begins with "/" or is empty
              / path-absolute ; begins with "/" but not "//"
              / path-noscheme ; begins with a non-colon segment
              / path-rootless ; begins with a segment
              / path-empty ; zero characters
path-abempty  = *( "/" segment )
path-absolute = "/" [ segment-nz *( "/" segment ) ]
path-noscheme = segment-nz-nc *( "/" segment )
path-rootless = segment-nz *( "/" segment )
path-empty    = 0<pchar>
segment       = *pchar
segment-nz    = 1*pchar
segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
              ; non-zero-length segment without any colon ":"
pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
query         = *( pchar / "/" / "?" )
fragment      = *( pchar / "/" / "?" )
pct-encoded   = "%" HEXDIG HEXDIG
unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
reserved      = gen-delims / sub-delims
gen-delims    = ":" / "/" / "?" / "#" / "[" / "]" / "@"
sub-delims    = "!" / "$" / "&" / "’" / "(" / ")" / "*" / "+" / "," / ";" / "="

B. Разбор ссылки на URI с помощью регулярного выражения

Поскольку алгоритм «first-match-wins» идентичен «жадному» методу устранения неоднозначности, используемому регулярными выражениями POSIX, вполне естественно использовать регулярное выражение для анализа потенциальных пяти компонентов ссылки на URI.

Следующая строка — это регулярное выражение для разбиения правильно сформированной ссылки URI на ее компоненты.

^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
 12            3  4          5       6  7        8 9
Регулярное выражение для разбиения правильно сформированной ссылки URI на ее компоненты
Регулярное выражение для разбиения правильно сформированной ссылки URI на ее компоненты

Цифры во второй строке выше предназначены только для удобства чтения; они указывают контрольные точки для каждого подвыражения (то есть для каждой парной скобки). Мы ссылаемся на значение для подвыражения <n> как $<n>. Например, соответствие приведенного выше выражения

http://www.ics.uci.edu/pub/ietf/uri/#Related

приводит к следующим совпадениям подвыражения:

$1 = http:
$2 = http
$3 = //www.ics.uci.edu
$4 = www.ics.uci.edu
$5 = /pub/ietf/uri/
$6 = <undefined>
$7 = <undefined>
$8 = #Related
$9 = Related

где <undefined> указывает, что компонент отсутствует, как в случае с компонентом запроса в приведенном выше примере. Таким образом, мы можем определить значение пяти компонентов как

scheme = $2
authority = $4
path = $5
query = $7
fragment = $9

Идя в обратном направлении, мы можем воссоздать ссылку на URI из ее компонентов, используя алгоритм из Раздела 5.3.

C. Разграничение URI в контексте

URI часто передаются через форматы, которые не обеспечивают четкого контекста для их интерпретации. Например, во многих случаях URI включается в простой текст; примеры включают в себя текст, отправленный по электронной почте, новости USENET и на печатной бумаге. В таких случаях важно иметь возможность отделить URI от остальной части текста, и в частности от знаков препинания, которые могут быть ошибочно приняты за часть URI.

На практике URI разделяются различными способами, но обычно в двойных кавычках «http://example.com/», в угловых скобках <http://example.com/> или просто с использованием пробелов:

http://example.com/

Эти оболочки не являются частью URI.

В некоторых случаях может потребоваться добавление лишних пробелов (пробелы, переносы строк, табуляции и т. Д.), Чтобы разбить длинный URI на строки. Пробел должен игнорироваться при извлечении URI.

Запрещается вводить пробел после символа дефиса («-«). Поскольку некоторые наборщики и принтеры могут (ошибочно) вводить дефис в конце строки при его разрыве, интерпретатор URI, содержащий разрыв строки сразу после дефиса, должен игнорировать все пробелы вокруг переноса строки и должен знать, что дефис может или не может фактически быть частью URI.

Использование угловых скобок <> вокруг каждого URI особенно рекомендуется в качестве стиля разграничения для ссылки, содержащей встроенные пробелы.

Префикс «URL:» (с пробелом или без него) ранее рекомендовался как способ отличить URI от других обозначений в квадратных скобках, хотя на практике он обычно не используется и более не рекомендуется.

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

Например, текст

Yes, Jim, I found it under "http://www.w3.org/Addressing/", but you can probably pick it up from <ftp://foo.example.com/rfc/>. Note the warning in <http://www.ics.uci.edu/pub/ietf/uri/historical.html#WARNING>.

содержит ссылки на URI

http://www.w3.org/Addressing/
ftp://foo.example.com/rfc/
http://www.ics.uci.edu/pub/ietf/uri/historical.html#WARNING

D. Отличия от RFC 2396

D.1. Дополнения

Введено правило ABNF для URI, соответствующее одному общему использованию термина: абсолютный URI с необязательным фрагментом.

Литералы IPv6 (и более поздние) были добавлены в список возможных идентификаторов для хост-части компонента оснований, как описано в [RFC2732 #], с добавлением «[» и «]» к зарезервированному набору и флагу версии предвидеть будущие версии литералов IP. Квадратные скобки теперь указываются как зарезервированные в компоненте оснований и не допускаются за пределами их использования в качестве разделителей для литерала IP внутри хоста. Чтобы внести это изменение без изменения технического определения компонентов пути, запроса и фрагмента, эти правила были переопределены для непосредственного указания разрешенных символов.

Поскольку [RFC2732 #] ссылается на [RFC3513 #] для определения литерального адреса IPv6, который, к сожалению, не имеет описания ABNF IPv6-адреса, мы создали новое правило ABNF для адреса IPv6, которое соответствует текстовым представлениям, определенным в разделе 2.2 [RFC3513 #]. Аналогично, определение IPv4-адреса было улучшено, чтобы ограничить каждый десятичный октет диапазоном 0-255.

Раздел 6, посвященный нормализации и сравнению URI, был полностью переписан и расширен с использованием материалов Тима Брея (Tim Bray) и обсуждений в группе технической архитектуры W3C.

D.2. Изменения

Специальный синтаксис BNF в RFC 2396 # был заменен на ABNF в [RFC2234 #]. Это изменение потребовало, чтобы все имена правил, которые ранее включали символы подчеркивания, были переименованы с дефисом. Кроме того, ряд синтаксических правил был исключен или упрощен, чтобы сделать общую грамматику более понятной. Спецификации, которые относятся к устаревшим правилам грамматики, можно понять, заменив эти правила в соответствии со следующей таблицей:

Таблица правил - более понятная грамматика
Таблица правил — более понятная грамматика

Использование вышеперечисленных устаревших правил для определения специфичного для схемы синтаксиса не рекомендуется.

Раздел 2, посвященный символам, был переписан, чтобы объяснить, какие символы зарезервированы, когда они зарезервированы и почему они зарезервированы, даже если они не используются в качестве разделителей общим синтаксисом. Символы метки, которые обычно небезопасны для декодирования, включая восклицательный знак («!»), Звездочку («*»), одинарные кавычки («‘») и открывающие и закрывающие скобки («(» и «)») , были перемещены в зарезервированный набор, чтобы прояснить различие между зарезервированным и незарезервированным и, мы надеемся, ответить на наиболее распространенный вопрос разработчиков схем. Аналогично, был переписан раздел, посвященный символам в процентах, и теперь нормализаторам URI предоставлена лицензия на декодирование любых октетов в процентах, соответствующих незарезервированным символам. В общем, термины «экранированный» и «неэкранированный» были заменены на «кодированный в процентах» и «декодированный» соответственно, чтобы уменьшить путаницу с другими формами механизмов выхода.

ABNF для URI и URI-ссылки были переработаны, чтобы сделать их более дружественными к анализаторам LALR и уменьшить сложность. В результате форма макета описания синтаксиса была удалена вместе с правилами^

  • uric,
  • uric_no_slash,
  • opaque_part,
  • net_path,
  • abs_path,
  • rel_path,
  • path_segments,
  • rel_segment
  • и правилами пометок.

Все ссылки на «непрозрачные» URI были заменены более подробным описанием того, как компонент пути может быть непрозрачным для иерархии. Правило relativeURI было заменено relative-ref, чтобы избежать ненужной путаницы относительно того, являются ли они подмножеством URI. Неоднозначность, связанная с разбором URI-ссылки как URI или относительной ссылки с двоеточием в первом сегменте, была устранена благодаря использованию пяти отдельных правил сопоставления путей.

Идентификатор фрагмента был перенесен обратно в раздел об общих компонентах синтаксиса и в правилах URI и относительной ссылки, хотя он остается исключенным из абсолютного URI. Символ знака числа («#») был перемещен обратно в зарезервированный набор в результате реинтеграции синтаксиса фрагмента.

ABNF был исправлен, чтобы позволить компоненту пути быть пустым. Это также позволяет абсолютному URI (absolute-URI) не состоять из ничего после «scheme:«, как на практике это происходит с пространством имен «dav:» [RFC2518 #] и со схемой «about:«, используемой внутри многих реализаций браузера WWW. Неопределенность в отношении границы между основаниями и путями была устранена благодаря использованию пяти отдельных правил сопоставления путей.

Основания именования на основе реестра, которые используют общий синтаксис, теперь определены в правиле хоста. Это изменение позволяет текущим реализациям, где любое предоставленное имя просто подается в локальный механизм разрешения имен, быть совместимым со спецификацией. Это также устраняет необходимость переопределять форматы DNS-имен здесь. Кроме того, он позволяет компоненту хоста содержать октеты, закодированные в процентах, что необходимо для предоставления интернационализированных доменных имен в URI, обработки в их собственных кодировках символов на прикладных уровнях выше обработки URI и передачи в библиотеку IDNA в виде зарегистрированное имя в кодировке UTF-8. Правила сервера, хоста, имени хоста, метки домена, метки топа и алфавита были удалены.

Алгоритм разрешения относительных ссылок [RFC2396 #] был переписан псевдокодом для этой ревизии, чтобы улучшить ясность и устранить следующие проблемы:

o [RFC2396] раздел 5.2, шаг 6a, не удалось учесть базовый URI без пути.

o Восстановлено поведение [RFC1808 #], где, если ссылка содержит пустой путь и определенный компонент запроса, целевой URI наследует компонент пути базового URI.

o Определение того, является ли ссылка URI ссылкой на тот же документ, было отделено от анализатора URI, упрощая интерфейс обработки URI в приложениях способом, совместимым с внутренней архитектурой развернутых реализаций обработки URI. Теперь определение основано на сравнении с базовым URI после преобразования ссылки в абсолютную форму, а не на формате самой ссылки. Это изменение может привести к тому, что согласно этой спецификации больше ссылок будет считаться «одним и тем же документом», чем в правилах, приведенных в RFC 2396, особенно когда нормализация используется для сокращения псевдонимов. Однако это не меняет статус существующих ссылок на один и тот же документ.

o Разделить подпрограмму слияния пути на две подпрограммы: слияние, для описания комбинации базового пути URI с ссылкой на относительный путь, и remove_dot_segments, для описания того, как удалить специальное «.» и «..» сегменты составного пути. Алгоритм remove_dot_segments теперь применяется ко всем ссылочным путям URI, чтобы соответствовать общим реализациям и улучшить нормализацию URI на практике. Это изменение влияет только на разбор аномальных ссылок и ссылок той же схемы, где базовый URI имеет неиерархический путь.

Индекс

A

ABNF
absolute
absolute-path
absolute-URI
access
authority

B

base URI

C

character encoding
character
characters
coded character set

D

dec-octet
dereference
dot-segments

F

fragment (раздел 3)
fragment (раздел 3.5)

G

gen-delims
generic syntax

H

h16
hier-part
hierarchical
host

I

identifier
IP-literal
IPv4
IPv4address
IPv6
IPv6address
IPvFuture

L

locator
ls32

M

merge

N

name
network-path

P

path 16, 22, 26
path-abempty
path-absolute
path-empty
path-noscheme
path-rootless
pchar
pct-encoded
percent-encoding
port

Q

query 16, 23

R

reg-name
registered name
relative 10, 28
relative-path
relative-ref
remove_dot_segments
representation
reserved
resolution 9, 28
resource
retrieval

S

same-document
sameness
scheme 16, 17
segment
segment-nz
segment-nz-nc
sub-delims
suffix

T

transcription

U

uniform
unreserved
URI grammar

absolute-URI 27
ALPHA 11
authority 18
CR 11
dec-octet
DIGIT 11
DQUOTE 11
fragment 24
gen-delims
h16
HEXDIG 11
hier-part 16
host 19
IP-literal
IPv4address 20
IPv6address 20
IPvFuture
LF 11
ls32
OCTET 11
path 22
path-abempty 22
path-absolute
path-empty
path-noscheme
path-rootless 22
pchar 23
pct-encoded 12
port 22
query 24
reg-name 21
relative-ref 26
reserved 13
scheme 17
segment 23
segment-nz 23
segment-nz-nc 23
SP 11
sub-delims 13
unreserved 13
URI 16
URI-reference 25
userinfo 18

URI
URI-reference
URL
URN
userinfo

Адреса авторов

Tim Berners-Lee
World Wide Web Consortium
Massachusetts Institute of Technology
77 Massachusetts Avenue
Cambridge, MA 02139
USA
Phone: +1-617-253-5702
Fax: +1-617-258-5999
EMail: timbl@w3.org
URI: http://www.w3.org/People/Berners-Lee/

Roy T. Fielding
Day Software
5251 California Ave., Suite 110
Irvine, CA 92617
USA
Phone: +1-949-679-2960
Fax: +1-949-679-2972
EMail: fielding@gbiv.com
URI: http://roy.gbiv.com/

Larry Masinter
Adobe Systems Incorporated
345 Park Ave
San Jose, CA 95110
USA
Phone: +1-408-536-3024
EMail: LMM@acm.org
URI: http://larry.masinter.net/

Поделись записью