arnaucube
arnaucube/socketioMEANseedPublic Self-hosted repository
socketioMEANseed/server/node_modules/socket.io-parser/index.js
server/node_modules/socket.io-parser/index.jsRaw
  1
  2/**
  3 * Module dependencies.
  4 */
  5
  6var debug = require('debug')('socket.io-parser');
  7var json = require('json3');
  8var Emitter = require('component-emitter');
  9var binary = require('./binary');
 10var isBuf = require('./is-buffer');
 11
 12/**
 13 * Protocol version.
 14 *
 15 * @api public
 16 */
 17
 18exports.protocol = 4;
 19
 20/**
 21 * Packet types.
 22 *
 23 * @api public
 24 */
 25
 26exports.types = [
 27  'CONNECT',
 28  'DISCONNECT',
 29  'EVENT',
 30  'ACK',
 31  'ERROR',
 32  'BINARY_EVENT',
 33  'BINARY_ACK'
 34];
 35
 36/**
 37 * Packet type `connect`.
 38 *
 39 * @api public
 40 */
 41
 42exports.CONNECT = 0;
 43
 44/**
 45 * Packet type `disconnect`.
 46 *
 47 * @api public
 48 */
 49
 50exports.DISCONNECT = 1;
 51
 52/**
 53 * Packet type `event`.
 54 *
 55 * @api public
 56 */
 57
 58exports.EVENT = 2;
 59
 60/**
 61 * Packet type `ack`.
 62 *
 63 * @api public
 64 */
 65
 66exports.ACK = 3;
 67
 68/**
 69 * Packet type `error`.
 70 *
 71 * @api public
 72 */
 73
 74exports.ERROR = 4;
 75
 76/**
 77 * Packet type 'binary event'
 78 *
 79 * @api public
 80 */
 81
 82exports.BINARY_EVENT = 5;
 83
 84/**
 85 * Packet type `binary ack`. For acks with binary arguments.
 86 *
 87 * @api public
 88 */
 89
 90exports.BINARY_ACK = 6;
 91
 92/**
 93 * Encoder constructor.
 94 *
 95 * @api public
 96 */
 97
 98exports.Encoder = Encoder;
 99
100/**
101 * Decoder constructor.
102 *
103 * @api public
104 */
105
106exports.Decoder = Decoder;
107
108/**
109 * A socket.io Encoder instance
110 *
111 * @api public
112 */
113
114function Encoder() {}
115
116/**
117 * Encode a packet as a single string if non-binary, or as a
118 * buffer sequence, depending on packet type.
119 *
120 * @param {Object} obj - packet object
121 * @param {Function} callback - function to handle encodings (likely engine.write)
122 * @return Calls callback with Array of encodings
123 * @api public
124 */
125
126Encoder.prototype.encode = function(obj, callback){
127  debug('encoding packet %j', obj);
128
129  if (exports.BINARY_EVENT == obj.type || exports.BINARY_ACK == obj.type) {
130    encodeAsBinary(obj, callback);
131  }
132  else {
133    var encoding = encodeAsString(obj);
134    callback([encoding]);
135  }
136};
137
138/**
139 * Encode packet as string.
140 *
141 * @param {Object} packet
142 * @return {String} encoded
143 * @api private
144 */
145
146function encodeAsString(obj) {
147  var str = '';
148  var nsp = false;
149
150  // first is type
151  str += obj.type;
152
153  // attachments if we have them
154  if (exports.BINARY_EVENT == obj.type || exports.BINARY_ACK == obj.type) {
155    str += obj.attachments;
156    str += '-';
157  }
158
159  // if we have a namespace other than `/`
160  // we append it followed by a comma `,`
161  if (obj.nsp && '/' != obj.nsp) {
162    nsp = true;
163    str += obj.nsp;
164  }
165
166  // immediately followed by the id
167  if (null != obj.id) {
168    if (nsp) {
169      str += ',';
170      nsp = false;
171    }
172    str += obj.id;
173  }
174
175  // json data
176  if (null != obj.data) {
177    if (nsp) str += ',';
178    str += json.stringify(obj.data);
179  }
180
181  debug('encoded %j as %s', obj, str);
182  return str;
183}
184
185/**
186 * Encode packet as 'buffer sequence' by removing blobs, and
187 * deconstructing packet into object with placeholders and
188 * a list of buffers.
189 *
190 * @param {Object} packet
191 * @return {Buffer} encoded
192 * @api private
193 */
194
195function encodeAsBinary(obj, callback) {
196
197  function writeEncoding(bloblessData) {
198    var deconstruction = binary.deconstructPacket(bloblessData);
199    var pack = encodeAsString(deconstruction.packet);
200    var buffers = deconstruction.buffers;
201
202    buffers.unshift(pack); // add packet info to beginning of data list
203    callback(buffers); // write all the buffers
204  }
205
206  binary.removeBlobs(obj, writeEncoding);
207}
208
209/**
210 * A socket.io Decoder instance
211 *
212 * @return {Object} decoder
213 * @api public
214 */
215
216function Decoder() {
217  this.reconstructor = null;
218}
219
220/**
221 * Mix in `Emitter` with Decoder.
222 */
223
224Emitter(Decoder.prototype);
225
226/**
227 * Decodes an ecoded packet string into packet JSON.
228 *
229 * @param {String} obj - encoded packet
230 * @return {Object} packet
231 * @api public
232 */
233
234Decoder.prototype.add = function(obj) {
235  var packet;
236  if ('string' == typeof obj) {
237    packet = decodeString(obj);
238    if (exports.BINARY_EVENT == packet.type || exports.BINARY_ACK == packet.type) { // binary packet's json
239      this.reconstructor = new BinaryReconstructor(packet);
240
241      // no attachments, labeled binary but no binary data to follow
242      if (this.reconstructor.reconPack.attachments === 0) {
243        this.emit('decoded', packet);
244      }
245    } else { // non-binary full packet
246      this.emit('decoded', packet);
247    }
248  }
249  else if (isBuf(obj) || obj.base64) { // raw binary data
250    if (!this.reconstructor) {
251      throw new Error('got binary data when not reconstructing a packet');
252    } else {
253      packet = this.reconstructor.takeBinaryData(obj);
254      if (packet) { // received final buffer
255        this.reconstructor = null;
256        this.emit('decoded', packet);
257      }
258    }
259  }
260  else {
261    throw new Error('Unknown type: ' + obj);
262  }
263};
264
265/**
266 * Decode a packet String (JSON data)
267 *
268 * @param {String} str
269 * @return {Object} packet
270 * @api private
271 */
272
273function decodeString(str) {
274  var p = {};
275  var i = 0;
276
277  // look up type
278  p.type = Number(str.charAt(0));
279  if (null == exports.types[p.type]) return error();
280
281  // look up attachments if type binary
282  if (exports.BINARY_EVENT == p.type || exports.BINARY_ACK == p.type) {
283    var buf = '';
284    while (str.charAt(++i) != '-') {
285      buf += str.charAt(i);
286      if (i == str.length) break;
287    }
288    if (buf != Number(buf) || str.charAt(i) != '-') {
289      throw new Error('Illegal attachments');
290    }
291    p.attachments = Number(buf);
292  }
293
294  // look up namespace (if any)
295  if ('/' == str.charAt(i + 1)) {
296    p.nsp = '';
297    while (++i) {
298      var c = str.charAt(i);
299      if (',' == c) break;
300      p.nsp += c;
301      if (i == str.length) break;
302    }
303  } else {
304    p.nsp = '/';
305  }
306
307  // look up id
308  var next = str.charAt(i + 1);
309  if ('' !== next && Number(next) == next) {
310    p.id = '';
311    while (++i) {
312      var c = str.charAt(i);
313      if (null == c || Number(c) != c) {
314        --i;
315        break;
316      }
317      p.id += str.charAt(i);
318      if (i == str.length) break;
319    }
320    p.id = Number(p.id);
321  }
322
323  // look up json data
324  if (str.charAt(++i)) {
325    p = tryParse(p, str.substr(i));
326  }
327
328  debug('decoded %s as %j', str, p);
329  return p;
330}
331
332function tryParse(p, str) {
333  try {
334    p.data = json.parse(str);
335  } catch(e){
336    return error();
337  }
338  return p; 
339};
340
341/**
342 * Deallocates a parser's resources
343 *
344 * @api public
345 */
346
347Decoder.prototype.destroy = function() {
348  if (this.reconstructor) {
349    this.reconstructor.finishedReconstruction();
350  }
351};
352
353/**
354 * A manager of a binary event's 'buffer sequence'. Should
355 * be constructed whenever a packet of type BINARY_EVENT is
356 * decoded.
357 *
358 * @param {Object} packet
359 * @return {BinaryReconstructor} initialized reconstructor
360 * @api private
361 */
362
363function BinaryReconstructor(packet) {
364  this.reconPack = packet;
365  this.buffers = [];
366}
367
368/**
369 * Method to be called when binary data received from connection
370 * after a BINARY_EVENT packet.
371 *
372 * @param {Buffer | ArrayBuffer} binData - the raw binary data received
373 * @return {null | Object} returns null if more binary data is expected or
374 *   a reconstructed packet object if all buffers have been received.
375 * @api private
376 */
377
378BinaryReconstructor.prototype.takeBinaryData = function(binData) {
379  this.buffers.push(binData);
380  if (this.buffers.length == this.reconPack.attachments) { // done with buffer list
381    var packet = binary.reconstructPacket(this.reconPack, this.buffers);
382    this.finishedReconstruction();
383    return packet;
384  }
385  return null;
386};
387
388/**
389 * Cleans up binary packet reconstruction variables.
390 *
391 * @api private
392 */
393
394BinaryReconstructor.prototype.finishedReconstruction = function() {
395  this.reconPack = null;
396  this.buffers = [];
397};
398
399function error(data){
400  return {
401    type: exports.ERROR,
402    data: 'parser error'
403  };
404}