Чтение Java недекодированного URL-адреса из сервлета

StackOverflow https://stackoverflow.com/questions/966077

Вопрос

Предположим, что у меня есть строка типа '=&?/;#+%', которая является частью моего URL-адреса, скажем так:

example.com/servletPath/someOtherPath/myString/something.html?a=b&c=d#asdf

где myString — указанная выше строка.Я закодировал важную часть, поэтому URL-адрес выглядит так:

example.com/servletPath/someOtherPath/%3D%26%3F%2F%3B%23%2B%25/something.html?a=b&c=d#asdf

Все идет нормально.

Когда я нахожусь в сервлете и читаю любое из request.getRequestURI(), request.getRequestURL() или request.getPathInfo(), возвращаемое значение уже декодировано, поэтому я получаю строку типа

someOtherPath/=&?/;#+%/something.html?a=b&c=d#asdf

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

Я решил конкретную проблему, полностью запретив вышеуказанные символы, что работает в этой ситуации, но мне все еще интересно, есть ли способ получить некодированный URL-адрес в классе сервлета.

ЕЩЕ ЕЩЕ ПРАВКА:Когда вчера вечером я столкнулся с этой проблемой, я был слишком утомлен, чтобы заметить, что происходит на самом деле, а именно: еще более странно! У меня есть сопоставленный сервлет, скажем, /servletPath/*, после чего я могу поместить все, что захочу, и получить ответ моего сервлета в зависимости от остальной части пути, кроме когда в пути есть %2F.В таком случае запрос никогда не попадает на сервлет, и я получаю 404!Если я поставлю «/» вместо %2F, все будет работать нормально.Я использую Tomcat 6.0.14 на Java 1.6.0-04 на Linux.

Это было полезно?

Решение

Между «%2F» и «/» существует фундаментальная разница как для браузера, так и для сервера.

В спецификации HttpServletRequest говорится (без какой-либо логики, AFAICT):

  • получитьКонтекстПат:не декодирован
  • получитьПатИнфо:декодированный
  • getPathTranslated:не декодирован
  • получитьQueryString:не декодирован
  • getRequestURI:не декодирован
  • getServletPath:декодированный

Результат getPathInfo() должен декодироваться, но результат getRequestURI() не должен быть расшифровано.Если это так, ваш контейнер сервлетов нарушает спецификацию (как правильно заметили Воутер Кукертс и Франсуа Гравель).Какую версию Tomcat вы используете?

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

Другие советы

Если есть %2F в декодированный URL, это означает закодированный URL-адрес содержится %252F.

С %2F является / Почему бы просто не разделить "\/" и не беспокоиться о кодировке URL?

Согласно Javadoc, getRequestURI не должен декодировать строку.С другой стороны, getServletPath возвращает декодированную строку.Я тестировал это локально с помощью Jetty, и он ведет себя так, как описано в документе.

Таким образом, в вашей ситуации может быть что-то еще, поскольку поведение, которое вы описываете, не соответствует документации Sun.

Кажется, вы пытаетесь сделать что-то RESTy (используйте Джерси).Можете ли вы просто проанализировать начальную и конечную части URL-адреса, чтобы получить искомые данные?

url.substring(startLength, url.length - endLength);

Обновлять: изначально в этом ответе ошибочно говорилось, что «/» и «%2F» в пути всегда следует рассматривать одинаково.На самом деле они разные, поскольку путь представляет собой список сегментов, разделенных /.

Вам не нужно делать разницу между закодированным и незакодированным символом в часть пути URL-адреса.Внутри пути нет символов, которые могли бы иметь особое значение в URL-адресе.Например.«%2F» должен интерпретироваться так же, как «/», и браузер, обращающийся к такому URL-адресу, может заменить один на другой по своему усмотрению.Разница между ними означает нарушение стандарта кодирования URL-адресов.

В полном URL-адресе необходимо различать экранированные и неэкранированные символы по разным причинам, в том числе:

  • Чтобы увидеть, где заканчивается часть пути.Потому что?закодированный в пути, не должен рассматриваться как конец.
  • Внутри запроса String.Поскольку часть значения параметра может содержать «&» или «=",...
  • Внутри пути символ «/» разделяет два сегмента, а «%2F» может содержаться внутри сегмента.

Java прекрасно справляется с первыми двумя случаями:

  • getPathInfo() который возвращает только часть пути, декодированную
  • getParameter(String) для доступа к частям части запроса

С третьим случаем дело обстоит не так хорошо.Если вы хотите сделать разницу между «/» как разделением двух сегментов пути и «/» внутри сегмента пути (%2F), вы не сможете последовательно представить путь как одну декодированную строку.Вы можете представить его как одну закодированную строку (например, «foo/bar%2Fbaz») или как список декодированных сегментов (например, «foo», «bar/baz»).Но поскольку API getPathInfo() обещает сделать именно это (одну декодированную строку), у него нет другого выбора, кроме как рассматривать '/' и '%2F' как одно и то же.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top