* @see https://websockets.spec.whatwg.org/#concept-websocket-establish * @param {URL} url * @param {string|string[]} protocols * @param {import('./websocket').Handler} handler * @param {Partial } options
(url, protocols, client, handler, options)
| 24 | * @param {Partial<import('../../../types/websocket').WebSocketInit>} options |
| 25 | */ |
| 26 | function establishWebSocketConnection (url, protocols, client, handler, options) { |
| 27 | // 1. Let requestURL be a copy of url, with its scheme set to "http", if url’s |
| 28 | // scheme is "ws", and to "https" otherwise. |
| 29 | const requestURL = url |
| 30 | |
| 31 | requestURL.protocol = url.protocol === 'ws:' ? 'http:' : 'https:' |
| 32 | |
| 33 | // 2. Let request be a new request, whose URL is requestURL, client is client, |
| 34 | // service-workers mode is "none", referrer is "no-referrer", mode is |
| 35 | // "websocket", credentials mode is "include", cache mode is "no-store" , |
| 36 | // redirect mode is "error", and use-URL-credentials flag is set. |
| 37 | const request = makeRequest({ |
| 38 | urlList: [requestURL], |
| 39 | client, |
| 40 | serviceWorkers: 'none', |
| 41 | referrer: 'no-referrer', |
| 42 | mode: 'websocket', |
| 43 | credentials: 'include', |
| 44 | cache: 'no-store', |
| 45 | redirect: 'error', |
| 46 | useURLCredentials: true |
| 47 | }) |
| 48 | |
| 49 | // Note: undici extension, allow setting custom headers. |
| 50 | if (options.headers) { |
| 51 | const headersList = getHeadersList(new Headers(options.headers)) |
| 52 | |
| 53 | request.headersList = headersList |
| 54 | } |
| 55 | |
| 56 | // 3. Append (`Upgrade`, `websocket`) to request’s header list. |
| 57 | // 4. Append (`Connection`, `Upgrade`) to request’s header list. |
| 58 | // Note: both of these are handled by undici currently. |
| 59 | // https://github.com/nodejs/undici/blob/68c269c4144c446f3f1220951338daef4a6b5ec4/lib/client.js#L1397 |
| 60 | |
| 61 | // 5. Let keyValue be a nonce consisting of a randomly selected |
| 62 | // 16-byte value that has been forgiving-base64-encoded and |
| 63 | // isomorphic encoded. |
| 64 | const keyValue = crypto.randomBytes(16).toString('base64') |
| 65 | |
| 66 | // 6. Append (`Sec-WebSocket-Key`, keyValue) to request’s |
| 67 | // header list. |
| 68 | request.headersList.append('sec-websocket-key', keyValue, true) |
| 69 | |
| 70 | // 7. Append (`Sec-WebSocket-Version`, `13`) to request’s |
| 71 | // header list. |
| 72 | request.headersList.append('sec-websocket-version', '13', true) |
| 73 | |
| 74 | // 8. For each protocol in protocols, combine |
| 75 | // (`Sec-WebSocket-Protocol`, protocol) in request’s header |
| 76 | // list. |
| 77 | for (const protocol of protocols) { |
| 78 | request.headersList.append('sec-websocket-protocol', protocol, true) |
| 79 | } |
| 80 | |
| 81 | // 9. Let permessageDeflate be a user-agent defined |
| 82 | // "permessage-deflate" extension header value. |
| 83 | // https://github.com/mozilla/gecko-dev/blob/ce78234f5e653a5d3916813ff990f053510227bc/netwerk/protocol/websocket/WebSocketChannel.cpp#L2673 |
no test coverage detected