Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

http: start connections checking interval on listen #48611

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions lib/_http_server.js
Original file line number Diff line number Diff line change
Expand Up @@ -500,14 +500,16 @@ function storeHTTPOptions(options) {
}
}

function setupConnectionsTracking(server) {
function setupConnectionsTracking() {
// Start connection handling
server[kConnections] = new ConnectionsList();
if (!this[kConnections]) {
this[kConnections] = new ConnectionsList();
}

// This checker is started without checking whether any headersTimeout or requestTimeout is non zero
// otherwise it would not be started if such timeouts are modified after createServer.
server[kConnectionsCheckingInterval] =
setInterval(checkConnections.bind(server), server.connectionsCheckingInterval).unref();
this[kConnectionsCheckingInterval] =
setInterval(checkConnections.bind(this), this.connectionsCheckingInterval).unref();
}

function httpServerPreClose(server) {
Expand Down Expand Up @@ -545,11 +547,12 @@ function Server(options, requestListener) {
this.httpAllowHalfOpen = false;

this.on('connection', connectionListener);
this.on('listening', setupConnectionsTracking);

this.timeout = 0;
this.maxHeadersCount = null;
this.maxRequestsPerSocket = 0;
setupConnectionsTracking(this);

this[kUniqueHeaders] = parseUniqueHeadersOption(options.uniqueHeaders);
}
ObjectSetPrototypeOf(Server.prototype, net.Server.prototype);
Expand All @@ -565,6 +568,10 @@ Server.prototype[SymbolAsyncDispose] = async function() {
};

Server.prototype.closeAllConnections = function() {
if (!this[kConnections]) {
return;
}

const connections = this[kConnections].all();

for (let i = 0, l = connections.length; i < l; i++) {
Expand All @@ -573,6 +580,10 @@ Server.prototype.closeAllConnections = function() {
};

Server.prototype.closeIdleConnections = function() {
if (!this[kConnections]) {
return;
}

const connections = this[kConnections].idle();

for (let i = 0, l = connections.length; i < l; i++) {
Expand Down
3 changes: 2 additions & 1 deletion lib/https.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,9 @@ function Server(opts, requestListener) {

this.timeout = 0;
this.maxHeadersCount = null;
setupConnectionsTracking(this);
this.on('listening', setupConnectionsTracking);
}

ObjectSetPrototypeOf(Server.prototype, tls.Server.prototype);
ObjectSetPrototypeOf(Server, tls.Server);

Expand Down
24 changes: 24 additions & 0 deletions test/parallel/test-http-server-connections-checking-leak.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
'use strict';
ShogunPanda marked this conversation as resolved.
Show resolved Hide resolved

// Flags: --expose-gc

// Check that creating a server without listening does not leak resources.

require('../common');
const onGC = require('../common/ongc');
ShogunPanda marked this conversation as resolved.
Show resolved Hide resolved
const Countdown = require('../common/countdown');

const http = require('http');
const max = 100;

// Note that Countdown internally calls common.mustCall, that's why it's not done here.
const countdown = new Countdown(max, () => {});
ShogunPanda marked this conversation as resolved.
Show resolved Hide resolved

for (let i = 0; i < max; i++) {
const server = http.createServer((req, res) => {});
onGC(server, { ongc: countdown.dec.bind(countdown) });
}

setImmediate(() => {
global.gc();
});
29 changes: 29 additions & 0 deletions test/parallel/test-https-server-connections-checking-leak.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
'use strict';

// Flags: --expose-gc

// Check that creating a server without listening does not leak resources.

const common = require('../common');
ShogunPanda marked this conversation as resolved.
Show resolved Hide resolved

if (!common.hasCrypto) {
common.skip('missing crypto');
}

const onGC = require('../common/ongc');
const Countdown = require('../common/countdown');

const https = require('https');
const max = 100;

// Note that Countdown internally calls common.mustCall, that's why it's not done here.
const countdown = new Countdown(max, () => {});

for (let i = 0; i < max; i++) {
const server = https.createServer((req, res) => {});
onGC(server, { ongc: countdown.dec.bind(countdown) });
}

setImmediate(() => {
global.gc();
});