Re: proxy cache key и fastcgi cache key
Валентин Бартенев
vbart at nginx.com
Fri Jan 10 23:51:15 UTC 2014
On Saturday 11 January 2014 01:06:00 Gena Makhomed wrote:
[..]
> >> с RFC то как раз все в порядке: "network location of the URI
> >> (authority) MUST be transmitted in a Host header field",
> >> только вот nginx не соответствует этим требованиям...
> >>
> >> http://tools.ietf.org/search/rfc2616#section-5.1.2
> ...
> > Если почитать внимательнее, то приведенные требования относятся к клиенту.
> > Понятно, что сервер в принципе не может влиять на то, что transmitted в
> > запросе.
>
> nginx выступает в роли сервера только в том случае,
> когда он самостоятельно обслуживает клиентский запос.
>
> В тот момент, когда nginx делает http запрос к удаленному
> серверу он выступает в роли клиента. поэтому я и цитировал 5.1.2
С точки зрения удаленного сервера да. И при этом поступает совершенно
корректно, а именно передает "network location of the URI (authority)"
в заголовки Host.
Представим себе строчку из конфигурации:
proxy_pass http://127.0.0.1:8181/some/path;
думаю очевидно, что в из заданного URI "http://127.0.0.1:8181/some/path"
является authority.
>
> а дальше, получив ответ от удаленного сервера он с этим ответом
> делает разные интересные вещи, например, сканирует его на предмет
> ssi-директив, или пропускает через свои sub/addition/и т.п. модули.
> и то, что получится в результате - складывает в файл кеша на диске,
> и после дополнительной цепочки преобразований - отправляет то,
> что получилось в результате как ответ на запрос своего клиента.
>
> например, если исходный запрос от клиента к nginx был
>
> GET http://good-site.com/pub/WWW/TheProject.html HTTP/1.1
> Host: bad-site.com
>
> содержимое заголовка Host: согласно 5.2.1 должно игнорироваться,
> адрес хоста в этом случае: good-site.com
>
> а согласно требований 5.1.2 - network location of the URI (authority)
> MUST be transmitted in a Host header field, то есть исходящий запрос
> должен быть
>
> GET /pub/WWW/TheProject.html HTTP/1.1
> Host: good-site.com
>
> nginx же в настройке по-умолчанию не соответсвует RFC,
> и вместо требуемого значения пишет в заголовок Host:
> значение переменной $proxy_host
Поздравляю. Это самое необычное толкование RFC 2616, которое я когда либо
встречал.
К счастью оно разбивается об определение терминов client и server из него же:
client
A program that establishes connections for the purpose of sending
requests.
server
An application program that accepts connections in order to
service requests by sending back responses. Any given program may
be capable of being both a client and a server; our use of these
terms refers only to the role being performed by the program for a
particular connection, rather than to the program's capabilities
in general. Likewise, any server may act as an origin server,
proxy, gateway, or tunnel, switching behavior based on the nature
of each request.
ключевой момент тут: "refers only to the role being performed by the program
for a particular connection".
Соединение между клиент->nginx и соединение nginx->upstream - это два
разных соединения, и в каждом из них nginx играет исключительно одну
единственную роль, применимую только к конкретному соединению.
В соединении "клиент->nginx" не играет роль клиента и клиентские требования
RFC 2616 в данном соединении к нему не применимы.
> Теперь рассмотрим вариант связи с backend`ом по протоколу FastCGI,
> но поскольку у нас большой и сложный сайт сделаем два фронтенда:
>
> 1) основной nginx frontend
> 2) nginx frontend на хосте backend`а
> 3) backend, работающий по протоколу FastCGI.
>
> запрос от клиента проходит цепочку (1)->(2)->(3).
> поскольку между (1) и (2) используется протокол http,
> то согласно требований 5.1.2 и 5.2.1 на (2) запрос приходит
> в виде
>
> GET /pub/WWW/TheProject.html HTTP/1.1
> Host: good-site.com
>
> не смотря на то, что в исходном запросе
> от клиента был игнорируемый заголовок Host: bad-site.com
>
> а дальше - все просто. В соответствии с требованиями
> спецификации протокола FastCGI - nginx записывает в переменную
> HTTP_HOST значение good-site.com.
>
> точнее, он ДОЛЖЕН так делать, согласно требований HTTP протокола
> прямо из коробки, без какой-либо дополнительной настройки.
В спецификации нет требования, согласно котором сервер из коробки
должен быть клиентом и отправлять запросы куда-то дальше.
Так что дополнительная настройка все равно потребуется, и я так
понимаю, исходя из описания, она была какой-то такой:
location {
proxy_pass http://good-site.com;
}
>
> Эта схема работает одинаково вне зависимости от количества
> промежуточных серверов между nginx frontend и backend.
>
> точнее, ДОЛЖНА работать одинаково,
> вне зависимости от количества промежуточных серверов.
Она работает, настройку см. выше.
> если в случае отсутствия промежуточных серверов nginx ведет себя
> не так, - то это BUG, ибо в случае, когда на nginx frontend
> приходит запрос в виде absoluteURI, - тогда "Any Host header
> field value in the request MUST be ignored".
> nginx этого по каким-то причинам не делает.
Почему не делает? Процитированная фраза относится к rules из
фразы которые находятся по общим заголовком из:
An origin server that does differentiate resources based on the host
requested (sometimes referred to as virtual hosts or vanity host
names) MUST use the following rules for determining the requested
resource on an HTTP/1.1 request:
именно таким правилом и пользуется nginx _при выборе_ виртуального хоста.
>
> хотя согласно требований RFC - обе эти формы записи:
>
> GET http://good-site.com/pub/WWW/TheProject.html HTTP/1.1
>
> и
>
> GET /pub/WWW/TheProject.html HTTP/1.1
> Host: good-site.com
>
> полностью эквивалентны между собой. и nginx имеет
> полное право и даже обязанность трансформировать
>
> запрос с absoluteURI в запрос с relativeURI
> и network location of the URI (authority)
> MUST be transmitted in a Host header field.
Как сервер он такой обязанности не имеет, а в данном конкретном соединении,
как я уже пояснил вначале, он выступает в роли сервера и никакой другой.
Сервер вообще не обязан делать запросы и что-то куда-то transmitted.
[..]
>
> Та часть nginx, которая работает в режиме сервера определяет Host
> правильно. И правильно сохранет его в свою переменную $host.
>
> Но дальше в нарушение RFC вместо $host зачем-то используется $http_host
> не смотря на прямой запрет: Any Host header field value in the request
> MUST be ignored.
>
> А несоответствие требованиям RFC 2616 - это ведь BUG, верно?
Поскольку мысль повторена по меньшей мере 3 раза, то и в третий раз,
на всякий случай: на ту часть nginx, которая работает в режиме сервера, не
распространяется клиентских требований RFC 2616, что в самом же RFC 2616
прописано, а именно роли клиента и сервера взаимоисключающие, и закреплены
для каждого индивидуального соединения.
--
Валентин Бартенев
Подробная информация о списке рассылки nginx-ru