aboutsummaryrefslogtreecommitdiffhomepage
path: root/node_modules/engine.io-parser/lib/index.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/engine.io-parser/lib/index.js')
-rw-r--r--node_modules/engine.io-parser/lib/index.js480
1 files changed, 480 insertions, 0 deletions
diff --git a/node_modules/engine.io-parser/lib/index.js b/node_modules/engine.io-parser/lib/index.js
new file mode 100644
index 0000000..c01b0a0
--- /dev/null
+++ b/node_modules/engine.io-parser/lib/index.js
@@ -0,0 +1,480 @@
+/**
+ * Module dependencies.
+ */
+
+var utf8 = require('./utf8');
+var hasBinary = require('has-binary2');
+var after = require('after');
+var keys = require('./keys');
+
+/**
+ * Current protocol version.
+ */
+exports.protocol = 3;
+
+/**
+ * Packet types.
+ */
+
+var packets = exports.packets = {
+ open: 0 // non-ws
+ , close: 1 // non-ws
+ , ping: 2
+ , pong: 3
+ , message: 4
+ , upgrade: 5
+ , noop: 6
+};
+
+var packetslist = keys(packets);
+
+/**
+ * Premade error packet.
+ */
+
+var err = { type: 'error', data: 'parser error' };
+
+/**
+ * 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) {
+ packet.data = arrayBufferToBuffer(packet.data);
+ return encodeBuffer(packet, supportsBinary, callback);
+ }
+
+ // Sending data as a utf-8 string
+ var 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);
+ }
+
+ var data = packet.data;
+ var typeBuffer = new Buffer(1);
+ typeBuffer[0] = 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
+ */
+
+exports.encodeBase64Packet = function(packet, callback){
+ if (!Buffer.isBuffer(packet.data)) {
+ packet.data = arrayBufferToBuffer(packet.data);
+ }
+
+ var message = 'b' + packets[packet.type];
+ message += packet.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;
+ }
+
+ var 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;
+ }
+ }
+
+ 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
+ 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) };
+};
+
+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) {
+ var type = packetslist[msg.charAt(0)];
+ var data = new Buffer(msg.substr(1), 'base64');
+ if (binaryType === 'arraybuffer') {
+ var abv = new Uint8Array(data.length);
+ for (var 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) {
+ var result = new Array(ary.length);
+ var next = after(ary.length, done);
+
+ for (var 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);
+ }
+
+ 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;
+ }
+
+ 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);
+ }
+
+ 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);
+ }
+
+};
+
+/**
+ *
+ * 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 = new Buffer(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 array = new Uint8Array(data.buffer || data);
+ var length = data.byteLength || data.length;
+ var offset = data.byteOffset || 0;
+ var buffer = new Buffer(length);
+
+ for (var i = 0; i < length; i++) {
+ buffer[i] = array[offset + i];
+ }
+ return buffer;
+}
+
+/**
+ * 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(new Buffer(0));
+ }
+
+ map(packets, encodeOneBinaryPacket, function(err, results) {
+ return callback(Buffer.concat(results));
+ });
+};
+
+function encodeOneBinaryPacket(p, doneCallback) {
+
+ function onBinaryPacketEncode(packet) {
+
+ var encodingLength = '' + packet.length;
+ var sizeBuffer;
+
+ if (typeof packet === 'string') {
+ sizeBuffer = new Buffer(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 = new Buffer(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]));
+ }
+
+ 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;
+ }
+
+ 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(exports.decodePacket(buffer, binaryType, true), i, total);
+ }
+};