Skip to content

Commit c4c2975

Browse files
authored
websocket: add tests for opening handshake (nodejs#1831)
* test: add tests for opening handshake * test: add tests for opening handshake * fix: run each test separately
1 parent f035bbc commit c4c2975

File tree

2 files changed

+240
-0
lines changed

2 files changed

+240
-0
lines changed

test/websocket/diagnostics-channel.js

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
'use strict'
2+
3+
const t = require('tap')
4+
const dc = require('diagnostics_channel')
5+
const { WebSocketServer } = require('ws')
6+
const { WebSocket } = require('../..')
7+
8+
t.test('diagnostics channel', { jobs: 1 }, (t) => {
9+
t.plan(2)
10+
11+
t.test('undici:websocket:open', (t) => {
12+
t.plan(3)
13+
14+
const server = new WebSocketServer({ port: 0 })
15+
16+
server.on('connection', (ws) => {
17+
ws.close(1000, 'goodbye')
18+
})
19+
20+
const listener = ({ extensions, protocol }) => {
21+
t.equal(extensions, null)
22+
t.equal(protocol, 'chat')
23+
}
24+
25+
t.teardown(() => {
26+
dc.channel('undici:websocket:open').unsubscribe(listener)
27+
return server.close()
28+
})
29+
30+
const { port } = server.address()
31+
32+
dc.channel('undici:websocket:open').subscribe(listener)
33+
34+
const ws = new WebSocket(`ws://localhost:${port}`, 'chat')
35+
36+
ws.addEventListener('open', () => {
37+
t.pass('Emitted open')
38+
})
39+
})
40+
41+
t.test('undici:websocket:close', (t) => {
42+
t.plan(4)
43+
44+
const server = new WebSocketServer({ port: 0 })
45+
46+
server.on('connection', (ws) => {
47+
ws.close(1000, 'goodbye')
48+
})
49+
50+
const listener = ({ websocket, code, reason }) => {
51+
t.type(websocket, WebSocket)
52+
t.equal(code, 1000)
53+
t.equal(reason, 'goodbye')
54+
}
55+
56+
t.teardown(() => {
57+
dc.channel('undici:websocket:close').unsubscribe(listener)
58+
return server.close()
59+
})
60+
61+
const { port } = server.address()
62+
63+
dc.channel('undici:websocket:close').subscribe(listener)
64+
65+
const ws = new WebSocket(`ws://localhost:${port}`, 'chat')
66+
67+
ws.addEventListener('close', () => {
68+
t.pass('Emitted open')
69+
})
70+
})
71+
})

test/websocket/opening-handshake.js

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,172 @@ test('Open event is emitted', (t) => {
4444
ws.onmessage = ws.onerror = t.fail
4545
ws.addEventListener('open', t.pass)
4646
})
47+
48+
test('Multiple protocols are joined by a comma', (t) => {
49+
t.plan(1)
50+
51+
const server = new WebSocketServer({ port: 0 })
52+
53+
server.on('connection', (ws, req) => {
54+
t.equal(req.headers['sec-websocket-protocol'], 'chat, echo')
55+
56+
ws.close(1000)
57+
server.close()
58+
})
59+
60+
t.teardown(server.close.bind(server))
61+
62+
const ws = new WebSocket(`ws://localhost:${server.address().port}`, ['chat', 'echo'])
63+
64+
ws.addEventListener('open', () => ws.close())
65+
})
66+
67+
test('Server doesn\'t send Sec-WebSocket-Protocol header when protocols are used', (t) => {
68+
t.plan(1)
69+
70+
const server = createServer((req, res) => {
71+
res.statusCode = 101
72+
73+
req.socket.destroy()
74+
}).listen(0, () => {
75+
const ws = new WebSocket(`ws://localhost:${server.address().port}`, 'chat')
76+
77+
ws.onopen = t.fail
78+
79+
ws.addEventListener('error', ({ error }) => {
80+
t.ok(error)
81+
})
82+
})
83+
84+
t.teardown(server.close.bind(server))
85+
})
86+
87+
test('Server sends invalid Upgrade header', (t) => {
88+
t.plan(1)
89+
90+
const server = createServer((req, res) => {
91+
res.setHeader('Upgrade', 'NotWebSocket')
92+
res.statusCode = 101
93+
94+
req.socket.destroy()
95+
}).listen(0, () => {
96+
const ws = new WebSocket(`ws://localhost:${server.address().port}`)
97+
98+
ws.onopen = t.fail
99+
100+
ws.addEventListener('error', ({ error }) => {
101+
t.ok(error)
102+
})
103+
})
104+
105+
t.teardown(server.close.bind(server))
106+
})
107+
108+
test('Server sends invalid Connection header', (t) => {
109+
t.plan(1)
110+
111+
const server = createServer((req, res) => {
112+
res.setHeader('Upgrade', 'websocket')
113+
res.setHeader('Connection', 'downgrade')
114+
res.statusCode = 101
115+
116+
req.socket.destroy()
117+
}).listen(0, () => {
118+
const ws = new WebSocket(`ws://localhost:${server.address().port}`)
119+
120+
ws.onopen = t.fail
121+
122+
ws.addEventListener('error', ({ error }) => {
123+
t.ok(error)
124+
})
125+
})
126+
127+
t.teardown(server.close.bind(server))
128+
})
129+
130+
test('Server sends invalid Sec-WebSocket-Accept header', (t) => {
131+
t.plan(1)
132+
133+
const server = createServer((req, res) => {
134+
res.setHeader('Upgrade', 'websocket')
135+
res.setHeader('Connection', 'upgrade')
136+
res.setHeader('Sec-WebSocket-Accept', 'abc')
137+
res.statusCode = 101
138+
139+
req.socket.destroy()
140+
}).listen(0, () => {
141+
const ws = new WebSocket(`ws://localhost:${server.address().port}`)
142+
143+
ws.onopen = t.fail
144+
145+
ws.addEventListener('error', ({ error }) => {
146+
t.ok(error)
147+
})
148+
})
149+
150+
t.teardown(server.close.bind(server))
151+
})
152+
153+
test('Server sends invalid Sec-WebSocket-Extensions header', (t) => {
154+
const uid = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
155+
const { createHash } = require('crypto')
156+
157+
t.plan(2)
158+
159+
const server = createServer((req, res) => {
160+
const key = req.headers['sec-websocket-key']
161+
t.ok(key)
162+
163+
const accept = createHash('sha1').update(key + uid).digest('base64')
164+
165+
res.setHeader('Upgrade', 'websocket')
166+
res.setHeader('Connection', 'upgrade')
167+
res.setHeader('Sec-WebSocket-Accept', accept)
168+
res.setHeader('Sec-WebSocket-Extensions', 'InvalidExtension')
169+
res.statusCode = 101
170+
171+
res.end()
172+
}).listen(0, () => {
173+
const ws = new WebSocket(`ws://localhost:${server.address().port}`)
174+
175+
ws.onopen = t.fail
176+
177+
ws.addEventListener('error', ({ error }) => {
178+
t.ok(error)
179+
})
180+
})
181+
182+
t.teardown(server.close.bind(server))
183+
})
184+
185+
test('Server sends invalid Sec-WebSocket-Extensions header', (t) => {
186+
const uid = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
187+
const { createHash } = require('crypto')
188+
189+
t.plan(2)
190+
191+
const server = createServer((req, res) => {
192+
const key = req.headers['sec-websocket-key']
193+
t.ok(key)
194+
195+
const accept = createHash('sha1').update(key + uid).digest('base64')
196+
197+
res.setHeader('Upgrade', 'websocket')
198+
res.setHeader('Connection', 'upgrade')
199+
res.setHeader('Sec-WebSocket-Accept', accept)
200+
res.setHeader('Sec-WebSocket-Protocol', 'echo') // <--
201+
res.statusCode = 101
202+
203+
res.end()
204+
}).listen(0, () => {
205+
const ws = new WebSocket(`ws://localhost:${server.address().port}`, 'chat')
206+
207+
ws.onopen = t.fail
208+
209+
ws.addEventListener('error', ({ error }) => {
210+
t.ok(error)
211+
})
212+
})
213+
214+
t.teardown(server.close.bind(server))
215+
})

0 commit comments

Comments
 (0)