RFC3986 - какие pchars нужно кодировать в процентах?

Мне нужно сгенерировать href на URI. Все просто, за исключением случаев, когда речь идет о зарезервированных символах, которые нуждаются в процентном кодировании, например, ссылка на /some/path;element должен появиться как <a href="/some/path%3Belement"> (Я знаю это path;element представляет собой единое целое).

Первоначально я искал библиотеку Java, которая делает это, но в итоге я сам что-то написал (посмотрите, что не удалось с Java, так как этот вопрос не специфичен для Java).

Итак, RFC 3986 предлагает, когда НЕ нужно кодировать. Это должно произойти, как я прочитал, когда персонаж попадает под unreserved (ALPHA / DIGIT / "-" / "." / "_" / "~") учебный класс. Все идет нормально. Но как насчет противоположного случая? RFC упоминает только этот процент (%) всегда нужна кодировка. А что насчет остальных?

Вопрос: правильно ли считать, что все, что не является зарезервированным, может / должно быть закодировано в процентах? Например, открывающая скобка ( не обязательно кодировка, но точка с запятой ; делает. Если я не закодирую это, я в конечном итоге ищу /first* при следовании <a href="/first;second">, Но следуя <a href="/first(second"> Я всегда заканчиваю тем, что искал /first(second, как и ожидалось. Что меня смущает, так это то, что оба ( а также ; в том же sub-delims класс, насколько RFC идет. Как я полагаю, кодирование всего, что не является незарезервированным, - безопасная ставка, но как насчет SEOability, удобства для пользователя, когда дело доходит до локализованных URI?

Теперь, что не удалось с библиотеками Java. Я пытался сделать это как
new java.net.URI("http", "site", "/pa;th", null).toASCIISTring()
но это дает http://site/pa;th что не хорошо. Аналогичные результаты наблюдаются с:

  • javax.ws.rs.core.UriBuilder
  • Spring's UriUtils - я пробовал оба encodePath(String, String) а также encodePathSegment(String, String)

[*] /first является результатом обращения к HttpServletRequest.getServletPath() на стороне сервера при нажатии на <a href="/first;second">

РЕДАКТИРОВАТЬ: Я, вероятно, должен упомянуть, что это поведение наблюдалось при Tomcat, и я проверил, как Tomcat 6 и 7 ведут себя одинаково.

2 ответа

Правильно ли предположить, что все, что не является зарезервированным, может / должно быть закодировано в процентах?

№ RFC 3986 говорит это:

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

Подразумевается, что вы решаете, какой из разделителей (то есть <delimiter> символы) должны быть закодированы в зависимости от контекста. Те, которые не нужно кодировать, не должны кодироваться.

Например, вы не должны кодировать в процентах / если он появляется в компоненте пути, но вы должны кодировать его в процентах, когда он появляется в запросе или фрагменте.

Так что, на самом деле, ; характер (который является членом <reserved> не должен автоматически кодироваться в процентах. И действительно, классы URL Java и URI этого не сделают; см. URI(...) Javadoc, в частности, шаг 7), чтобы узнать, как <path> Компонент обрабатывается.

Это подтверждается этим пунктом:

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

Так что это говорит о том, что URL-адрес, содержащий в процентах ; не совпадает с URL-адресом, который содержит ;, И последнее предложение подразумевает, что они НЕ должны автоматически кодироваться или декодироваться в процентах.


Что оставляет нас с вопросом - почему вы хотите ; быть в процентах закодированы?

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

Извините, но из этого не следует, что нужно ставить точку с запятой.

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

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

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

Что это значит, зная "правильные действия", требует глубоких знаний о том, что URI означает для конечного пользователя и / или сайта. Для этого потребуется продвинутая технология чтения мыслей. Моя рекомендация состоит в том, чтобы заставить CMS решить эту проблему путем надлежащего экранирования любых разделителей путей URI, прежде чем они доставят их в ваше программное обеспечение. Алгоритм обязательно будет специфичным для CMS и платформы доставки контента. Он / она будет отвечать на запросы документов, идентифицированных по URL-адресам, и ему необходимо знать, как их интерпретировать.

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

ABNF для абсолютной части пути:

 path-absolute = "/" [ segment-nz *( "/" segment ) ]
 segment       = *pchar
 segment-nz    = 1*pchar
 pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
 pct-encoded   = "%" HEXDIG HEXDIG
 unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
 reserved      = gen-delims / sub-delims
 sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
               / "*" / "+" / "," / ";" / "="

pchar включает в себя вложенные разделы, поэтому вам не придется кодировать ни один из них в части пути: :@-._~!$&'()*+,;=

Я написал свой собственный конструктор URL, который включает в себя кодировщик для пути - как всегда, caveat emptor.

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