Spaces:
Running
Running
; | |
// imported from https://github.com/socketio/engine.io-parser/tree/2.2.x | |
Object.defineProperty(exports, "__esModule", { value: true }); | |
exports.decodePayloadAsBinary = exports.encodePayloadAsBinary = exports.decodePayload = exports.encodePayload = exports.decodeBase64Packet = exports.decodePacket = exports.encodeBase64Packet = exports.encodePacket = exports.packets = exports.protocol = void 0; | |
/** | |
* Module dependencies. | |
*/ | |
var utf8 = require('./utf8'); | |
/** | |
* Current protocol version. | |
*/ | |
exports.protocol = 3; | |
const hasBinary = (packets) => { | |
for (const packet of packets) { | |
if (packet.data instanceof ArrayBuffer || ArrayBuffer.isView(packet.data)) { | |
return true; | |
} | |
} | |
return false; | |
}; | |
/** | |
* Packet types. | |
*/ | |
exports.packets = { | |
open: 0 // non-ws | |
, | |
close: 1 // non-ws | |
, | |
ping: 2, | |
pong: 3, | |
message: 4, | |
upgrade: 5, | |
noop: 6 | |
}; | |
var packetslist = Object.keys(exports.packets); | |
/** | |
* Premade error packet. | |
*/ | |
var err = { type: 'error', data: 'parser error' }; | |
const EMPTY_BUFFER = Buffer.concat([]); | |
/** | |
* Encodes a packet. | |
* | |
* <packet type id> [ <data> ] | |
* | |
* Example: | |
* | |
* 5hello world | |
* 3 | |
* 4 | |
* | |
* Binary is encoded in an identical principle | |
* | |
* @api private | |
*/ | |
function encodePacket(packet, supportsBinary, utf8encode, callback) { | |
if (typeof supportsBinary === 'function') { | |
callback = supportsBinary; | |
supportsBinary = null; | |
} | |
if (typeof utf8encode === 'function') { | |
callback = utf8encode; | |
utf8encode = null; | |
} | |
if (Buffer.isBuffer(packet.data)) { | |
return encodeBuffer(packet, supportsBinary, callback); | |
} | |
else if (packet.data && (packet.data.buffer || packet.data) instanceof ArrayBuffer) { | |
return encodeBuffer({ type: packet.type, data: arrayBufferToBuffer(packet.data) }, supportsBinary, callback); | |
} | |
// Sending data as a utf-8 string | |
var encoded = exports.packets[packet.type]; | |
// data fragment is optional | |
if (undefined !== packet.data) { | |
encoded += utf8encode ? utf8.encode(String(packet.data), { strict: false }) : String(packet.data); | |
} | |
return callback('' + encoded); | |
} | |
exports.encodePacket = encodePacket; | |
; | |
/** | |
* Encode Buffer data | |
*/ | |
function encodeBuffer(packet, supportsBinary, callback) { | |
if (!supportsBinary) { | |
return encodeBase64Packet(packet, callback); | |
} | |
var data = packet.data; | |
var typeBuffer = Buffer.allocUnsafe(1); | |
typeBuffer[0] = exports.packets[packet.type]; | |
return callback(Buffer.concat([typeBuffer, data])); | |
} | |
/** | |
* Encodes a packet with binary data in a base64 string | |
* | |
* @param {Object} packet, has `type` and `data` | |
* @return {String} base64 encoded message | |
*/ | |
function encodeBase64Packet(packet, callback) { | |
var data = Buffer.isBuffer(packet.data) ? packet.data : arrayBufferToBuffer(packet.data); | |
var message = 'b' + exports.packets[packet.type]; | |
message += data.toString('base64'); | |
return callback(message); | |
} | |
exports.encodeBase64Packet = encodeBase64Packet; | |
; | |
/** | |
* Decodes a packet. Data also available as an ArrayBuffer if requested. | |
* | |
* @return {Object} with `type` and `data` (if any) | |
* @api private | |
*/ | |
function decodePacket(data, binaryType, utf8decode) { | |
if (data === undefined) { | |
return err; | |
} | |
var type; | |
// String data | |
if (typeof data === 'string') { | |
type = data.charAt(0); | |
if (type === 'b') { | |
return decodeBase64Packet(data.slice(1), binaryType); | |
} | |
if (utf8decode) { | |
data = tryDecode(data); | |
if (data === false) { | |
return err; | |
} | |
} | |
if (Number(type) != type || !packetslist[type]) { | |
return err; | |
} | |
if (data.length > 1) { | |
return { type: packetslist[type], data: data.slice(1) }; | |
} | |
else { | |
return { type: packetslist[type] }; | |
} | |
} | |
// Binary data | |
if (binaryType === 'arraybuffer') { | |
// wrap Buffer/ArrayBuffer data into an Uint8Array | |
var intArray = new Uint8Array(data); | |
type = intArray[0]; | |
return { type: packetslist[type], data: intArray.buffer.slice(1) }; | |
} | |
if (data instanceof ArrayBuffer) { | |
data = arrayBufferToBuffer(data); | |
} | |
type = data[0]; | |
return { type: packetslist[type], data: data.slice(1) }; | |
} | |
exports.decodePacket = decodePacket; | |
; | |
function tryDecode(data) { | |
try { | |
data = utf8.decode(data, { strict: false }); | |
} | |
catch (e) { | |
return false; | |
} | |
return data; | |
} | |
/** | |
* Decodes a packet encoded in a base64 string. | |
* | |
* @param {String} base64 encoded message | |
* @return {Object} with `type` and `data` (if any) | |
*/ | |
function decodeBase64Packet(msg, binaryType) { | |
var type = packetslist[msg.charAt(0)]; | |
var data = Buffer.from(msg.slice(1), 'base64'); | |
if (binaryType === 'arraybuffer') { | |
var abv = new Uint8Array(data.length); | |
for (var i = 0; i < abv.length; i++) { | |
abv[i] = data[i]; | |
} | |
// @ts-ignore | |
data = abv.buffer; | |
} | |
return { type: type, data: data }; | |
} | |
exports.decodeBase64Packet = decodeBase64Packet; | |
; | |
/** | |
* Encodes multiple messages (payload). | |
* | |
* <length>:data | |
* | |
* Example: | |
* | |
* 11:hello world2:hi | |
* | |
* If any contents are binary, they will be encoded as base64 strings. Base64 | |
* encoded strings are marked with a b before the length specifier | |
* | |
* @param {Array} packets | |
* @api private | |
*/ | |
function encodePayload(packets, supportsBinary, callback) { | |
if (typeof supportsBinary === 'function') { | |
callback = supportsBinary; | |
supportsBinary = null; | |
} | |
if (supportsBinary && hasBinary(packets)) { | |
return encodePayloadAsBinary(packets, callback); | |
} | |
if (!packets.length) { | |
return callback('0:'); | |
} | |
function encodeOne(packet, doneCallback) { | |
encodePacket(packet, supportsBinary, false, function (message) { | |
doneCallback(null, setLengthHeader(message)); | |
}); | |
} | |
map(packets, encodeOne, function (err, results) { | |
return callback(results.join('')); | |
}); | |
} | |
exports.encodePayload = encodePayload; | |
; | |
function setLengthHeader(message) { | |
return message.length + ':' + message; | |
} | |
/** | |
* Async array map using after | |
*/ | |
function map(ary, each, done) { | |
const results = new Array(ary.length); | |
let count = 0; | |
for (let i = 0; i < ary.length; i++) { | |
each(ary[i], (error, msg) => { | |
results[i] = msg; | |
if (++count === ary.length) { | |
done(null, results); | |
} | |
}); | |
} | |
} | |
/* | |
* Decodes data when a payload is maybe expected. Possible binary contents are | |
* decoded from their base64 representation | |
* | |
* @param {String} data, callback method | |
* @api public | |
*/ | |
function decodePayload(data, binaryType, callback) { | |
if (typeof data !== 'string') { | |
return decodePayloadAsBinary(data, binaryType, callback); | |
} | |
if (typeof binaryType === 'function') { | |
callback = binaryType; | |
binaryType = null; | |
} | |
if (data === '') { | |
// parser error - ignoring payload | |
return callback(err, 0, 1); | |
} | |
var length = '', n, msg, packet; | |
for (var i = 0, l = data.length; i < l; i++) { | |
var chr = data.charAt(i); | |
if (chr !== ':') { | |
length += chr; | |
continue; | |
} | |
// @ts-ignore | |
if (length === '' || (length != (n = Number(length)))) { | |
// parser error - ignoring payload | |
return callback(err, 0, 1); | |
} | |
msg = data.slice(i + 1, i + 1 + n); | |
if (length != msg.length) { | |
// parser error - ignoring payload | |
return callback(err, 0, 1); | |
} | |
if (msg.length) { | |
packet = decodePacket(msg, binaryType, false); | |
if (err.type === packet.type && err.data === packet.data) { | |
// parser error in individual packet - ignoring payload | |
return callback(err, 0, 1); | |
} | |
var more = callback(packet, i + n, l); | |
if (false === more) | |
return; | |
} | |
// advance cursor | |
i += n; | |
length = ''; | |
} | |
if (length !== '') { | |
// parser error - ignoring payload | |
return callback(err, 0, 1); | |
} | |
} | |
exports.decodePayload = decodePayload; | |
; | |
/** | |
* | |
* Converts a buffer to a utf8.js encoded string | |
* | |
* @api private | |
*/ | |
function bufferToString(buffer) { | |
var str = ''; | |
for (var i = 0, l = buffer.length; i < l; i++) { | |
str += String.fromCharCode(buffer[i]); | |
} | |
return str; | |
} | |
/** | |
* | |
* Converts a utf8.js encoded string to a buffer | |
* | |
* @api private | |
*/ | |
function stringToBuffer(string) { | |
var buf = Buffer.allocUnsafe(string.length); | |
for (var i = 0, l = string.length; i < l; i++) { | |
buf.writeUInt8(string.charCodeAt(i), i); | |
} | |
return buf; | |
} | |
/** | |
* | |
* Converts an ArrayBuffer to a Buffer | |
* | |
* @api private | |
*/ | |
function arrayBufferToBuffer(data) { | |
// data is either an ArrayBuffer or ArrayBufferView. | |
var length = data.byteLength || data.length; | |
var offset = data.byteOffset || 0; | |
return Buffer.from(data.buffer || data, offset, length); | |
} | |
/** | |
* Encodes multiple messages (payload) as binary. | |
* | |
* <1 = binary, 0 = string><number from 0-9><number from 0-9>[...]<number | |
* 255><data> | |
* | |
* Example: | |
* 1 3 255 1 2 3, if the binary contents are interpreted as 8 bit integers | |
* | |
* @param {Array} packets | |
* @return {Buffer} encoded payload | |
* @api private | |
*/ | |
function encodePayloadAsBinary(packets, callback) { | |
if (!packets.length) { | |
return callback(EMPTY_BUFFER); | |
} | |
map(packets, encodeOneBinaryPacket, function (err, results) { | |
return callback(Buffer.concat(results)); | |
}); | |
} | |
exports.encodePayloadAsBinary = encodePayloadAsBinary; | |
; | |
function encodeOneBinaryPacket(p, doneCallback) { | |
function onBinaryPacketEncode(packet) { | |
var encodingLength = '' + packet.length; | |
var sizeBuffer; | |
if (typeof packet === 'string') { | |
sizeBuffer = Buffer.allocUnsafe(encodingLength.length + 2); | |
sizeBuffer[0] = 0; // is a string (not true binary = 0) | |
for (var i = 0; i < encodingLength.length; i++) { | |
sizeBuffer[i + 1] = parseInt(encodingLength[i], 10); | |
} | |
sizeBuffer[sizeBuffer.length - 1] = 255; | |
return doneCallback(null, Buffer.concat([sizeBuffer, stringToBuffer(packet)])); | |
} | |
sizeBuffer = Buffer.allocUnsafe(encodingLength.length + 2); | |
sizeBuffer[0] = 1; // is binary (true binary = 1) | |
for (var i = 0; i < encodingLength.length; i++) { | |
sizeBuffer[i + 1] = parseInt(encodingLength[i], 10); | |
} | |
sizeBuffer[sizeBuffer.length - 1] = 255; | |
doneCallback(null, Buffer.concat([sizeBuffer, packet])); | |
} | |
encodePacket(p, true, true, onBinaryPacketEncode); | |
} | |
/* | |
* Decodes data when a payload is maybe expected. Strings are decoded by | |
* interpreting each byte as a key code for entries marked to start with 0. See | |
* description of encodePayloadAsBinary | |
* @param {Buffer} data, callback method | |
* @api public | |
*/ | |
function decodePayloadAsBinary(data, binaryType, callback) { | |
if (typeof binaryType === 'function') { | |
callback = binaryType; | |
binaryType = null; | |
} | |
var bufferTail = data; | |
var buffers = []; | |
var i; | |
while (bufferTail.length > 0) { | |
var strLen = ''; | |
var isString = bufferTail[0] === 0; | |
for (i = 1;; i++) { | |
if (bufferTail[i] === 255) | |
break; | |
// 310 = char length of Number.MAX_VALUE | |
if (strLen.length > 310) { | |
return callback(err, 0, 1); | |
} | |
strLen += '' + bufferTail[i]; | |
} | |
bufferTail = bufferTail.slice(strLen.length + 1); | |
var msgLength = parseInt(strLen, 10); | |
var msg = bufferTail.slice(1, msgLength + 1); | |
if (isString) | |
msg = bufferToString(msg); | |
buffers.push(msg); | |
bufferTail = bufferTail.slice(msgLength + 1); | |
} | |
var total = buffers.length; | |
for (i = 0; i < total; i++) { | |
var buffer = buffers[i]; | |
callback(decodePacket(buffer, binaryType, true), i, total); | |
} | |
} | |
exports.decodePayloadAsBinary = decodePayloadAsBinary; | |
; | |