/** * HyBi Receiver implementation. * * @extends Writable
*/ class Receiver extends Writable { /** * Creates a Receiver instance. * * @param {Object} [options] Options object * @param {String} [options.binaryType=nodebuffer] The type for binary data * @param {Object} [options.extensions] An object containing the negotiated * extensions * @param {Boolean} [options.isServer=false] Specifies whether to operate in * client or server mode * @param {Number} [options.maxPayload=0] The maximum allowed message length * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or * not to skip UTF-8 validation for text and close messages
*/
constructor(options = {}) { super();
/** * Consumes `n` bytes from the buffered data. * * @param {Number} n The number of bytes to consume * @return {Buffer} The consumed bytes * @private
*/
consume(n) { this._bufferedBytes -= n;
if (n === this._buffers[0].length) returnthis._buffers.shift();
do { switch (this._state) { case GET_INFO:
err = this.getInfo(); break; case GET_PAYLOAD_LENGTH_16:
err = this.getPayloadLength16(); break; case GET_PAYLOAD_LENGTH_64:
err = this.getPayloadLength64(); break; case GET_MASK: this.getMask(); break; case GET_DATA:
err = this.getData(cb); break; default: // `INFLATING` this._loop = false; return;
}
} while (this._loop);
cb(err);
}
/** * Reads the first two bytes of a frame. * * @return {(RangeError|undefined)} A possible error * @private
*/
getInfo() { if (this._bufferedBytes < 2) { this._loop = false; return;
}
const buf = this.consume(2);
if ((buf[0] & 0x30) !== 0x00) { this._loop = false; return error(
RangeError, 'RSV2 and RSV3 must be clear', true,
1002, 'WS_ERR_UNEXPECTED_RSV_2_3'
);
}
const compressed = (buf[0] & 0x40) === 0x40;
if (compressed && !this._extensions[PerMessageDeflate.extensionName]) { this._loop = false; return error(
RangeError, 'RSV1 must be clear', true,
1002, 'WS_ERR_UNEXPECTED_RSV_1'
);
}
/** * Gets extended payload length (7+64). * * @return {(RangeError|undefined)} A possible error * @private
*/
getPayloadLength64() { if (this._bufferedBytes < 8) { this._loop = false; return;
}
const buf = this.consume(8); const num = buf.readUInt32BE(0);
// // The maximum safe integer in JavaScript is 2^53 - 1. An error is returned // if payload length is greater than this number. // if (num > Math.pow(2, 53 - 32) - 1) { this._loop = false; return error(
RangeError, 'Unsupported WebSocket frame: payload length > 2^53 - 1', false,
1009, 'WS_ERR_UNSUPPORTED_DATA_PAYLOAD_LENGTH'
);
}
this._payloadLength = num * Math.pow(2, 32) + buf.readUInt32BE(4); returnthis.haveLength();
}
/** * Payload length has been read. * * @return {(RangeError|undefined)} A possible error * @private
*/
haveLength() { if (this._payloadLength && this._opcode < 0x08) { this._totalPayloadLength += this._payloadLength; if (this._totalPayloadLength > this._maxPayload && this._maxPayload > 0) { this._loop = false; return error(
RangeError, 'Max payload size exceeded', false,
1009, 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH'
);
}
}
if (this._masked) this._state = GET_MASK; elsethis._state = GET_DATA;
}
if (this._opcode > 0x07) returnthis.controlMessage(data);
if (this._compressed) { this._state = INFLATING; this.decompress(data, cb); return;
}
if (data.length) { // // This message is not compressed so its length is the sum of the payload // length of all fragments. // this._messageLength = this._totalPayloadLength; this._fragments.push(data);
}
/** * Handles a control message. * * @param {Buffer} data Data to handle * @return {(Error|RangeError|undefined)} A possible error * @private
*/
controlMessage(data) { if (this._opcode === 0x08) { this._loop = false;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.