http: use listenerCount when adding noop event

PR-URL: https://github.com/nodejs/node/pull/46769
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
Paolo Insogna 2023-03-08 08:09:21 +01:00 committed by GitHub
parent f94ef7c2e8
commit 0d3faaef90
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 67 additions and 1 deletions

View File

@ -822,10 +822,29 @@ const requestHeaderFieldsTooLargeResponse = Buffer.from(
`HTTP/1.1 431 ${STATUS_CODES[431]}\r\n` +
'Connection: close\r\n\r\n', 'ascii',
);
function warnUnclosedSocket() {
if (warnUnclosedSocket.emitted) {
return;
}
warnUnclosedSocket.emitted = true;
process.emitWarning(
'An error event has already been emitted on the socket. ' +
'Please use the destroy method on the socket while handling ' +
"a 'clientError' event.",
);
}
function socketOnError(e) {
// Ignore further errors
this.removeListener('error', socketOnError);
this.on('error', noop);
if (this.listenerCount('error', noop) === 0) {
this.on('error', noop);
} else {
warnUnclosedSocket();
}
if (!this.server.emit('clientError', e, this)) {
// Caution must be taken to avoid corrupting the remote peer.

View File

@ -0,0 +1,47 @@
// Flags: --no-warnings
'use strict';
const common = require('../common');
const assert = require('assert');
const http = require('http');
const net = require('net');
// This test sends an invalid character to a HTTP server and purposely
// does not handle clientError (even if it sets an event handler).
//
// The idea is to let the server emit multiple errors on the socket,
// mostly due to parsing error, and make sure they don't result
// in leaking event listeners.
{
let i = 0;
let socket;
process.on('warning', common.mustCall());
const server = http.createServer(common.mustNotCall());
server.on('clientError', common.mustCallAtLeast((err) => {
assert.strictEqual(err.code, 'HPE_INVALID_METHOD');
assert.strictEqual(err.rawPacket.toString(), '*');
if (i === 20) {
socket.end();
} else {
socket.write('*');
i++;
}
}, 1));
server.listen(0, () => {
socket = net.createConnection({ port: server.address().port });
socket.on('connect', () => {
socket.write('*');
});
socket.on('close', () => {
server.close();
});
});
}