diff --git a/lib/_http_client.js b/lib/_http_client.js index 6837c94df98eea..1846e36e12bf88 100644 --- a/lib/_http_client.js +++ b/lib/_http_client.js @@ -562,7 +562,13 @@ function tickOnSocket(req, socket) { socket.on('close', socketCloseListener); if (req.timeout) { - socket.once('timeout', () => req.emit('timeout')); + const emitRequestTimeout = () => req.emit('timeout'); + socket.once('timeout', emitRequestTimeout); + req.once('response', (res) => { + res.once('end', () => { + socket.removeListener('timeout', emitRequestTimeout); + }); + }); } req.emit('socket', socket); } diff --git a/test/parallel/test-http-client-timeout-option-listeners.js b/test/parallel/test-http-client-timeout-option-listeners.js new file mode 100644 index 00000000000000..3ac6cd4616b496 --- /dev/null +++ b/test/parallel/test-http-client-timeout-option-listeners.js @@ -0,0 +1,44 @@ +'use strict'; +const common = require('../common'); +const http = require('http'); +const assert = require('assert'); + +const agent = new http.Agent({ keepAlive: true }); + +const server = http.createServer((req, res) => { + res.end(''); +}); + +const options = { + agent, + method: 'GET', + port: undefined, + host: common.localhostIPv4, + path: '/', + timeout: common.platformTimeout(100) +}; + +server.listen(0, options.host, common.mustCall(() => { + options.port = server.address().port; + doRequest(common.mustCall((numListeners) => { + assert.strictEqual(numListeners, 1); + doRequest(common.mustCall((numListeners) => { + assert.strictEqual(numListeners, 1); + server.close(); + agent.destroy(); + })); + })); +})); + +function doRequest(cb) { + http.request(options, common.mustCall((response) => { + const sockets = agent.sockets[`${options.host}:${options.port}:`]; + assert.strictEqual(sockets.length, 1); + const socket = sockets[0]; + const numListeners = socket.listeners('timeout').length; + response.resume(); + response.once('end', common.mustCall(() => { + process.nextTick(cb, numListeners); + })); + })).end(); +}