Skip to content

Commit f1517cc

Browse files
Karl BöhlmarkMylesBorins
authored andcommitted
http: remove stale timeout listeners
In order to prevent a memory leak when using keep alive, ensure that the timeout listener for the request is removed when the response has ended. PR-URL: #9440 Reviewed-By: Evan Lucas <evanlucas@me.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
1 parent f7792de commit f1517cc

2 files changed

Lines changed: 51 additions & 1 deletion

File tree

‎lib/_http_client.js‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -563,7 +563,13 @@ function tickOnSocket(req, socket) {
563563
socket.on('close',socketCloseListener);
564564

565565
if(req.timeout){
566-
socket.once('timeout',()=>req.emit('timeout'));
566+
constemitRequestTimeout=()=>req.emit('timeout');
567+
socket.once('timeout',emitRequestTimeout);
568+
req.once('response',(res)=>{
569+
res.once('end',()=>{
570+
socket.removeListener('timeout',emitRequestTimeout);
571+
});
572+
});
567573
}
568574
req.emit('socket',socket);
569575
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
'use strict';
2+
constcommon=require('../common');
3+
consthttp=require('http');
4+
constassert=require('assert');
5+
6+
constagent=newhttp.Agent({keepAlive: true});
7+
8+
constserver=http.createServer((req,res)=>{
9+
res.end('');
10+
});
11+
12+
constoptions={
13+
agent,
14+
method: 'GET',
15+
port: undefined,
16+
host: common.localhostIPv4,
17+
path: '/',
18+
timeout: common.platformTimeout(100)
19+
};
20+
21+
server.listen(0,options.host,common.mustCall(()=>{
22+
options.port=server.address().port;
23+
doRequest(common.mustCall((numListeners)=>{
24+
assert.strictEqual(numListeners,1);
25+
doRequest(common.mustCall((numListeners)=>{
26+
assert.strictEqual(numListeners,1);
27+
server.close();
28+
agent.destroy();
29+
}));
30+
}));
31+
}));
32+
33+
functiondoRequest(cb){
34+
http.request(options,common.mustCall((response)=>{
35+
constsockets=agent.sockets[`${options.host}:${options.port}:`];
36+
assert.strictEqual(sockets.length,1);
37+
constsocket=sockets[0];
38+
constnumListeners=socket.listeners('timeout').length;
39+
response.resume();
40+
response.once('end',common.mustCall(()=>{
41+
process.nextTick(cb,numListeners);
42+
}));
43+
})).end();
44+
}

0 commit comments

Comments
 (0)