Opened 8 years ago

Closed 8 years ago

Last modified 8 years ago

#151 closed defect (invalid)

X-Accel-Expires send by upstream overrides all values set with fastcgi_cache_valid, including 50x errors

Reported by: Albert Szelagowski Owned by: somebody
Priority: minor Milestone:
Component: nginx-core Version: 1.0.x
Keywords: Cc:
uname -a: Linux #1 SMP Mon Aug 9 10:18:48 BST 2010 x86_64 GNU/Linux
nginx -V: nginx version: nginx/1.0.14
built by gcc 4.3.2 (Debian 4.3.2-1.1)
TLS SNI support enabled
configure arguments: --prefix=/usr --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/ --lock-path=/var/lock/nginx.lock --user=www-data --group=www-data --with-http_realip_module --with-http_gzip_static_module --with-http_stub_status_module --with-http_ssl_module --without-mail_pop3_module --without-mail_imap_module --without-mail_smtp_module --without-http_scgi_module --without-http_uwsgi_module --with-debug --with-ipv6 --with-http_geoip_module --add-module=/var/opt/nginx-upload-progress-module/ --add-module=/var/opt/ngx_cache_purge/


It is a very useful feature, as it allows you to override default TTL set for various responses in fastcgi_cache_valid directive, but the problem is that it allows to override all of them, including all 50x errors, so you may end up caching WSOD if the TTL logic used to send X-Accel-Expires header in the upstream app (in our case it is Drupal) has some default TTL with value higher than one second.

It looks like Nginx should allow to override TTL only for those OK default codes: 200, 301 and 302 and never allow to override the TTL set in fastcgi_cache_valid if the response is different than 200, 301 and 302, so all other responses will honor TTL set (if any) in fastcgi_cache_valid instead of accept whatever is send in the X-Accel-Expires header from the backend.

Change History (4)

comment:1 by Albert Szelagowski, 8 years ago

Of course it is a problem only if you have fastcgi_pass_header X-Accel-Expires; in your config.

comment:2 by Maxim Dounin, 8 years ago

Resolution: invalid
Status: newclosed

The X-Accel-Expires header is much like request-specific config settings, and it's goal is to allow to override what's set in config. E.g. it may be used (and actually used) to explicitly cache 404 responses till some upcoming event only application knows. I see no reason why it should be limited to a particular status codes. If you don't trust your application - use "proxy_ignore_headers X-Accel-Expires".

comment:3 by Albert Szelagowski, 8 years ago

Yes, it is valid and useful behavior for errors like 404 and maybe even 403 but it is never useful for errors you can't control if they happen because the app user managed to break his app so it causes WSOD which is still cached, because the app has no way to not send its X-Accel-Expires header on 50x error since it is an egg/chicken syndrome, and on the app level the header is send in the early bootstrap phase, before the request reaches the point where the code is broken and causes WSOD, hence my suggestion that Nginx should never respect X-Accel-Expires header when the upstream response is 50x code/error. It just doesn't make any sense to cache 50x errors and this Nginx behavior makes using X-Accel-Expires header not really safe.

comment:4 by Maxim Dounin, 8 years ago

If e.g. the app knows it won't be able to reach some backend server till some time - it's perfectly ok to use 502 with X-Accel-Expires. There is no real difference from any other codes, there are situation when you may want to cache responses. If your app adds X-Accel-Expires unconditionally and/or framework you use doesn't allow you to do it nicely - you may want to focus on enhancing your app / framework instead of trying to claim there is a problem in nginx.

Note: See TracTickets for help on using tickets.