Opened 11 years ago

Closed 11 years ago

#459 closed defect (invalid)

HTTP 304 NOT MODIFIED should not set Content-Length

Reported by: robin.smidsrod.no Owned by:
Priority: minor Milestone:
Component: nginx-core Version: 1.3.x
Keywords: Cc: robin@…
uname -a: Linux pf 2.6.32-54-server #116-Ubuntu SMP Tue Nov 12 19:37:57 UTC 2013 x86_64 GNU/Linux
nginx -V: nginx version: nginx/1.4.1
TLS SNI support enabled
configure arguments: --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --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 --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --with-pcre-jit --with-http_gzip_static_module --with-http_ssl_module --with-ipv6 --without-http_browser_module --without-http_geo_module --without-http_limit_req_module --without-http_limit_zone_module --without-http_memcached_module --without-http_referer_module --without-http_scgi_module --without-http_split_clients_module --with-http_stub_status_module --without-http_ssi_module --without-http_userid_module --without-http_uwsgi_module --add-module=/build/buildd/nginx-1.4.1/debian/modules/nginx-echo

Description

Using nginx from the stable Ubuntu PPA.

Had a long conversation with people on IRC and noticed that HTTP 304 NOT MODIFIED responses for static content has Content-Length set to the actual size of the content, and an empty body.

According to http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5 and http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.3 Content-Length (which is an entity header) should not even be returned in 304 responses.

I noticed this when I had a FastCGI backend server which sent 304 responses with non-zero Content-Length or with a HTTP body (both which seem wrong). This caused some kind of keep-alive error in Chrome 31 which caused corrupt content to be downloaded.

After I fixed that error in the backend FastCGI server I also noticed nginx does the same thing for static content. It sets Content-Length to the size of the file.

Setting Content-Length to 0 for 304 responses seem to solve all issues I've had with Chrome, but I'm not sure if that is actually the right solution. From my understanding of the RFCs it seems like Content-Length shouldn't be set at all.

Change History (4)

comment:1 by Maxim Dounin, 11 years ago

Resolution: invalid
Status: newclosed

The Content-Length header is not returned for 304 responses, it's removed by the |not modified filter. Example conversation:

HEAD / HTTP/1.1
Host: mdounin.ru

HTTP/1.1 200 OK
Server: nginx/1.5.7
Date: Fri, 06 Dec 2013 15:35:46 GMT
Content-Type: text/html
Content-Length: 1047
Last-Modified: Mon, 13 Feb 2012 01:20:52 GMT
Connection: keep-alive
ETag: "4f386574-417"
Accept-Ranges: bytes

GET / HTTP/1.1
Host: mdounin.ru
If-Modified-Since: Mon, 13 Feb 2012 01:20:52 GMT

HTTP/1.1 304 Not Modified
Server: nginx/1.5.7
Date: Fri, 06 Dec 2013 15:36:05 GMT
Last-Modified: Mon, 13 Feb 2012 01:20:52 GMT
Connection: keep-alive
ETag: "4f386574-417"

GET / HTTP/1.1
Host: mdounin.ru
If-None-Match: "4f386574-417"

HTTP/1.1 304 Not Modified
Server: nginx/1.5.7
Date: Fri, 06 Dec 2013 15:36:18 GMT
Last-Modified: Mon, 13 Feb 2012 01:20:52 GMT
Connection: keep-alive
ETag: "4f386574-417"

If you used your browser to look at headers returned, it's probably the culprit. Browsers tends to lie about headers returned, especially if a cache is involved. Using telnet, or nc, or tcpdump for such tests is better idea.

comment:2 by robin.smidsrod.no, 11 years ago

Okay. Thanks for clarifying. I guess I need to complain to the browser authors about their developer tools, *sigh*.

I did notice that the content coming from the FastCGI backend server I'm using does contain Content-Length on 304 responses (which is wrong according to RFC). Example generated using telnet. :)

GET /data/3b6d1cfe-a562-44b3-ad8c-acadc7da566f HTTP/1.1
Host: pf.smidsrod.lan

HTTP/1.1 200 OK
Server: nginx/1.4.1
Content-Type: text/plain; charset=UTF-8
Content-Length: 4
Connection: keep-alive
Set-Cookie: session_id_pf.smidsrod.lan=64da9517-8142-4399-bf66-51ac40e24419; path=/
Expires: Fri, 06 Dec 2013 18:20:42 GMT
Date: Sat, 07 Dec 2013 18:20:42 GMT
Last-modified: Sat, 07 Dec 2013 18:20:03 GMT
Content-disposition: inline; size=4; filename="test.txt"
Cache-control: private; must-revalidate
X-Request-Time: 4.727 seconds

test

GET /data/3b6d1cfe-a562-44b3-ad8c-acadc7da566f HTTP/1.1
Host: pf.smidsrod.lan
If-Modified-Since: Sat, 07 Dec 2013 18:20:03 GMT

HTTP/1.1 304 Not Modified
Server: nginx/1.4.1
Content-Type: text/plain; charset=UTF-8
Content-Length: 0
Connection: keep-alive
Set-Cookie: session_id_pf.smidsrod.lan=6456d464-d81d-423e-8dba-2106ba276945; path=/
Expires: Fri, 06 Dec 2013 18:21:09 GMT
Date: Sat, 07 Dec 2013 18:21:09 GMT
Last-modified: Sat, 07 Dec 2013 18:20:03 GMT
Content-disposition: inline; size=4; filename="test.txt"
Cache-control: private; must-revalidate
X-Request-Time: 15.560 seconds

Is that considered solely the responsibility of the backend server, even if it generates invalid HTTP responses according to RFC? Or should nginx filter out broken/invalid headers to ensure consistent response to clients? I'm guessing you already have a policy on how to handle this kind of issue?

comment:3 by robin.smidsrod.no, 11 years ago

Resolution: invalid
Status: closedreopened

Reopened to clarify behavior on FastCGI proxying.

comment:4 by Maxim Dounin, 11 years ago

Resolution: invalid
Status: reopenedclosed

It's not an nginx responsibility to fix backend bugs.

Note: See TracTickets for help on using tickets.