Why do requests return 'Connection: keep-alive' headers when I'm expecting 'Connection: close'?
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.
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-aliveby default, if the initial request had an explicit
connection: closeheader 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.