Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

engine.io-parser

Package Overview
Dependencies
Maintainers
2
Versions
52
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

engine.io-parser - npm Package Compare versions

Comparing version 4.0.0-alpha.0 to 4.0.0-alpha.1

CHANGELOG.md

492

lib/index.js

@@ -1,478 +0,40 @@

const utf8 = require("./utf8");
const hasBinary = require("has-binary2");
const after = require("after");
const encodePacket = require("./encodePacket");
const decodePacket = require("./decodePacket");
/**
* Current protocol version.
*/
exports.protocol = 4;
const SEPARATOR = "\x1e"; // see https://en.wikipedia.org/wiki/Delimiter#ASCII_delimited_text
/**
* Packet types.
*/
const packets = (exports.packets = {
open: 0, // non-ws
close: 1, // non-ws
ping: 2,
pong: 3,
message: 4,
upgrade: 5,
noop: 6
});
const encodePayload = (packets, callback) => {
const encodedPackets = new Array(packets.length);
let count = 0;
const packetslist = Object.keys(packets);
/**
* Premade error packet.
*/
const 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
*/
exports.encodePacket = function(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
let encoded = 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);
};
/**
* Encode Buffer data
*/
function encodeBuffer(packet, supportsBinary, callback) {
if (!supportsBinary) {
return exports.encodeBase64Packet(packet, callback);
}
return callback(packet.data);
}
/**
* Encodes a packet with binary data in a base64 string
*
* @param {Object} packet, has `type` and `data`
* @return {String} base64 encoded message
*/
exports.encodeBase64Packet = function(packet, callback) {
const data = Buffer.isBuffer(packet.data)
? packet.data
: arrayBufferToBuffer(packet.data);
let message = "b" + packets[packet.type];
message += data.toString("base64");
return callback(message);
};
/**
* Decodes a packet. Data also available as an ArrayBuffer if requested.
*
* @return {Object} with `type` and `data` (if any)
* @api private
*/
exports.decodePacket = function(data, binaryType, utf8decode) {
if (data === undefined) {
return err;
}
let type;
// String data
if (typeof data === "string") {
type = data.charAt(0);
if (type === "b") {
return exports.decodeBase64Packet(data.substr(1), binaryType);
}
if (utf8decode) {
data = tryDecode(data);
if (data === false) {
return err;
packets.forEach((packet, i) => {
// force base64 encoding for binary packets
encodePacket(packet, false, encodedPacket => {
encodedPackets[i] = encodedPacket;
if (++count === packets.length) {
callback(encodedPackets.join(SEPARATOR));
}
}
if (Number(type) != type || !packetslist[type]) {
return err;
}
if (data.length > 1) {
return { type: packetslist[type], data: data.substring(1) };
} else {
return { type: packetslist[type] };
}
}
// Binary data
if (binaryType === "arraybuffer") {
// wrap Buffer/ArrayBuffer data into an Uint8Array
const intArray = new Uint8Array(data);
return { type: "message", data: intArray.buffer };
}
if (data instanceof ArrayBuffer) {
data = arrayBufferToBuffer(data);
}
// only 'message' packets can contain binary data
return { type: "message", data };
};
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)
*/
exports.decodeBase64Packet = function(msg, binaryType) {
const type = packetslist[msg.charAt(0)];
let data = Buffer.from(msg.substr(1), "base64");
if (binaryType === "arraybuffer") {
const abv = new Uint8Array(data.length);
for (let i = 0; i < abv.length; i++) {
abv[i] = data[i];
}
data = abv.buffer;
}
return { type: type, data: data };
};
/**
* 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
*/
exports.encodePayload = function(packets, supportsBinary, callback) {
if (typeof supportsBinary === "function") {
callback = supportsBinary;
supportsBinary = null;
}
if (supportsBinary && hasBinary(packets)) {
return exports.encodePayloadAsBinary(packets, callback);
}
if (!packets.length) {
return callback("0:");
}
function encodeOne(packet, doneCallback) {
exports.encodePacket(packet, supportsBinary, false, function(message) {
doneCallback(null, setLengthHeader(message));
});
}
map(packets, encodeOne, function(err, results) {
return callback(results.join(""));
});
};
function setLengthHeader(message) {
return message.length + ":" + message;
}
/**
* Async array map using after
*/
function map(ary, each, done) {
const result = new Array(ary.length);
const next = after(ary.length, done);
for (let i = 0; i < ary.length; i++) {
each(ary[i], function(error, msg) {
result[i] = msg;
next(error, result);
});
}
}
/*
* Decodes data when a payload is maybe expected. Possible binary contents are
* decoded from their base64 representation
*
* @param {String} data, callback method
* @api public
*/
exports.decodePayload = function(data, binaryType, callback) {
if (typeof data !== "string") {
return exports.decodePayloadAsBinary(data, binaryType, callback);
}
if (typeof binaryType === "function") {
callback = binaryType;
binaryType = null;
}
if (data === "") {
// parser error - ignoring payload
return callback(err, 0, 1);
}
let length = "",
n,
msg,
packet;
let i = 0;
const l = data.length;
for (; i < l; i++) {
const chr = data.charAt(i);
if (chr !== ":") {
length += chr;
continue;
const decodePayload = (encodedPayload, binaryType) => {
const encodedPackets = encodedPayload.split(SEPARATOR);
const packets = [];
for (let i = 0; i < encodedPackets.length; i++) {
const decodedPacket = decodePacket(encodedPackets[i], binaryType);
packets.push(decodedPacket);
if (decodedPacket.type === "error") {
break;
}
if (length === "" || length != (n = Number(length))) {
// parser error - ignoring payload
return callback(err, 0, 1);
}
msg = data.substr(i + 1, n);
if (length != msg.length) {
// parser error - ignoring payload
return callback(err, 0, 1);
}
if (msg.length) {
packet = exports.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);
}
const 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);
}
return packets;
};
/**
*
* Converts a buffer to a utf8.js encoded string
*
* @api private
*/
function bufferToString(buffer) {
let str = "";
let i = 0;
const l = buffer.length;
for (; i < l; i++) {
str += String.fromCharCode(buffer[i]);
}
return str;
}
/**
*
* Converts a utf8.js encoded string to a buffer
*
* @api private
*/
function stringToBuffer(string) {
const buf = Buffer.allocUnsafe(string.length);
let i = 0;
const l = string.length;
for (; 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.
const length = data.byteLength || data.length;
const 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
*/
exports.encodePayloadAsBinary = function(packets, callback) {
if (!packets.length) {
return callback(EMPTY_BUFFER);
}
map(packets, encodeOneBinaryPacket, function(err, results) {
return callback(Buffer.concat(results));
});
module.exports = {
protocol: 4,
encodePacket,
encodePayload,
decodePacket,
decodePayload
};
function encodeOneBinaryPacket(p, doneCallback) {
function onBinaryPacketEncode(packet) {
const encodingLength = "" + packet.length;
let sizeBuffer;
if (typeof packet === "string") {
sizeBuffer = Buffer.allocUnsafe(encodingLength.length + 2);
sizeBuffer[0] = 0; // is a string (not true binary = 0)
for (let 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 (let i = 0; i < encodingLength.length; i++) {
sizeBuffer[i + 1] = parseInt(encodingLength[i], 10);
}
sizeBuffer[sizeBuffer.length - 1] = 255;
doneCallback(null, Buffer.concat([sizeBuffer, packet]));
}
exports.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
*/
exports.decodePayloadAsBinary = function(data, binaryType, callback) {
if (typeof binaryType === "function") {
callback = binaryType;
binaryType = null;
}
let bufferTail = data;
const buffers = [];
let i;
while (bufferTail.length > 0) {
let strLen = "";
const 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);
const msgLength = parseInt(strLen, 10);
let msg = bufferTail.slice(1, msgLength + 1);
if (isString) msg = bufferToString(msg);
buffers.push(msg);
bufferTail = bufferTail.slice(msgLength + 1);
}
const total = buffers.length;
for (i = 0; i < total; i++) {
const buffer = buffers[i];
callback(exports.decodePacket(buffer, binaryType, true), i, total);
}
};

@@ -5,10 +5,11 @@ {

"license": "MIT",
"version": "4.0.0-alpha.0",
"version": "4.0.0-alpha.1",
"main": "lib/index.js",
"homepage": "https://github.com/socketio/engine.io-parser",
"devDependencies": {
"@babel/core": "^7.8.3",
"@babel/preset-env": "^7.8.3",
"@babel/core": "~7.9.6",
"@babel/preset-env": "~7.9.6",
"babel-eslint": "^10.0.3",
"babelify": "^10.0.0",
"base64-arraybuffer": "0.1.5",
"benchmark": "^2.1.4",

@@ -19,2 +20,3 @@ "eslint": "^6.8.0",

"mocha": "^5.2.0",
"nyc": "~15.0.1",
"prettier": "^1.19.1",

@@ -25,11 +27,7 @@ "socket.io-browsers": "^1.0.4",

},
"dependencies": {
"after": "0.8.2",
"arraybuffer.slice": "~0.0.7",
"base64-arraybuffer": "0.1.5",
"blob": "0.0.5",
"has-binary2": "~1.0.2"
},
"dependencies": {},
"scripts": {
"test": "npm run lint && npm run format:check && make test",
"test": "npm run lint && npm run format:check && if test \"$BROWSERS\" = \"1\" ; then npm run test:browser; else npm run test:node; fi",
"test:node": "nyc mocha test/index.js",
"test:browser": "zuul test/index.js --no-coverage",
"format:check": "prettier --check 'lib/**/*.js' 'test/**/*.js'",

@@ -46,3 +44,6 @@ "format:fix": "prettier --write 'lib/**/*.js' 'test/**/*.js'",

],
"browser": "./lib/browser.js",
"browser": {
"./lib/encodePacket.js": "./lib/encodePacket.browser.js",
"./lib/decodePacket.js": "./lib/decodePacket.browser.js"
},
"engines": {

@@ -49,0 +50,0 @@ "node": ">=8.0.0"

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc