RFC3986 - какие pchars нужно кодировать в процентах? - PullRequest
10 голосов
/ 06 мая 2011

Мне нужно сгенерировать 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 UriUtils - я пробовал и encodePath(String, String) и encodePathSegment(String, String)

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

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

Ответы [ 2 ]

3 голосов
/ 16 мая 2011

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

Нет.В RFC 3986 говорится следующее:

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

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

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

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

Это подкрепляется этим параграфом:

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

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


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

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

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

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

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

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

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

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

1 голос
/ 06 мая 2011

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.

...