# Nginx and upstream Content-Length

**URL:** <https://www.ruby-forum.com/t/nginx-and-upstream-content-length/212347>\
**Category:** NGINX\
**Created:** [September 30, 2011, 10:12am UTC](https://www.ruby-forum.com/t/nginx-and-upstream-content-length/212347 "2011-09-30T10:12:40Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![dubstep](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/cdc98d/32.png) [@dubstep](https://www.ruby-forum.com/u/dubstep)\
**Post date:** [September 30, 2011, 10:12am UTC](https://www.ruby-forum.com/t/nginx-and-upstream-content-length/212347/1 "2011-09-30T10:12:40Z")

</div>

Hi,

In a recent thread on the uwsgi mailing list[1], I began suspecting that  
nginx will not honor an upstream’s Content-Length header. i.e., if an  
upstream mentions a Content-Length of 1,000 bytes, but the connection is  
broken after 500 bytes, nginx will still happily serve this entity with  
a  
200 OK status.

This may be a known bug in nginx, I wanted to be certain I indeed  
understand  
it correctly and raise the attention to it on the nginx mailing list -  
because I think this is a very serious bug with potentially disastrous  
consequences, as I describe below.

I was able to confirm this both for uwsgi\_pass and proxy\_pass; if the  
upstream sets a Content-Length and then breaks the connection before  
that  
length was achieved, nginx will pass this onwards to the client.  
Furthermore, since the upstream protocol is HTTP 1.0 but the  
nginx-client  
protocl is HTTP 1.1 (with keepalive), the request will simply not  
terminate,  
because the client can’t tell that the server has nothing more to send  
and  
nginx will not break the connection, despite the fact its connection  
with  
the upstream was broken and there’s no chance this request will ever be  
fulfilled.

Things get far worse with gzip compression on - nginx will remove the  
Content-Length header sent by the client and replace it with chunked  
encoding - /incorrect chunked encoding/, that will make the client  
believe  
it has the full entity, even though it has only a part of this.

Think about this with regard to caching, ETags and transparent proxy  
caching

- if something like this happens to a cachable entity, especially one  
with  
an ETag, especially if a large ISP’s transparent proxy intercepts the  
request - you might end up serving an incorrect representation of the  
entity  
for a very long time and for many thousands of requests (!).

Anyhow, I think the only sane resolution is that nginx will honor  
upstream  
Content-Length (and chunked encoding, if and when nginx will support  
it),  
and intentionally close the downstream connection prematurely in case  
the  
upstream connection is closed before the end of the Content-Length or  
the  
last chunk is received.

I suspect the recent work in nginx 1.1.4 for  
ngx\_http\_upstream\_keepalivecould be relevant here, but not sure,  
didn’t read the code.

I’ll be happy to hear your thoughts or provide further data.

- Yaniv

1: [http://comments.gmane.org/gmane.comp.python.wsgi.uwsgi.general/2061](http://comments.gmane.org/gmane.comp.python.wsgi.uwsgi.general/2061)

---

<div class="post-metadata">

**Author:** ![Yaniv\_Aknin](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/y/5f9b8f/32.png) [@Yaniv\_Aknin](https://www.ruby-forum.com/u/Yaniv_Aknin)\
**Post date:** [September 30, 2011, 11:59am UTC](https://www.ruby-forum.com/t/nginx-and-upstream-content-length/212347/2 "2011-09-30T11:59:34Z")

</div>

Hello!

On Fri, Sep 30, 2011 at 11:11:53AM +0300, Yaniv Aknin wrote:

> In a recent thread on the uwsgi mailing list[1], I began suspecting that  
> nginx will not honor an upstream’s Content-Length header. i.e., if an  
> upstream mentions a Content-Length of 1,000 bytes, but the connection is  
> broken after 500 bytes, nginx will still happily serve this entity with a  
> 200 OK status.

Status code 200 is irrelevant - as it’s generally not possible to  
know if connection will be broken in advance (i.e. before sending  
status).

> because the client can’t tell that the server has nothing more to send and  
> nginx will not break the connection, despite the fact its connection with  
> the upstream was broken and there’s no chance this request will ever be  
> fulfilled.
> 
> Things get far worse with gzip compression on - nginx will remove the  
> Content-Length header sent by the client and replace it with chunked  
> encoding - /incorrect chunked encoding/, that will make the client believe  
> it has the full entity, even though it has only a part of this.

Yes, this is a known problem. Upstream module expects backend to  
behave properly, and if it misbehaves (or, more importantly,  
connection is broken for some reason) bad things may happen.

Upstream’s module code needs carefull auditing to fix this. It’s  
somewhere in my TODO (though not very high).

Maxim D.

---

<div class="post-metadata">

**Author:** ![Yaniv\_Aknin](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/y/5f9b8f/32.png) [@Yaniv\_Aknin](https://www.ruby-forum.com/u/Yaniv_Aknin)\
**Post date:** [September 30, 2011, 4:36pm UTC](https://www.ruby-forum.com/t/nginx-and-upstream-content-length/212347/3 "2011-09-30T16:36:46Z")

</div>

Well, I appreciate the time every contributor to nginx put into the  
project  
and especially your and Igor’s work, and I know I don’t dictate the  
priority  
of your TODO, but I humbly think this is a far more serious issue than  
you’re portraying.

Simply put, this bug can cause nginx to cause an otherwise _noticeable  
data  
corruption_ to become a _silent data corruption_ (including the serious  
cache poisoning ramifications), and I think there are few bugs less  
urgent  
than that.

Anyhow, I’ve said all I have to say on the matter, so unless further  
information comes up on this, I’ll leave this topic alone (at least  
until  
I’ll get off my bum and come back here with a suggested patch to fix  
this…).

Thank you for your concise, timely and complete reply,

- Yaniv

---

<div class="post-metadata">

**Author:** ![Yaniv\_Aknin](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/y/5f9b8f/32.png) [@Yaniv\_Aknin](https://www.ruby-forum.com/u/Yaniv_Aknin)\
**Post date:** [September 30, 2011, 6:08pm UTC](https://www.ruby-forum.com/t/nginx-and-upstream-content-length/212347/4 "2011-09-30T18:08:06Z")

</div>

Sorry, I didn’t test FastCGI so can’t say for sure. I suspect it will  
happen  
there as well, but it’s just an assumption.

- Yaniv

---

<div class="post-metadata">

**Author:** ![Yaniv\_Aknin](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/y/5f9b8f/32.png) [@Yaniv\_Aknin](https://www.ruby-forum.com/u/Yaniv_Aknin)\
**Post date:** [September 30, 2011, 5:08pm UTC](https://www.ruby-forum.com/t/nginx-and-upstream-content-length/212347/5 "2011-09-30T17:08:51Z")

</div>

Hi Yaniv

Thanks for investigating and reporting on this. Do you know whether  
the gzip chunked-encoding problem exists for fastcgi\_pass as well?

Cheers  
Thomas
