diff --git a/lib/transports/websocket.ts b/lib/transports/websocket.ts index 4e868707..a2ad827f 100644 --- a/lib/transports/websocket.ts +++ b/lib/transports/websocket.ts @@ -93,11 +93,31 @@ export class WebSocket extends Transport { if (packet.options && typeof packet.options.wsPreEncoded === "string") { send(packet.options.wsPreEncoded); + } else if (this._canSendPreEncodedFrame(packet)) { + // the WebSocket frame was computed with WebSocket.Sender.frame() + // see https://github.com/websockets/ws/issues/617#issuecomment-283002469 + this.socket._sender.sendFrame(packet.options.wsPreEncodedFrame, err => { + if (err) return this.onError("write error", err.stack); + this.send(packets); + }); } else { this.parser.encodePacket(packet, this.supportsBinary, send); } } + /** + * Whether the encoding of the WebSocket frame can be skipped. + * @param packet + * @private + */ + private _canSendPreEncodedFrame(packet) { + return ( + !this.perMessageDeflate && + typeof this.socket?._sender?.sendFrame === "function" && + packet.options?.wsPreEncodedFrame !== undefined + ); + } + /** * Closes the transport. * diff --git a/test/server.js b/test/server.js index 74ad2a17..6bb461a9 100644 --- a/test/server.js +++ b/test/server.js @@ -2822,6 +2822,53 @@ describe("server", () => { }); }); }); + + it("should use the pre-encoded frame", function(done) { + if (process.env.EIO_WS_ENGINE === "uws") { + return this.skip(); + } + engine = listen(port => { + client = new ClientSocket(`ws://localhost:${port}`, { + transports: ["websocket"] + }); + + engine.on("connection", conn => { + conn.send("test", { + wsPreEncodedFrame: [ + Buffer.from([129, 4]), + Buffer.from([52, 49, 50, 51]) + ] + }); + }); + + client.on("message", msg => { + expect(msg).to.be("123"); + done(); + }); + }); + }); + + it("should not use the pre-encoded frame when the permessage-deflate extension is enabled", done => { + engine = listen({ perMessageDeflate: true }, port => { + client = new ClientSocket(`ws://localhost:${port}`, { + transports: ["websocket"] + }); + + engine.on("connection", conn => { + conn.send("test", { + wsPreEncodedFrame: [ + Buffer.from([129, 4]), + Buffer.from([52, 49, 50, 51]) + ] + }); + }); + + client.on("message", msg => { + expect(msg).to.be("test"); + done(); + }); + }); + }); }); });