Skip to content

Commit 9717e90

Browse files
committed
http: use listenerCount when adding noop event
1 parent 7a5b9d0 commit 9717e90

File tree

2 files changed

+88
-1
lines changed

2 files changed

+88
-1
lines changed

lib/_http_server.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -825,7 +825,10 @@ const requestHeaderFieldsTooLargeResponse = Buffer.from(
825825
function socketOnError(e) {
826826
// Ignore further errors
827827
this.removeListener('error', socketOnError);
828-
this.on('error', noop);
828+
829+
if (this.listenerCount('error', noop) === 0) {
830+
this.on('error', noop);
831+
}
829832

830833
if (!this.server.emit('clientError', e, this)) {
831834
// Caution must be taken to avoid corrupting the remote peer.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const assert = require('assert');
5+
const http = require('http');
6+
const net = require('net');
7+
8+
// This test sends an invalid character to a HTTP server and purposely
9+
// does not handle clientError (even if it sets an event handler).
10+
//
11+
// The idea is to let the server emit multiple errors on the socket,
12+
// mostly due to parsing error, and make sure they don't result
13+
// in leaking event listeners.
14+
15+
{
16+
let i = 0;
17+
let socket;
18+
const mustNotCall = common.mustNotCall.bind(null);
19+
process.on('warning', mustNotCall);
20+
21+
const server = http.createServer(common.mustNotCall());
22+
23+
server.on('clientError', common.mustCallAtLeast((err) => {
24+
assert.strictEqual(err.code, 'HPE_INVALID_METHOD');
25+
assert.strictEqual(err.rawPacket.toString(), '*');
26+
27+
if (i === 20) {
28+
socket.end();
29+
} else {
30+
socket.write('*');
31+
i++;
32+
}
33+
}, 1));
34+
35+
server.listen(0, () => {
36+
socket = net.createConnection({ port: server.address().port });
37+
38+
socket.on('connect', () => {
39+
socket.write('*');
40+
});
41+
42+
socket.on('close', () => {
43+
server.close();
44+
process.removeListener('warning', mustNotCall);
45+
});
46+
});
47+
}
48+
49+
{
50+
const valid = 'GET / HTTP/1.1\r\nHost:a\r\nContent-Length:1\r\n\r\n1\r\n';
51+
52+
const server = http.createServer((req, res) => {
53+
const handler = common.mustCall(function handler(error) {
54+
req.socket.removeListener('error', handler);
55+
}, 2);
56+
57+
req.on('end', handler);
58+
req.socket.on('error', handler);
59+
60+
res.removeHeader('date');
61+
res.writeHead(204);
62+
res.end();
63+
});
64+
65+
server.listen(0, () => {
66+
const client = net.createConnection({ host: '127.0.0.1', port: server.address().port });
67+
let data = Buffer.alloc(0);
68+
69+
client.on('data', (chunk) => {
70+
data = Buffer.concat([data, chunk]);
71+
});
72+
73+
client.on('end', () => {
74+
assert.strictEqual(
75+
data.toString('utf-8'),
76+
'HTTP/1.1 204 No Content\r\nConnection: keep-alive\r\nKeep-Alive: timeout=5\r\n\r\n' +
77+
'HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n',
78+
);
79+
server.close();
80+
});
81+
82+
client.write(valid + 'INVALID');
83+
});
84+
}

0 commit comments

Comments
 (0)