Rewrite "break" directive - a strange behavior

Maxim Dounin mdounin at mdounin.ru
Fri Apr 5 09:58:11 UTC 2013


Hello!

On Fri, Apr 05, 2013 at 05:38:22AM -0400, andrea.mandolo wrote:

> Hi,
> 
> I'd like to report a strange behaviour of REWRITE "break" directives inside
> a "location" block, when it is used a SET directive subsequently.
> 
> Now, i quote a little example, with a basic Nginx configuration that
> simulate the issue.

[...]

> server {
> 	listen 0.0.0.0:80;
> 	server_name _;
> 
> 	set $cache_max_age "600";
> 	set $cache_crossdomain "2";
> 
> 	location ~* "/crossdomain\.xml$" {
> 		rewrite ^/pippo/(.*) /$1 break;
> 		set $cache_max_age "$cache_crossdomain";
> 		proxy_pass http://media_server;
> 	}
> 
> 	add_header Test-Cache-Control "max-age=$cache_max_age";
> }
> ############### END #########################
> 
> I expect the response to a request ( performed via WGET for example ) to
> "http://localhost/pippo/crossdomain.xml"
> contains the HEADER "Test-Cache-Control: max-age=2"

This is wrong expectation.  As "rewrite ... break" stops 
processing of rewrite module directives, and "set" is the rewrite 
module directive, the

    set $cache_max_age "$cache_crossdomain";

is never executed due to break.  The add_header configured 
uses previously computed value of the $cache_max_age variable, 
i.e. "600".

The confusion likely comes from the fact that rewrite module 
directives are imperative, in contrast to other parts of the nginx 
config, which is declarative.

Reading docs here (in particular, preface and internal 
implementation sections) should be helpfull to understand how it 
works:

http://nginx.org/en/docs/http/ngx_http_rewrite_module.html

> Instead, i get a wrong answer with HEADER  "Test-Cache-Control:
> max-age=600",
> as if the variable "$cache_max_age" is not re-setted with the new value
> "2".

This is expected behviour.

If you want "set ..." to be executed, you have two basic options:

1) Don't use "rewrite ... break" but use "break" after rewrite 
module directives, i.e.

    rewrite ...
    set ...
    break;

    proxy_pass ...

2) Just switch order of "rewrite" and "break" directives in your 
config: 

    set ...
    rewrite ... break;

    proxy_pass ...

[...]

> I searched inside the official documentation:
> - REWRITE "break" descriptions say:
> -- http://wiki.nginx.org/HttpRewriteModule#rewrite
> --- "completes processing of current rewrite directives and non-rewrite
> processing continues within the current location block only."
> -- http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite
> --- "stops processing the current set of ngx_http_rewrite_module
> directives."
> 
> I haven't found anything that justifies this behaviour.
> 
> Maybe, the set directive is considerated an "ngx_http_rewrite_module
> directive" ?
> or, is this a potential issue ?

The "set" directive _is_ rewrite module directive.

http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#set

-- 
Maxim Dounin
http://nginx.org/en/donation.html



More information about the nginx mailing list