'use strict' ;
const assert = require('assert' );
const crypto = require('crypto' );
const PerMessageDeflate = require('../lib/permessage-deflate' );
const Receiver = require('../lib/receiver' );
const Sender = require('../lib/sender' );
const { EMPTY_BUFFER, kStatusCode } = require('../lib/constants' );
describe('Receiver' , () => {
it('parses an unmasked text message' , (done) => {
const receiver = new Receiver();
receiver.on('message' , (data, isBinary) => {
assert .deepStrictEqual(data, Buffer.from('Hello' ));
assert .ok(!isBinary);
done();
});
receiver.write(Buffer.from('810548656c6c6f' , 'hex' ));
});
it('parses a close message' , (done) => {
const receiver = new Receiver();
receiver.on('conclude' , (code, data) => {
assert .strictEqual(code, 1005 );
assert .strictEqual(data, EMPTY_BUFFER);
done();
});
receiver.write(Buffer.from('8800' , 'hex' ));
});
it('parses a close message spanning multiple writes' , (done) => {
const receiver = new Receiver();
receiver.on('conclude' , (code, data) => {
assert .strictEqual(code, 1000 );
assert .deepStrictEqual(data, Buffer.from('DONE' ));
done();
});
receiver.write(Buffer.from('8806' , 'hex' ));
receiver.write(Buffer.from('03e8444F4E45' , 'hex' ));
});
it('parses a masked text message' , (done) => {
const receiver = new Receiver({ isServer: true });
receiver.on('message' , (data, isBinary) => {
assert .deepStrictEqual(data, Buffer.from('5:::{"name":"echo"}' ));
assert .ok(!isBinary);
done();
});
receiver.write(
Buffer.from('81933483a86801b992524fa1c60959e68a5216e6cb005ba1d5' , 'hex' )
);
});
it('parses a masked text message longer than 125 B' , (done) => {
const receiver = new Receiver({ isServer: true });
const msg = Buffer.from('A' .repeat(200 ));
const list = Sender.frame(msg, {
fin: true ,
rsv1: false ,
opcode: 0 x01,
mask: true ,
readOnly: true
});
const frame = Buffer.concat(list);
receiver.on('message' , (data, isBinary) => {
assert .deepStrictEqual(data, msg);
assert .ok(!isBinary);
done();
});
receiver.write(frame.slice(0 , 2 ));
setImmediate(() => receiver.write(frame.slice(2 )));
});
it('parses a really long masked text message' , (done) => {
const receiver = new Receiver({ isServer: true });
const msg = Buffer.from('A' .repeat(64 * 1024 ));
const list = Sender.frame(msg, {
fin: true ,
rsv1: false ,
opcode: 0 x01,
mask: true ,
readOnly: true
});
const frame = Buffer.concat(list);
receiver.on('message' , (data, isBinary) => {
assert .deepStrictEqual(data, msg);
assert .ok(!isBinary);
done();
});
receiver.write(frame);
});
it('parses a 300 B fragmented masked text message' , (done) => {
const receiver = new Receiver({ isServer: true });
const msg = Buffer.from('A' .repeat(300 ));
const fragment1 = msg.slice(0 , 150 );
const fragment2 = msg.slice(150 );
const options = { rsv1: false , mask: true , readOnly: true };
const frame1 = Buffer.concat(
Sender.frame(fragment1, {
fin: false ,
opcode: 0 x01,
...options
})
);
const frame2 = Buffer.concat(
Sender.frame(fragment2, {
fin: true ,
opcode: 0 x00,
...options
})
);
receiver.on('message' , (data, isBinary) => {
assert .deepStrictEqual(data, msg);
assert .ok(!isBinary);
done();
});
receiver.write(frame1);
receiver.write(frame2);
});
it('parses a ping message' , (done) => {
const receiver = new Receiver({ isServer: true });
const msg = Buffer.from('Hello' );
const list = Sender.frame(msg, {
fin: true ,
rsv1: false ,
opcode: 0 x09,
mask: true ,
readOnly: true
});
const frame = Buffer.concat(list);
receiver.on('ping' , (data) => {
assert .deepStrictEqual(data, msg);
done();
});
receiver.write(frame);
});
it('parses a ping message with no data' , (done) => {
const receiver = new Receiver();
receiver.on('ping' , (data) => {
assert .strictEqual(data, EMPTY_BUFFER);
done();
});
receiver.write(Buffer.from('8900' , 'hex' ));
});
it('parses a 300 B fragmented masked text message with a ping in the middle (1/2)' , (done) => {
const receiver = new Receiver({ isServer: true });
const msg = Buffer.from('A' .repeat(300 ));
const pingMessage = Buffer.from('Hello' );
const fragment1 = msg.slice(0 , 150 );
const fragment2 = msg.slice(150 );
const options = { rsv1: false , mask: true , readOnly: true };
const frame1 = Buffer.concat(
Sender.frame(fragment1, {
fin: false ,
opcode: 0 x01,
...options
})
);
const frame2 = Buffer.concat(
Sender.frame(pingMessage, {
fin: true ,
opcode: 0 x09,
...options
})
);
const frame3 = Buffer.concat(
Sender.frame(fragment2, {
fin: true ,
opcode: 0 x00,
...options
})
);
let gotPing = false ;
receiver.on('message' , (data, isBinary) => {
assert .deepStrictEqual(data, msg);
assert .ok(!isBinary);
assert .ok(gotPing);
done();
});
receiver.on('ping' , (data) => {
gotPing = true ;
assert .ok(data.equals(pingMessage));
});
receiver.write(frame1);
receiver.write(frame2);
receiver.write(frame3);
});
it('parses a 300 B fragmented masked text message with a ping in the middle (2/2)' , (done) => {
const receiver = new Receiver({ isServer: true });
const msg = Buffer.from('A' .repeat(300 ));
const pingMessage = Buffer.from('Hello' );
const fragment1 = msg.slice(0 , 150 );
const fragment2 = msg.slice(150 );
const options = { rsv1: false , mask: true , readOnly: false };
const frame1 = Buffer.concat(
Sender.frame(Buffer.from(fragment1), {
fin: false ,
opcode: 0 x01,
...options
})
);
const frame2 = Buffer.concat(
Sender.frame(Buffer.from(pingMessage), {
fin: true ,
opcode: 0 x09,
...options
})
);
const frame3 = Buffer.concat(
Sender.frame(Buffer.from(fragment2), {
fin: true ,
opcode: 0 x00,
...options
})
);
let chunks = [];
const splitBuffer = (buf) => {
const i = Math.floor(buf.length / 2 );
return [buf.slice(0 , i), buf.slice(i)];
};
chunks = chunks.concat(splitBuffer(frame1));
chunks = chunks.concat(splitBuffer(frame2));
chunks = chunks.concat(splitBuffer(frame3));
let gotPing = false ;
receiver.on('message' , (data, isBinary) => {
assert .deepStrictEqual(data, msg);
assert .ok(!isBinary);
assert .ok(gotPing);
done();
});
receiver.on('ping' , (data) => {
gotPing = true ;
assert .ok(data.equals(pingMessage));
});
for (let i = 0 ; i < chunks.length; ++i) {
receiver.write(chunks[i]);
}
});
it('parses a 100 B masked binary message' , (done) => {
const receiver = new Receiver({ isServer: true });
const msg = crypto.randomBytes(100 );
const list = Sender.frame(msg, {
fin: true ,
rsv1: false ,
opcode: 0 x02,
mask: true ,
readOnly: true
});
const frame = Buffer.concat(list);
receiver.on('message' , (data, isBinary) => {
assert .deepStrictEqual(data, msg);
assert .ok(isBinary);
done();
});
receiver.write(frame);
});
it('parses a 256 B masked binary message' , (done) => {
const receiver = new Receiver({ isServer: true });
const msg = crypto.randomBytes(256 );
const list = Sender.frame(msg, {
fin: true ,
rsv1: false ,
opcode: 0 x02,
mask: true ,
readOnly: true
});
const frame = Buffer.concat(list);
receiver.on('message' , (data, isBinary) => {
assert .deepStrictEqual(data, msg);
assert .ok(isBinary);
done();
});
receiver.write(frame);
});
it('parses a 200 KiB masked binary message' , (done) => {
const receiver = new Receiver({ isServer: true });
const msg = crypto.randomBytes(200 * 1024 );
const list = Sender.frame(msg, {
fin: true ,
rsv1: false ,
opcode: 0 x02,
mask: true ,
readOnly: true
});
const frame = Buffer.concat(list);
receiver.on('message' , (data, isBinary) => {
assert .deepStrictEqual(data, msg);
assert .ok(isBinary);
done();
});
receiver.write(frame);
});
it('parses a 200 KiB unmasked binary message' , (done) => {
const receiver = new Receiver();
const msg = crypto.randomBytes(200 * 1024 );
const list = Sender.frame(msg, {
fin: true ,
rsv1: false ,
opcode: 0 x02,
mask: false ,
readOnly: true
});
const frame = Buffer.concat(list);
receiver.on('message' , (data, isBinary) => {
assert .deepStrictEqual(data, msg);
assert .ok(isBinary);
done();
});
receiver.write(frame);
});
it('parses a compressed message' , (done) => {
const perMessageDeflate = new PerMessageDeflate();
perMessageDeflate.accept([{}]);
const receiver = new Receiver({
extensions: {
'permessage-deflate' : perMessageDeflate
}
});
const buf = Buffer.from('Hello' );
receiver.on('message' , (data, isBinary) => {
assert .deepStrictEqual(data, buf);
assert .ok(!isBinary);
done();
});
perMessageDeflate.compress(buf, true , (err, data) => {
if (err) return done(err);
receiver.write(Buffer.from([0 xc1, data.length]));
receiver.write(data);
});
});
it('parses a compressed and fragmented message' , (done) => {
const perMessageDeflate = new PerMessageDeflate();
perMessageDeflate.accept([{}]);
const receiver = new Receiver({
extensions: {
'permessage-deflate' : perMessageDeflate
}
});
const buf1 = Buffer.from('foo' );
const buf2 = Buffer.from('bar' );
receiver.on('message' , (data, isBinary) => {
assert .deepStrictEqual(data, Buffer.concat([buf1, buf2]));
assert .ok(!isBinary);
done();
});
perMessageDeflate.compress(buf1, false , (err, fragment1) => {
if (err) return done(err);
receiver.write(Buffer.from([0 x41, fragment1.length]));
receiver.write(fragment1);
perMessageDeflate.compress(buf2, true , (err, fragment2) => {
if (err) return done(err);
receiver.write(Buffer.from([0 x80, fragment2.length]));
receiver.write(fragment2);
});
});
});
it('parses a buffer with thousands of frames' , (done) => {
const buf = Buffer.allocUnsafe(40000 );
for (let i = 0 ; i < buf.length; i += 2 ) {
buf[i] = 0 x81;
buf[i + 1 ] = 0 x00;
}
const receiver = new Receiver();
let counter = 0 ;
receiver.on('message' , (data, isBinary) => {
assert .strictEqual(data, EMPTY_BUFFER);
assert .ok(!isBinary);
if (++counter === 20000 ) done();
});
receiver.write(buf);
});
it('resets `totalPayloadLength` only on final frame (unfragmented)' , (done) => {
const receiver = new Receiver({ maxPayload: 10 });
receiver.on('message' , (data, isBinary) => {
assert .strictEqual(receiver._totalPayloadLength, 0 );
assert .deepStrictEqual(data, Buffer.from('Hello' ));
assert .ok(!isBinary);
done();
});
assert .strictEqual(receiver._totalPayloadLength, 0 );
receiver.write(Buffer.from('810548656c6c6f' , 'hex' ));
});
it('resets `totalPayloadLength` only on final frame (fragmented)' , (done) => {
const receiver = new Receiver({ maxPayload: 10 });
receiver.on('message' , (data, isBinary) => {
assert .strictEqual(receiver._totalPayloadLength, 0 );
assert .deepStrictEqual(data, Buffer.from('Hello' ));
assert .ok(!isBinary);
done();
});
assert .strictEqual(receiver._totalPayloadLength, 0 );
receiver.write(Buffer.from('01024865' , 'hex' ));
assert .strictEqual(receiver._totalPayloadLength, 2 );
receiver.write(Buffer.from('80036c6c6f' , 'hex' ));
});
it('resets `totalPayloadLength` only on final frame (fragmented + ping)' , (done) => {
const receiver = new Receiver({ maxPayload: 10 });
let data;
receiver.on('ping' , (buf) => {
assert .strictEqual(receiver._totalPayloadLength, 2 );
data = buf;
});
receiver.on('message' , (buf, isBinary) => {
assert .strictEqual(receiver._totalPayloadLength, 0 );
assert .deepStrictEqual(data, EMPTY_BUFFER);
assert .deepStrictEqual(buf, Buffer.from('Hello' ));
assert .ok(isBinary);
done();
});
assert .strictEqual(receiver._totalPayloadLength, 0 );
receiver.write(Buffer.from('02024865' , 'hex' ));
receiver.write(Buffer.from('8900' , 'hex' ));
receiver.write(Buffer.from('80036c6c6f' , 'hex' ));
});
it('ignores any data after a close frame' , (done) => {
const perMessageDeflate = new PerMessageDeflate();
perMessageDeflate.accept([{}]);
const receiver = new Receiver({
extensions: {
'permessage-deflate' : perMessageDeflate
}
});
const results = [];
const push = results.push.bind(results);
receiver.on('conclude' , push).on('message' , push);
receiver.on('finish' , () => {
assert .deepStrictEqual(results, [
EMPTY_BUFFER,
false ,
1005 ,
EMPTY_BUFFER
]);
done();
});
receiver.write(Buffer.from([0 xc1, 0 x01, 0 x00]));
receiver.write(Buffer.from([0 x88, 0 x00]));
receiver.write(Buffer.from([0 x81, 0 x00]));
});
it('emits an error if RSV1 is on and permessage-deflate is disabled' , (done) => {
const receiver = new Receiver();
receiver.on('error' , (err) => {
assert .ok(err instanceof RangeError);
assert .strictEqual(err.code, 'WS_ERR_UNEXPECTED_RSV_1' );
assert .strictEqual(
err.message,
'Invalid WebSocket frame: RSV1 must be clear'
);
assert .strictEqual(err[kStatusCode], 1002 );
done();
});
receiver.write(Buffer.from([0 xc2, 0 x80, 0 x00, 0 x00, 0 x00, 0 x00]));
});
it('emits an error if RSV1 is on and opcode is 0' , (done) => {
const perMessageDeflate = new PerMessageDeflate();
perMessageDeflate.accept([{}]);
const receiver = new Receiver({
extensions: {
'permessage-deflate' : perMessageDeflate
}
});
receiver.on('error' , (err) => {
assert .ok(err instanceof RangeError);
assert .strictEqual(err.code, 'WS_ERR_UNEXPECTED_RSV_1' );
assert .strictEqual(
err.message,
'Invalid WebSocket frame: RSV1 must be clear'
);
assert .strictEqual(err[kStatusCode], 1002 );
done();
});
receiver.write(Buffer.from([0 x40, 0 x00]));
});
it('emits an error if RSV2 is on' , (done) => {
const receiver = new Receiver();
receiver.on('error' , (err) => {
assert .ok(err instanceof RangeError);
assert .strictEqual(err.code, 'WS_ERR_UNEXPECTED_RSV_2_3' );
assert .strictEqual(
err.message,
'Invalid WebSocket frame: RSV2 and RSV3 must be clear'
);
assert .strictEqual(err[kStatusCode], 1002 );
done();
});
receiver.write(Buffer.from([0 xa2, 0 x00]));
});
it('emits an error if RSV3 is on' , (done) => {
const receiver = new Receiver();
receiver.on('error' , (err) => {
assert .ok(err instanceof RangeError);
assert .strictEqual(err.code, 'WS_ERR_UNEXPECTED_RSV_2_3' );
assert .strictEqual(
err.message,
'Invalid WebSocket frame: RSV2 and RSV3 must be clear'
);
assert .strictEqual(err[kStatusCode], 1002 );
done();
});
receiver.write(Buffer.from([0 x92, 0 x00]));
});
it('emits an error if the first frame in a fragmented message has opcode 0' , (done) => {
const receiver = new Receiver();
receiver.on('error' , (err) => {
assert .ok(err instanceof RangeError);
assert .strictEqual(err.code, 'WS_ERR_INVALID_OPCODE' );
assert .strictEqual(
err.message,
'Invalid WebSocket frame: invalid opcode 0'
);
assert .strictEqual(err[kStatusCode], 1002 );
done();
});
receiver.write(Buffer.from([0 x00, 0 x00]));
});
it('emits an error if a frame has opcode 1 in the middle of a fragmented message' , (done) => {
const receiver = new Receiver();
receiver.on('error' , (err) => {
assert .ok(err instanceof RangeError);
assert .strictEqual(err.code, 'WS_ERR_INVALID_OPCODE' );
assert .strictEqual(
err.message,
'Invalid WebSocket frame: invalid opcode 1'
);
assert .strictEqual(err[kStatusCode], 1002 );
done();
});
receiver.write(Buffer.from([0 x01, 0 x00]));
receiver.write(Buffer.from([0 x01, 0 x00]));
});
it('emits an error if a frame has opcode 2 in the middle of a fragmented message' , (done) => {
const receiver = new Receiver();
receiver.on('error' , (err) => {
assert .ok(err instanceof RangeError);
assert .strictEqual(err.code, 'WS_ERR_INVALID_OPCODE' );
assert .strictEqual(
err.message,
'Invalid WebSocket frame: invalid opcode 2'
);
assert .strictEqual(err[kStatusCode], 1002 );
done();
});
receiver.write(Buffer.from([0 x01, 0 x00]));
receiver.write(Buffer.from([0 x02, 0 x00]));
});
it('emits an error if a control frame has the FIN bit off' , (done) => {
const receiver = new Receiver();
receiver.on('error' , (err) => {
assert .ok(err instanceof RangeError);
assert .strictEqual(err.code, 'WS_ERR_EXPECTED_FIN' );
assert .strictEqual(
err.message,
'Invalid WebSocket frame: FIN must be set'
);
assert .strictEqual(err[kStatusCode], 1002 );
done();
});
receiver.write(Buffer.from([0 x09, 0 x00]));
});
it('emits an error if a control frame has the RSV1 bit on' , (done) => {
const perMessageDeflate = new PerMessageDeflate();
perMessageDeflate.accept([{}]);
const receiver = new Receiver({
extensions: {
'permessage-deflate' : perMessageDeflate
}
});
receiver.on('error' , (err) => {
assert .ok(err instanceof RangeError);
assert .strictEqual(err.code, 'WS_ERR_UNEXPECTED_RSV_1' );
assert .strictEqual(
err.message,
'Invalid WebSocket frame: RSV1 must be clear'
);
assert .strictEqual(err[kStatusCode], 1002 );
done();
});
receiver.write(Buffer.from([0 xc9, 0 x00]));
});
it('emits an error if a control frame has the FIN bit off' , (done) => {
const receiver = new Receiver();
receiver.on('error' , (err) => {
assert .ok(err instanceof RangeError);
assert .strictEqual(err.code, 'WS_ERR_EXPECTED_FIN' );
assert .strictEqual(
err.message,
'Invalid WebSocket frame: FIN must be set'
);
assert .strictEqual(err[kStatusCode], 1002 );
done();
});
receiver.write(Buffer.from([0 x09, 0 x00]));
});
it('emits an error if a frame has the MASK bit off (server mode)' , (done) => {
const receiver = new Receiver({ isServer: true });
receiver.on('error' , (err) => {
assert .ok(err instanceof RangeError);
assert .strictEqual(err.code, 'WS_ERR_EXPECTED_MASK' );
assert .strictEqual(
err.message,
'Invalid WebSocket frame: MASK must be set'
);
assert .strictEqual(err[kStatusCode], 1002 );
done();
});
receiver.write(Buffer.from([0 x81, 0 x02, 0 x68, 0 x69]));
});
it('emits an error if a frame has the MASK bit on (client mode)' , (done) => {
const receiver = new Receiver();
receiver.on('error' , (err) => {
assert .ok(err instanceof RangeError);
assert .strictEqual(err.code, 'WS_ERR_UNEXPECTED_MASK' );
assert .strictEqual(
err.message,
'Invalid WebSocket frame: MASK must be clear'
);
assert .strictEqual(err[kStatusCode], 1002 );
done();
});
receiver.write(
Buffer.from([0 x81, 0 x82, 0 x56, 0 x3a, 0 xac, 0 x80, 0 x3e, 0 x53])
);
});
it('emits an error if a control frame has a payload bigger than 125 B' , (done) => {
const receiver = new Receiver();
receiver.on('error' , (err) => {
assert .ok(err instanceof RangeError);
assert .strictEqual(err.code, 'WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH' );
assert .strictEqual(
err.message,
'Invalid WebSocket frame: invalid payload length 126'
);
assert .strictEqual(err[kStatusCode], 1002 );
done();
});
receiver.write(Buffer.from([0 x89, 0 x7e]));
});
it('emits an error if a data frame has a payload bigger than 2^53 - 1 B' , (done) => {
const receiver = new Receiver();
receiver.on('error' , (err) => {
assert .ok(err instanceof RangeError);
assert .strictEqual(err.code, 'WS_ERR_UNSUPPORTED_DATA_PAYLOAD_LENGTH' );
assert .strictEqual(
err.message,
'Unsupported WebSocket frame: payload length > 2^53 - 1'
);
assert .strictEqual(err[kStatusCode], 1009 );
done();
});
receiver.write(Buffer.from([0 x82, 0 x7f]));
setImmediate(() =>
receiver.write(
Buffer.from([0 x00, 0 x20, 0 x00, 0 x00, 0 x00, 0 x00, 0 x00, 0 x00])
)
);
});
it('emits an error if a text frame contains invalid UTF-8 data (1/2)' , (done) => {
const receiver = new Receiver();
receiver.on('error' , (err) => {
assert .ok(err instanceof Error);
assert .strictEqual(err.code, 'WS_ERR_INVALID_UTF8' );
assert .strictEqual(
err.message,
'Invalid WebSocket frame: invalid UTF-8 sequence'
);
assert .strictEqual(err[kStatusCode], 1007 );
done();
});
receiver.write(Buffer.from([0 x81, 0 x04, 0 xce, 0 xba, 0 xe1, 0 xbd]));
});
it('emits an error if a text frame contains invalid UTF-8 data (2/2)' , (done) => {
const perMessageDeflate = new PerMessageDeflate();
perMessageDeflate.accept([{}]);
const receiver = new Receiver({
extensions: {
'permessage-deflate' : perMessageDeflate
}
});
const buf = Buffer.from([0 xce, 0 xba, 0 xe1, 0 xbd]);
receiver.on('error' , (err) => {
assert .ok(err instanceof Error);
assert .strictEqual(err.code, 'WS_ERR_INVALID_UTF8' );
assert .strictEqual(
err.message,
'Invalid WebSocket frame: invalid UTF-8 sequence'
);
assert .strictEqual(err[kStatusCode], 1007 );
done();
});
perMessageDeflate.compress(buf, true , (err, data) => {
if (err) return done(err);
receiver.write(Buffer.from([0 xc1, data.length]));
receiver.write(data);
});
});
it('emits an error if a close frame has a payload of 1 B' , (done) => {
const receiver = new Receiver();
receiver.on('error' , (err) => {
assert .ok(err instanceof RangeError);
assert .strictEqual(err.code, 'WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH' );
assert .strictEqual(
err.message,
'Invalid WebSocket frame: invalid payload length 1'
);
assert .strictEqual(err[kStatusCode], 1002 );
done();
});
receiver.write(Buffer.from([0 x88, 0 x01, 0 x00]));
});
it('emits an error if a close frame contains an invalid close code' , (done) => {
const receiver = new Receiver();
receiver.on('error' , (err) => {
assert .ok(err instanceof RangeError);
assert .strictEqual(err.code, 'WS_ERR_INVALID_CLOSE_CODE' );
assert .strictEqual(
err.message,
'Invalid WebSocket frame: invalid status code 0'
);
assert .strictEqual(err[kStatusCode], 1002 );
done();
});
receiver.write(Buffer.from([0 x88, 0 x02, 0 x00, 0 x00]));
});
it('emits an error if a close frame contains invalid UTF-8 data' , (done) => {
const receiver = new Receiver();
receiver.on('error' , (err) => {
assert .ok(err instanceof Error);
assert .strictEqual(err.code, 'WS_ERR_INVALID_UTF8' );
assert .strictEqual(
err.message,
'Invalid WebSocket frame: invalid UTF-8 sequence'
);
assert .strictEqual(err[kStatusCode], 1007 );
done();
});
receiver.write(
Buffer.from([0 x88, 0 x06, 0 x03, 0 xef, 0 xce, 0 xba, 0 xe1, 0 xbd])
);
});
it('emits an error if a frame payload length is bigger than `maxPayload`' , (done) => {
const receiver = new Receiver({ isServer: true , maxPayload: 20 * 1024 });
const msg = crypto.randomBytes(200 * 1024 );
const list = Sender.frame(msg, {
fin: true ,
rsv1: false ,
opcode: 0 x02,
mask: true ,
readOnly: true
});
const frame = Buffer.concat(list);
receiver.on('error' , (err) => {
assert .ok(err instanceof RangeError);
assert .strictEqual(err.code, 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH' );
assert .strictEqual(err.message, 'Max payload size exceeded' );
assert .strictEqual(err[kStatusCode], 1009 );
done();
});
receiver.write(frame);
});
it('emits an error if the message length exceeds `maxPayload`' , (done) => {
const perMessageDeflate = new PerMessageDeflate({}, false , 25 );
perMessageDeflate.accept([{}]);
const receiver = new Receiver({
extensions: { 'permessage-deflate' : perMessageDeflate },
isServer: false ,
maxPayload: 25
});
const buf = Buffer.from('A' .repeat(50 ));
receiver.on('error' , (err) => {
assert .ok(err instanceof RangeError);
assert .strictEqual(err.code, 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH' );
assert .strictEqual(err.message, 'Max payload size exceeded' );
assert .strictEqual(err[kStatusCode], 1009 );
done();
});
perMessageDeflate.compress(buf, true , (err, data) => {
if (err) return done(err);
receiver.write(Buffer.from([0 xc1, data.length]));
receiver.write(data);
});
});
it('emits an error if the sum of fragment lengths exceeds `maxPayload`' , (done) => {
const perMessageDeflate = new PerMessageDeflate({}, false , 25 );
perMessageDeflate.accept([{}]);
const receiver = new Receiver({
extensions: { 'permessage-deflate' : perMessageDeflate },
isServer: false ,
maxPayload: 25
});
const buf = Buffer.from('A' .repeat(15 ));
receiver.on('error' , (err) => {
assert .ok(err instanceof RangeError);
assert .strictEqual(err.code, 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH' );
assert .strictEqual(err.message, 'Max payload size exceeded' );
assert .strictEqual(err[kStatusCode], 1009 );
done();
});
perMessageDeflate.compress(buf, false , (err, fragment1) => {
if (err) return done(err);
receiver.write(Buffer.from([0 x41, fragment1.length]));
receiver.write(fragment1);
perMessageDeflate.compress(buf, true , (err, fragment2) => {
if (err) return done(err);
receiver.write(Buffer.from([0 x80, fragment2.length]));
receiver.write(fragment2);
});
});
});
it("honors the 'nodebuffer' binary type" , (done) => {
const receiver = new Receiver();
const frags = [
crypto.randomBytes(7321 ),
crypto.randomBytes(137 ),
crypto.randomBytes(285787 ),
crypto.randomBytes(3 )
];
receiver.on('message' , (data, isBinary) => {
assert .deepStrictEqual(data, Buffer.concat(frags));
assert .ok(isBinary);
done();
});
frags.forEach((frag, i) => {
Sender.frame(frag, {
fin: i === frags.length - 1 ,
opcode: i === 0 ? 2 : 0 ,
readOnly: true ,
mask: false ,
rsv1: false
}).forEach((buf) => receiver.write(buf));
});
});
it("honors the 'arraybuffer' binary type" , (done) => {
const receiver = new Receiver({ binaryType: 'arraybuffer' });
const frags = [
crypto.randomBytes(19221 ),
crypto.randomBytes(954 ),
crypto.randomBytes(623987 )
];
receiver.on('message' , (data, isBinary) => {
assert .ok(data instanceof ArrayBuffer);
assert .deepStrictEqual(Buffer.from(data), Buffer.concat(frags));
assert .ok(isBinary);
done();
});
frags.forEach((frag, i) => {
Sender.frame(frag, {
fin: i === frags.length - 1 ,
opcode: i === 0 ? 2 : 0 ,
readOnly: true ,
mask: false ,
rsv1: false
}).forEach((buf) => receiver.write(buf));
});
});
it("honors the 'fragments' binary type" , (done) => {
const receiver = new Receiver({ binaryType: 'fragments' });
const frags = [
crypto.randomBytes(17 ),
crypto.randomBytes(419872 ),
crypto.randomBytes(83 ),
crypto.randomBytes(9928 ),
crypto.randomBytes(1 )
];
receiver.on('message' , (data, isBinary) => {
assert .deepStrictEqual(data, frags);
assert .ok(isBinary);
done();
});
frags.forEach((frag, i) => {
Sender.frame(frag, {
fin: i === frags.length - 1 ,
opcode: i === 0 ? 2 : 0 ,
readOnly: true ,
mask: false ,
rsv1: false
}).forEach((buf) => receiver.write(buf));
});
});
it('honors the `skipUTF8Validation` option (1/2)' , (done) => {
const receiver = new Receiver({ skipUTF8Validation: true });
receiver.on('message' , (data, isBinary) => {
assert .deepStrictEqual(data, Buffer.from([0 xf8]));
assert .ok(!isBinary);
done();
});
receiver.write(Buffer.from([0 x81, 0 x01, 0 xf8]));
});
it('honors the `skipUTF8Validation` option (2/2)' , (done) => {
const receiver = new Receiver({ skipUTF8Validation: true });
receiver.on('conclude' , (code, data) => {
assert .strictEqual(code, 1000 );
assert .deepStrictEqual(data, Buffer.from([0 xf8]));
done();
});
receiver.write(Buffer.from([0 x88, 0 x03, 0 x03, 0 xe8, 0 xf8]));
});
});
Messung V0.5 in Prozent C=94 H=96 G=94
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-06-04)
¤
*© Formatika GbR, Deutschland