Skip to content

Commit 9426219

Browse files
committed
http: avoid retaining unneeded memory
Prevent the events listeners of the sockets obtained with the HTTP upgrade mechanism from retaining unneeded memory. Ref: nodejs#11868 PR-URL: nodejs#11926 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]>
1 parent 517f13b commit 9426219

File tree

4 files changed

+33
-25
lines changed

4 files changed

+33
-25
lines changed

lib/_http_common.js

+1-5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const methods = binding.methods;
55
const HTTPParser = binding.HTTPParser;
66

77
const FreeList = require('internal/freelist').FreeList;
8+
const ondrain = require('internal/http').ondrain;
89
const incoming = require('_http_incoming');
910
const IncomingMessage = incoming.IncomingMessage;
1011
const readStart = incoming.readStart;
@@ -209,11 +210,6 @@ function freeParser(parser, req, socket) {
209210
exports.freeParser = freeParser;
210211

211212

212-
function ondrain() {
213-
if (this._httpMessage) this._httpMessage.emit('drain');
214-
}
215-
216-
217213
function httpSocketSetup(socket) {
218214
socket.removeListener('drain', ondrain);
219215
socket.on('drain', ondrain);

lib/_http_server.js

+22-20
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const continueExpression = common.continueExpression;
1313
const chunkExpression = common.chunkExpression;
1414
const httpSocketSetup = common.httpSocketSetup;
1515
const OutgoingMessage = require('_http_outgoing').OutgoingMessage;
16+
const ondrain = require('internal/http').ondrain;
1617

1718
const STATUS_CODES = exports.STATUS_CODES = {
1819
100: 'Continue',
@@ -274,7 +275,7 @@ function connectionListener(socket) {
274275
// otherwise, destroy on timeout by default
275276
if (this.timeout)
276277
socket.setTimeout(this.timeout);
277-
socket.on('timeout', socketOnTimeout.bind(undefined, this, socket));
278+
socket.on('timeout', socketOnTimeout);
278279

279280
var parser = parsers.alloc();
280281
parser.reinitialize(HTTPParser.REQUEST);
@@ -292,9 +293,9 @@ function connectionListener(socket) {
292293

293294
var state = {
294295
onData: null,
295-
onError: null,
296296
onEnd: null,
297297
onClose: null,
298+
onDrain: null,
298299
outgoing: [],
299300
incoming: [],
300301
// `outgoingData` is an approximate amount of bytes queued through all
@@ -304,21 +305,20 @@ function connectionListener(socket) {
304305
outgoingData: 0
305306
};
306307
state.onData = socketOnData.bind(undefined, this, socket, parser, state);
307-
state.onError = socketOnError.bind(undefined, this, socket, state);
308308
state.onEnd = socketOnEnd.bind(undefined, this, socket, parser, state);
309309
state.onClose = socketOnClose.bind(undefined, socket, state);
310+
state.onDrain = socketOnDrain.bind(undefined, socket, state);
310311
socket.on('data', state.onData);
311-
socket.on('error', state.onError);
312+
socket.on('error', socketOnError);
312313
socket.on('end', state.onEnd);
313314
socket.on('close', state.onClose);
315+
socket.on('drain', state.onDrain);
314316
parser.onIncoming = parserOnIncoming.bind(undefined, this, socket, state);
315317

316318
// We are consuming socket, so it won't get any actual data
317319
socket.on('resume', onSocketResume);
318320
socket.on('pause', onSocketPause);
319321

320-
socket.on('drain', socketOnDrain.bind(undefined, socket, state));
321-
322322
// Override on to unconsume on `data`, `readable` listeners
323323
socket.on = socketOnWrap;
324324

@@ -356,15 +356,15 @@ function socketOnDrain(socket, state) {
356356
}
357357
}
358358

359-
function socketOnTimeout(server, socket) {
360-
var req = socket.parser && socket.parser.incoming;
361-
var reqTimeout = req && !req.complete && req.emit('timeout', socket);
362-
var res = socket._httpMessage;
363-
var resTimeout = res && res.emit('timeout', socket);
364-
var serverTimeout = server.emit('timeout', socket);
359+
function socketOnTimeout() {
360+
var req = this.parser && this.parser.incoming;
361+
var reqTimeout = req && !req.complete && req.emit('timeout', this);
362+
var res = this._httpMessage;
363+
var resTimeout = res && res.emit('timeout', this);
364+
var serverTimeout = this.server.emit('timeout', this);
365365

366366
if (!reqTimeout && !resTimeout && !serverTimeout)
367-
socket.destroy();
367+
this.destroy();
368368
}
369369

370370
function socketOnClose(socket, state) {
@@ -391,7 +391,7 @@ function socketOnEnd(server, socket, parser, state) {
391391

392392
if (ret instanceof Error) {
393393
debug('parse error');
394-
state.onError(ret);
394+
socketOnError.call(socket, ret);
395395
return;
396396
}
397397

@@ -421,19 +421,19 @@ function onParserExecute(server, socket, parser, state, ret, d) {
421421
onParserExecuteCommon(server, socket, parser, state, ret, undefined);
422422
}
423423

424-
function socketOnError(server, socket, state, e) {
424+
function socketOnError(e) {
425425
// Ignore further errors
426-
socket.removeListener('error', state.onError);
427-
socket.on('error', () => {});
426+
this.removeListener('error', socketOnError);
427+
this.on('error', () => {});
428428

429-
if (!server.emit('clientError', e, socket))
430-
socket.destroy(e);
429+
if (!this.server.emit('clientError', e, this))
430+
this.destroy(e);
431431
}
432432

433433
function onParserExecuteCommon(server, socket, parser, state, ret, d) {
434434
if (ret instanceof Error) {
435435
debug('parse error');
436-
state.onError(ret);
436+
socketOnError.call(socket, ret);
437437
} else if (parser.incoming && parser.incoming.upgrade) {
438438
// Upgrade or CONNECT
439439
var bytesParsed = ret;
@@ -446,6 +446,8 @@ function onParserExecuteCommon(server, socket, parser, state, ret, d) {
446446
socket.removeListener('data', state.onData);
447447
socket.removeListener('end', state.onEnd);
448448
socket.removeListener('close', state.onClose);
449+
socket.removeListener('drain', state.onDrain);
450+
socket.removeListener('drain', ondrain);
449451
unconsume(parser, socket);
450452
parser.finish();
451453
freeParser(parser, req, null);

lib/internal/http.js

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
'use strict';
2+
3+
function ondrain() {
4+
if (this._httpMessage) this._httpMessage.emit('drain');
5+
}
6+
7+
module.exports = {
8+
ondrain,
9+
};

node.gyp

+1
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@
8585
'lib/internal/errors.js',
8686
'lib/internal/freelist.js',
8787
'lib/internal/fs.js',
88+
'lib/internal/http.js',
8889
'lib/internal/linkedlist.js',
8990
'lib/internal/net.js',
9091
'lib/internal/module.js',

0 commit comments

Comments
 (0)