barbitoff programmer`s blog

Здесь я публикую заметки из программерской жизни: грабли, на которые мне случилось наступить, проблемы, для которых было найдено элегантное (или не очень) решение, а также все, с чем мне пришлось столкнуться и чем хотелось бы поделиться =)
PS Если хотите меня поблагодарить - на странице есть 3 места, чтобы это сделать =)
Показаны сообщения с ярлыком HTTP header. Показать все сообщения
Показаны сообщения с ярлыком HTTP header. Показать все сообщения

четверг, 15 сентября 2016 г.

IE: как побороть режим совместимости

Проблема

У пользователя в IE стоит галка "Display intranet sites in Compability View", из-за которой некий сайт во внутренней сетке отображается коряво. Нужно исправить ситуацию, не беспокоя конечного пользователя.

Решение

Если есть доступ к исходникам сайта, можно воспользоваться мета-тегом X-UA-Compatible, вставив его во все html-страницы:
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
Этот мета-тег превалирует над настройками совместимости браузера. Для того, чтобы тег работал, он должен идти в блоке <head> перед остальными элементами (исключение составляют <title> и другие мета-элементы). 
Другой вариант - воспользоваться аналогичным http-заголовком X-UA-Compatible, эффект будет тот же.

понедельник, 11 апреля 2016 г.

Java: подмена HTTP-заголовка, выдаваемого сервлетом / JSP-страницей

Задача

Есть некий сервлет (или JSP-страница), недоступный для модификации. Необходимо подменить один из выдаваемых сервлетом HTTP-заголоков. Например, сервлет выдает для скачивания некий файл. Необходимо подменить имя этого файла, т.е. заголовок "Content-Disposition".

Решение

Делаем jsp-страничку, которая будет служить своего рода прокси-объектом для оригинального сервлета, в ней делаем следующее:
<%
javax.servlet.http.HttpServletResponseWrapper wrappedResponse = new javax.servlet.http.HttpServletResponseWrapper(response) {
public void setHeader(String name, String value) {
if(name.equals("My-Header")) {
value = "my_value";
}
super.setHeader(name, value);
} public void addHeader(String name, String value) {
if(name.equals("My-Header")) {
value = "my_value";
}
super.addHeader(name, value);
} };
request.getRequestDispatcher("MyServlet").forward(request, wrappedResponse);
%>
Т.е. заворачиваем объект оригинального HTTP-ответа во wrapper, переопределяем методы установки заголовков, после чего выполняем forward на целевой сервлет. В итоге значение заголовка HTTP-заголовка "My-Header", генерируемого сервлетом, развернутым по относительному пути "MyServlet", будет заменено на "my_value".

пятница, 29 августа 2014 г.

Дамп HTTP-запросов tcpdump-ом

Возникла необходимость посмотреть http-заголовки запросов, приходящих на weblogic. Т.к. вывести произвольный заголовок в access-log без написания кода невозможно (http://technotoddle.blogspot.ru/2010/07/logging-more-information-in-http-logs.html), я решил особо не заморачиваться и посмотреть траффик сниффером. На Win обычно использую для подобных целей Wireshark, но здесь я был на linux-сервере без иксов, поэтому первый раз в жизни воспользовался tcpdump-ом. Делается это так:
tcpdump -A -s 0 'tcp dst port 8080 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)'
(здесь сниффятся входящие запросы на порт 8080, если убрать dst, то получим в дампе и запросы, и ответы)
На выходе получил то, что хотел:
17:17:25.769127 IP xxx >yyy: . 297430808:297432068(1260) ack 1587021758 win 16695
E.....@.....
..I
..5.d....o.^...P.A7....GET /da/component/main?__dmfClientId=1409209083173&__dmfRequestId=__client1~~2&__dmfJumpType=jump&__dmfTzoff=-240 HTTP/1.1
Accept: */*
Accept-Language: en-US
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727)
Accept-Encoding: gzip, deflate
Host: 10.2.5.53:8080
Connection: Keep-Alive
Cookie: appname=da;  ...
Спасибо https://sites.google.com/site/jimmyxu101/testing/use-tcpdump-to-monitor-http-traffic. 

среда, 5 декабря 2012 г.

пятница, 5 октября 2012 г.

php: установка заголовков запроса при загрузке данных по http с помощью функции file_get_contents()

Чтобы установить какой-нибудь заголовок http-запроса при загрузке данных по http функцией file_get_contents(), нужно использовать третий параметр этой функции - $context. Например, чтобы установить User-Agent как у 15ого Firefox`а, нужно:
$opts = array('http'=>array('header' => "User-Agent:Mozilla/5.0 (Windows NT 6.1; rv:15.0) Gecko/20100101 Firefox/15.0.1\r\n"));
$context = stream_context_create($opts);
$html = file_get_contents($link,false,$context);
А то некоторые сайты, например, без этого плюются 500ой ошибкой и не дают себя по-человечески сграбить =)
Warning: file_get_contents(http://***.ru/***): failed to open stream: HTTP request failed! HTTP/1.1 500 Internal Server Error

понедельник, 18 июня 2012 г.

WCF-веб-сервис: ответ "415 Unsupported Media Type"

Проблема:  

Бидинг WCF-веб-сервис имеет примерно следующий конфиг:
<wsHttpBinding>
<binding name="myBinding">
  <!-- Аудентификация клиента по сертификату. -->
  <security>
<message clientCredentialType="Certificate" />
  </security>
</binding>
</wsHttpBinding>  
При отправке запроса на веб-сервис последний отвеча HTTP-кодом:
415 Unsupported Media Type.
При этом заголовок "Content-Type" запроса установлен в "text/xml;charset=UTF-8".

Причина:

Неверный заголовок "Content-Type", для биндинга "wsHttpBinding" WCF ожидает значение "application/soap+xml".

вторник, 17 апреля 2012 г.

JSON POST запросы к Redmine REST API

Проблема:

При выполнении POST-запроса в JSON-формате к Redmine REST API сервер ведет себя так, как будто не воспринимает тело запроса. Например, при попытке добавить Issue возвращается ошибка 404, а в логах Redmine видно:
Processing IssuesController#create to json (for 192.168.10.156 at 2012-04-17 13:59:05) [POST]
  Parameters: {"format"=>"json", "action"=>"create", "controller"=>"issues"}
Filter chain halted as [:find_project] rendered_or_redirected.
Completed in 47ms (View: 0, DB: 10) | 404 Not Found [http://redmine-tp/issues.json]
, хотя передаваемый идентификатор проекта 100% верен (существует в таблице "projects" в БД Redmine). При этом в заголовке Content-Type запроса указывается вроде бы корректное значение "text/json"; при попытке указать неверное "text/xml" возвращается вообще 500 ошибка, а в логи валится:

/!\ FAILSAFE /!\  Tue Apr 17 14:13:38 +0400 2012
  Status: 500 Internal Server Error
  undefined method `name' for nil:NilClass
    /usr/lib/ruby/gems/1.8/gems/activesupport-2.3.14/lib/active_support/xml_mini/rexml.rb:29:in `merge_element!'
    /usr/lib/ruby/gems/1.8/gems/activesupport-2.3.14/lib/active_support/xml_mini/rexml.rb:18:in `parse'
    /usr/lib/ruby/gems/1.8/gems/activesupport-2.3.14/lib/active_support/xml_mini.rb:12:in `__send__'
...
    /usr/lib/ruby/1.8/phusion_passenger/abstract_server.rb:196:in `start_synchronously'
    /usr/lib/phusion_passenger/passenger-spawn-server:61

Причина:

Неверно установлен заголовок Content-Type запроса. Вместо "text/json" необходимо использовать "application/json".

среда, 29 февраля 2012 г.

Модификация Path в заголовке Set-Cookie, отправляемом backend-сервером, сидящим за Apache2 с mod_proxy

Проблема:

За Apache2 веб-сервером сидит backend-сервер Tomcat, при этом путь на Apache2, по которому ведется проксирование, отличается от пути на Tomcat`е, и, следовательно, куки, устанавливаемые томкатом, оказываются недействительными, т.к. в заголовке Set-Cookie браузер видит не тот Path, который указан в URL`е.

Решение:

mod_proxy предусматривает модификацию отправляемого клиенту заголовка Set-Cookie директивой ProxyPassReverseCookiePath. Например, если запросы в корень апача проксируются на путь /mypath томката, директива будет выглядеть следующим образом:
ProxyPassReverseCookiePath /mypath /
Тогда заголовки вида:
Set-Cookie JSESSIONID=2CAF42328709F0A93ABD515651002089; Path=/mypath
будут преобразовываться проксёй в:
Set-Cookie JSESSIONID=2CAF42328709F0A93ABD515651002089; Path=/

среда, 18 января 2012 г.

Просмотр HTTP-заголовков в Firefox

Смотреть HTTP-заголовки запросов/ответов позволяет дополнение HttpFox. Помимо заголовков, можно смотреть куки, данные POST и содержимое ответа сервера.

вторник, 17 января 2012 г.

IE, загрузка файлов и Cache-Control: no-cache, no-store

Проблема:
Заголовок "Cache-Control: no-cache, no-store", предусмотренный в HTTP/1.1 для предотвращения кэширования информации браузерами и прокси-серверами, будучи установленным для ответа, отсылающего файл, вызывает у Internet Explorer появление сообщения (правда не в 100% случаев, я так и не нашел закономерности):
"Не удалось открыть этот интернет-узел. Запрошенный узел недоступен или не найден..."
и файл, естественно, не загружается.

Решение:
Ничего не поделаешь, для файлов заголовок "Cache-Control: no-cache, no-store" придется не ставить. Впрочем, я думаю IE и так не будет кэшировать файлы =)

понедельник, 16 января 2012 г.

HttpServlet: установка Content-Disposition заголовка для скачивания файла с русскими символами в имени

Проблема:
Задача следующая: отправить в браузер файл с русскими символами в имени. Проблема заключается в том, что если помещать имя файла в заголовок непосредственно кодом:
response.setHeader("Content-Disposition", "attachment; filename="+fileName);
вместо корректного имени получаем кракозябры, а IE 8 вообще выкидывает невнятное сообщение о невозможности загрузки.

Решение:
Ниже приведет кроссбраузерный код (работает в IE 8, FF 9, Opera 11.60, Chrome 16):

        if(request.getHeader("user-agent")!=null && request.getHeader("user-agent").indexOf("Firefox")!=-1) // Firefox
            response.setHeader("Content-Disposition", "attachment; filename*=utf-8''"+java.net.URLEncoder.encode(fileName, "UTF-8") + ";");
        else
            response.setHeader("Content-Disposition", "attachment; filename="+java.net.URLEncoder.encode(fileName, "UTF-8"));



среда, 28 декабря 2011 г.

Отключение кэширования данных браузером или прокси-сервером с помощью заголовков HTTP

Кэширование данных браузером и прокси-сервером отключается следующими 4 заголовками:
Expires: Mon, 26 Jul 1997 05:00:00 GMT
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Last-Modified: <now>
, где <now> - текущая дата и время. В JSP (и вообще в любом HTTP-сервлете) это можно установить следующим образом:
DateFormat fullDateTimeFormat = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z", new Locale("EN"));
response.setHeader("Expires", "Mon, 26 Jul 1997 05:00:00 GMT");
response.setHeader("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate");
response.setHeader("Pragma", "no-cache");
response.setHeader("Last-Modified", fullDateTimeFormat.format(new java.util.Date()));