From 8ac03a073a17af04c569dff59c7878a0e56417bc Mon Sep 17 00:00:00 2001 From: Luigi Pinca Date: Sun, 20 Aug 2023 12:04:24 +0200 Subject: [PATCH] [feature] Allow http/https scheme Allow HTTP(S) URLs to be used in the WebSocket constructor. They are immediately converted to the ws and wss schemes. Refs: https://github.com/whatwg/websockets/pull/45 --- lib/websocket.js | 12 ++++++--- test/websocket.test.js | 57 ++++++++++++++++++++++++++++++++++++------ 2 files changed, 59 insertions(+), 10 deletions(-) diff --git a/lib/websocket.js b/lib/websocket.js index b2b2b0926..f71d3d8e7 100644 --- a/lib/websocket.js +++ b/lib/websocket.js @@ -667,24 +667,30 @@ function initAsClient(websocket, address, protocols, options) { if (address instanceof URL) { parsedUrl = address; - websocket._url = address.href; } else { try { parsedUrl = new URL(address); } catch (e) { throw new SyntaxError(`Invalid URL: ${address}`); } + } - websocket._url = address; + if (parsedUrl.protocol === 'http:') { + parsedUrl.protocol = 'ws:'; + } else if (parsedUrl.protocol === 'https:') { + parsedUrl.protocol = 'wss:'; } + websocket._url = parsedUrl.href; + const isSecure = parsedUrl.protocol === 'wss:'; const isIpcUrl = parsedUrl.protocol === 'ws+unix:'; let invalidUrlMessage; if (parsedUrl.protocol !== 'ws:' && !isSecure && !isIpcUrl) { invalidUrlMessage = - 'The URL\'s protocol must be one of "ws:", "wss:", or "ws+unix:"'; + 'The URL\'s protocol must be one of "ws:", "wss:", ' + + '"http:", "https", or "ws+unix:"'; } else if (isIpcUrl && !parsedUrl.pathname) { invalidUrlMessage = "The URL's pathname is empty"; } else if (parsedUrl.hash) { diff --git a/test/websocket.test.js b/test/websocket.test.js index 7b3978428..7b4e01fe6 100644 --- a/test/websocket.test.js +++ b/test/websocket.test.js @@ -36,8 +36,16 @@ describe('WebSocket', () => { ); assert.throws( - () => new WebSocket('https://websocket-echo.com'), - /^SyntaxError: The URL's protocol must be one of "ws:", "wss:", or "ws\+unix:"$/ + () => new WebSocket('bad-scheme://websocket-echo.com'), + (err) => { + assert.strictEqual( + err.message, + 'The URL\'s protocol must be one of "ws:", "wss:", ' + + '"http:", "https", or "ws+unix:"' + ); + + return true; + } ); assert.throws( @@ -72,6 +80,30 @@ describe('WebSocket', () => { const ws = new WebSocket(new URL('ws://[::1]'), { agent }); }); + it('allows the http scheme', (done) => { + const agent = new CustomAgent(); + + agent.addRequest = (req, opts) => { + assert.strictEqual(opts.host, 'localhost'); + assert.strictEqual(opts.port, 80); + done(); + }; + + const ws = new WebSocket('http://localhost', { agent }); + }); + + it('allows the https scheme', (done) => { + const agent = new https.Agent(); + + agent.addRequest = (req, opts) => { + assert.strictEqual(opts.host, 'localhost'); + assert.strictEqual(opts.port, 443); + done(); + }; + + const ws = new WebSocket('https://localhost', { agent }); + }); + describe('options', () => { it('accepts the `options` object as 3rd argument', () => { const agent = new http.Agent(); @@ -539,10 +571,18 @@ describe('WebSocket', () => { }); it('exposes the server url', () => { - const url = 'ws://localhost'; - const ws = new WebSocket(url, { agent: new CustomAgent() }); + const schemes = new Map([ + ['ws', 'ws'], + ['wss', 'wss'], + ['http', 'ws'], + ['https', 'wss'] + ]); + + for (const [key, value] of schemes) { + const ws = new WebSocket(`${key}://localhost/`, { lookup() {} }); - assert.strictEqual(ws.url, url); + assert.strictEqual(ws.url, `${value}://localhost/`); + } }); }); }); @@ -1174,7 +1214,9 @@ describe('WebSocket', () => { it('emits an error if the redirect URL is invalid (2/2)', (done) => { server.once('upgrade', (req, socket) => { - socket.end('HTTP/1.1 302 Found\r\nLocation: http://localhost\r\n\r\n'); + socket.end( + 'HTTP/1.1 302 Found\r\nLocation: bad-scheme://localhost\r\n\r\n' + ); }); const ws = new WebSocket(`ws://localhost:${server.address().port}`, { @@ -1186,7 +1228,8 @@ describe('WebSocket', () => { assert.ok(err instanceof SyntaxError); assert.strictEqual( err.message, - 'The URL\'s protocol must be one of "ws:", "wss:", or "ws+unix:"' + 'The URL\'s protocol must be one of "ws:", "wss:", ' + + '"http:", "https", or "ws+unix:"' ); assert.strictEqual(ws._redirects, 1);