nginx closing connection instead of returning HTTP 414 on long URIs with TLS and http2

Viewed 29

I am debugging an issue where requests are being dropped without any HTTP response and without ever getting to our backend code. I have pinpointed this down to nginx and the request URIs being too long (in the area of 5000 characters). The request does not need to be that long, that is a bug in the frontend code, but I would expect nginx to return 414 URI Too Long, that's exactly why that response exists. But instead I get

$ curl https://my.server?foo=barbarbar(repeat*many times)
...
curl: (92) HTTP/2 stream 1 was not closed cleanly before end of the underlying stream

This only happens with https and http2. With plain http I get

...
< HTTP/1.1 414 Request-URI Too Large
...

as expected.

With https but without http2, I also get HTTP 414.


The following nginx configuration reproduces the issue:

server {
    listen               443 ssl http2;
    ssl_certificate      /etc/ssl/private/cert.pem;
    ssl_certificate_key  /etc/ssl/private/key.pem;
    server_name          localhost;

    # large_client_header_buffers 4 16k;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

(the TLS certs are self-signed, but the same issue reproduces for proper certs)

This issue is happening for

  • Ubuntu 20.04 (both server and in-Docker)
  • nginx 1.18.0, 1.20.2, 1.22.0

Is this expected, or a bug in nginx?

1 Answers

You're likely hitting a request size or field size limit, which specifically in HTTP/2 is difficult to recover from, quoting from ticket #1520:

Since headers in HTTP/2 protocol are encoded using stateful compression algorithm, it's impossible to continue maintaining connection if there's any problem with handling headers in a request (e.g. limits are reached). Note that nginx doesn't just drop the connection, but it sends a GOAWAY frame with ENHANCE_YOUR_CALM protocol error.

In other words, it appears nginx can't send a 414 response in this case even if it wanted to; it seems unlikely that that will change, looking at the number of duplicate tickets are linked to this one.

If you like, you can increase the limits to avoid this case altogether:

But since you said the bad URL was not expected, I would leave the limits at their defaults.

Related