arnaucube
arnaucube/comunicationLeapPublic Self-hosted repository
comunicationLeap/node_modules/engine.io/lib/transports/polling.js
node_modules/engine.io/lib/transports/polling.jsRaw
  1
  2/**
  3 * Module requirements.
  4 */
  5
  6var Transport = require('../transport')
  7  , parser = require('engine.io-parser')
  8  , debug = require('debug')('engine:polling');
  9
 10/**
 11 * Exports the constructor.
 12 */
 13
 14module.exports = Polling;
 15
 16/**
 17 * HTTP polling constructor.
 18 *
 19 * @api public.
 20 */
 21
 22function Polling (req) {
 23  Transport.call(this, req);
 24}
 25
 26/**
 27 * Inherits from Transport.
 28 *
 29 * @api public.
 30 */
 31
 32Polling.prototype.__proto__ = Transport.prototype;
 33
 34/**
 35 * Transport name
 36 *
 37 * @api public
 38 */
 39
 40Polling.prototype.name = 'polling';
 41
 42/**
 43 * Overrides onRequest.
 44 *
 45 * @param {http.ServerRequest}
 46 * @api private
 47 */
 48
 49Polling.prototype.onRequest = function (req) {
 50  var res = req.res;
 51
 52  if ('GET' == req.method) {
 53    this.onPollRequest(req, res);
 54  } else if ('POST' == req.method) {
 55    this.onDataRequest(req, res);
 56  } else {
 57    res.writeHead(500);
 58    res.end();
 59  }
 60};
 61
 62/**
 63 * The client sends a request awaiting for us to send data.
 64 *
 65 * @api private
 66 */
 67
 68Polling.prototype.onPollRequest = function (req, res) {
 69  if (this.req) {
 70    debug('request overlap');
 71    // assert: this.res, '.req and .res should be (un)set together'
 72    this.onError('overlap from client');
 73    res.writeHead(500);
 74    return;
 75  }
 76
 77  debug('setting request');
 78
 79  this.req = req;
 80  this.res = res;
 81
 82  var self = this;
 83
 84  function onClose () {
 85    self.onError('poll connection closed prematurely');
 86  }
 87
 88  function cleanup () {
 89    req.removeListener('close', onClose);
 90    self.req = self.res = null;
 91  }
 92
 93  req.cleanup = cleanup;
 94  req.on('close', onClose);
 95
 96  this.writable = true;
 97  this.emit('drain');
 98
 99  // if we're still writable but had a pending close, trigger an empty send
100  if (this.writable && this.shouldClose) {
101    debug('triggering empty send to append close packet');
102    this.send([{ type: 'noop' }]);
103  }
104};
105
106/**
107 * The client sends a request with data.
108 *
109 * @api private
110 */
111
112Polling.prototype.onDataRequest = function (req, res) {
113  if (this.dataReq) {
114    // assert: this.dataRes, '.dataReq and .dataRes should be (un)set together'
115    this.onError('data request overlap from client');
116    res.writeHead(500);
117    return;
118  }
119
120  var isBinary = 'application/octet-stream' == req.headers['content-type'];
121
122  this.dataReq = req;
123  this.dataRes = res;
124
125  var chunks = isBinary ? new Buffer(0) : '';
126  var self = this;
127
128  function cleanup () {
129    chunks = isBinary ? new Buffer(0) : '';
130    req.removeListener('data', onData);
131    req.removeListener('end', onEnd);
132    req.removeListener('close', onClose);
133    self.dataReq = self.dataRes = null;
134  }
135
136  function onClose () {
137    cleanup();
138    self.onError('data request connection closed prematurely');
139  }
140
141  function onData (data) {
142    var contentLength;
143    if (typeof data == 'string') {
144      chunks += data;
145      contentLength = Buffer.byteLength(chunks);
146    } else {
147      chunks = Buffer.concat([chunks, data]);
148      contentLength = chunks.length;
149    }
150
151    if (contentLength > self.maxHttpBufferSize) {
152      chunks = '';
153      req.connection.destroy();
154    }
155  }
156
157  function onEnd () {
158    self.onData(chunks);
159
160    var headers = {
161      // text/html is required instead of text/plain to avoid an
162      // unwanted download dialog on certain user-agents (GH-43)
163      'Content-Type': 'text/html',
164      'Content-Length': 2
165    };
166
167    // prevent XSS warnings on IE
168    // https://github.com/LearnBoost/socket.io/pull/1333
169    var ua = req.headers['user-agent'];
170    if (ua && (~ua.indexOf(';MSIE') || ~ua.indexOf('Trident/'))) {
171      headers['X-XSS-Protection'] = '0';
172    }
173
174    res.writeHead(200, self.headers(req, headers));
175    res.end('ok');
176    cleanup();
177  }
178
179  req.abort = cleanup;
180  req.on('close', onClose);
181  req.on('data', onData);
182  req.on('end', onEnd);
183  if (!isBinary) req.setEncoding('utf8');
184};
185
186/**
187 * Processes the incoming data payload.
188 *
189 * @param {String} encoded payload
190 * @api private
191 */
192
193Polling.prototype.onData = function (data) {
194  debug('received "%s"', data);
195  var self = this;
196  var callback = function(packet) {
197    if ('close' == packet.type) {
198      debug('got xhr close packet');
199      self.onClose();
200      return false;
201    }
202
203    self.onPacket(packet);
204  };
205
206  parser.decodePayload(data, callback);
207};
208
209/**
210 * Writes a packet payload.
211 *
212 * @param {Object} packet
213 * @api private
214 */
215
216Polling.prototype.send = function (packets) {
217  if (this.shouldClose) {
218    debug('appending close packet to payload');
219    packets.push({ type: 'close' });
220    this.shouldClose();
221    this.shouldClose = null;
222  }
223
224  var self = this;
225  parser.encodePayload(packets, this.supportsBinary, function(data) {
226    self.write(data);
227  });
228};
229
230/**
231 * Writes data as response to poll request.
232 *
233 * @param {String} data
234 * @api private
235 */
236
237Polling.prototype.write = function (data) {
238  debug('writing "%s"', data);
239  this.doWrite(data);
240  this.req.cleanup();
241  this.writable = false;
242};
243
244/**
245 * Closes the transport.
246 *
247 * @api private
248 */
249
250Polling.prototype.doClose = function (fn) {
251  debug('closing');
252
253  if (this.dataReq) {
254    // FIXME: should we do this?
255    debug('aborting ongoing data request');
256    this.dataReq.abort();
257  }
258
259  if (this.writable) {
260    debug('transport writable - closing right away');
261    this.send([{ type: 'close' }]);
262    fn();
263  } else {
264    debug('transport not writable - buffering orderly close');
265    this.shouldClose = fn;
266  }
267};