Имеем ситуацию - cервер (назовём его server) с включенным keep-alive.
httpd.conf:
Redirect temp /aaa http://server/bbb.htm
wget -S server/aaa
HTTP/1.1 302 Found
Location: http://server/bbb.htm
Connection: close
Content-Type: text/html; charset=iso-8859-1
Location: http://server/bbb.htm [following]
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Length: XXX
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Content-Type: text/html
(для простоты часть header'ов поскипана).
Всё бы хорошо. Если бы не "Connection: close" в первом response.
Это - типичная фишка apach'а, напрямую следующая из логики
ap_set_keepalive() (src/main/http_protocol.c). Если, скажем, нет заголовка
"Content-Length" (или просто body, или ещё десяток условий) - то закрываем
соединение.
Эта логика была бы логична, если исходить из того, что redirect
всенепременнейше ведёт на другие сайты. Но вся прелесть в том, что чаще-то
redirect определяется в пределах одного сервера. Типичнейший (для меня)
пример - сайт с несколькими языками, и проброс с корня сайта на его
версию-с-языком-по-умолчанию, скажем так:
RewriteRule ^/(index\.html?)?$ en/index.htm [R,L]
Именно этот момент "проброса" хочется сделать моментальным, раз уж, скрепя
сердце, разрешён keep-alive для сервера (с побочным эффектом в виде
ненавистных FIN_WAIT_2). Быстро вывести первую страницу - это почти как
победа в сражении.
Решений напрашивается два:
1. Выдавать body и, соотв., выставлять честный "Content-Length".
Это удобно для redirect'ов, приходящих от backend'а (скажем, как результат
авторизации) - keep-alive гарантированно заработает.
И так делают многие и для frontend'ов (см. wget -S google.com).
2. Патчить mod_alias.c/mod_rewrite.c на предмет добавления после строки:
ap_table_setn(r->headers_out, "Location", ret);
такой вот вещи как:
r->header_only = 1;
(Выставлять "Content-Length: 0" - явный моветон).
Пропатченный сервер делает всё как надо:
HTTP/1.1 302 Found
Location: http://server/bbb.htm
Keep-Alive: timeout=15, max=99
Connection: Keep-Alive
Content-Type: text/html; charset=iso-8859-1
Location: http://server/bbb.htm [following]
......
Вопрос первый - стоит ли так вот пошло обманывать Apache?
Он, в принципе, и сам обманываться рад - см. в ap_set_byterange() (всё тот
же src/main/http_protocol.c) такие строчки:
r->header_only = 1;
r->status = HTTP_RANGE_NOT_SATISFIABLE;
Вопрос второй - а не послать ли этот патчик, чтоб данное поведение стало
по-умолчанию?
Конечно основная проблема не в сути патча (проще выкинуть mod_rewrite и
написать нехитрый модуль для "проброса") - а в изменении r->header_only и
правомерности самого подхода - возвращать "Location" с "Connection:
Keep-Alive" но без "Content-Length". В RFC2616 вопрос соответствия http
status codes и заголовка "Connection" как-то вовсе не рассматривается.
--
Sergey Skvortsov
mailto: skv@xxxxxxxxx