Java Чтение Undecoded URL из сервлета - PullRequest
5 голосов
/ 08 июня 2009

Давайте предположим, что у меня есть строка типа '= &? /; # +%', Которая будет частью моего 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.

Ответы [ 5 ]

21 голосов
/ 30 июня 2009

Существует принципиальная разница между "% 2F" и "/" как для браузера, так и для сервера.

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

  • getContextPath: не декодируется
  • getPathInfo: расшифровано
  • getPathTranslated: не декодируется
  • getQueryString: не декодировано
  • getRequestURI: не декодировано
  • getServletPath: декодированный

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

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

2 голосов
/ 08 июня 2009

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

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

1 голос
/ 09 июня 2009

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

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

0 голосов
/ 09 июня 2009

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

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

В полном URL вы должны различать экранированные и не экранированные символы по разным причинам, включая:

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

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

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

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

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

0 голосов
/ 09 июня 2009

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

url.substring (начальная длина, длина URL - конечная длина);

...