From d2cf8cfb65abbf77a4d17cf62ff6cd3853c4c619 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Wed, 30 Aug 2023 13:42:26 +0100 Subject: [PATCH 1/2] [fix] ensure handleUpgrade doesn't break if socket is just a stream --- lib/websocket.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/websocket.js b/lib/websocket.js index f71d3d8e7..f536aaf4d 100644 --- a/lib/websocket.js +++ b/lib/websocket.js @@ -224,7 +224,10 @@ class WebSocket extends EventEmitter { receiver.on('pong', receiverOnPong); socket.setTimeout(0); - socket.setNoDelay(); + if (socket.setNoDelay) { + // May not be available if 'socket' is actually a stream + socket.setNoDelay(); + } if (head.length > 0) socket.unshift(head); From 8943b5622feb182bb0ce50617d811f1f05cb7202 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Thu, 31 Aug 2023 16:55:03 +0200 Subject: [PATCH 2/2] [fix] improve upgrade-a-stream fix: add a test & handle setTimeout too --- lib/websocket.js | 6 ++++-- package.json | 1 + test/websocket-server.test.js | 30 ++++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/lib/websocket.js b/lib/websocket.js index f536aaf4d..15f61acee 100644 --- a/lib/websocket.js +++ b/lib/websocket.js @@ -223,9 +223,11 @@ class WebSocket extends EventEmitter { receiver.on('ping', receiverOnPing); receiver.on('pong', receiverOnPong); - socket.setTimeout(0); + // These methods may not be available if `socket` is actually just a stream: + if (socket.setTimeout) { + socket.setTimeout(0); + } if (socket.setNoDelay) { - // May not be available if 'socket' is actually a stream socket.setNoDelay(); } diff --git a/package.json b/package.json index 2f076d2f3..0cc387471 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "eslint-config-prettier": "^9.0.0", "eslint-plugin-prettier": "^5.0.0", "mocha": "^8.4.0", + "native-duplexpair": "^1.0.0", "nyc": "^15.0.0", "prettier": "^3.0.0", "utf-8-validate": "^6.0.0" diff --git a/test/websocket-server.test.js b/test/websocket-server.test.js index 176c29dbd..33d7a65f8 100644 --- a/test/websocket-server.test.js +++ b/test/websocket-server.test.js @@ -10,6 +10,7 @@ const path = require('path'); const net = require('net'); const fs = require('fs'); const os = require('os'); +const DuplexPair = require('native-duplexpair'); const Sender = require('../lib/sender'); const WebSocket = require('..'); @@ -514,6 +515,35 @@ describe('WebSocketServer', () => { }); }); }); + + it('can complete a WebSocket upgrade over any duplex stream', (done) => { + const server = http.createServer(); + + server.listen(0, () => { + const wss = new WebSocket.Server({ noServer: true }); + + server.on('upgrade', (req, socket, head) => { + // Put a stream between the raw socket and our websocket processing: + const { socket1: stream1, socket2: stream2 } = new DuplexPair(); + socket.pipe(stream1); + stream1.pipe(socket); + + // Pass the other side of the stream as the socket to upgrade: + wss.handleUpgrade(req, stream2, head, (ws) => { + ws.send('hello'); + ws.close(); + }); + }); + + const ws = new WebSocket(`ws://localhost:${server.address().port}`); + + ws.on('message', (message, isBinary) => { + assert.deepStrictEqual(message, Buffer.from('hello')); + assert.ok(!isBinary); + server.close(done); + }); + }); + }); }); describe('#completeUpgrade', () => {