Why do requests return 'Connection: keep-alive' headers when I'm expecting 'Connection: close'?

Issue

Your application returns a Connection: close header when you test sending requests to it locally, but you get Connection: keep-alive headers for requests to your application on Heroku.

Resolution

This is expected and is due to a difference in routing behavior based on the version of HTTP being used for requests. This behavior is described in our routing documentation here:

Additionally, while HTTP/1.1 requests and responses are expected to be keep-alive by default, if the initial request had an explicit connection: close header from the router to the dyno, the dyno can send a response delimited by the connection termination, without a specific content-encoding nor an explicit content-length.

So, requests over HTTP/1.1 use keep-alive by default if no Connection header is sent specifying otherwise. You can see this in action using curl:

$ curl -v -X POST http://test-app.com/test
...
> POST /test HTTP/1.1
...
> 
< HTTP/1.1 200 OK
< Connection: keep-alive
...

Note that the POST is using HTTP/1.1. If you force curl to use HTTP/1.0 you get this:

$ curl -v -X POST --http1.0 http://test-app.com/test
...
> POST /test HTTP/1.0
...
> 
< HTTP/1.1 200 OK
< Connection: close
...

Note that HTTP/1.0 is being used now and that the connection header coming back is Connection: close this time. As per the RFC and routing documentation, if the request uses HTTP/1.1, but specifies a Connection: close header, then it respects that:

$ curl -v -X POST -H 'Connection: close' http://test-app.com/test
...
> POST /test HTTP/1.1
...
> Connection: close
> 
< HTTP/1.1 200 OK
< Connection: close
...

You can see that this is expected behavior in this whitepaper doc that outlines differences between HTTP/1.0 and HTTP/1.1 (search for "keep-alive" to find the "Persistent Connections" section that discusses this). The relevant bit is as follows:

HTTP/1.0, in its documented form, made no provision for persistent connections. Some HTTP/1.0 implementations, however, use a Keep-Alive header (described in [Fie95]) to request that a connection persist. This design did not interoperate with intermediate proxies (see Section 19.6.2 of [FGM+98]); HTTP/1.1 specifies a more general solution.

In recognition of their desirable properties, HTTP/1.1 makes persistent connections the default. HTTP/1.1 clients, servers, and proxies assume that a connection will be kept open after the transmission of a request and its response. The protocol does allow an implementation to close a connection at any time, in order to manage its resources, although it is best to do so only after the end of a response.

Because an implementation may prefer not to use persistent connections if it cannot efficiently scale to large numbers of connections or may want to cleanly terminate one for resource-management reasons, the protocol permits it to send a Connection: close header to inform the recipient that the connection will not be reused.

As such, to ensure Connection: close is used under HTTP/1.1 you need to specify that header in the original request.

Ask on Stack Overflow

Engage with a community of passionate experts to get the answers you need

Ask on Stack Overflow

Heroku Support

Create a support ticket and our support experts will get back to you

Contact Heroku Support