arnaucube
arnaucube/raspberryGPIOhtmlserverPublic Self-hosted repository
raspberryGPIOhtmlserver/node_modules/ws/lib/Receiver.hixie.js
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  this.state = EMPTY;
 24  this.buffers = [];
 25  this.messageEnd = -1;
 26  this.spanLength = 0;
 27  this.dead = false;
 28
 29  this.onerror = function() {};
 30  this.ontext = function() {};
 31  this.onbinary = function() {};
 32  this.onclose = function() {};
 33  this.onping = function() {};
 34  this.onpong = function() {};
 35}
 36
 37module.exports = Receiver;
 38
 39/**
 40 * Add new data to the parser.
 41 *
 42 * @api public
 43 */
 44
 45Receiver.prototype.add = function(data) {
 46  var self = this;
 47  function doAdd() {
 48    if (self.state === EMPTY) {
 49      if (data.length == 2 && data[0] == 0xFF && data[1] == 0x00) {
 50        self.reset();
 51        self.onclose();
 52        return;
 53      }
 54      if (data[0] === 0x80) {
 55        self.messageEnd = 0;
 56	self.state = BINARYLENGTH;
 57        data = data.slice(1);
 58      } else {
 59
 60      if (data[0] !== 0x00) {
 61        self.error('payload must start with 0x00 byte', true);
 62        return;
 63      }
 64      data = data.slice(1);
 65      self.state = BODY;
 66
 67      }
 68    }
 69    if (self.state === BINARYLENGTH) {
 70      var i = 0;
 71      while ((i < data.length) && (data[i] & 0x80)) {
 72        self.messageEnd = 128 * self.messageEnd + (data[i] & 0x7f);
 73        ++i;
 74      }
 75      if (i < data.length) {
 76        self.messageEnd = 128 * self.messageEnd + (data[i] & 0x7f);
 77        self.state = BINARYBODY;
 78        ++i;
 79      }
 80      if (i > 0)
 81        data = data.slice(i);
 82    }
 83    if (self.state === BINARYBODY) {
 84      var dataleft = self.messageEnd - self.spanLength;
 85      if (data.length >= dataleft) {
 86	// consume the whole buffer to finish the frame
 87        self.buffers.push(data);
 88        self.spanLength += dataleft;
 89        self.messageEnd = dataleft;
 90        return self.parse();
 91      }
 92      // frame's not done even if we consume it all
 93      self.buffers.push(data);
 94      self.spanLength += data.length;
 95      return;
 96    }
 97    self.buffers.push(data);
 98    if ((self.messageEnd = bufferIndex(data, 0xFF)) != -1) {
 99      self.spanLength += self.messageEnd;
100      return self.parse();
101    }
102    else self.spanLength += data.length;
103  }
104  while(data) data = doAdd();
105}
106
107/**
108 * Releases all resources used by the receiver.
109 *
110 * @api public
111 */
112
113Receiver.prototype.cleanup = function() {
114  this.dead = true;
115  this.state = EMPTY;
116  this.buffers = [];
117}
118
119/**
120 * Process buffered data.
121 *
122 * @api public
123 */
124
125Receiver.prototype.parse = function() {
126  var output = new Buffer(this.spanLength);
127  var outputIndex = 0;
128  for (var bi = 0, bl = this.buffers.length; bi < bl - 1; ++bi) {
129    var buffer = this.buffers[bi];
130    buffer.copy(output, outputIndex);
131    outputIndex += buffer.length;
132  }
133  var lastBuffer = this.buffers[this.buffers.length - 1];
134  if (this.messageEnd > 0) lastBuffer.copy(output, outputIndex, 0, this.messageEnd);
135  if (this.state !== BODY) --this.messageEnd;
136  var tail = null;
137  if (this.messageEnd < lastBuffer.length - 1) {
138    tail = lastBuffer.slice(this.messageEnd + 1);
139  }
140  this.reset();
141  this.ontext(output.toString('utf8'));
142  return tail;
143}
144
145/**
146 * Handles an error
147 *
148 * @api private
149 */
150
151Receiver.prototype.error = function (reason, terminate) {
152  this.reset();
153  this.onerror(reason, terminate);
154  return this;
155}
156
157/**
158 * Reset parser state
159 *
160 * @api private
161 */
162
163Receiver.prototype.reset = function (reason) {
164  if (this.dead) return;
165  this.state = EMPTY;
166  this.buffers = [];
167  this.messageEnd = -1;
168  this.spanLength = 0;
169}
170
171/**
172 * Internal api
173 */
174
175function bufferIndex(buffer, byte) {
176  for (var i = 0, l = buffer.length; i < l; ++i) {
177    if (buffer[i] === byte) return i;
178  }
179  return -1;
180}