Rewrite "break" directive - a strange behavior

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.

/etc/nginx/nginx.conf

worker_processes auto;
pid /var/run/nginx.pid;

events {
worker_connections 2048;
}
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;

    upstream media_server {
            server 127.0.0.1:1935; ### Our media server}
    }

include /etc/nginx/sites-enabled/example.conf;
}
############## END ##########################

Example server block:

/etc/nginx/sites-enabled/example.conf

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”

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 a WGET example.
######### START #############################
[root ~]# wget -S -O - http://localhost/pippo/crossdomain.xml
–2013-04-04 09:05:11-- http://localhost/pippo/crossdomain.xml
Resolving localhost (localhost)… 127.0.0.1
Connecting to localhost (localhost)|127.0.0.1|:80… connected.
HTTP request sent, awaiting response…
HTTP/1.1 200 OK
Server: nginx/1.2.6
Date: Thu, 04 Apr 2013 09:05:11 GMT
Content-Type: text/xml
Content-Length: 250
Connection: keep-alive
Cache-Control: no-cache
Test-Cache-Control: max-age=600
Length: 250 [text/xml]
Saving to: `STDOUT’

0% [

             ] 0           --.-K/s              <?xml 

version=“1.0”?>

100%[=====================================================================================================================================================================>] 250 --.-K/s in 0s

2013-04-04 09:05:11 (21.1 MB/s) - written to stdout [250/250]
######### END ########################

I tried to move the SET directive before REWRITE “break” and everything
works.
####### START ##########
location ~* “/crossdomain.xml$” {
set $cache_max_age “$cache_crossdomain”;
rewrite ^/pippo/(.*) /$1 break;
proxy_pass http://media_server;
}

END

Example request, after moving the SET directive ( “Test-Cache-Control:
max-age=2” is NOW correct )
########## START #########################
[root ~]# wget -S -O - http://localhost/pippo/crossdomain.xml
–2013-04-04 09:12:37-- http://localhost/pippo/crossdomain.xml
Resolving localhost (localhost)… 127.0.0.1
Connecting to localhost (localhost)|127.0.0.1|:80… connected.
HTTP request sent, awaiting response…
HTTP/1.1 200 OK
Server: nginx/1.2.6
Date: Thu, 04 Apr 2013 09:12:37 GMT
Content-Type: text/xml
Content-Length: 250
Connection: keep-alive
Cache-Control: no-cache
Test-Cache-Control: max-age=2
Length: 250 [text/xml]
Saving to: `STDOUT’

0% [

             ] 0           --.-K/s              <?xml 

version=“1.0”?>

100%[=====================================================================================================================================================================>] 250 --.-K/s in 0s

2013-04-04 09:12:37 (15.9 MB/s) - written to stdout [250/250]
############# END ######################

I searched inside the official documentation:

  • REWRITE “break” descriptions say:
    Module ngx_http_rewrite_module
    — “completes processing of current rewrite directives and non-rewrite
    processing continues within the current location block only.”
    Module ngx_http_rewrite_module
    — “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 ?

Thanks in advance for your support !!

Posted at Nginx Forum:

Sorry, i forgot to post Nginx version and build details.

NGINX_VERSION=“1.2.6”

CONFIGURE command used to build

./configure --conf-path=/etc/nginx/nginx.conf --prefix=/etc/nginx
–error-log-path=/var/log/nginx/error.log
–http-client-body-temp-path=/var/lib/nginx/body
–http-fastcgi-temp-path=/var/lib/nginx/fastcgi
–http-log-path=/var/log/nginx/access.log
–http-proxy-temp-path=/var/lib/nginx/proxy
–http-scgi-temp-path=/var/lib/nginx/scgi
–http-uwsgi-temp-path=/var/lib/nginx/uwsgi
–lock-path=/var/lock/nginx.lock --pid-path=/var/run/nginx.pid
–without-mail_pop3_module
–without-mail_imap_module --without-mail_smtp_module --with-debug
–with-rtsig_module --with-file-aio
–with-http_realip_module --with-http_addition_module
–with-http_sub_module --with-http_random_index_module
–with-http_secure_link_module --with-http_dav_module
–with-http_gzip_static_module --with-http_random_index_module
–add-module=modules/lua-nginx-module
–add-module=modules/nginx-push-stream-module
–add-module=modules/chunkin-nginx-module
–add-module=modules/nginx-upload-progress-module
–add-module=modules/substitutions4nginx-read-only
–add-module=modules/echo-nginx-module
–add-module=modules/ngx_devel_kit
–add-module=modules/headers-more-nginx-module
–add-module=modules/nginx_upload_module-2.2.0
–with-pcre=modules/pcre-8.32
–with-zlib=modules/zlib-1.2.7
–with-http_ssl_module --with-openssl=modules/openssl-1.0.1c
–with-http_xslt_module --with-ipv6
–with-sha1=/usr/include/openssl --with-md5=/usr/include/openssl
–with-cc-opt=-Wno-error
####################################################

Posted at Nginx Forum:

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.

[…]

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 …

[…]

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 D.
http://nginx.org/en/donation.html

Thank you very much for the immediate answer !! :slight_smile:

Just reading this documentation
(“Module ngx_http_rewrite_module”)
i had the suspect that “set” is a rewrite module`s directive.

But, in this other documentation
(“Module ngx_http_rewrite_module”) i was a little in
confusion.

The first documentation
(Module ngx_http_rewrite_module) is
certainly more helpful to understand this behaviour.

Thanks again!

Posted at Nginx Forum: