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
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
http: start connections checking interval on listen
Co-authored-by: Luigi Pinca <[email protected]>
ShogunPanda and lpinca committed Jul 24, 2023
commit 4e50ff1f360714a68a0c7859803a34ef6c471ba0
21 changes: 16 additions & 5 deletions lib/_http_server.js
Original file line number Diff line number Diff line change
@@ -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) {
@@ -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);
@@ -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++) {
@@ -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++) {
3 changes: 2 additions & 1 deletion lib/https.js
Original file line number Diff line number Diff line change
@@ -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);

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';

// Flags: --expose-gc

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

require('../common');
const onGC = require('../common/ongc');
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, () => {});

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');

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();
});