Skip to content

Http connections aborted after 5s / keepAliveTimeout #13391

@pbininda

Description

@pbininda
  • Version: v8.0.0
  • Platform: Windows 10, 64bit
  • Subsystem: http

Short Description

Node 8 introduced a change in the handling of http keep-alive connections. IMHO, this is (at least) a breaking change. When an http server does long-running requests (>5s), and the client requests a Connection: keep-alive connection, the http server closes the connection after 5s. This potentially causes browsers to re-send the request even if it is a POST request.

To Reproduce

clone https://github.com/pbininda/node8keepAliveTimeout and npm install. Then

 npm test 

Starts a little express server (server.js) and a client.

  • The server is a standard express server with a long running post request (/longpost takes 10s).
  • The client calls the POST /longpost with a preflight OPTIONS /longpost.

The test runs through fine on node 6 and node 7:

> node test.js got request OPTIONS /longpost got options response 200 sending post request got request POST /longpost got post response 200{status: 'OK' } 

but fails on node 8 with

> node test.js got request OPTIONS /longpost got options response 200 sending post request got request POST /longpost C:\Users\pbininda\projects\ATRON\node8keepAliveTimeout\client.js:39 throw err; ^ Error: socket hang up at createHangUpError (_http_client.js:343:15) at Socket.socketOnEnd (_http_client.js:435:23) at emitNone (events.js:110:20) at Socket.emit (events.js:207:7) at endReadableNT (_stream_readable.js:1045:12) at _combinedTickCallback (internal/process/next_tick.js:102:11) at process._tickCallback (internal/process/next_tick.js:161:9) 

Browser Retries

It seems, most of the major browsers (Chrome, Firefox, Edge) implement https://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html#sec8.2.4. Since the server closes the connection on which it received the POST request before sending an answer, the Browsers re-send the POST. Note that you don't see the re-send in chrome dev tools but using Wireshark shows the retransmission. To have a look at this, run

 npm start 

which launches the server (server.js) and then load browsertest.html in chrome. This runs browsertest.js in the browser which does a simple $.ajax request against the server. On the server side you will see:

> node server.js got request OPTIONS /longpost got request POST /longpost got request POST /longpost format called 5003ms after previous 

This shows, that the server received two POST requests the second one 5s after the first one, even though the browser client code only does one request.

Bug or Breaking Change?

I'm not sure if this is a bug or a breaking change. It probably got introduced through #2534. It only seems to happen when two connections are used (that's why the prefight OPTIONS is forced to happen in my code), so it may be that the wrong connection is being closed here.

Workaround

Setting the keepAliveTimeout (see https://nodejs.org/dist/latest-v8.x/docs/api/http.html#http_server_keepalivetimeout) of the http server to a value greater than the maximum duration of a request solves the problem. You can try this with

 npm start -- --keepAliveTimeout 20000 

and then in another terminal

 node client.js 

Metadata

Metadata

Assignees

Labels

httpIssues or PRs related to the http subsystem.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions