Nginx Content-Length Header – Why Removed for Chunked Content?

nginx

I use nginx 1.2.3 to proxy to a script:

proxy_set_header Host $host;
proxy_pass http://127.0.0.1:8880;
proxy_buffering off;
proxy_read_timeout 300s;
gzip off;

The scripts sends both Transfer-encoding: chunked and Content-Length: 251:

HTTP/1.0 307 Temporary Redirect
Content-length: 251
Pragma: no-cache
Location: /...
Cache-control: no-cache
Transfer-encoding: chunked

I need both, but nginx automatically removes the Content-Length:

HTTP/1.1 302 Found
Server: nginx/1.2.3
Content-Type: application/json; charset=utf-8
Content-Length: 58
Connection: keep-alive
Location: /...

As a result, the clients do not wait for the chunks to be sent. This used to work with an earlier version of nginx.

Best Answer

Unfortunately, I can't comment on cnst's post - so I'm going to answer here.

The nginx_http_proxy module by default talks with the upstream in HTTP/1.0. This can be changed with the directive proxy_http_version 1.1.

This might also be the cause for your script to return a HTTP/1.0 answer, although chunked coding and status code 307 don't exist in this version.

You shouldn't use chunked coding with a redirect either, as this doesn't really make sense.

Additionally, it seems like nginx doesn't pass chunks from the upstream to the client one by one, but it buffers the upstream's response. The Content-Length header field is ignored because it is against the definition. I had to look at the source code of the module because all this appears to be undocumented.

You may want to try out the nginx_tcp_proxy_module to proxy the chunked content as raw TCP data: Module at Github


UPDATE (10.04.14)
The nginx_http_proxy module has support for X-Accel-* headers, of which one (X-Accel-Buffering: yes|no) controls whether the response should be buffered or not.

Adding this header (X-Accel-Buffering: no) to the backend's response will cause nginx to directly pass chunks to the client.

This header allows to control buffering on an per-request basis.

The module also has a configuration directive proxy_buffering to enable or disable response buffering (not buffering means sending chunks will work).

Proxy buffering (both header and directive based) is documented here.