http2: fix allowHttp1+Upgrade, broken by shouldUpgradeCallback · nodejs/node@c5d910a

3 files changed

lines changed

Original file line numberDiff line numberDiff line change

@@ -3374,6 +3374,9 @@ class Http2SecureServer extends TLSServer {

33743374

this.headersTimeout = 60_000; // Minimum between 60 seconds or requestTimeout

33753375

this.requestTimeout = 300_000; // 5 minutes

33763376

this.connectionsCheckingInterval = 30_000; // 30 seconds

3377+

this.shouldUpgradeCallback = function() {

3378+

return this.listenerCount('upgrade') > 0;

3379+

};

33773380

this.on('listening', setupConnectionsTracking);

33783381

}

33793382

if (typeof requestListener === 'function')

Original file line numberDiff line numberDiff line change

@@ -8,9 +8,10 @@ const crypto = require('crypto');

88

class WebSocketServer {

99

constructor({

1010

port = 0,

11+

server,

1112

}) {

1213

this.port = port;

13-

this.server = http.createServer();

14+

this.server = server || http.createServer();

1415

this.clients = new Set();

1516
1617

this.server.on('upgrade', this.handleUpgrade.bind(this));

@@ -44,6 +45,8 @@ class WebSocketServer {

4445

const opcode = buffer[0] & 0x0f;

4546
4647

if (opcode === 0x8) {

48+

// Send a minimal close frame in response:

49+

socket.write(Buffer.from([0x88, 0x00]));

4750

socket.end();

4851

this.clients.delete(socket);

4952

return;

Original file line numberDiff line numberDiff line change

@@ -0,0 +1,39 @@

1+

// Flags: --expose-internals

2+

'use strict';

3+
4+

const common = require('../common');

5+

const fixtures = require('../common/fixtures');

6+

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

7+
8+

const http2 = require('http2');

9+
10+

const undici = require('internal/deps/undici/undici');

11+

const WebSocketServer = require('../common/websocket-server');

12+
13+

(async function main() {

14+

const server = http2.createSecureServer({

15+

key: fixtures.readKey('agent1-key.pem'),

16+

cert: fixtures.readKey('agent1-cert.pem'),

17+

allowHTTP1: true,

18+

});

19+
20+

server.on('request', common.mustNotCall());

21+

new WebSocketServer({ server }); // Handles websocket 'upgrade' events

22+
23+

await new Promise((resolve) => server.listen(0, resolve));

24+
25+

await new Promise((resolve, reject) => {

26+

const ws = new WebSocket(`wss://localhost:${server.address().port}`, {

27+

dispatcher: new undici.EnvHttpProxyAgent({

28+

connect: { rejectUnauthorized: false }

29+

})

30+

});

31+

ws.addEventListener('open', common.mustCall(() => {

32+

ws.close();

33+

resolve();

34+

}));

35+

ws.addEventListener('error', reject);

36+

});

37+
38+

server.close();

39+

})().then(common.mustCall());