Update receiver.js
This commit is contained in:
parent
e73aa40151
commit
f5c71c06a9
1 changed files with 126 additions and 26 deletions
152
node_modules/ws/lib/receiver.js
generated
vendored
152
node_modules/ws/lib/receiver.js
generated
vendored
|
@ -22,17 +22,17 @@ const INFLATING = 5;
|
||||||
/**
|
/**
|
||||||
* HyBi Receiver implementation.
|
* HyBi Receiver implementation.
|
||||||
*
|
*
|
||||||
* @extends stream.Writable
|
* @extends Writable
|
||||||
*/
|
*/
|
||||||
class Receiver extends Writable {
|
class Receiver extends Writable {
|
||||||
/**
|
/**
|
||||||
* Creates a Receiver instance.
|
* Creates a Receiver instance.
|
||||||
*
|
*
|
||||||
* @param {String} binaryType The type for binary data
|
* @param {String} [binaryType=nodebuffer] The type for binary data
|
||||||
* @param {Object} extensions An object containing the negotiated extensions
|
* @param {Object} [extensions] An object containing the negotiated extensions
|
||||||
* @param {Boolean} isServer Specifies whether to operate in client or server
|
* @param {Boolean} [isServer=false] Specifies whether to operate in client or
|
||||||
* mode
|
* server mode
|
||||||
* @param {Number} maxPayload The maximum allowed message length
|
* @param {Number} [maxPayload=0] The maximum allowed message length
|
||||||
*/
|
*/
|
||||||
constructor(binaryType, extensions, isServer, maxPayload) {
|
constructor(binaryType, extensions, isServer, maxPayload) {
|
||||||
super();
|
super();
|
||||||
|
@ -168,14 +168,26 @@ class Receiver extends Writable {
|
||||||
|
|
||||||
if ((buf[0] & 0x30) !== 0x00) {
|
if ((buf[0] & 0x30) !== 0x00) {
|
||||||
this._loop = false;
|
this._loop = false;
|
||||||
return error(RangeError, 'RSV2 and RSV3 must be clear', true, 1002);
|
return error(
|
||||||
|
RangeError,
|
||||||
|
'RSV2 and RSV3 must be clear',
|
||||||
|
true,
|
||||||
|
1002,
|
||||||
|
'WS_ERR_UNEXPECTED_RSV_2_3'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const compressed = (buf[0] & 0x40) === 0x40;
|
const compressed = (buf[0] & 0x40) === 0x40;
|
||||||
|
|
||||||
if (compressed && !this._extensions[PerMessageDeflate.extensionName]) {
|
if (compressed && !this._extensions[PerMessageDeflate.extensionName]) {
|
||||||
this._loop = false;
|
this._loop = false;
|
||||||
return error(RangeError, 'RSV1 must be clear', true, 1002);
|
return error(
|
||||||
|
RangeError,
|
||||||
|
'RSV1 must be clear',
|
||||||
|
true,
|
||||||
|
1002,
|
||||||
|
'WS_ERR_UNEXPECTED_RSV_1'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._fin = (buf[0] & 0x80) === 0x80;
|
this._fin = (buf[0] & 0x80) === 0x80;
|
||||||
|
@ -185,31 +197,61 @@ class Receiver extends Writable {
|
||||||
if (this._opcode === 0x00) {
|
if (this._opcode === 0x00) {
|
||||||
if (compressed) {
|
if (compressed) {
|
||||||
this._loop = false;
|
this._loop = false;
|
||||||
return error(RangeError, 'RSV1 must be clear', true, 1002);
|
return error(
|
||||||
|
RangeError,
|
||||||
|
'RSV1 must be clear',
|
||||||
|
true,
|
||||||
|
1002,
|
||||||
|
'WS_ERR_UNEXPECTED_RSV_1'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this._fragmented) {
|
if (!this._fragmented) {
|
||||||
this._loop = false;
|
this._loop = false;
|
||||||
return error(RangeError, 'invalid opcode 0', true, 1002);
|
return error(
|
||||||
|
RangeError,
|
||||||
|
'invalid opcode 0',
|
||||||
|
true,
|
||||||
|
1002,
|
||||||
|
'WS_ERR_INVALID_OPCODE'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._opcode = this._fragmented;
|
this._opcode = this._fragmented;
|
||||||
} else if (this._opcode === 0x01 || this._opcode === 0x02) {
|
} else if (this._opcode === 0x01 || this._opcode === 0x02) {
|
||||||
if (this._fragmented) {
|
if (this._fragmented) {
|
||||||
this._loop = false;
|
this._loop = false;
|
||||||
return error(RangeError, `invalid opcode ${this._opcode}`, true, 1002);
|
return error(
|
||||||
|
RangeError,
|
||||||
|
`invalid opcode ${this._opcode}`,
|
||||||
|
true,
|
||||||
|
1002,
|
||||||
|
'WS_ERR_INVALID_OPCODE'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._compressed = compressed;
|
this._compressed = compressed;
|
||||||
} else if (this._opcode > 0x07 && this._opcode < 0x0b) {
|
} else if (this._opcode > 0x07 && this._opcode < 0x0b) {
|
||||||
if (!this._fin) {
|
if (!this._fin) {
|
||||||
this._loop = false;
|
this._loop = false;
|
||||||
return error(RangeError, 'FIN must be set', true, 1002);
|
return error(
|
||||||
|
RangeError,
|
||||||
|
'FIN must be set',
|
||||||
|
true,
|
||||||
|
1002,
|
||||||
|
'WS_ERR_EXPECTED_FIN'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compressed) {
|
if (compressed) {
|
||||||
this._loop = false;
|
this._loop = false;
|
||||||
return error(RangeError, 'RSV1 must be clear', true, 1002);
|
return error(
|
||||||
|
RangeError,
|
||||||
|
'RSV1 must be clear',
|
||||||
|
true,
|
||||||
|
1002,
|
||||||
|
'WS_ERR_UNEXPECTED_RSV_1'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._payloadLength > 0x7d) {
|
if (this._payloadLength > 0x7d) {
|
||||||
|
@ -218,12 +260,19 @@ class Receiver extends Writable {
|
||||||
RangeError,
|
RangeError,
|
||||||
`invalid payload length ${this._payloadLength}`,
|
`invalid payload length ${this._payloadLength}`,
|
||||||
true,
|
true,
|
||||||
1002
|
1002,
|
||||||
|
'WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this._loop = false;
|
this._loop = false;
|
||||||
return error(RangeError, `invalid opcode ${this._opcode}`, true, 1002);
|
return error(
|
||||||
|
RangeError,
|
||||||
|
`invalid opcode ${this._opcode}`,
|
||||||
|
true,
|
||||||
|
1002,
|
||||||
|
'WS_ERR_INVALID_OPCODE'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this._fin && !this._fragmented) this._fragmented = this._opcode;
|
if (!this._fin && !this._fragmented) this._fragmented = this._opcode;
|
||||||
|
@ -232,11 +281,23 @@ class Receiver extends Writable {
|
||||||
if (this._isServer) {
|
if (this._isServer) {
|
||||||
if (!this._masked) {
|
if (!this._masked) {
|
||||||
this._loop = false;
|
this._loop = false;
|
||||||
return error(RangeError, 'MASK must be set', true, 1002);
|
return error(
|
||||||
|
RangeError,
|
||||||
|
'MASK must be set',
|
||||||
|
true,
|
||||||
|
1002,
|
||||||
|
'WS_ERR_EXPECTED_MASK'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else if (this._masked) {
|
} else if (this._masked) {
|
||||||
this._loop = false;
|
this._loop = false;
|
||||||
return error(RangeError, 'MASK must be clear', true, 1002);
|
return error(
|
||||||
|
RangeError,
|
||||||
|
'MASK must be clear',
|
||||||
|
true,
|
||||||
|
1002,
|
||||||
|
'WS_ERR_UNEXPECTED_MASK'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._payloadLength === 126) this._state = GET_PAYLOAD_LENGTH_16;
|
if (this._payloadLength === 126) this._state = GET_PAYLOAD_LENGTH_16;
|
||||||
|
@ -285,7 +346,8 @@ class Receiver extends Writable {
|
||||||
RangeError,
|
RangeError,
|
||||||
'Unsupported WebSocket frame: payload length > 2^53 - 1',
|
'Unsupported WebSocket frame: payload length > 2^53 - 1',
|
||||||
false,
|
false,
|
||||||
1009
|
1009,
|
||||||
|
'WS_ERR_UNSUPPORTED_DATA_PAYLOAD_LENGTH'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,7 +366,13 @@ class Receiver extends Writable {
|
||||||
this._totalPayloadLength += this._payloadLength;
|
this._totalPayloadLength += this._payloadLength;
|
||||||
if (this._totalPayloadLength > this._maxPayload && this._maxPayload > 0) {
|
if (this._totalPayloadLength > this._maxPayload && this._maxPayload > 0) {
|
||||||
this._loop = false;
|
this._loop = false;
|
||||||
return error(RangeError, 'Max payload size exceeded', false, 1009);
|
return error(
|
||||||
|
RangeError,
|
||||||
|
'Max payload size exceeded',
|
||||||
|
false,
|
||||||
|
1009,
|
||||||
|
'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -384,7 +452,13 @@ class Receiver extends Writable {
|
||||||
this._messageLength += buf.length;
|
this._messageLength += buf.length;
|
||||||
if (this._messageLength > this._maxPayload && this._maxPayload > 0) {
|
if (this._messageLength > this._maxPayload && this._maxPayload > 0) {
|
||||||
return cb(
|
return cb(
|
||||||
error(RangeError, 'Max payload size exceeded', false, 1009)
|
error(
|
||||||
|
RangeError,
|
||||||
|
'Max payload size exceeded',
|
||||||
|
false,
|
||||||
|
1009,
|
||||||
|
'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH'
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -431,7 +505,13 @@ class Receiver extends Writable {
|
||||||
|
|
||||||
if (!isValidUTF8(buf)) {
|
if (!isValidUTF8(buf)) {
|
||||||
this._loop = false;
|
this._loop = false;
|
||||||
return error(Error, 'invalid UTF-8 sequence', true, 1007);
|
return error(
|
||||||
|
Error,
|
||||||
|
'invalid UTF-8 sequence',
|
||||||
|
true,
|
||||||
|
1007,
|
||||||
|
'WS_ERR_INVALID_UTF8'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.emit('message', buf.toString());
|
this.emit('message', buf.toString());
|
||||||
|
@ -456,18 +536,36 @@ class Receiver extends Writable {
|
||||||
this.emit('conclude', 1005, '');
|
this.emit('conclude', 1005, '');
|
||||||
this.end();
|
this.end();
|
||||||
} else if (data.length === 1) {
|
} else if (data.length === 1) {
|
||||||
return error(RangeError, 'invalid payload length 1', true, 1002);
|
return error(
|
||||||
|
RangeError,
|
||||||
|
'invalid payload length 1',
|
||||||
|
true,
|
||||||
|
1002,
|
||||||
|
'WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH'
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
const code = data.readUInt16BE(0);
|
const code = data.readUInt16BE(0);
|
||||||
|
|
||||||
if (!isValidStatusCode(code)) {
|
if (!isValidStatusCode(code)) {
|
||||||
return error(RangeError, `invalid status code ${code}`, true, 1002);
|
return error(
|
||||||
|
RangeError,
|
||||||
|
`invalid status code ${code}`,
|
||||||
|
true,
|
||||||
|
1002,
|
||||||
|
'WS_ERR_INVALID_CLOSE_CODE'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const buf = data.slice(2);
|
const buf = data.slice(2);
|
||||||
|
|
||||||
if (!isValidUTF8(buf)) {
|
if (!isValidUTF8(buf)) {
|
||||||
return error(Error, 'invalid UTF-8 sequence', true, 1007);
|
return error(
|
||||||
|
Error,
|
||||||
|
'invalid UTF-8 sequence',
|
||||||
|
true,
|
||||||
|
1007,
|
||||||
|
'WS_ERR_INVALID_UTF8'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.emit('conclude', code, buf.toString());
|
this.emit('conclude', code, buf.toString());
|
||||||
|
@ -488,20 +586,22 @@ module.exports = Receiver;
|
||||||
/**
|
/**
|
||||||
* Builds an error object.
|
* Builds an error object.
|
||||||
*
|
*
|
||||||
* @param {(Error|RangeError)} ErrorCtor The error constructor
|
* @param {function(new:Error|RangeError)} ErrorCtor The error constructor
|
||||||
* @param {String} message The error message
|
* @param {String} message The error message
|
||||||
* @param {Boolean} prefix Specifies whether or not to add a default prefix to
|
* @param {Boolean} prefix Specifies whether or not to add a default prefix to
|
||||||
* `message`
|
* `message`
|
||||||
* @param {Number} statusCode The status code
|
* @param {Number} statusCode The status code
|
||||||
|
* @param {String} errorCode The exposed error code
|
||||||
* @return {(Error|RangeError)} The error
|
* @return {(Error|RangeError)} The error
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
function error(ErrorCtor, message, prefix, statusCode) {
|
function error(ErrorCtor, message, prefix, statusCode, errorCode) {
|
||||||
const err = new ErrorCtor(
|
const err = new ErrorCtor(
|
||||||
prefix ? `Invalid WebSocket frame: ${message}` : message
|
prefix ? `Invalid WebSocket frame: ${message}` : message
|
||||||
);
|
);
|
||||||
|
|
||||||
Error.captureStackTrace(err, error);
|
Error.captureStackTrace(err, error);
|
||||||
|
err.code = errorCode;
|
||||||
err[kStatusCode] = statusCode;
|
err[kStatusCode] = statusCode;
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue