Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion lib/web/fetch/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -1476,5 +1476,6 @@ module.exports = {
buildContentRange,
parseMetadata,
createInflate,
extractMimeType
extractMimeType,
getDecodeSplit
}
16 changes: 13 additions & 3 deletions lib/web/websocket/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const { CloseEvent } = require('./events')
const { makeRequest } = require('../fetch/request')
const { fetching } = require('../fetch/index')
const { Headers } = require('../fetch/headers')
const { getDecodeSplit } = require('../fetch/util')
const { kHeadersList } = require('../../core/symbols')

/** @type {import('crypto')} */
Expand Down Expand Up @@ -176,9 +177,18 @@ function establishWebSocketConnection (url, protocols, ws, onEstablish, options)
// the WebSocket Connection_.
const secProtocol = response.headersList.get('Sec-WebSocket-Protocol')

if (secProtocol !== null && secProtocol !== request.headersList.get('Sec-WebSocket-Protocol')) {
failWebsocketConnection(ws, 'Protocol was not set in the opening handshake.')
return
if (secProtocol !== null) {
const requestProtocols = getDecodeSplit('sec-websocket-protocol', request.headersList)

// The client can request that the server use a specific subprotocol by
// including the |Sec-WebSocket-Protocol| field in its handshake. If it
// is specified, the server needs to include the same field and one of
// the selected subprotocol values in its response for the connection to
// be established.
if (!requestProtocols.includes(secProtocol)) {
failWebsocketConnection(ws, 'Protocol was not set in the opening handshake.')
return
}
}

response.socket.on('data', onSocketData)
Expand Down
41 changes: 41 additions & 0 deletions test/websocket/issue-2844.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
'use strict'

const { test } = require('node:test')
const { once } = require('node:events')
const { WebSocketServer } = require('ws')
const { WebSocket } = require('../..')
const { tspl } = require('@matteo.collina/tspl')

test('The server must reply with at least one subprotocol the client sends', async (t) => {
const { completed, deepStrictEqual, fail } = tspl(t, { plan: 2 })

const wss = new WebSocketServer({
handleProtocols: (protocols) => {
deepStrictEqual(protocols, new Set(['msgpack', 'json']))

return protocols.values().next().value
},
port: 0
})

wss.on('connection', (ws) => {
ws.on('error', fail)
ws.send('something')
})

await once(wss, 'listening')

const ws = new WebSocket(`ws://localhost:${wss.address().port}`, {
protocols: ['msgpack', 'json']
})

ws.onerror = fail
ws.onopen = () => deepStrictEqual(ws.protocol, 'msgpack')

t.after(() => {
wss.close()
ws.close()
})

await completed
})