The Linux Page

Why would nginx not return any HTTP headers?!

A couple of swans swimming together with their heads underwater.

As I'm working with nginx, I ran in a problem where the HTTP headers would not appear at all.

Each time I was testing with

wget --server-response

I would get the correct response (i.e. the file looked just fine and could be opened as expected) but no header at all.

I'm writing a module and learning details about nginx which are just not documented out there.

The fact is that if your module returns HTTP data to a client's request, you are pretty much responsible for everything in the reply to make it work as expected. nginx is rough that way (but really very fast as a result! That's definitely what you call bare bone!)

So the fact is that you must send the header to the client yourselves. This is done with a call to the ngx_http_send_header() function. You probably also want to define the status to be sent along the request result.

Note that a transfer that fails mid-way is not an HTTP error, it's a network error that each, the server and the client, have to handle. So it makes sense that you would be sending the headers with a 200 HTTP code before you know whether the body can be sent in full.

It is also a really good idea to include the Content-Length header. This is useful for many reasons. However, nginx will send a Transfer-Encoding: chunked if no Content-Length is found in your headers. A chunked transfer is a stream transfer which sends data as it comes to the server so the server doesn't know about the size ahead of time.

So the three lines of code which were missing in my module are the following:

r->headers_out.status = NGX_HTTP_OK;
r->headers_out.content_length_n = 123;
rc = ngx_http_send_header(data->request);

Then you can test rc to make sure the the function call worked as expected. It should be NGX_OK.

That one function sends all the HTTP headers to the client and without that call, nginx is fine to send your file data as is. Wow! Why is that?

My theory is that the cached files are ready to be sent to the client as is. There is (nearly) no need to do anything and all the data can be sent from a cache file to a client's socket connection. From what I can tell, there is a binary file header to certainly defines how long the file can stay in the cache and which cache it is a part of. They certainly have an offset to the start of the HTTP headers and another to the start of the body and the size of the body (although that one can also be inferred assuming nothing else appears after the body data in those cache files.)