Nginx rewrite: last & break

Hello,

According to document: http://wiki.nginx.org/HttpRewriteModule#rewrite

It said “break - completes processing of rewrite directives and
breakes location lookup cycle by not doing any location lookup and
internal jump at all”

However, seems my config below is an exception?

server {
listen 80;

    server_name .example.com
    root /data/example/;

    if ($request_uri ~ "foo") {
        rewrite ^/foo /bar break;
    }

    location /bar {
        echo "error";
    }

}

When I curl using: curl http://example.com/foo

the string “error” was returned.

However, isn’t the break will skip any following location block? So it
shouldn’t matche the location below, right?

Thanks.

Hello!

On Fri, Oct 21, 2011 at 12:12:01AM +0800, Ryan C. wrote:

server {
echo “error”;
}
}

When I curl using: curl http://example.com/foo

the string “error” was returned.

However, isn’t the break will skip any following location block? So it
shouldn’t matche the location below, right?

Processing of rewrite directives at server level may be stopped
via break, but the location lookup will follow anyway (as there is
no location at this stage where request may be processed).

Note original documentation doesn’t say anything about “breakes
location lookup cycle …”. It’s looks like it was added by
Agentzh here:

http://wiki.nginx.org/index.php?title=HttpRewriteModule&action=historysubmit&diff=7141&oldid=6736

I’ve reverted it as it’s incorrect and obviously causes confusion.

Maxim D.

On 20 October 2011 19:38, Maxim D. [email protected] wrote:

internal jump at all"
rewrite ^/foo /bar break;

http://wiki.nginx.org/index.php?title=HttpRewriteModule&action=historysubmit&diff=7141&oldid=6736

I’ve reverted it as it’s incorrect and obviously causes confusion.

Still quite confusing because the “last” portion goes on to say “after
which searches for corresponding URI and location”. As the “break”
part does not say anything, it implies that “after which DOES NOT
search for corresponding URI OR location”. I.E. It implies what
agentzh wrote.

Perhaps needs some clarification about it being appropriate at server
level (If I understand you — totally confused lol).

On Fri, Oct 21, 2011 at 12:38 AM, Maxim D. [email protected]
wrote:

Yes, I forgot to take into account server-level rewrites. And sorry
about that. But what I said is correct for location-level rewrites,
no?

We definitely need more clarification here. And in fact, location jump
actually happens in post-rewrite phase handler for location-wise
rewrites! LOL

Regards,
-agentzh

Hello,

On Fri, Oct 21, 2011 at 12:19 PM, agentzh [email protected] wrote:

We definitely need more clarification here. And in fact, location jump
actually happens in post-rewrite phase handler for location-wise
rewrites! LOL

Regards,
-agentzh


Thanks.

Anyone would like to do a quick summary for the issue?

On Fri, Oct 21, 2011 at 12:54 AM, Nginx U. [email protected]
wrote:

Still quite confusing because the “last” portion goes on to say “after
which searches for corresponding URI and location”. As the “break”
part does not say anything, it implies that “after which DOES NOT
search for corresponding URI OR location”. I.E. It implies what
agentzh wrote.

Perhaps needs some clarification about it being appropriate at server
level (If I understand you — totally confused lol).

Agreed.

Perhaps need some examples as well.

It is quit dangerous because sometimes we think it just worked and it
is ok, but in fact we are wrong

e.g.:
http://serverfault.com/questions/131474/nginx-url-rewriting-difference-between-break-and-last

I spent a whole day to debug this issue…

Nginx U. Wrote:

Adding Maxim’s statement above into account,
outside a location block,
“break” behaves just like “last” does since there
are no location
directives to run here.

Someone just needs to update the docs if this is
correct.

I have experienced situations when “rewrite something target last;” in
the server {} section generates the 503 page, while “rewrite something
target break;” instead works OK. It means that “break” does not behave
like “last” in the server section of the virtual host either.

Andrejs

Posted at Nginx Forum:
http://forum.nginx.org/read.php?2,216965,217052#msg-217052

On 22 October 2011 06:30, Ryan C. [email protected] wrote:

Anyone would like to do a quick summary for the issue?

Minaev’s answer in the serverfault link you provided is the clearest
explanation I have seen to date of this.

To paraphrase, he says, within a location block, when you use “last”
the rewrites are stopped and a new subrequest is generated which will
take all all locations into account. When you use “break” the rewrites
are stopped and processing continued within the location you are in.

Adding Maxim’s statement above into account, outside a location block,
“break” behaves just like “last” does since there are no location
directives to run here.

Someone just needs to update the docs if this is correct.

Hello,

On Sat, Oct 22, 2011 at 7:04 PM, Nginx U. [email protected] wrote:

This is also my understanding, so if it is right, please update the
wiki as this feature is quite important.

Hello!

On Sat, Oct 22, 2011 at 02:04:21PM +0300, Nginx U. wrote:

On 22 October 2011 06:30, Ryan C. [email protected] wrote:

Anyone would like to do a quick summary for the issue?

Minaev’s answer in the serverfault link you provided is the clearest
explanation I have seen to date of this.

To paraphrase, he says, within a location block, when you use “last”
the rewrites are stopped and a new subrequest is generated which will

Just a side note: “subrequest” is incorrect term here.

take all all locations into account. When you use “break” the rewrites
are stopped and processing continued within the location you are in.

Adding Maxim’s statement above into account, outside a location block,
“break” behaves just like “last” does since there are no location
directives to run here.

Someone just needs to update the docs if this is correct.

Reading rewrite module docs carefully enough will tell basically
the same:


If the URI changed as a result of the execution of directives
inside location, then location is again determined for the new
URI. This cycle can be repeated up to 10 times, after which Nginx
returns a 500 error.


Example:

rewrite  ^(/download/.*)/media/(.*)\..*$  $1/mp3/$2.mp3  last;
rewrite  ^(/download/.*)/audio/(.*)\..*$  $1/mp3/$2.ra   last;
return   403;

But if we place these directives in location /download/, then it
is necessary to replace flag “last” by “break”, otherwise Nginx
will hit the 10 cycle limit and return error 500:

location /download/ {
    rewrite  ^(/download/.*)/media/(.*)\..*$  $1/mp3/$2.mp3  break;
    rewrite  ^(/download/.*)/audio/(.*)\..*$  $1/mp3/$2.ra   break;
    return   403;
}

The translation though looks awful and needs re-translation;
additionally, it was already polluted with user comments, and this
doesn’t improve readability either.

Maxim D.

On 23 Out 2011 16h26 WEST, [email protected] wrote:

Hello Maxim,

Can this be reasoned like this?

  1. last means the last rewrite, after which the location matching
    phase reoccurs, in search of a content handler.

  2. break means that the rewrite phase is done and we proceed to the
    next phase. There must be a content handler (be a location) for
    this to be true.

  3. Outside a location block there’s no content handler, hence using
    last or break is basically the same.

Thx,
— appa

Hello!

On Sat, Oct 22, 2011 at 10:25:29AM -0400, locojohn wrote:

correct.

I have experienced situations when “rewrite something target last;” in
the server {} section generates the 503 page, while “rewrite something
target break;” instead works OK. It means that “break” does not behave
like “last” in the server section of the virtual host either.

The 500, likely. This might happen with nginx before 1.1.6 due to
completely different reason: if there were no matching location
found, the rewrite directives specified at server level were
executed inside an implicit location again.

It is fixed in 1.1.6:

*) Bugfix: the ngx_http_rewrite_module directives specified at 

“server”
level were executed twice if no matching locations were defined.

Simple and effective way to prevent such sort of problems is to
always define “location /”.

Maxim D.

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs