arnaucube
arnaucube/socketioMEANseedPublic Self-hosted repository
socketioMEANseed/server/node_modules/ws/lib/Receiver.hixie.js
server/node_modules/ws/lib/Receiver.hixie.jsRaw
  1/*!
  2 * ws: a node.js websocket client
  3 * Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
  4 * MIT Licensed
  5 */
  6
  7var util = require('util');
  8
  9/**
 10 * State constants
 11 */
 12
 13var EMPTY = 0
 14  , BODY = 1;
 15var BINARYLENGTH = 2
 16  , BINARYBODY = 3;
 17
 18/**
 19 * Hixie Receiver implementation
 20 */
 21
 22function Receiver () {
 23  if (this instanceof Receiver === false) {
 24    throw new TypeError("Classes can't be function-called");
 25  }
 26
 27  this.state = EMPTY;
 28  this.buffers = [];
 29  this.messageEnd = -1;
 30  this.spanLength = 0;
 31  this.dead = false;
 32
 33  this.onerror = function() {};
 34  this.ontext = function() {};
 35  this.onbinary = function() {};
 36  this.onclose = function() {};
 37  this.onping = function() {};
 38  this.onpong = function() {};
 39}
 40
 41module.exports = Receiver;
 42
 43/**
 44 * Add new data to the parser.
 45 *
 46 * @api public
 47 */
 48
 49Receiver.prototype.add = function(data) {
 50  if (this.dead) return;
 51  var self = this;
 52  function doAdd() {
 53    if (self.state === EMPTY) {
 54      if (data.length == 2 && data[0] == 0xFF && data[1] == 0x00) {
 55        self.reset();
 56        self.onclose();
 57        return;
 58      }
 59      if (data[0] === 0x80) {
 60        self.messageEnd = 0;
 61        self.state = BINARYLENGTH;
 62        data = data.slice(1);
 63      } else {
 64
 65      if (data[0] !== 0x00) {
 66        self.error('payload must start with 0x00 byte', true);
 67        return;
 68      }
 69      data = data.slice(1);
 70      self.state = BODY;
 71
 72      }
 73    }
 74    if (self.state === BINARYLENGTH) {
 75      var i = 0;
 76      while ((i < data.length) && (data[i] & 0x80)) {
 77        self.messageEnd = 128 * self.messageEnd + (data[i] & 0x7f);
 78        ++i;
 79      }
 80      if (i < data.length) {
 81        self.messageEnd = 128 * self.messageEnd + (data[i] & 0x7f);
 82        self.state = BINARYBODY;
 83        ++i;
 84      }
 85      if (i > 0)
 86        data = data.slice(i);
 87    }
 88    if (self.state === BINARYBODY) {
 89      var dataleft = self.messageEnd - self.spanLength;
 90      if (data.length >= dataleft) {
 91        // consume the whole buffer to finish the frame
 92        self.buffers.push(data);
 93        self.spanLength += dataleft;
 94        self.messageEnd = dataleft;
 95        return self.parse();
 96      }
 97      // frame's not done even if we consume it all
 98      self.buffers.push(data);
 99      self.spanLength += data.length;
100      return;
101    }
102    self.buffers.push(data);
103    if ((self.messageEnd = bufferIndex(data, 0xFF)) != -1) {
104      self.spanLength += self.messageEnd;
105      return self.parse();
106    }
107    else self.spanLength += data.length;
108  }
109  while(data) data = doAdd();
110};
111
112/**
113 * Releases all resources used by the receiver.
114 *
115 * @api public
116 */
117
118Receiver.prototype.cleanup = function() {
119  this.dead = true;
120  this.state = EMPTY;
121  this.buffers = [];
122};
123
124/**
125 * Process buffered data.
126 *
127 * @api public
128 */
129
130Receiver.prototype.parse = function() {
131  var output = new Buffer(this.spanLength);
132  var outputIndex = 0;
133  for (var bi = 0, bl = this.buffers.length; bi < bl - 1; ++bi) {
134    var buffer = this.buffers[bi];
135    buffer.copy(output, outputIndex);
136    outputIndex += buffer.length;
137  }
138  var lastBuffer = this.buffers[this.buffers.length - 1];
139  if (this.messageEnd > 0) lastBuffer.copy(output, outputIndex, 0, this.messageEnd);
140  if (this.state !== BODY) --this.messageEnd;
141  var tail = null;
142  if (this.messageEnd < lastBuffer.length - 1) {
143    tail = lastBuffer.slice(this.messageEnd + 1);
144  }
145  this.reset();
146  this.ontext(output.toString('utf8'));
147  return tail;
148};
149
150/**
151 * Handles an error
152 *
153 * @api private
154 */
155
156Receiver.prototype.error = function (reason, terminate) {
157  if (this.dead) return;
158  this.reset();
159  if(typeof reason == 'string'){
160    this.onerror(new Error(reason), terminate);
161  }
162  else if(reason.constructor == Error){
163    this.onerror(reason, terminate);
164  }
165  else{
166    this.onerror(new Error("An error occured"),terminate);
167  }
168  return this;
169};
170
171/**
172 * Reset parser state
173 *
174 * @api private
175 */
176
177Receiver.prototype.reset = function (reason) {
178  if (this.dead) return;
179  this.state = EMPTY;
180  this.buffers = [];
181  this.messageEnd = -1;
182  this.spanLength = 0;
183};
184
185/**
186 * Internal api
187 */
188
189function bufferIndex(buffer, byte) {
190  for (var i = 0, l = buffer.length; i < l; ++i) {
191    if (buffer[i] === byte) return i;
192  }
193  return -1;
194}