http: start connections checking interval on listen

Co-authored-by: Luigi Pinca <luigipinca@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/48611
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
This commit is contained in:
Paolo Insogna
2023-07-24 22:55:19 +02:00
committed by GitHub
parent 5cbf73ec9c
commit 8490318df8
4 changed files with 71 additions and 6 deletions

View File

@@ -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++) {

View File

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

View File

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

View File

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