socketioMEANseed/server/node_modules/engine.io-client/lib/transports/polling.js
server/node_modules/engine.io-client/lib/transports/polling.jsRaw
1/**
2 * Module dependencies.
3 */
4
5var Transport = require('../transport');
6var parseqs = require('parseqs');
7var parser = require('engine.io-parser');
8var inherit = require('component-inherit');
9var yeast = require('yeast');
10var debug = require('debug')('engine.io-client:polling');
11
12/**
13 * Module exports.
14 */
15
16module.exports = Polling;
17
18/**
19 * Is XHR2 supported?
20 */
21
22var hasXHR2 = (function () {
23 var XMLHttpRequest = require('xmlhttprequest-ssl');
24 var xhr = new XMLHttpRequest({ xdomain: false });
25 return null != xhr.responseType;
26})();
27
28/**
29 * Polling interface.
30 *
31 * @param {Object} opts
32 * @api private
33 */
34
35function Polling (opts) {
36 var forceBase64 = (opts && opts.forceBase64);
37 if (!hasXHR2 || forceBase64) {
38 this.supportsBinary = false;
39 }
40 Transport.call(this, opts);
41}
42
43/**
44 * Inherits from Transport.
45 */
46
47inherit(Polling, Transport);
48
49/**
50 * Transport name.
51 */
52
53Polling.prototype.name = 'polling';
54
55/**
56 * Opens the socket (triggers polling). We write a PING message to determine
57 * when the transport is open.
58 *
59 * @api private
60 */
61
62Polling.prototype.doOpen = function () {
63 this.poll();
64};
65
66/**
67 * Pauses polling.
68 *
69 * @param {Function} callback upon buffers are flushed and transport is paused
70 * @api private
71 */
72
73Polling.prototype.pause = function (onPause) {
74 var self = this;
75
76 this.readyState = 'pausing';
77
78 function pause () {
79 debug('paused');
80 self.readyState = 'paused';
81 onPause();
82 }
83
84 if (this.polling || !this.writable) {
85 var total = 0;
86
87 if (this.polling) {
88 debug('we are currently polling - waiting to pause');
89 total++;
90 this.once('pollComplete', function () {
91 debug('pre-pause polling complete');
92 --total || pause();
93 });
94 }
95
96 if (!this.writable) {
97 debug('we are currently writing - waiting to pause');
98 total++;
99 this.once('drain', function () {
100 debug('pre-pause writing complete');
101 --total || pause();
102 });
103 }
104 } else {
105 pause();
106 }
107};
108
109/**
110 * Starts polling cycle.
111 *
112 * @api public
113 */
114
115Polling.prototype.poll = function () {
116 debug('polling');
117 this.polling = true;
118 this.doPoll();
119 this.emit('poll');
120};
121
122/**
123 * Overloads onData to detect payloads.
124 *
125 * @api private
126 */
127
128Polling.prototype.onData = function (data) {
129 var self = this;
130 debug('polling got data %s', data);
131 var callback = function (packet, index, total) {
132 // if its the first message we consider the transport open
133 if ('opening' === self.readyState) {
134 self.onOpen();
135 }
136
137 // if its a close packet, we close the ongoing requests
138 if ('close' === packet.type) {
139 self.onClose();
140 return false;
141 }
142
143 // otherwise bypass onData and handle the message
144 self.onPacket(packet);
145 };
146
147 // decode payload
148 parser.decodePayload(data, this.socket.binaryType, callback);
149
150 // if an event did not trigger closing
151 if ('closed' !== this.readyState) {
152 // if we got data we're not polling
153 this.polling = false;
154 this.emit('pollComplete');
155
156 if ('open' === this.readyState) {
157 this.poll();
158 } else {
159 debug('ignoring poll - transport state "%s"', this.readyState);
160 }
161 }
162};
163
164/**
165 * For polling, send a close packet.
166 *
167 * @api private
168 */
169
170Polling.prototype.doClose = function () {
171 var self = this;
172
173 function close () {
174 debug('writing close packet');
175 self.write([{ type: 'close' }]);
176 }
177
178 if ('open' === this.readyState) {
179 debug('transport open - closing');
180 close();
181 } else {
182 // in case we're trying to close while
183 // handshaking is in progress (GH-164)
184 debug('transport not open - deferring close');
185 this.once('open', close);
186 }
187};
188
189/**
190 * Writes a packets payload.
191 *
192 * @param {Array} data packets
193 * @param {Function} drain callback
194 * @api private
195 */
196
197Polling.prototype.write = function (packets) {
198 var self = this;
199 this.writable = false;
200 var callbackfn = function () {
201 self.writable = true;
202 self.emit('drain');
203 };
204
205 parser.encodePayload(packets, this.supportsBinary, function (data) {
206 self.doWrite(data, callbackfn);
207 });
208};
209
210/**
211 * Generates uri for connection.
212 *
213 * @api private
214 */
215
216Polling.prototype.uri = function () {
217 var query = this.query || {};
218 var schema = this.secure ? 'https' : 'http';
219 var port = '';
220
221 // cache busting is forced
222 if (false !== this.timestampRequests) {
223 query[this.timestampParam] = yeast();
224 }
225
226 if (!this.supportsBinary && !query.sid) {
227 query.b64 = 1;
228 }
229
230 query = parseqs.encode(query);
231
232 // avoid port if default for schema
233 if (this.port && (('https' === schema && Number(this.port) !== 443) ||
234 ('http' === schema && Number(this.port) !== 80))) {
235 port = ':' + this.port;
236 }
237
238 // prepend ? to query
239 if (query.length) {
240 query = '?' + query;
241 }
242
243 var ipv6 = this.hostname.indexOf(':') !== -1;
244 return schema + '://' + (ipv6 ? '[' + this.hostname + ']' : this.hostname) + port + this.path + query;
245};