You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							193 lines
						
					
					
						
							4.7 KiB
						
					
					
				
			
		
		
	
	
							193 lines
						
					
					
						
							4.7 KiB
						
					
					
				'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;
 | 
						|
 |