Skip to content

Commit ec2037d

Browse files
santigimenoMylesBorins
authored andcommitted
child_process: fix leak when passing http sockets
After passing an HTTP socket, release its associated resources. PR-URL: #20305 Fixes: #15651 Reviewed-By: Gireesh Punathil <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent 57e5a3e commit ec2037d

File tree

2 files changed

+66
-0
lines changed

2 files changed

+66
-0
lines changed

lib/internal/child_process.js

+10
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ const SocketList = require('internal/socket_list');
3131
const { convertToValidSignal } = require('internal/util');
3232
const { isUint8Array } = require('internal/util/types');
3333
const spawn_sync = process.binding('spawn_sync');
34+
const { HTTPParser } = process.binding('http_parser');
35+
const { freeParser } = require('_http_common');
3436

3537
const {
3638
UV_EACCES,
@@ -107,6 +109,14 @@ const handleConversion = {
107109
if (!options.keepOpen) {
108110
handle.onread = nop;
109111
socket._handle = null;
112+
socket.setTimeout(0);
113+
// In case of an HTTP connection socket, release the associated
114+
// resources
115+
if (socket.parser && socket.parser instanceof HTTPParser) {
116+
freeParser(socket.parser, null, socket);
117+
if (socket._httpMessage)
118+
socket._httpMessage.detachSocket(socket);
119+
}
110120
}
111121

112122
return handle;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Flags: --expose_internals
2+
3+
'use strict';
4+
5+
const common = require('../common');
6+
const assert = require('assert');
7+
const { fork } = require('child_process');
8+
const http = require('http');
9+
const { kTimeout } = require('internal/timers');
10+
11+
if (process.argv[2] === 'child') {
12+
process.once('message', (req, socket) => {
13+
const res = new http.ServerResponse(req);
14+
res.assignSocket(socket);
15+
res.end();
16+
});
17+
18+
process.send('ready');
19+
return;
20+
}
21+
22+
let child;
23+
let socket;
24+
25+
const server = http.createServer(common.mustCall((req, res) => {
26+
const r = {
27+
method: req.method,
28+
headers: req.headers,
29+
path: req.path,
30+
httpVersionMajor: req.httpVersionMajor,
31+
query: req.query,
32+
};
33+
34+
socket = res.socket;
35+
child.send(r, socket);
36+
server.close();
37+
}));
38+
39+
server.listen(0, common.mustCall(() => {
40+
child = fork(__filename, [ 'child' ]);
41+
child.once('message', (msg) => {
42+
assert.strictEqual(msg, 'ready');
43+
const req = http.request({
44+
port: server.address().port,
45+
}, common.mustCall((res) => {
46+
res.on('data', () => {});
47+
res.on('end', common.mustCall(() => {
48+
assert.strictEqual(socket[kTimeout]._idleTimeout, -1);
49+
assert.strictEqual(socket.parser, null);
50+
assert.strictEqual(socket._httpMessage, null);
51+
}));
52+
}));
53+
54+
req.end();
55+
});
56+
}));

0 commit comments

Comments
 (0)