Matching & Acting upon Headers received from Upstream with proxy_pass

Alec Muffett alec.muffett at
Fri Feb 1 14:32:18 UTC 2019

On Fri, 1 Feb 2019 at 13:30, Maxim Dounin <mdounin at> wrote:

Hi Maxim!

The 406 looks wrong to me.  It tells the client that the response
> is not acceptable as per accept headers in the request.  In your
> case it is more like 500,

Concur.  I did some research on Wikipedia and followed Cloudflare's example
to use 520.

Note well that HTTP servers are allowed to return gzipped
> responses even to requests with "Accept-Encoding: identify".
> Quoting RFC 2616 (
>       Note: HTTP/1.1 servers are allowed to return responses which are
>       not acceptable according to the accept headers sent in the
>       request. In some cases, this may even be preferable to sending a
>       406 response. User agents are encouraged to inspect the headers of
>       an incoming response to determine if it is acceptable.

Being a reverse proxy, in a sense it is that sort of inspection which I am
attempting :-)

They are certainly allowed to do it in this circumstance, but it's not
helpful for the proxy in question.

This is not going to work as rewrite module directives are
> processed while selecting a configuration to work with (see
> Obviously enough this happens before the request is passed to the
> upstream, and before the response is received.

Yep.  NGINX is a marvel, but working out which bits of configuration are
executed in what order, is still a challenge for me without coffee.

> You should be able to do what you want by writing a header filter
> which will check headers returned and will return an error if
> these headers don't match your expectations.

Eventually I went with this, using Lua; I am still trying to work out how
to make it return an informative message AS WELL AS the 520 error code,
perhaps by using an internal redirect?

I am wondering whether a header filter can cause an internal redirect to a
more useful "520 page"

Thank you for getting back to me!  :-)

- alec

Extract from:

  init_by_lua_block {
    Dictionary = function (list)
      local set = {}
      for _, l in ipairs(list) do set[l] = true end
      return set
    is_compression = Dictionary{ "br", "compress", "deflate", "gzip", }

  header_filter_by_lua_block {
    local ce = ngx.var.upstream_http_content_encoding or ""
    if is_compression[ce] then
      -- I'd prefer to do something nice like this:
      --   ngx.status = 520
      --   ngx.say("upstream content was compressed and therefore not
      --   ngx.exit(ngx.OK)
      -- ...but say() needs an API that is not available in this phase:
      -- therefore:
      ngx.exit(520) --

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the nginx mailing list