Skip to content

Commit

Permalink
websocket: add websocketinit
Browse files Browse the repository at this point in the history
  • Loading branch information
KhafraDev committed Apr 23, 2023
1 parent 1b3fed9 commit d57f380
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 6 deletions.
5 changes: 2 additions & 3 deletions lib/websocket/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ const { fireEvent, failWebsocketConnection } = require('./util')
const { CloseEvent } = require('./events')
const { makeRequest } = require('../fetch/request')
const { fetching } = require('../fetch/index')
const { getGlobalDispatcher } = require('../global')

const channels = {}
channels.open = diagnosticsChannel.channel('undici:websocket:open')
Expand All @@ -27,7 +26,7 @@ channels.socketError = diagnosticsChannel.channel('undici:websocket:socket_error
* @param {import('./websocket').WebSocket} ws
* @param {(response: any) => void} onEstablish
*/
function establishWebSocketConnection (url, protocols, ws, onEstablish) {
function establishWebSocketConnection (url, protocols, ws, onEstablish, options) {
// 1. Let requestURL be a copy of url, with its scheme set to "http", if url’s
// scheme is "ws", and to "https" otherwise.
const requestURL = url
Expand Down Expand Up @@ -88,7 +87,7 @@ function establishWebSocketConnection (url, protocols, ws, onEstablish) {
const controller = fetching({
request,
useParallelQueue: true,
dispatcher: getGlobalDispatcher(),
dispatcher: options.dispatcher,
processResponse (response) {
// 1. If response is a network error or its status is not 101,
// fail the WebSocket connection.
Expand Down
46 changes: 43 additions & 3 deletions lib/websocket/websocket.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const { establishWebSocketConnection } = require('./connection')
const { WebsocketFrameSend } = require('./frame')
const { ByteParser } = require('./receiver')
const { kEnumerableProperty, isBlobLike } = require('../core/util')
const { getGlobalDispatcher } = require('../global')
const { types } = require('util')

let experimentalWarned = false
Expand All @@ -39,7 +40,7 @@ class WebSocket extends EventTarget {
* @param {string} url
* @param {string|string[]} protocols
*/
constructor (url, protocols = []) {
constructor (url, protocols = [], options = undefined) {
super()

webidl.argumentLengthCheck(arguments, 1, { header: 'WebSocket constructor' })
Expand All @@ -52,7 +53,19 @@ class WebSocket extends EventTarget {
}

url = webidl.converters.USVString(url)
protocols = webidl.converters['DOMString or sequence<DOMString>'](protocols)
protocols = webidl.converters['DOMString or sequence<DOMString> or WebSocketInit'](protocols)

// user passed a WebSocketInit as 2nd argument
if (!Array.isArray(protocols) && typeof protocols === 'object') {
options = protocols
protocols = protocols.protocols
} else {
if (options != null && typeof options === 'object') {
options = webidl.converters.WebSocketInit(options)
} else {
options = webidl.converters.WebSocketInit({})
}
}

// 1. Let urlRecord be the result of applying the URL parser to url.
let urlRecord
Expand Down Expand Up @@ -110,7 +123,8 @@ class WebSocket extends EventTarget {
urlRecord,
protocols,
this,
(response) => this.#onConnectionEstablished(response)
(response) => this.#onConnectionEstablished(response),
options
)

// Each WebSocket object has an associated ready state, which is a
Expand Down Expand Up @@ -577,6 +591,32 @@ webidl.converters['DOMString or sequence<DOMString>'] = function (V) {
return webidl.converters.DOMString(V)
}

// This implements the propsal made in https://github.com/whatwg/websockets/issues/42
webidl.converters.WebSocketInit = webidl.dictionaryConverter([
{
key: 'protocols',
converter: webidl.converters['DOMString or sequence<DOMString>'],
get defaultValue () {
return []
}
},
{
key: 'dispatcher',
converter: (V) => V,
get defaultValue () {
return getGlobalDispatcher()
}
}
])

webidl.converters['DOMString or sequence<DOMString> or WebSocketInit'] = function (V) {
if (webidl.util.Type(V) === 'Object' && !(Symbol.iterator in V)) {
return webidl.converters.WebSocketInit(V)
}

return webidl.converters['DOMString or sequence<DOMString>'](V)
}

webidl.converters.WebSocketSendData = function (V) {
if (webidl.util.Type(V) === 'Object') {
if (isBlobLike(V)) {
Expand Down
75 changes: 75 additions & 0 deletions test/websocket/websocketinit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
'use strict'

const { test } = require('tap')
const { WebSocketServer } = require('ws')
const { WebSocket, Dispatcher, Agent } = require('../..')

test('WebSocketInit', (t) => {
t.plan(4)

class WsDispatcher extends Dispatcher {
constructor () {
super()
this.agent = new Agent()
}

dispatch () {
t.pass()
return this.agent.dispatch(...arguments)
}
}

t.test('WebSocketInit as 2nd param', (t) => {
t.plan(1)

const server = new WebSocketServer({ port: 0 })

server.on('connection', (ws) => {
ws.send(Buffer.from('hello, world'))
})

t.teardown(server.close.bind(server))

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

ws.onerror = t.fail

ws.addEventListener('message', async (event) => {
t.equal(await event.data.text(), 'hello, world')
server.close()
ws.close()
})
})

t.test('WebSocketInit as 3rd param', (t) => {
t.plan(1)

const server = new WebSocketServer({ port: 0 })

server.on('connection', (ws) => {
ws.send(Buffer.from('hello, world'))
})

t.teardown(server.close.bind(server))

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

console.log(ws)

ws.onerror = t.fail

ws.addEventListener('message', async (event) => {
t.equal(await event.data.text(), 'hello, world')
server.close()
ws.close()
})
})
})

0 comments on commit d57f380

Please sign in to comment.