Редирект HTTP заголовком "Location" 2

Maxim Dounin mdounin at mdounin.ru
Tue Jul 22 03:04:11 MSD 2008


Hello!

On Tue, Jul 22, 2008 at 02:07:04AM +0400, Maxim Dounin wrote:

> Hello!
>
> On Tue, Jul 22, 2008 at 12:42:12AM +0400, Alexey Kalinnikov wrote:
>
>>  Не так давно (по весне) было уже обсуждение темы о редиректе при
>>  заголовке "Location". Хотяелось бы еще раз поднять ее.
>>
>>  Проблема в том, что если необходим редирект (в моем случае
>>  происходит выполнение fcgi perl) то помимо указания Location
>>  необходимо обязательно указывать "302 Found", в противном случае
>>  nginx ставит статус 200. Apache, lighttpd и другие сервера ставят
>>  302 и все отрабатывается "правильно".
>>
>>  Достаточно четко проблема прописана как в той теме (Редирект HTTP
>>  заголовком "Location") так и к примеру в
>>  http://www.zag.ru/page/item_view/tarakan_tarakan_tarakashechka_zhidkonogaja_kozjavochka_bukashechka.html
>>
>>  Внимательное изучение RFC 1945 ничего не дало. а гугление выдало
>>  следующую сентенцию
>
> Курить надо не RFC1945, а спеки FastCGI.  Спеки FastCGI говорят, что:
>
> % 6.2 Responder
> % A Responder FastCGI application has the same purpose as a CGI/1.1
> % program: It receives all the information associated with an HTTP
> % request and generates an HTTP response.
> ...
> % The Responder application sends CGI/1.1 stdout data to the Web
> % server over FCGI_STDOUT, and CGI/1.1 stderr data over FCGI_STDERR. 
>
> Т.е. по формату самого ответа нас отсылают к CGI/1.1. Идём курить спеки 
> CGI/1.1 и находим там:
>
> http://hoohoo.ncsa.uiuc.edu/cgi/out.html
>
> % Parsed headers
> % The output of scripts begins with a small header. This header
> % consists of text lines, in the same format as an HTTP header,
> % terminated by a blank line (a line with only a linefeed or CR/LF).
> % Any headers which are not server directives are sent directly back
> % to the client. Currently, this specification defines three server
> % directives:
> %
> % Content-type
> % This is the MIME type of the document you are returning.
> %
> % Location
> % This is used to specify to the server that you are returning a
> % reference to a document rather than an actual document.
> %
> % If the argument to this is a URL, the server will issue a redirect
> % to the client. 
>
> А в RFC3875 (который ни разу не стандарт, но суть более формальное  
> описание CGI/1.1) так вообще чёрным по белому что должен быть 302:
>
> % 2.3.  Client Redirect Response
> %
> %    The CGI script can return an absolute URI path in a Location header
> %    field, to indicate to the client that it should reprocess the request
> %    using the URI specified.
> %
> %       client-redir-response = client-Location *extension-field NL
> %
> %    The script MUST not provide any other header fields, except for
> %    server-defined CGI extension fields.  For an HTTP client request, the
> %    server MUST generate a 302 'Found' HTTP response message.
>
> Такая вот многоходовка получается, по которой вообще говоря надо  
> возвращать 302 если fastcgi-скрипт вернул заголовок Location.
>
>>  "The HTTP status code changes the way browsers and robots handle
>>  redirects, so if you are using header(Location:) it's a good idea
>>  to set the status code at the same time. Browsers typically
>>  re-request a 307 page every time, cache a 302 page for the session,
>>  and cache a 301 page for longer, or even indefinitely.
>>  Search engines typically transfer "page rank" to the new location for 301 redirects,
>>  but not for 302, 303 or 307.
>>
>>  If the status code is not specified, header('Location:') defaults to 302."
>>
>>
>>  Нельзя ли в и в nginx добавить данный функционал (возврат кода 302
>>  вместо 200 если в хедере есть указание Location)? Или может быть кто
>>  то может подсказать как реализовать его "на стороне веб-сервера"?
>
> В ngx_http_fastcgi_module это легко запихивается.  Если я сподоблюсь 
> построить тестовую среду для FastCGI - сделаю патч.

Патч.

Maxim Dounin
-------------- next part --------------
# HG changeset patch
# User Maxim Dounin <mdounin at mdounin.ru>
# Date 1216680959 -14400
# Node ID 1e54028db936e988171a4eb9a5c8eff81c0ad827
# Parent  1d9bef53cd8e9461c73ed537a953f3a7bae6dbd2
Set 302 status if there is Location header in fastcgi reply.

Per FastCGI specification application reply is actually CGI/1.1 stdout
reply.  And per CGI/1.1 spec if application reply has Location header -
server must generate 302 redirect.

diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -1167,6 +1167,13 @@ ngx_http_fastcgi_process_header(ngx_http
                     u->headers_in.status_n = status;
                     u->headers_in.status_line = *status_line;
 
+                } else if (u->headers_in.location) {
+                    u->headers_in.status_n = 302;
+                    u->headers_in.status_line.len =
+                                           sizeof("302 Moved Temporarily") - 1;
+                    u->headers_in.status_line.data =
+                                           (u_char *) "302 Moved Temporarily";
+
                 } else {
                     u->headers_in.status_n = 200;
                     u->headers_in.status_line.len = sizeof("200 OK") - 1;
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -137,7 +137,8 @@ ngx_http_upstream_header_t  ngx_http_ups
                  ngx_http_upstream_copy_header_line, 0, 0 },
 
     { ngx_string("Location"),
-                 ngx_http_upstream_ignore_header_line, 0,
+                 ngx_http_upstream_process_header_line,
+                 offsetof(ngx_http_upstream_headers_in_t, location),
                  ngx_http_upstream_rewrite_location, 0, 0 },
 
     { ngx_string("Refresh"),


More information about the nginx-ru mailing list