diff --git a/lib/sender.js b/lib/sender.js index c84885362..eb57704d6 100644 --- a/lib/sender.js +++ b/lib/sender.js @@ -89,7 +89,8 @@ class Sender { if (typeof data === 'string') { if ( (!options.mask || skipMasking) && - options[kByteLength] !== undefined + options[kByteLength] !== undefined && + options[kByteLength] > 125 ) { dataLength = options[kByteLength]; } else { @@ -101,6 +102,8 @@ class Sender { merge = options.mask && options.readOnly && !skipMasking; } + if (dataLength < 126) merge = true; + let payloadLength = dataLength; if (dataLength >= 65536) { @@ -125,22 +128,30 @@ class Sender { target.writeUIntBE(dataLength, 4, 6); } - if (!options.mask) return [target, data]; - - target[1] |= 0x80; - target[offset - 4] = mask[0]; - target[offset - 3] = mask[1]; - target[offset - 2] = mask[2]; - target[offset - 1] = mask[3]; - - if (skipMasking) return [target, data]; + if (options.mask) { + target[1] |= 0x80; + target[offset - 4] = mask[0]; + target[offset - 3] = mask[1]; + target[offset - 2] = mask[2]; + target[offset - 1] = mask[3]; + } if (merge) { - applyMask(data, mask, target, offset, dataLength); + if (options.mask && !skipMasking) { + applyMask(data, mask, target, offset, dataLength); + } else { + for (let i = 0; i < dataLength; i++) { + target[i + offset] = data[i]; + } + } + return [target]; } - applyMask(data, mask, data, 0, dataLength); + if (options.mask && !skipMasking) { + applyMask(data, mask, data, 0, dataLength); + } + return [target, data]; } diff --git a/test/sender.test.js b/test/sender.test.js index 532239fa1..8be2d374c 100644 --- a/test/sender.test.js +++ b/test/sender.test.js @@ -57,31 +57,21 @@ describe('Sender', () => { fin: true }); - assert.deepStrictEqual(list[0], Buffer.from('8103', 'hex')); - assert.deepStrictEqual(list[1], Buffer.from('e282ac', 'hex')); + assert.deepStrictEqual(list[0], Buffer.from('8103e282ac', 'hex')); }); }); describe('#send', () => { it('compresses data if compress option is enabled', (done) => { - const chunks = []; - const perMessageDeflate = new PerMessageDeflate(); + let count = 0; + const expected = Buffer.from('c104cac80400', 'hex'); const mockSocket = new MockSocket({ write: (chunk) => { - chunks.push(chunk); - if (chunks.length !== 6) return; - - assert.strictEqual(chunks[0].length, 2); - assert.strictEqual(chunks[0][0] & 0x40, 0x40); - - assert.strictEqual(chunks[2].length, 2); - assert.strictEqual(chunks[2][0] & 0x40, 0x40); - - assert.strictEqual(chunks[4].length, 2); - assert.strictEqual(chunks[4][0] & 0x40, 0x40); - done(); + assert.deepStrictEqual(chunk, expected); + if (++count === 3) done(); } }); + const perMessageDeflate = new PerMessageDeflate(); const sender = new Sender(mockSocket, { 'permessage-deflate': perMessageDeflate }); @@ -98,16 +88,10 @@ describe('Sender', () => { describe('when context takeover is disabled', () => { it('honors the compression threshold', (done) => { - const chunks = []; const perMessageDeflate = new PerMessageDeflate(); const mockSocket = new MockSocket({ write: (chunk) => { - chunks.push(chunk); - if (chunks.length !== 2) return; - - assert.strictEqual(chunks[0].length, 2); - assert.notStrictEqual(chunk[0][0] & 0x40, 0x40); - assert.strictEqual(chunks[1], 'hi'); + assert.deepStrictEqual(chunk, Buffer.from('81026869', 'hex')); done(); } }); @@ -124,23 +108,21 @@ describe('Sender', () => { }); it('compresses all fragments of a fragmented message', (done) => { - const chunks = []; - const perMessageDeflate = new PerMessageDeflate({ threshold: 3 }); + let count = 0; const mockSocket = new MockSocket({ write: (chunk) => { - chunks.push(chunk); - if (chunks.length !== 4) return; - - assert.strictEqual(chunks[0].length, 2); - assert.strictEqual(chunks[0][0] & 0x40, 0x40); - assert.strictEqual(chunks[1].length, 9); - - assert.strictEqual(chunks[2].length, 2); - assert.strictEqual(chunks[2][0] & 0x40, 0x00); - assert.strictEqual(chunks[3].length, 4); - done(); + if (++count === 1) { + assert.deepStrictEqual( + chunk, + Buffer.from('410932343206000000ffff', 'hex') + ); + } else { + assert.deepStrictEqual(chunk, Buffer.from('800432340200', 'hex')); + done(); + } } }); + const perMessageDeflate = new PerMessageDeflate({ threshold: 3 }); const sender = new Sender(mockSocket, { 'permessage-deflate': perMessageDeflate }); @@ -155,23 +137,18 @@ describe('Sender', () => { }); it('does not compress any fragments of a fragmented message', (done) => { - const chunks = []; - const perMessageDeflate = new PerMessageDeflate({ threshold: 3 }); + let count = 0; const mockSocket = new MockSocket({ write: (chunk) => { - chunks.push(chunk); - if (chunks.length !== 4) return; - - assert.strictEqual(chunks[0].length, 2); - assert.strictEqual(chunks[0][0] & 0x40, 0x00); - assert.strictEqual(chunks[1].length, 2); - - assert.strictEqual(chunks[2].length, 2); - assert.strictEqual(chunks[2][0] & 0x40, 0x00); - assert.strictEqual(chunks[3].length, 3); - done(); + if (++count === 1) { + assert.deepStrictEqual(chunk, Buffer.from('01023132', 'hex')); + } else { + assert.deepStrictEqual(chunk, Buffer.from('8003313233', 'hex')); + done(); + } } }); + const perMessageDeflate = new PerMessageDeflate({ threshold: 3 }); const sender = new Sender(mockSocket, { 'permessage-deflate': perMessageDeflate }); @@ -186,23 +163,24 @@ describe('Sender', () => { }); it('compresses empty buffer as first fragment', (done) => { - const chunks = []; - const perMessageDeflate = new PerMessageDeflate({ threshold: 0 }); + let count = 0; const mockSocket = new MockSocket({ write: (chunk) => { - chunks.push(chunk); - if (chunks.length !== 4) return; - - assert.strictEqual(chunks[0].length, 2); - assert.strictEqual(chunks[0][0] & 0x40, 0x40); - assert.strictEqual(chunks[1].length, 5); - - assert.strictEqual(chunks[2].length, 2); - assert.strictEqual(chunks[2][0] & 0x40, 0x00); - assert.strictEqual(chunks[3].length, 6); - done(); + if (++count === 1) { + assert.deepStrictEqual( + chunk, + Buffer.from('4105000000ffff', 'hex') + ); + } else { + assert.deepStrictEqual( + chunk, + Buffer.from('80064a492c490400', 'hex') + ); + done(); + } } }); + const perMessageDeflate = new PerMessageDeflate({ threshold: 0 }); const sender = new Sender(mockSocket, { 'permessage-deflate': perMessageDeflate }); @@ -217,23 +195,21 @@ describe('Sender', () => { }); it('compresses empty buffer as last fragment', (done) => { - const chunks = []; - const perMessageDeflate = new PerMessageDeflate({ threshold: 0 }); + let count = 0; const mockSocket = new MockSocket({ write: (chunk) => { - chunks.push(chunk); - if (chunks.length !== 4) return; - - assert.strictEqual(chunks[0].length, 2); - assert.strictEqual(chunks[0][0] & 0x40, 0x40); - assert.strictEqual(chunks[1].length, 10); - - assert.strictEqual(chunks[2].length, 2); - assert.strictEqual(chunks[2][0] & 0x40, 0x00); - assert.strictEqual(chunks[3].length, 1); - done(); + if (++count === 1) { + assert.deepStrictEqual( + chunk, + Buffer.from('410a4a492c4904000000ffff', 'hex') + ); + } else { + assert.deepStrictEqual(chunk, Buffer.from('800100', 'hex')); + done(); + } } }); + const perMessageDeflate = new PerMessageDeflate({ threshold: 0 }); const sender = new Sender(mockSocket, { 'permessage-deflate': perMessageDeflate }); @@ -255,15 +231,9 @@ describe('Sender', () => { let count = 0; const mockSocket = new MockSocket({ write: (data) => { - if (++count < 3) return; - - if (count % 2) { - assert.ok(data.equals(Buffer.from([0x89, 0x02]))); - } else if (count < 8) { - assert.ok(data.equals(Buffer.from([0x68, 0x69]))); - } else { - assert.strictEqual(data, 'hi'); - done(); + if (++count > 1) { + assert.deepStrictEqual(data, Buffer.from('89026869', 'hex')); + if (count === 4) done(); } } }); @@ -288,16 +258,11 @@ describe('Sender', () => { let count = 0; const mockSocket = new MockSocket({ write: (data) => { - if (++count < 3) return; - - if (count % 2) { - assert.ok(data.equals(Buffer.from([0x8a, 0x02]))); - } else if (count < 8) { - assert.ok(data.equals(Buffer.from([0x68, 0x69]))); - } else { - assert.strictEqual(data, 'hi'); - done(); - } + if (++count === 1) return; + + assert.deepStrictEqual(data, Buffer.from('8a026869', 'hex')); + + if (count === 4) done(); } }); const sender = new Sender(mockSocket, { @@ -362,7 +327,7 @@ describe('Sender', () => { sender.send('baz', { compress: true, fin: true }); sender.close(1000, undefined, false, () => { - assert.strictEqual(count, 8); + assert.strictEqual(count, 4); done(); }); }); diff --git a/test/websocket.test.js b/test/websocket.test.js index 7b3978428..45a9f0833 100644 --- a/test/websocket.test.js +++ b/test/websocket.test.js @@ -3992,7 +3992,7 @@ describe('WebSocket', () => { ]; for (let i = 0; i < 399; i++) { - list.push(list[list.length - 2], list[list.length - 1]); + list.push(list[list.length - 1]); } // This hack is used because there is no guarantee that more than