-!function(e){if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.eio=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
+!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.eio=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
module.exports = _dereq_('./lib/');
this.upgrade = false !== opts.upgrade;
this.path = (opts.path || '/engine.io').replace(/\/$/, '') + '/';
this.forceJSONP = !!opts.forceJSONP;
+ this.jsonp = false !== opts.jsonp;
this.forceBase64 = !!opts.forceBase64;
+ this.enablesXDR = !!opts.enablesXDR;
this.timestampParam = opts.timestampParam || 't';
this.timestampRequests = opts.timestampRequests;
this.transports = opts.transports || ['polling', 'websocket'];
path: this.path,
query: query,
forceJSONP: this.forceJSONP,
+ jsonp: this.jsonp,
forceBase64: this.forceBase64,
+ enablesXDR: this.enablesXDR,
timestampRequests: this.timestampRequests,
timestampParam: this.timestampParam,
policyPort: this.policyPort,
var transport;
if (this.rememberUpgrade && Socket.priorWebsocketSuccess && this.transports.indexOf('websocket') != -1) {
transport = 'websocket';
+ } else if (0 == this.transports.length) {
+ // Emit error on next tick so it can be listened to
+ var self = this;
+ setTimeout(function() {
+ self.emit('error', 'No transports available');
+ }, 0);
+ return;
} else {
transport = this.transports[0];
}
this.readyState = 'opening';
- var transport = this.createTransport(transport);
+
+ // Retry with the next transport if the transport is disabled (jsonp: false)
+ var transport;
+ try {
+ transport = this.createTransport(transport);
+ } catch (e) {
+ this.transports.shift();
+ this.open();
+ return;
+ }
+
transport.open();
this.setTransport(transport);
};
this.readyState = '';
this.agent = opts.agent || false;
this.socket = opts.socket;
+ this.enablesXDR = opts.enablesXDR;
}
/**
*/
Transport.prototype.onData = function(data){
- try {
- var packet = parser.decodePacket(data, this.socket.binaryType);
- this.onPacket(packet);
- } catch(e){
- e.data = data;
- this.onError('parser decode error', e);
- }
+ var packet = parser.decodePacket(data, this.socket.binaryType);
+ this.onPacket(packet);
};
/**
function polling(opts){
var xhr;
var xd = false;
+ var xs = false;
+ var jsonp = false !== opts.jsonp;
if (global.location) {
var isSSL = 'https:' == location.protocol;
}
xd = opts.hostname != location.hostname || port != opts.port;
+ xs = opts.secure != isSSL;
}
opts.xdomain = xd;
+ opts.xscheme = xs;
xhr = new XMLHttpRequest(opts);
if ('open' in xhr && !opts.forceJSONP) {
return new XHR(opts);
} else {
+ if (!jsonp) throw new Error('JSONP disabled');
return new JSONP(opts);
}
}
this.xd = opts.hostname != global.location.hostname ||
port != opts.port;
+ this.xs = opts.secure != isSSL;
}
}
opts = opts || {};
opts.uri = this.uri();
opts.xd = this.xd;
+ opts.xs = this.xs;
opts.agent = this.agent || false;
opts.supportsBinary = this.supportsBinary;
+ opts.enablesXDR = this.enablesXDR;
return new Request(opts);
};
this.method = opts.method || 'GET';
this.uri = opts.uri;
this.xd = !!opts.xd;
+ this.xs = !!opts.xs;
this.async = false !== opts.async;
this.data = undefined != opts.data ? opts.data : null;
this.agent = opts.agent;
- this.create(opts.isBinary, opts.supportsBinary);
+ this.isBinary = opts.isBinary;
+ this.supportsBinary = opts.supportsBinary;
+ this.enablesXDR = opts.enablesXDR;
+ this.create();
}
/**
* @api private
*/
-Request.prototype.create = function(isBinary, supportsBinary){
- var xhr = this.xhr = new XMLHttpRequest({ agent: this.agent, xdomain: this.xd });
+Request.prototype.create = function(){
+ var xhr = this.xhr = new XMLHttpRequest({ agent: this.agent, xdomain: this.xd, xscheme: this.xs, enablesXDR: this.enablesXDR });
var self = this;
try {
debug('xhr open %s: %s', this.method, this.uri);
xhr.open(this.method, this.uri, this.async);
- if (supportsBinary) {
+ if (this.supportsBinary) {
// This has to be done after open because Firefox is stupid
// http://stackoverflow.com/questions/13216903/get-binary-data-with-xmlhttprequest-in-a-firefox-extension
xhr.responseType = 'arraybuffer';
if ('POST' == this.method) {
try {
- if (isBinary) {
+ if (this.isBinary) {
xhr.setRequestHeader('Content-type', 'application/octet-stream');
} else {
xhr.setRequestHeader('Content-type', 'text/plain;charset=UTF-8');
xhr.withCredentials = true;
}
- xhr.onreadystatechange = function(){
- var data;
-
- try {
+ if (this.hasXDR()) {
+ xhr.onload = function(){
+ self.onLoad();
+ };
+ xhr.onerror = function(){
+ self.onError(xhr.responseText);
+ };
+ } else {
+ xhr.onreadystatechange = function(){
if (4 != xhr.readyState) return;
if (200 == xhr.status || 1223 == xhr.status) {
- var contentType = xhr.getResponseHeader('Content-Type');
- if (contentType === 'application/octet-stream') {
- data = xhr.response;
- } else {
- if (!supportsBinary) {
- data = xhr.responseText;
- } else {
- data = 'ok';
- }
- }
+ self.onLoad();
} else {
// make sure the `error` event handler that's user-set
// does not throw in the same tick and gets caught here
self.onError(xhr.status);
}, 0);
}
- } catch (e) {
- self.onError(e);
- }
-
- if (null != data) {
- self.onData(data);
- }
- };
+ };
+ }
debug('xhr data %s', this.data);
xhr.send(this.data);
return;
}
// xmlhttprequest
- this.xhr.onreadystatechange = empty;
+ if (this.hasXDR()) {
+ this.xhr.onload = this.xhr.onerror = empty;
+ } else {
+ this.xhr.onreadystatechange = empty;
+ }
try {
this.xhr.abort();
this.xhr = null;
};
+/**
+ * Called upon load.
+ *
+ * @api private
+ */
+
+Request.prototype.onLoad = function(){
+ var data;
+ try {
+ var contentType;
+ try {
+ contentType = this.xhr.getResponseHeader('Content-Type');
+ } catch (e) {}
+ if (contentType === 'application/octet-stream') {
+ data = this.xhr.response;
+ } else {
+ if (!this.supportsBinary) {
+ data = this.xhr.responseText;
+ } else {
+ data = 'ok';
+ }
+ }
+ } catch (e) {
+ this.onError(e);
+ }
+ if (null != data) {
+ this.onData(data);
+ }
+};
+
+/**
+ * Check if it has XDomainRequest.
+ *
+ * @api private
+ */
+
+Request.prototype.hasXDR = function(){
+ return 'undefined' !== typeof global.XDomainRequest && !this.xs && this.enablesXDR;
+};
+
/**
* Aborts the request.
*
module.exports = function(opts) {
var xdomain = opts.xdomain;
+ // scheme must be same when usign XDomainRequest
+ // http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx
+ var xscheme = opts.xscheme;
+
+ // XDomainRequest has a flow of not sending cookie, therefore it should be disabled as a default.
+ // https://github.com/Automattic/engine.io-client/pull/217
+ var enablesXDR = opts.enablesXDR;
+
+ // Use XDomainRequest for IE8 if enablesXDR is true
+ // because loading bar keeps flashing when using jsonp-polling
+ // https://github.com/yujiosaka/socke.io-ie8-loading-example
+ try {
+ if ('undefined' != typeof XDomainRequest && !xscheme && enablesXDR) {
+ return new XDomainRequest();
+ }
+ } catch (e) { }
+
// XMLHttpRequest can be disabled on IE
try {
if ('undefined' != typeof XMLHttpRequest && (!xdomain || hasCORS)) {
* Current protocol version.
*/
-exports.protocol = 2;
+exports.protocol = 3;
/**
* Packet types.
* @api private
*/
-exports.encodePacket = function (packet, supportsBinary, callback) {
- if (typeof supportsBinary == 'function') {
+exports.encodePacket = function (packet, supportsBinary, utf8encode, callback) {
+ if ('function' == typeof supportsBinary) {
callback = supportsBinary;
supportsBinary = false;
}
+ if ('function' == typeof utf8encode) {
+ callback = utf8encode;
+ utf8encode = null;
+ }
+
var data = (packet.data === undefined)
? undefined
: packet.data.buffer || packet.data;
// data fragment is optional
if (undefined !== packet.data) {
- encoded += utf8.encode(String(packet.data));
+ encoded += utf8encode ? utf8.encode(String(packet.data)) : String(packet.data);
}
return callback('' + encoded);
var fr = new FileReader();
fr.onload = function() {
packet.data = fr.result;
- exports.encodePacket(packet, supportsBinary, callback);
+ exports.encodePacket(packet, supportsBinary, true, callback);
};
return fr.readAsArrayBuffer(packet.data);
}
* @api private
*/
-exports.decodePacket = function (data, binaryType) {
+exports.decodePacket = function (data, binaryType, utf8decode) {
// String data
if (typeof data == 'string' || data === undefined) {
if (data.charAt(0) == 'b') {
return exports.decodeBase64Packet(data.substr(1), binaryType);
}
- data = utf8.decode(data);
+ if (utf8decode) {
+ try {
+ data = utf8.decode(data);
+ } catch (e) {
+ return err;
+ }
+ }
var type = data.charAt(0);
if (Number(type) != type || !packetslist[type]) {
}
function encodeOne(packet, doneCallback) {
- exports.encodePacket(packet, supportsBinary, function(message) {
+ exports.encodePacket(packet, supportsBinary, true, function(message) {
doneCallback(null, setLengthHeader(message));
});
}
}
if (msg.length) {
- packet = exports.decodePacket(msg, binaryType);
+ packet = exports.decodePacket(msg, binaryType, true);
if (err.type == packet.type && err.data == packet.data) {
// parser error in individual packet - ignoring payload
}
function encodeOne(packet, doneCallback) {
- exports.encodePacket(packet, true, function(data) {
+ exports.encodePacket(packet, true, true, function(data) {
return doneCallback(null, data);
});
}
exports.encodePayloadAsBlob = function(packets, callback) {
function encodeOne(packet, doneCallback) {
- exports.encodePacket(packet, true, function(encoded) {
+ exports.encodePacket(packet, true, true, function(encoded) {
var binaryIdentifier = new Uint8Array(1);
binaryIdentifier[0] = 1;
if (typeof encoded === 'string') {
var bufferTail = data;
var buffers = [];
+ var numberTooLong = false;
while (bufferTail.byteLength > 0) {
var tailArray = new Uint8Array(bufferTail);
var isString = tailArray[0] === 0;
var msgLength = '';
+
for (var i = 1; ; i++) {
if (tailArray[i] == 255) break;
+
+ if (msgLength.length > 310) {
+ numberTooLong = true;
+ break;
+ }
+
msgLength += tailArray[i];
}
+
+ if(numberTooLong) return callback(err, 0, 1);
+
bufferTail = sliceBuffer(bufferTail, 2 + msgLength.length);
msgLength = parseInt(msgLength);
}
}
}
+
buffers.push(msg);
bufferTail = sliceBuffer(bufferTail, msgLength);
}
var total = buffers.length;
buffers.forEach(function(buffer, i) {
- callback(exports.decodePacket(buffer, binaryType), i, total);
+ callback(exports.decodePacket(buffer, binaryType, true), i, total);
});
};
var re = /^(?:(?![^:@]+:[^:@\/]*@)(http|https|ws|wss):\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/;
var parts = [
- 'source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host'
- , 'port', 'relative', 'path', 'directory', 'file', 'query', 'anchor'
+ 'source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'anchor'
];
module.exports = function parseuri(str) {
- var m = re.exec(str || '')
- , uri = {}
- , i = 14;
+ var src = str,
+ b = str.indexOf('['),
+ e = str.indexOf(']');
- while (i--) {
- uri[parts[i]] = m[i] || '';
- }
+ if (b != -1 && e != -1) {
+ str = str.substring(0, b) + str.substring(b, e).replace(/:/g, ';') + str.substring(e, str.length);
+ }
+
+ var m = re.exec(str || ''),
+ uri = {},
+ i = 14;
+
+ while (i--) {
+ uri[parts[i]] = m[i] || '';
+ }
+
+ if (b != -1 && e != -1) {
+ uri.source = src;
+ uri.host = uri.host.substring(1, uri.host.length - 1).replace(/;/g, ':');
+ uri.authority = uri.authority.replace('[', '').replace(']', '').replace(/;/g, ':');
+ uri.ipv6uri = true;
+ }
- return uri;
+ return uri;
};
},{}],27:[function(_dereq_,module,exports){