From 73dec34b4b8ba783c5364111ae28ae9a12c6039e Mon Sep 17 00:00:00 2001 From: Luigi Pinca Date: Mon, 22 Nov 2021 15:27:29 +0100 Subject: [PATCH] [fix] Do not throw if the redirect URL is invalid If the redirect URL is invalid, then emit the error instead of throwing it, otherwise there is no way to handle it. --- lib/websocket.js | 35 +++++++++++++++++++++++++++----- test/websocket.test.js | 45 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 5 deletions(-) diff --git a/lib/websocket.js b/lib/websocket.js index 40696100e..2613af169 100644 --- a/lib/websocket.js +++ b/lib/websocket.js @@ -618,7 +618,14 @@ function initAsClient(websocket, address, protocols, options) { const isUnixSocket = parsedUrl.protocol === 'ws+unix:'; if (!parsedUrl.host && (!isUnixSocket || !parsedUrl.pathname)) { - throw new Error(`Invalid URL: ${websocket.url}`); + const err = new Error(`Invalid URL: ${websocket.url}`); + + if (websocket._redirects === 0) { + throw err; + } else { + emitErrorAndClose(websocket, err); + return; + } } const isSecure = @@ -687,9 +694,7 @@ function initAsClient(websocket, address, protocols, options) { if (req === null || req.aborted) return; req = websocket._req = null; - websocket._readyState = WebSocket.CLOSING; - websocket.emit('error', err); - websocket.emitClose(); + emitErrorAndClose(websocket, err); }); req.on('response', (res) => { @@ -709,7 +714,14 @@ function initAsClient(websocket, address, protocols, options) { req.abort(); - const addr = new URL(location, address); + let addr; + + try { + addr = new URL(location, address); + } catch (err) { + emitErrorAndClose(websocket, err); + return; + } initAsClient(websocket, addr, protocols, options); } else if (!websocket.emit('unexpected-response', req, res)) { @@ -811,6 +823,19 @@ function initAsClient(websocket, address, protocols, options) { }); } +/** + * Emit the `'error'` and `'close'` event. + * + * @param {WebSocket} websocket The WebSocket instance + * @param {Error} The error to emit + * @private + */ +function emitErrorAndClose(websocket, err) { + websocket._readyState = WebSocket.CLOSING; + websocket.emit('error', err); + websocket.emitClose(); +} + /** * Create a `net.Socket` and initiate a connection. * diff --git a/test/websocket.test.js b/test/websocket.test.js index 6c24feded..84c615b5a 100644 --- a/test/websocket.test.js +++ b/test/websocket.test.js @@ -941,6 +941,51 @@ describe('WebSocket', () => { ws.on('close', () => done()); }); }); + + it('emits an error if the redirect URL is invalid (1/2)', (done) => { + const onUpgrade = (req, socket) => { + socket.end('HTTP/1.1 302 Found\r\nLocation: ws://\r\n\r\n'); + }; + + server.on('upgrade', onUpgrade); + + const ws = new WebSocket(`ws://localhost:${server.address().port}`, { + followRedirects: true + }); + + ws.on('open', () => done(new Error("Unexpected 'open' event"))); + ws.on('error', (err) => { + assert.ok(err instanceof Error); + assert.ok(/Invalid URL/.test(err.message)); + assert.strictEqual(err.input, 'ws://'); + assert.strictEqual(ws._redirects, 1); + + server.removeListener('upgrade', onUpgrade); + ws.on('close', () => done()); + }); + }); + + it('emits an error if the redirect URL is invalid (2/2)', (done) => { + const onUpgrade = (req, socket) => { + socket.end('HTTP/1.1 302 Found\r\nLocation: ws+unix:\r\n\r\n'); + }; + + server.on('upgrade', onUpgrade); + + const ws = new WebSocket(`ws://localhost:${server.address().port}`, { + followRedirects: true + }); + + ws.on('open', () => done(new Error("Unexpected 'open' event"))); + ws.on('error', (err) => { + assert.ok(err instanceof Error); + assert.strictEqual(err.message, 'Invalid URL: ws+unix:'); + assert.strictEqual(ws._redirects, 1); + + server.removeListener('upgrade', onUpgrade); + ws.on('close', () => done()); + }); + }); }); describe('Connection with query string', () => {