Support for relative URL in Location header

HTTP status codes such as 201, 301, 302, etc rely on the HTTP Location
header. The current standard of HTTP specifies that this URL must be
absolute. However, all popular browsers will accept a relative URL,
and it is correct according to the upcoming revision of HTTP/1.1. See
also [1].

I noticed that the version of nginx that I’m running (1.1.9, ubuntu
precise) does not properly interpret a relative URL. The docs on
“proxy_redirect” state that "The default replacement specified by the
default parameter uses the parameters of the location and proxy_pass
directives. " [2]. However it does not work when the Location path is
relative. For example if:

location /one/ {
proxy_pass http://upstream:port/two/;
proxy_redirect default;
}

Then a location header “http://upstream:port/two/foo.bar” gets
rewritten to “/one/foo.bar”. However a location header “/two/foo.bar”
does not get rewritten to “/one/foo.bar”, as it should if the relative
URL were supported.

Is this something that will, or already has been implemented in more
recent versions of nginx?

[1] HTTP location - Wikipedia
[2]
Module ngx_http_proxy_module

On Mon, Nov 4, 2013 at 5:08 PM, Maxim D. [email protected] wrote:

The proxy_redirect directive does string replacement, not URI
mapping. If you want it to replace “/two/” with “/one/”, you can
configure it to do so. It’s just not something it does by
default.

Exactly. I was trying to argue that it probably should do this by
default, otherwise it leads to behavior that is incorrect in light of
the revised interpretation of the Location header.

Hello!

On Mon, Nov 04, 2013 at 10:42:00AM -0800, Jeroen O. wrote:

directives. " [2]. However it does not work when the Location path is
relative. For example if:

location /one/ {
proxy_pass http://upstream:port/two/;
proxy_redirect default;
}

Docs explicity say that this is equivalent to

location /one/ {
    proxy_pass     http://upstream:port/two/;
    proxy_redirect http://upstream:port/two/ /one/;

Note that it just illustrates what the sentence you’ve quoted
means.

Then a location header “http://upstream:port/two/foo.bar” gets
rewritten to “/one/foo.bar”. However a location header “/two/foo.bar”
does not get rewritten to “/one/foo.bar”, as it should if the relative
URL were supported.

Is this something that will, or already has been implemented in more
recent versions of nginx?

The proxy_redirect directive does string replacement, not URI
mapping. If you want it to replace “/two/” with “/one/”, you can
configure it to do so. It’s just not something it does by
default.


Maxim D.
http://nginx.org/en/donation.html

Hello!

On Tue, Nov 05, 2013 at 08:30:42AM -0800, Jeroen O. wrote:

On Mon, Nov 4, 2013 at 5:08 PM, Maxim D. [email protected] wrote:

The proxy_redirect directive does string replacement, not URI
mapping. If you want it to replace “/two/” with “/one/”, you can
configure it to do so. It’s just not something it does by
default.

Exactly. I was trying to argue that it probably should do this by
default, otherwise it leads to behavior that is incorrect in light of
the revised interpretation of the Location header.

It does exactly what’s advertised, so I don’t think it’s incorrect
in any light.

It might be more convenient to have it to replace “/two/” with
“/one/” by default, but given the number of various relative URI
forms (e.g., consider “//upstream:port/two/”), I don’t think it’s
feasible without changing proxy_redirect to actually do URI
mapping instead of string replacement.


Maxim D.
http://nginx.org/en/donation.html