diff --git a/lib/_http_client.js b/lib/_http_client.js index c447b695c8b45b..3f335aa6eaa7ce 100644 --- a/lib/_http_client.js +++ b/lib/_http_client.js @@ -665,6 +665,12 @@ function responseKeepAlive(req) { // Mark this socket as available, AFTER user-added end // handlers have a chance to run. defaultTriggerAsyncIdScope(asyncId, process.nextTick, emitFreeNT, req); + + if (req.res) { + // Detach socket from IncomingMessage to avoid destroying the freed + // socket in IncomingMessage.destroy(). + req.res.socket = null; + } } function responseOnEnd() { diff --git a/test/parallel/test-http-agent-destroyed-socket.js b/test/parallel/test-http-agent-destroyed-socket.js index 5b58ef0f52a50b..47123ed6c364b2 100644 --- a/test/parallel/test-http-agent-destroyed-socket.js +++ b/test/parallel/test-http-agent-destroyed-socket.js @@ -48,7 +48,7 @@ const server = http.createServer(common.mustCall((req, res) => { response.on('end', common.mustCall(() => { request1.socket.destroy(); - response.socket.once('close', common.mustCall(() => { + request1.socket.once('close', common.mustCall(() => { // Assert request2 was removed from the queue assert(!agent.requests[key]); process.nextTick(() => { diff --git a/test/parallel/test-http-client-abort-keep-alive-destroy-res.js b/test/parallel/test-http-client-abort-keep-alive-destroy-res.js new file mode 100644 index 00000000000000..238430a83d31fd --- /dev/null +++ b/test/parallel/test-http-client-abort-keep-alive-destroy-res.js @@ -0,0 +1,39 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const http = require('http'); + +let socketsCreated = 0; + +class Agent extends http.Agent { + createConnection(options, oncreate) { + const socket = super.createConnection(options, oncreate); + socketsCreated++; + return socket; + } +} + +const server = http.createServer((req, res) => res.end()); + +server.listen(0, common.mustCall(() => { + const port = server.address().port; + const agent = new Agent({ + keepAlive: true, + maxSockets: 1 + }); + + const req = http.get({ agent, port }, common.mustCall((res) => { + res.resume(); + res.on('end', () => { + res.destroy(); + + http.get({ agent, port }, common.mustCall((res) => { + res.resume(); + assert.strictEqual(socketsCreated, 1); + agent.destroy(); + server.close(); + })); + }); + })); + req.end(); +}));