Skip to content

Commit 4ea127e

Browse files
committed
test: fix undici 8 websocket and proxy tests
1 parent 969313c commit 4ea127e

File tree

4 files changed

+91
-26
lines changed

4 files changed

+91
-26
lines changed
Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,33 @@
1-
// This tests that invalid proxy URLs are handled correctly.
1+
// This tests that a scheme-less proxy value no longer crashes startup.
22
import * as common from '../common/index.mjs';
33
import assert from 'node:assert';
44
import { once } from 'events';
55
import http from 'node:http';
66
import { runProxiedRequest } from '../common/proxy-server.js';
77

8-
// Start a target server that should not be reached.
9-
const server = http.createServer(common.mustNotCall());
8+
// Start a target server. The built-in http agent still ignores a scheme-less
9+
// proxy value, so the request is sent directly.
10+
const server = http.createServer(common.mustCall((req, res) => {
11+
assert.strictEqual(req.url, '/test');
12+
res.end('Hello world');
13+
}));
1014
server.on('error', common.mustNotCall((err) => { console.error('Server error', err); }));
1115
server.listen(0);
1216
await once(server, 'listening');
1317

1418
const serverHost = `localhost:${server.address().port}`;
1519
const requestUrl = `http://${serverHost}/test`;
1620

17-
// Test invalid proxy URL
1821
const { code, signal, stderr, stdout } = await runProxiedRequest({
1922
NODE_USE_ENV_PROXY: 1,
2023
REQUEST_URL: requestUrl,
2124
HTTP_PROXY: 'not-a-valid-url',
2225
});
2326

24-
// Should get an error about invalid URL
25-
assert.match(stderr, /TypeError.*Invalid URL/);
26-
assert.strictEqual(stdout.trim(), '');
27-
assert.strictEqual(code, 1);
27+
assert.strictEqual(stderr.trim(), '');
28+
assert.match(stdout, /Status Code: 200/);
29+
assert.match(stdout, /Hello world/);
30+
assert.strictEqual(code, 0);
2831
assert.strictEqual(signal, null);
2932

3033
server.close();

test/client-proxy/test-https-proxy-request-invalid-url.mjs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
// This tests that invalid proxy URLs are handled correctly for HTTPS requests.
1+
// This tests that a scheme-less proxy value no longer crashes startup for
2+
// HTTPS requests.
23
import * as common from '../common/index.mjs';
34
import fixtures from '../common/fixtures.js';
45
import assert from 'node:assert';
@@ -15,26 +16,28 @@ const { default: https } = await import('node:https');
1516
const server = https.createServer({
1617
cert: fixtures.readKey('agent8-cert.pem'),
1718
key: fixtures.readKey('agent8-key.pem'),
18-
}, common.mustNotCall());
19+
}, common.mustCall((req, res) => {
20+
assert.strictEqual(req.url, '/test');
21+
res.end('Hello world');
22+
}));
1923
server.on('error', common.mustNotCall((err) => { console.error('Server error', err); }));
2024
server.listen(0);
2125
await once(server, 'listening');
2226

2327
const serverHost = `localhost:${server.address().port}`;
2428
const requestUrl = `https://${serverHost}/test`;
2529

26-
// Test invalid proxy URL
2730
const { code, signal, stderr, stdout } = await runProxiedRequest({
2831
NODE_USE_ENV_PROXY: 1,
2932
REQUEST_URL: requestUrl,
3033
HTTPS_PROXY: 'not-a-valid-url',
3134
NODE_EXTRA_CA_CERTS: fixtures.path('keys', 'fake-startcom-root-cert.pem'),
3235
});
3336

34-
// Should get an error about invalid URL
35-
assert.match(stderr, /TypeError.*Invalid URL/);
36-
assert.strictEqual(stdout.trim(), '');
37-
assert.strictEqual(code, 1);
37+
assert.strictEqual(stderr.trim(), '');
38+
assert.match(stdout, /Status Code: 200/);
39+
assert.match(stdout, /Hello world/);
40+
assert.strictEqual(code, 0);
3841
assert.strictEqual(signal, null);
3942

4043
server.close();

test/common/websocket-server.js

Lines changed: 66 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ class WebSocketServer {
1717
this.customHandleUpgradeHeaders = customHandleUpgradeHeaders;
1818

1919
this.server.on('upgrade', this.handleUpgrade.bind(this));
20+
this.server.on('connect', this.handleConnect.bind(this));
21+
this.server.on('stream', this.handleStream.bind(this));
2022
}
2123

2224
start() {
@@ -42,32 +44,86 @@ class WebSocketServer {
4244
];
4345

4446
socket.write(responseHeaders.join('\r\n') + '\r\n\r\n');
45-
this.clients.add(socket);
47+
this.addClient(socket, {
48+
close: () => socket.end(),
49+
});
50+
}
51+
52+
handleConnect(req, response) {
53+
if (req.headers[':protocol'] !== 'websocket') {
54+
return;
55+
}
56+
57+
const stream = response.stream;
58+
const key = req.headers['sec-websocket-key'];
59+
const acceptKey = this.generateAcceptValue(key);
60+
stream.respond({
61+
':status': 200,
62+
'sec-websocket-accept': acceptKey,
63+
...this.getCustomHeadersObject(),
64+
});
65+
66+
this.addClient(stream, {
67+
close: () => stream.end(),
68+
});
69+
}
4670

47-
socket.on('data', (buffer) => {
71+
handleStream(stream, headers) {
72+
if (stream.headersSent ||
73+
headers[':method'] !== 'CONNECT' ||
74+
headers[':protocol'] !== 'websocket') {
75+
return;
76+
}
77+
78+
const key = headers['sec-websocket-key'];
79+
const acceptKey = this.generateAcceptValue(key);
80+
stream.respond({
81+
':status': 200,
82+
'sec-websocket-accept': acceptKey,
83+
...this.getCustomHeadersObject(),
84+
});
85+
86+
this.addClient(stream, {
87+
close: () => stream.end(),
88+
});
89+
}
90+
91+
addClient(client, { close }) {
92+
this.clients.add(client);
93+
94+
client.on('data', (buffer) => {
4895
const opcode = buffer[0] & 0x0f;
4996

5097
if (opcode === 0x8) {
5198
// Send a minimal close frame in response:
52-
socket.write(Buffer.from([0x88, 0x00]));
53-
socket.end();
54-
this.clients.delete(socket);
99+
client.write(Buffer.from([0x88, 0x00]));
100+
close();
101+
this.clients.delete(client);
55102
return;
56103
}
57104

58-
socket.write(this.encodeMessage('Hello from server!'));
105+
client.write(this.encodeMessage('Hello from server!'));
59106
});
60107

61-
socket.on('close', () => {
62-
this.clients.delete(socket);
108+
client.on('close', () => {
109+
this.clients.delete(client);
63110
});
64111

65-
socket.on('error', (err) => {
112+
client.on('error', (err) => {
66113
console.error('Socket error:', err);
67-
this.clients.delete(socket);
114+
this.clients.delete(client);
68115
});
69116
}
70117

118+
getCustomHeadersObject() {
119+
return Object.fromEntries(
120+
this.customHandleUpgradeHeaders.map((header) => {
121+
const index = header.indexOf(':');
122+
return [header.slice(0, index).trim(), header.slice(index + 1).trim()];
123+
})
124+
);
125+
}
126+
71127
generateAcceptValue(secWebSocketKey) {
72128
return crypto
73129
.createHash('sha1')

test/parallel/test-http2-allow-http1-upgrade-ws.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,13 @@ const WebSocketServer = require('../common/websocket-server');
1515
key: fixtures.readKey('agent1-key.pem'),
1616
cert: fixtures.readKey('agent1-cert.pem'),
1717
allowHTTP1: true,
18+
settings: {
19+
enableConnectProtocol: true,
20+
},
1821
});
1922

2023
server.on('request', common.mustNotCall());
21-
new WebSocketServer({ server }); // Handles websocket 'upgrade' events
24+
new WebSocketServer({ server });
2225

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

0 commit comments

Comments
 (0)