Nginx parse var in if file exist statement error?

Hi guys,

I found a stange bug in nginx 0.7.65, 0.8.54, and 1.0.6

Here is my setup of three machines

$ nginx -V
nginx version: nginx/0.7.65
TLS SNI support enabled
configure arguments: --conf-path=/etc/nginx/nginx.conf
–error-log-path=/var/log/nginx/error.log --pid-path=/var/run/nginx.pid
–lock-path=/var/lock/nginx.lock
–http-log-path=/var/log/nginx/access.log
–http-client-body-temp-path=/var/lib/nginx/body
–http-proxy-temp-path=/var/lib/nginx/proxy
–http-fastcgi-temp-path=/var/lib/nginx/fastcgi --with-debug
–with-http_stub_status_module --with-http_flv_module
–with-http_ssl_module --with-http_dav_module
–with-http_gzip_static_module --with-http_realip_module --with-mail
–with-mail_ssl_module --with-ipv6
–add-module=/build/buildd/nginx-0.7.65/modules/nginx-upstream-fair

$nginx -V
nginx version: nginx/0.8.54
built by gcc 4.2.4 (Ubuntu 4.2.4-1ubuntu4)
configure arguments: --user=www-data --group=www-data
–prefix=/usr/local/nginx --with-http_stub_status_module

$ nginx -V
nginx: nginx version: nginx/1.0.6
nginx: TLS SNI support enabled
nginx: configure arguments: --prefix=/etc/nginx/
–sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf
–error-log-path=/var/log/nginx/error.log
–http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid
–lock-path=/var/run/nginx.lock
–http-client-body-temp-path=/var/cache/nginx/client_temp
–http-proxy-temp-path=/var/cache/nginx/proxy_temp
–http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp
–http-uwsgi-temp-path=/var/cache/nginx/uwcgi_temp
–http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx
–group=nginx --with-http_ssl_module --with-http_realip_module
–with-http_addition_module --with-http_sub_module
–with-http_dav_module --with-http_flv_module
–with-http_gzip_static_module --with-http_random_index_module
–with-http_secure_link_module --with-http_stub_status_module
–with-mail --with-mail_ssl_module --with-file-aio --with-ipv6

So I have dir to store images, either jpg or png, the file name (image
id) is unique. I want the URL to provide image id only, nginx to serve
static jpg or png.

the config snippet is something like this:

server {
listen 80;
error_log /var/log/nginx/error_imglib.log debug;
root /home/develop/image_library;

location ~* ^/img/small/(\d+)/?$ {
set $fext ‘jpg’;
if (!-f ‘/home/develop/image_library/dump/$1-s.jpg’){
set $fext png;
}
alias ‘/home/develop/image_library/dump/$1-s.$fext’ ;
}
}

When running curl it returls something like this

$ curl “http://127.0.0.1/img/small/1

404 Not Found

404 Not Found


nginx/1.0.6

Now the bug:

in three of my machines I set the error_log level to “debug”, here is
the output:

2011/11/02 14:01:09 [debug] 4194#0: *24 http script capture: “1”
2011/11/02 14:01:09 [debug] 4194#0: *24 http script copy: “-s.”
2011/11/02 14:01:09 [debug] 4194#0: *24 http script var: “png”
2011/11/02 14:01:09 [debug] 4194#0: *24 http filename:
“/home/steve/image_library/dump/1-s.png1
User-Agent”
2011/11/02 14:01:09 [debug] 4194#0: *24 add cleanup: 0833B2F0
2011/11/02 14:01:09 [error] 4194#0: *24 open()
“/home/steve/image_library/dump/1” failed (2: No such file or
directory), client: 127.0.0.1, request: “GET /img/small/1 HTTP/1.1”

2011/11/01 23:00:53 [alert] 7793#0: *38
“/home/develop/image_library/dump/1-s.jpgindex.html” is not a directory,
request: “GET /img/small/1 HTTP/1.1”

2011/11/02 02:30:18 [error] 7666#0: *2491 open()
“/home/develop/image_library/dump/1-s.pn” failed (2: No such file or
directory), client: 127.0.0.1, request: “GET /img/small/1 HTTP/1.1”

2011/11/01 22:47:45 [error] 6740#0: *24
“/home/develop/image_library/dump/1-s.jpgTP/1.1
Hostindex.html” is not found (2: No such file or directory), request:
“GET /img/small/1 HTTP/1.1”

So clearly somehow, nginx managed to mess HTTP headers into filename
parser.

Can anyone help me? This is the weirdest bug I have ever encountered
with nginx.

Posted at Nginx Forum:

On Wednesday 02 November 2011 14:09:59 est wrote:
[…]

root /home/develop/image_library;

location ~* ^/img/small/(\d+)/?$ {
set $fext ‘jpg’;
if (!-f ‘/home/develop/image_library/dump/$1-s.jpg’){
set $fext png;
}
alias ‘/home/develop/image_library/dump/$1-s.$fext’ ;
}
}

[…]

server {
listen 80;
error_log /var/log/nginx/error_imglib.log debug;
root /home/develop/image_library;

location ~* ^/img/small/(\d+)/?$ {
try_files /dump/$1-s.jpg /dump/$1-s.png =404
}
}

wbr, Valentin V. Bartenev

Oh thanks very much guys. try_files worked well. I tried using try_files
before, but mistakenly wrote it as something like this

try_files dump/$1-s.jpg dump/$1-s.png 404;

The correct working line should be like this

try_files /dump/$1-s.jpg /dump/$1-s.png =404;

And I didn’t expect IF is evil. Suprise!

Thanks again.

Posted at Nginx Forum:

Hello!

On Wed, Nov 02, 2011 at 06:09:59AM -0400, est wrote:

[…]

So clearly somehow, nginx managed to mess HTTP headers into filename
parser.

Can anyone help me? This is the weirdest bug I have ever encountered
with nginx.

Valentin already replied how to do this properly. As for the bug
itself, it’s documented here:

Maxim D.