|
|
'use strict';
var EventEmitter = require('events').EventEmitter , inherits = require('inherits') , utils = require('../../utils/event') , urlUtils = require('../../utils/url') , XHR = global.XMLHttpRequest ;
var debug = function() {}; if (process.env.NODE_ENV !== 'production') { debug = require('debug')('sockjs-client:browser:xhr'); }
function AbstractXHRObject(method, url, payload, opts) { debug(method, url); var self = this; EventEmitter.call(this);
setTimeout(function () { self._start(method, url, payload, opts); }, 0); }
inherits(AbstractXHRObject, EventEmitter);
AbstractXHRObject.prototype._start = function(method, url, payload, opts) { var self = this;
try { this.xhr = new XHR(); } catch (x) { // intentionally empty
}
if (!this.xhr) { debug('no xhr'); this.emit('finish', 0, 'no xhr support'); this._cleanup(); return; }
// several browsers cache POSTs
url = urlUtils.addQuery(url, 't=' + (+new Date()));
// Explorer tends to keep connection open, even after the
// tab gets closed: http://bugs.jquery.com/ticket/5280
this.unloadRef = utils.unloadAdd(function() { debug('unload cleanup'); self._cleanup(true); }); try { this.xhr.open(method, url, true); if (this.timeout && 'timeout' in this.xhr) { this.xhr.timeout = this.timeout; this.xhr.ontimeout = function() { debug('xhr timeout'); self.emit('finish', 0, ''); self._cleanup(false); }; } } catch (e) { debug('exception', e); // IE raises an exception on wrong port.
this.emit('finish', 0, ''); this._cleanup(false); return; }
if ((!opts || !opts.noCredentials) && AbstractXHRObject.supportsCORS) { debug('withCredentials'); // Mozilla docs says https://developer.mozilla.org/en/XMLHttpRequest :
// "This never affects same-site requests."
this.xhr.withCredentials = true; } if (opts && opts.headers) { for (var key in opts.headers) { this.xhr.setRequestHeader(key, opts.headers[key]); } }
this.xhr.onreadystatechange = function() { if (self.xhr) { var x = self.xhr; var text, status; debug('readyState', x.readyState); switch (x.readyState) { case 3: // IE doesn't like peeking into responseText or status
// on Microsoft.XMLHTTP and readystate=3
try { status = x.status; text = x.responseText; } catch (e) { // intentionally empty
} debug('status', status); // IE returns 1223 for 204: http://bugs.jquery.com/ticket/1450
if (status === 1223) { status = 204; }
// IE does return readystate == 3 for 404 answers.
if (status === 200 && text && text.length > 0) { debug('chunk'); self.emit('chunk', status, text); } break; case 4: status = x.status; debug('status', status); // IE returns 1223 for 204: http://bugs.jquery.com/ticket/1450
if (status === 1223) { status = 204; } // IE returns this for a bad port
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa383770(v=vs.85).aspx
if (status === 12005 || status === 12029) { status = 0; }
debug('finish', status, x.responseText); self.emit('finish', status, x.responseText); self._cleanup(false); break; } } };
try { self.xhr.send(payload); } catch (e) { self.emit('finish', 0, ''); self._cleanup(false); } };
AbstractXHRObject.prototype._cleanup = function(abort) { debug('cleanup'); if (!this.xhr) { return; } this.removeAllListeners(); utils.unloadDel(this.unloadRef);
// IE needs this field to be a function
this.xhr.onreadystatechange = function() {}; if (this.xhr.ontimeout) { this.xhr.ontimeout = null; }
if (abort) { try { this.xhr.abort(); } catch (x) { // intentionally empty
} } this.unloadRef = this.xhr = null; };
AbstractXHRObject.prototype.close = function() { debug('close'); this._cleanup(true); };
AbstractXHRObject.enabled = !!XHR; // override XMLHttpRequest for IE6/7
// obfuscate to avoid firewalls
var axo = ['Active'].concat('Object').join('X'); if (!AbstractXHRObject.enabled && (axo in global)) { debug('overriding xmlhttprequest'); XHR = function() { try { return new global[axo]('Microsoft.XMLHTTP'); } catch (e) { return null; } }; AbstractXHRObject.enabled = !!new XHR(); }
var cors = false; try { cors = 'withCredentials' in new XHR(); } catch (ignored) { // intentionally empty
}
AbstractXHRObject.supportsCORS = cors;
module.exports = AbstractXHRObject;
|