| '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; |