Какие символы делают URL недействительным?

Какие символы делают URL недействительным?

Это действительные URL?

  • example.com/file[/].html
  • http://example.com/file[/].html

14 ответов

В целом URI, определенные в RFC 3986 (см. Раздел 2: Символы), могут содержать любой из следующих символов:

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~:/?#[]@!$&'()*+,;=

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

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

Чтобы добавить некоторые пояснения и непосредственно обратиться к вышеупомянутому вопросу, есть несколько классов символов, которые вызывают проблемы для URL-адресов и URI.

Есть некоторые символы, которые запрещены и никогда не должны появляться в URL/URI, зарезервированных символах (описанных ниже) и других символах, которые могут вызывать проблемы в некоторых случаях, но помечаются как "неразумные" или "небезопасные". Объяснения причин ограничения символов четко изложены в RFC-1738 (URL-адреса) и RFC-2396 (URI). Обратите внимание, что более новый RFC-3986 (обновление к RFC-1738) определяет конструкцию символов, которые разрешены в данном контексте, но более старая спецификация предлагает более простое и более общее описание того, какие символы недопустимы с помощью следующих правил.

Исключенные символы US-ASCII, запрещенные в синтаксисе URI:

   control     = <US-ASCII coded characters 00-1F and 7F hexadecimal>
   space       = <US-ASCII coded character 20 hexadecimal>
   delims      = "<" | ">" | "#" | "%" | <">

Список неразумных символов разрешен, но может вызвать проблемы:

   unwise      = "{" | "}" | "|" | "\" | "^" | "[" | "]" | "`"

Символы, которые зарезервированы в компоненте запроса и / или имеют специальное значение в URI/URL:

  reserved    = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","

Вышеуказанный "зарезервированный" синтаксический класс относится к тем символам, которые разрешены в URI, но которые не могут быть разрешены в конкретном компоненте общего синтаксиса URI. Символы в "зарезервированном" наборе не зарезервированы во всех контекстах. Например, имя хоста может содержать необязательное имя пользователя, поэтому это может быть что-то вроде ftp://user@hostname/ где символ "@" имеет особое значение.

Вот пример URL, который содержит недопустимые и неразумные символы (например, $, [], ']') и должен быть правильно закодирован:

http://mw1.google.com/mw-earth-vectordb/kml-samples/gp/seattle/gigapxl/$[level]/r$[y]_c$[x].jpg

Некоторые ограничения символов для URI / URL зависят от языка программирования. Например, '|' (0x7C), хотя в спецификации URI помечается только как "неразумный", в конструкторе Java java.net.URI создается исключение URISyntaxException, поэтому URL http://api.google.com/q?exp=a|b не допускается и должен быть закодирован вместо http://api.google.com/q?exp=a%7Cb при использовании Java с экземпляром объекта URI.

Большинство существующих ответов здесь нецелесообразно, потому что они полностью игнорируют реальное использование таких адресов, как:

Итак, согласно RFC 3986, такие адреса не являются URI (и, следовательно, не являются URL, поскольку URL являются типом URI). Если мы считаем себя приверженными терминологии существующих стандартов IETF, то мы должны правильно называть их IRI (интернационализированные идентификаторы ресурсов), как это определено в RFC 3987, которые технически не являются URI, но могут быть преобразованы в URI просто путем процентного кодирования всех не -ASCII символы в IRI. Обычные люди, тем не менее, никогда не слышали об IRI и просто называют эти URI или URL-адреса (и действительно, в настоящее время предпринимаются усилия WHATWG по созданию новой, более широкой спецификации URL, которая просто классифицирует все "URI" и "IRI" как "URL-адреса" для выравнивания). с современным использованием этих терминов в реальном мире).

Предположим, что мы хотим немедленно принять это значение URL (что не соответствует спецификации IETF, но приводит нас в соответствие с повседневным использованием). В таком случае, какие символы допустимы в URL?

Прежде всего, у нас есть два типа зарезервированных символов RFC 3986:

  • :/?#[]@, которые являются частью общего синтаксиса для URI, определенного в RFC 3986
  • !$&'()*+,;=, которые не являются частью общего синтаксиса RFC, но зарезервированы для использования в качестве синтаксических компонентов определенных схем URI. Например, точки с запятой и запятые используются как часть синтаксиса URI данных, и & а также = используются как часть вездесущего ?foo=bar&qux=baz формат в строках запроса (который не указан в RFC 3986).

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

RFC 3986 также определяет некоторые незарезервированные символы, которые всегда можно использовать просто для представления данных без какой-либо кодировки:

  • abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~

Наконец, % сам символ разрешен для процентного кодирования.

Это оставляет только следующие символы ASCII, которые запрещено появляться в URL:

  • Управляющие символы (символы 0-1F и 7F), включая новую строку, символ табуляции и возврат каретки.
  • "<>\^`{|}

Любой другой символ из ASCII может быть юридически представлен в URL.

Затем RFC 3987 расширяет этот набор незарезервированных символов следующими диапазонами символов Юникода:

  %xA0-D7FF / %xF900-FDCF / %xFDF0-FFEF
/ %x10000-1FFFD / %x20000-2FFFD / %x30000-3FFFD
/ %x40000-4FFFD / %x50000-5FFFD / %x60000-6FFFD
/ %x70000-7FFFD / %x80000-8FFFD / %x90000-9FFFD
/ %xA0000-AFFFD / %xB0000-BFFFD / %xC0000-CFFFD
/ %xD0000-DFFFD / %xE1000-EFFFD

Но эти варианты блоков кажутся странными и произвольными, учитывая последние определения блоков Unicode; Вероятно, это связано с тем, что блоки были добавлены за десятилетие, прошедшее с момента написания RFC 3987. У текущей спецификации WhatWG есть более щедрый список:

U + 00A0 до U+D7FF, U+E000 до U+FDCF, U+FDF0 до U+FFFD, U+10000 до U+1FFFD, U+20000 до U+2FFFD, U+30000 до U+3FFFD, U+40000 до U+4FFFD, U+50000 до U+5FFFD, U+60000 до U+6FFFD, U+70000 до U+7FFFD, U+80000 до U+8FFFD, U+90000 до U+9FFFD, U+A0000 до U+AFFFD, U+B0000 до U+BFFFD, U+C0000 до U+CFFFD, U+D0000 до U+DFFFD, U+E0000 до U+EFFFD, U+F0000 до U+FFFFD, U+100000 до U+10FFFD

Конечно, следует отметить, что простого знания того, какие символы могут юридически появляться в URL-адресе, недостаточно для определения того, является ли данная строка допустимым URL-адресом или нет, поскольку некоторые символы допустимы только в определенных частях URL-адреса. Например, зарезервированные символы [ а также ] допустимы как часть литерального хоста IPv6 в URL-адресе, таком как http://[1080::8:800:200c:417a]/foo, но не являются допустимыми в любом другом контексте, поэтому пример OP http://example.com/file[/].html незаконно

В своем дополнительном вопросе вы спросили www.example.com/file[/].html является действительным URL

Этот URL-адрес недействителен, поскольку URL-адрес является типом URI, а действительный URI должен иметь следующую схему http: (см. RFC 3986).

Если вы хотели спросить, если http://www.example.com/file[/].html является действительным URL, тогда ответ все еще нет, потому что символы в квадратных скобках там недопустимы.

Символы в квадратных скобках зарезервированы для URL в следующем формате: http://[2001:db8:85a3::8a2e:370:7334]/foo/bar (т.е. литерал IPv6 вместо имени хоста)

Стоит внимательно прочитать RFC 3986, если вы хотите полностью понять проблему.

Все допустимые символы, которые можно использовать в URI ( URL является типом URI), определены в RFC 3986.

Все остальные символы могут быть использованы в URL-адресе при условии, что они сначала "закодированы". Это включает в себя изменение недопустимого символа для определенных "кодов" (обычно в форме символа процента (%), за которым следует шестнадцатеричное число).

Эта ссылка, HTML HTML Encoding Reference, содержит список кодировок для недопустимых символов.

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

Например, href Документы говорят http://www.w3.org/TR/html5/links.html:

Атрибут href в элементах a и area должен иметь значение, которое является допустимым URL-адресом, потенциально окруженным пробелами.

Тогда определение "действительного URL" указывает на http://url.spec.whatwg.org/, что говорит о том, что он нацелен на:

Совместите RFC 3986 и RFC 3987 с современными реализациями и устарели в процессе.

Этот документ определяет точки кода URL как:

ASCII буквенно-цифровой, "!", "$", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/", ":", ";", "=", "?", "@", "_", "~" и кодовые точки в диапазонах от U+00A0 до U+D7FF, от U+E000 до U+FDCF, U+FDF0 до U+FFFD, U+10000 до U+1FFFD, U+20000 до U+2FFFD, U+30000 до U+3FFFD, U+40000 до U+4FFFD, U+50000 до U+5FFFD, U+60000 до U+6FFFD, U+70000 до U+7FFFD, U+80000 до U+8FFFD, U+90000 до U+9FFFD, U+A0000 до U+AFFFD, U+B0000 до U+BFFFD, U+C0000 до U+CFFFD, от U + D0000 до U + DFFFD, от U+E1000 до U+EFFFD, от U + F0000 до U + FFFFD, от U+100000 до U+10FFFD.

Термин "кодовые точки URL" затем используется в выражении:

Если c не является точкой кода URL и не "%", ошибка синтаксического анализа.

в нескольких частях алгоритма синтаксического анализа, включая схему, полномочия, относительный путь, запрос и состояния фрагмента: так в основном весь URL.

Кроме того, валидатор http://validator.w3.org/ передает URL-адреса, такие как "你好", и не подходит для URL с символами, такими как пробелы "a b"

Конечно, как упомянул Стивен С, речь идет не только о символах, но и о контексте: вы должны понимать весь алгоритм. Но поскольку класс "кодовые точки URL" используется в ключевых точках алгоритма, он дает хорошее представление о том, что вы можете использовать или нет.

Смотрите также: символы Юникода в URL

Мне нужно выбрать символ для разделения URL в строке, поэтому я решил создать список символов, которые не могут быть найдены в URL самостоятельно:

>>> allowed = "-_.~!*'();:@&=+$,/?%#[]?@ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
>>> from string import printable
>>> ''.join(set(printable).difference(set(allowed)))
'`" <\x0b\n\r\x0c\\\t{^}|>'

Таким образом, возможны следующие варианты: перевод строки, табуляция, пробел, обратный слеш и "<>{}^|, Я думаю, я пойду с пробелом или переводом строки.:)

На самом деле это не ответ на ваш вопрос, но проверка URL-адресов - это действительно серьезная проблема. Вам, вероятно, лучше проверить доменное имя и оставить часть запроса в URL-адресе. Это мой опыт. Вы также можете прибегнуть к проверке URL-адреса и посмотреть, приведет ли он к правильному ответу, но это может быть слишком много для такой простой задачи.

Регулярные выражения для определения URL-адресов в изобилии, Google это:)

Я использую старый HTTP (0.9, 1.0, 1.1) для чтения / записи запросов и ответов. URI запроса - самое проблемное место.

Вы не можете просто использовать RFC 1738, 2396 или 3986 как есть. Есть много старых HTTP-клиентов и серверов, которые позволяют использовать больше символов. Итак, я провел исследование на основе случайно опубликованных журналов доступа к веб-серверу:"GET URI HTTP/1.0" 200.

Я обнаружил, что в URI часто используются следующие нестандартные символы:

\ { } < > | ` ^ "

Эти символы были описаны в RFC 1738 как небезопасные.

Если вы хотите быть совместимыми со всеми старыми HTTP-клиентами и серверами, вы должны разрешить эти символы в URI запроса.

Подробнее об этом исследовании читайте в https://github.com/andrew-aladev/oghttp-request-collector.

Из источника (выделение добавлено, если необходимо):

Небезопасно:

Персонажи могут быть небезопасными по ряду причин. Символ пробела небезопасен, поскольку значительные пробелы могут исчезнуть, а незначащие пробелы могут появиться, когда URL-адреса расшифровываются, набираются или подвергаются обработке текстовыми программами.

Символы «<» и «>» небезопасны , поскольку они используются в качестве разделителей URL-адресов в свободном тексте; кавычка (""") используется для разделения URL-адресов в некоторых системах. Символ "#" небезопасен и всегда должен быть закодирован, поскольку он используется во Всемирной паутине и в других системах для отделения URL-адреса от фрагмента/привязки идентификатор, который может следовать за ним. Символ "%" небезопасен , поскольку он используется для кодирования других символов. Другие символы небезопасны , поскольку известно, что шлюзы и другие транспортные агенты иногда изменяют такие символы. Это символы "{", "} ", "|", "", "^", "~", "[", "]",

Все небезопасные символы всегда должны быть закодированы в URL-адресе. Например, символ «#» должен быть закодирован в URL-адресах даже в системах, которые обычно не имеют дело с идентификаторами фрагментов или привязок, чтобы, если URL-адрес был скопирован в другую систему, которая их использует, не было необходимости изменять Кодировка URL. Источник

Я не могу комментировать приведенные выше ответы, но хотел подчеркнуть (в другом ответе), что разрешенные символы разрешены не везде. Например, доменные имена не могут иметь символы подчеркивания, поэтому http://test_url.com недействителен.

Если вам нужна более широкая проверка, включающая смайлы (которые в настоящее время время от времени используются в URL-адресах), например:

http://factmyth.com/factoids/you--can--put--emojis--in--urls-/

И даже в доменных именах типа: .tld

Тогда это полезное регулярное выражение:

      [-a-zA-Z0-9\u1F60-\uFFFF@:%_\+.~#?&//=!'(),;*\$\[\]]*

PS: Это не действительно для всех «разновидностей» регулярных выражений, используемых в языках программирования. Это будет справедливо для Python, Rust, Golang, современного Javascript, но не для PHP, например. Проверьте здесь, выбрав «ароматы» слева и проверив сообщения об ошибках: https://regex101.com/

Я придумал пару регулярных выражений для PHP, которые преобразуют URL-адреса в тексте в теги привязки. (Сначала он преобразует все URL-адреса www. В http://, затем преобразует все URL-адреса с помощью https?:// в ссылки href=... html

$string = preg_replace('/(https?:\/\/)([!#$&-;=?\-\[\]_a-z~%]+)/sim', '<a href="$1$2">$2</a>', preg_replace('/(\s)((www\.)([!#$&-;=?\-\[\]_a-z~%]+))/sim', '$1http://$2', $string) );

Используйте urlencode, чтобы разрешить произвольные символы в вашем URL.

Другие вопросы по тегам