Sending empty response from http_upstream

Maxim Dounin mdounin at
Sat Jan 14 18:15:10 UTC 2023


On Fri, Jan 13, 2023 at 11:19:14PM -0500, Jeff Heisz wrote:

> Hello!
> I've been trying to debug an issue with a custom nginx module, which
> is working 'properly' with desktop browsers but failing on Apple
> browsers with an 'invalid response' error message.
> I don't know exactly what it doesn't like (so much fun debugging on
> i-devices)  but I am seeing one specific oddity when tracing the
> response from nginx through the desktop debugging console that might
> be the cause.
> My module communicates with an upstream manager process that signals
> the kind of response to be sent along with associated data.  The
> response that has the issue is when the manager signals a redirect
> instead of a content response.
> The module extracts the data from the upstream buffer and pushes a
> req->headers_out.location header record with the URL from the
> upstream.  It then sets up the response as:
>        upstr->headers_in.content_length_n = 0;
>        // (tried this) ngx_http_clear_content_length(req);
>        upstr->headers_in.status_n = NGX_HTTP_MOVED_TEMPORARILY;
>        upstr->state->status = NGX_HTTP_MOVED_TEMPORARILY;
>        upstr->buffer.pos += url_len;
>        req->header_only = 1;
>        upstr->keepalive = 1;

At least "req->header_only = 1;" looks problematic.

In general, you shouldn't touch request properties from an 
upstream protocol module.  Instead, you should set appropriate 
upstream's header_in data, so the upstream module will copy 
relevant information when needed (and if needed).

Further, req->header_only is almost always wrong when you are 
trying to set it yourself.  It is expected to be set for responses 
without response body, such as responses to HEAD requests and 
304/204 responses, but this is something nginx header filter will 
do for you.  For other responses, such as 302 in your code, it's 
incorrect: these are responses with body, and the response body is 
expected to be sent.  With content length set to 0 things might 
appear to work in some simple cases, but will break nicely if the 
content length is removed for some reason (e.g., due to potential 
response modifications by some filter, such as SSI or gzip).

That is, things might appear to work correctly with 
req->header_only explicitly set to 1, but most likely they aren't.  
Further, the fact it's there suggests it was added to "fix" 
something, and this in turn might indicate you are doing something 
else incorrectly.

> Basically, a response of zero length and a 302 response code,
> advancing the upstream buffer position to the end of the URL (no
> additional data in the upstream buffer to be processed).
> However, when I examine the response through the debugger, I see the
> appropriate location header but the content-length is always 32677!
> Not zero.  Attempting to look at the response shows no data.  This is
> highly suspicious as to why an error is occuring on the i-device.  I
> should also mention that the upstream response with the redirect URL
> is only 489 bytes, so that's not the source of the value.
> What I don't understand is where that content-length is coming from.
> Other cases where I set a non-zero length and have data in the
> upstream buffer works properly.  But for the zero case it doesn't send
> any content but sends this non-zero length.  From the code above you
> can see that I tried deleting the response content length information
> in case it was already in place from somewhere but that had no effect.
> Any thoughts?  I've tried doing some tracing in the nginx core code
> itself but so far have not been able to see where this length is
> originating from.

It is hard to say anything beyond the above without seeing the 
code, but first thing I would recommend to do is to look into 
nginx debug logs, see here for details:

Debug logs contain detailed information about request processing, 
including all the headers sent, and should be helpful to 
understand what's going on.

Maxim Dounin

More information about the nginx-devel mailing list