[Pkg-javascript-commits] [sockjs-client] 99/350: Add xhr for node. Refactor jsonp.

tonnerre at ancient-solutions.com tonnerre at ancient-solutions.com
Fri Aug 5 01:03:47 UTC 2016


This is an automated email from the git hooks/post-receive script.

tonnerre-guest pushed a commit to branch upstream
in repository sockjs-client.

commit 94c88742c13311f79995583fce08e01404b8bdef
Author: Bryce Kahle <bkahle at gmail.com>
Date:   Thu Oct 9 16:50:36 2014 -0400

    Add xhr for node. Refactor jsonp.
---
 lib/entry.js                                      |   2 +
 lib/transport/{sender => browser}/abstract-xhr.js |   8 +
 lib/transport/driver/xhr.js                       |  57 +++++
 lib/transport/iframe-xhr-polling.js               |   3 +-
 lib/transport/jsonp-polling.js                    | 258 ++--------------------
 lib/transport/lib/ajax-based.js                   |   6 +
 lib/transport/receiver/jsonp.js                   | 153 +++++++++++++
 lib/transport/sender/jsonp.js                     |  67 ++++++
 lib/transport/sender/xhr-cors.js                  |   8 +-
 lib/transport/sender/xhr-fake.js                  |   1 +
 lib/transport/sender/xhr-local.js                 |   8 +-
 lib/transport/xdr-polling.js                      |   2 +-
 lib/transport/xhr-polling.js                      |   8 +-
 lib/transport/xhr-streaming.js                    |  11 +-
 package.json                                      |   9 +-
 15 files changed, 340 insertions(+), 261 deletions(-)

diff --git a/lib/entry.js b/lib/entry.js
index 1591a96..9e188c8 100644
--- a/lib/entry.js
+++ b/lib/entry.js
@@ -17,6 +17,8 @@ var browserTransports = [
 
 var nodeTransports = [
   require('./transport/websocket')
+, require('./transport/xhr-streaming')
+, require('./transport/xhr-polling')
 ];
 
 var transports = typeof window !== 'undefined' ? browserTransports : nodeTransports;
diff --git a/lib/transport/sender/abstract-xhr.js b/lib/transport/browser/abstract-xhr.js
similarity index 93%
rename from lib/transport/sender/abstract-xhr.js
rename to lib/transport/browser/abstract-xhr.js
index a20b8d3..066b01e 100644
--- a/lib/transport/sender/abstract-xhr.js
+++ b/lib/transport/browser/abstract-xhr.js
@@ -110,4 +110,12 @@ AbstractXHRObject.prototype.close = function() {
   this._cleanup(true);
 };
 
+AbstractXHRObject.enabled = !!global.XMLHttpRequest;
+
+var cors = false;
+try { cors = 'withCredentials' in new global.XMLHttpRequest(); }
+catch (ignored) {}
+
+AbstractXHRObject.supportsCORS = cors;
+
 module.exports = AbstractXHRObject;
diff --git a/lib/transport/driver/xhr.js b/lib/transport/driver/xhr.js
new file mode 100644
index 0000000..87b4580
--- /dev/null
+++ b/lib/transport/driver/xhr.js
@@ -0,0 +1,57 @@
+'use strict';
+
+var EventEmitter = require('events').EventEmitter
+  , util = require('util')
+  , http = require('http')
+  , u = require('url')
+  ;
+
+function XhrDriver(method, url, payload, opts) {
+  var self = this;
+  EventEmitter.call(this);
+
+  var parsedUrl = u.parse(url);
+  var options = {
+    method: method
+  , hostname: parsedUrl.hostname
+  , port: parsedUrl.port
+  , path: parsedUrl.path
+  , headers: opts && opts.headers
+  , agent: false
+  };
+
+  this.req = http.request(options, function (res) {
+    res.setEncoding('utf8');
+    var responseText;
+
+    res.on('data', function (chunk) {
+      responseText += chunk;
+    });
+    res.on('end', function () {
+      self.emit('finish', res.statusCode, responseText);
+      self.req = null;
+    });
+  });
+
+  this.req.on('error', function (e) {
+    self.emit('finish', 0, e.message);
+  });
+
+  this.req.write(payload);
+  this.req.end();
+}
+
+util.inherits(XhrDriver, EventEmitter);
+
+XhrDriver.prototype.close = function() {
+  this.removeAllListeners();
+  if (this.req) {
+    this.req.abort();
+    this.req = null;
+  }
+};
+
+XhrDriver.enabled = true;
+XhrDriver.supportsCORS = true;
+
+module.exports = XhrDriver;
\ No newline at end of file
diff --git a/lib/transport/iframe-xhr-polling.js b/lib/transport/iframe-xhr-polling.js
index 43fa15a..231460c 100644
--- a/lib/transport/iframe-xhr-polling.js
+++ b/lib/transport/iframe-xhr-polling.js
@@ -2,6 +2,7 @@
 
 var util = require('util')
   , IframeTransport = require('./lib/iframe')
+  , XHRLocalObject = require('./sender/xhr-local')
   ;
 
 function XhrPollingIframeTransport(transUrl, baseUrl) {
@@ -11,7 +12,7 @@ function XhrPollingIframeTransport(transUrl, baseUrl) {
 util.inherits(XhrPollingIframeTransport, IframeTransport);
 
 XhrPollingIframeTransport.enabled = function () {
-  return global.XMLHttpRequest && IframeTransport.enabled();
+  return XHRLocalObject.enabled && IframeTransport.enabled();
 };
 
 XhrPollingIframeTransport.transportName = 'iframe-xhr-polling';
diff --git a/lib/transport/jsonp-polling.js b/lib/transport/jsonp-polling.js
index 492e872..b713dcf 100644
--- a/lib/transport/jsonp-polling.js
+++ b/lib/transport/jsonp-polling.js
@@ -2,265 +2,37 @@
 
 // The simplest and most robust transport, using the well-know cross
 // domain hack - JSONP. This transport is quite inefficient - one
-// mssage could use up to one http request. But at least it works almost
+// message could use up to one http request. But at least it works almost
 // everywhere.
 // Known limitations:
 //   o you will get a spinning cursor
 //   o for Konqueror a dumb timer is needed to detect errors
 
 var util = require('util')
-  , utils = require('../utils')
   , BufferedSender = require('./lib/buffered-sender')
-  , TransportMessageEvent = require('./lib/trans-message-event')
+  , Polling = require('./lib/polling')
+  , JsonpReceiver = require('./receiver/jsonp')
+  , jsonpSender = require('./sender/jsonp')
   ;
 
-// Abstract away code that handles global namespace pollution.
-var jsonPReceiverWrapper = function(url, constructReceiver, userCallback) {
-  var id = 'a' + utils.randomString(6);
-  var urlId = url + '?c=' + encodeURIComponent(utils.WPrefix + '.' + id);
-
-  // Unfortunately it is not possible to abort loading of the
-  // script. We need to keep track of frake close frames.
-  var aborting = 0;
-
-  // Callback will be called exactly once.
-  var callback = function(frame) {
-    switch(aborting) {
-    case 0:
-      // Normal behaviour - delete hook _and_ emit message.
-      delete window[utils.WPrefix][id];
-      userCallback(frame);
-      break;
-    case 1:
-      // Fake close frame - emit but don't delete hook.
-      userCallback(frame);
-      aborting = 2;
-      break;
-    case 2:
-      // Got frame after connection was closed, delete hook, don't emit.
-      delete window[utils.WPrefix][id];
-      break;
-    }
-  };
-
-  var closeScript = constructReceiver(urlId, callback);
-  window[utils.WPrefix][id] = closeScript;
-  var stop = function() {
-    if (window[utils.WPrefix][id]) {
-      aborting = 1;
-      var err = new Error('JSONP user aborted read');
-      err.code = 1000;
-      window[utils.WPrefix][id](err);
-    }
-  };
-  return stop;
-};
-
-function jsonPGenericSender(url, payload, callback) {
-  var form = window._sendForm;
-  var area = window._sendArea;
-
-  if (!form) {
-    form = window._sendForm = document.createElement('form');
-    area = window._sendArea = document.createElement('textarea');
-    area.name = 'd';
-    form.style.display = 'none';
-    form.style.position = 'absolute';
-    form.method = 'POST';
-    form.enctype = 'application/x-www-form-urlencoded';
-    form.acceptCharset = 'UTF-8';
-    form.appendChild(area);
-    document.body.appendChild(form);
-  }
-  var id = 'a' + utils.randomString(8);
-  form.target = id;
-  form.action = url + '/jsonp_send?i=' + id;
-
-  var iframe;
-  try {
-    // ie6 dynamic iframes with target="" support (thanks Chris Lambacher)
-    iframe = document.createElement('<iframe name="' + id + '">');
-  } catch(x) {
-    iframe = document.createElement('iframe');
-    iframe.name = id;
-  }
-  iframe.id = id;
-  form.appendChild(iframe);
-  iframe.style.display = 'none';
-
-  try {
-    area.value = payload;
-  } catch(e) {
-    utils.log('Your browser is seriously broken. Go home! ' + e.message);
-  }
-  form.submit();
-
-  var completed = function() {
-    if (!iframe.onerror) {
-      return;
-    }
-    iframe.onreadystatechange = iframe.onerror = iframe.onload = null;
-    // Opera mini doesn't like if we GC iframe
-    // immediately, thus this timeout.
-    setTimeout(function() {
-                   iframe.parentNode.removeChild(iframe);
-                   iframe = null;
-               }, 500);
-    area.value = '';
-    // It is not possible to detect if the iframe succeeded or
-    // failed to submit our form.
-    callback();
-  };
-  iframe.onerror = iframe.onload = completed;
-  iframe.onreadystatechange = function() {
-    if (iframe.readyState === 'complete') {
-      completed();
-    }
-  };
-  return completed;
-}
-
-// Parts derived from Socket.io:
-//    https://github.com/LearnBoost/socket.io/blob/0.6.17/lib/socket.io/transports/jsonp-polling.js
-// and jQuery-JSONP:
-//    https://code.google.com/p/jquery-jsonp/source/browse/trunk/core/jquery.jsonp.js
-function jsonPGenericReceiver(url, callback) {
-  var tref;
-  var script = global.document.createElement('script');
-  var script2;  // Opera synchronous load trick.
-  var closeScript = function(err) {
-    if (script2) {
-      script2.parentNode.removeChild(script2);
-      script2 = null;
-    }
-    if (script) {
-      clearTimeout(tref);
-      // Unfortunately, you can't really abort script loading of
-      // the script.
-      script.parentNode.removeChild(script);
-      script.onreadystatechange = script.onerror =
-          script.onload = script.onclick = null;
-      script = null;
-      callback(err);
-      callback = null;
-    }
-  };
-
-  // IE9 fires 'error' event after orsc or before, in random order.
-  var loadedOkay = false;
-  var errorTimer = null;
-
-  script.id = 'a' + utils.randomString(8);
-  script.src = url;
-  script.type = 'text/javascript';
-  script.charset = 'UTF-8';
-  script.onerror = function() {
-    if (!errorTimer) {
-      // Delay firing closeScript.
-      errorTimer = setTimeout(function() {
-        if (!loadedOkay) {
-          closeScript(new Error('JSONP script loaded abnormally (onerror)'));
-        }
-      }, 1000);
-    }
-  };
-  script.onload = function() {
-    closeScript(new Error('JSONP script loaded abnormally (onload)'));
-  };
-
-  script.onreadystatechange = function() {
-    if (/loaded|closed/.test(script.readyState)) {
-      if (script && script.htmlFor && script.onclick) {
-        loadedOkay = true;
-        try {
-            // In IE, actually execute the script.
-            script.onclick();
-        } catch (x) {}
-      }
-      if (script) {
-        closeScript(new Error('JSONP script loaded abnormally (onreadystatechange)'));
-      }
-    }
-  };
-  // IE: event/htmlFor/onclick trick.
-  // One can't rely on proper order for onreadystatechange. In order to
-  // make sure, set a 'htmlFor' and 'event' properties, so that
-  // script code will be installed as 'onclick' handler for the
-  // script object. Later, onreadystatechange, manually execute this
-  // code. FF and Chrome doesn't work with 'event' and 'htmlFor'
-  // set. For reference see:
-  //   http://jaubourg.net/2010/07/loading-script-as-onclick-handler-of.html
-  // Also, read on that about script ordering:
-  //   http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order
-  if (typeof script.async === 'undefined' && document.attachEvent) {
-    // According to mozilla docs, in recent browsers script.async defaults
-    // to 'true', so we may use it to detect a good browser:
-    // https://developer.mozilla.org/en/HTML/Element/script
-    if (!/opera/i.test(navigator.userAgent)) {
-      // Naively assume we're in IE
-      try {
-          script.htmlFor = script.id;
-          script.event = 'onclick';
-      } catch (x) {}
-      script.async = true;
-    } else {
-      // Opera, second sync script hack
-      script2 = document.createElement('script');
-      script2.text = "try{var a = document.getElementById('" + script.id + "'); if(a)a.onerror();}catch(x){};";
-      script.async = script2.async = false;
-    }
-  }
-  if (typeof script.async !== 'undefined') {
-    script.async = true;
-  }
-
-  // Fallback mostly for Konqueror - stupid timer, 35 seconds shall be plenty.
-  tref = setTimeout(function() {
-    closeScript(new Error('JSONP script loaded abnormally (timeout)'));
-  }, 35000);
-
-  var head = document.getElementsByTagName('head')[0];
-  head.insertBefore(script, head.firstChild);
-  if (script2) {
-    head.insertBefore(script2, head.firstChild);
-  }
-  return closeScript;
-}
-
 function JsonPTransport(transUrl) {
-  utils.polluteGlobalNamespace();
-  this.transUrl = transUrl;
-  BufferedSender.call(this, transUrl, jsonPGenericSender);
-  this._scheduleReceiver();
+  var self = this;
+  BufferedSender.call(this, transUrl, jsonpSender);
+  
+  this.poll = new Polling(JsonpReceiver, this.transUrl + '/jsonp');
+  this.poll.onmessage = this.poll.onclose = function (e) {
+    self.dispatchEvent(e);
+  };
 }
 
 util.inherits(JsonPTransport, BufferedSender);
 
-JsonPTransport.prototype._scheduleReceiver = function() {
-  var self = this;
-  var callback = function(data) {
-    self._receiveStop = null;
-    if (data) {
-      // no data - heartbeat;
-      if (!self._isClosing) {
-        self.dispatchEvent(new TransportMessageEvent(data));
-      }
-    }
-    // The message can be a close message, and change is_closing state.
-    if (!self._isClosing) {
-      self._scheduleReceiver();
-    }
-  };
-  this._receiveStop = jsonPReceiverWrapper(this.transUrl + '/jsonp',
-                                         jsonPGenericReceiver, callback);
-};
-
 JsonPTransport.prototype.close = function() {
-  this._isClosing = true;
-  if (this._receiveStop) {
-    this._receiveStop();
+  if (this.poll) {
+    this.poll.abort();
+    this.poll.onmessage = this.poll.onclose = null;
+    this.poll = null;
   }
-  this._receiveStop = null;
   this.stop();
 };
 
diff --git a/lib/transport/lib/ajax-based.js b/lib/transport/lib/ajax-based.js
index 9257328..f70190f 100644
--- a/lib/transport/lib/ajax-based.js
+++ b/lib/transport/lib/ajax-based.js
@@ -25,8 +25,13 @@ function createAjaxSender(AjaxObject) {
 }
 
 function AjaxBasedTransport(transUrl, urlSuffix, Receiver, AjaxObject) {
+  var self = this;
   BufferedSender.call(this, transUrl, createAjaxSender(AjaxObject));
+  
   this.poll = new Polling(Receiver, transUrl + urlSuffix, AjaxObject);
+  this.poll.onmessage = this.poll.onclose = function (e) {
+    self.dispatchEvent(e);
+  };
 }
 
 util.inherits(AjaxBasedTransport, BufferedSender);
@@ -34,6 +39,7 @@ util.inherits(AjaxBasedTransport, BufferedSender);
 AjaxBasedTransport.prototype.close = function() {
   if (this.poll) {
     this.poll.abort();
+    this.poll.onmessage = this.poll.onclose = null;
     this.poll = null;
   }
   this.stop();
diff --git a/lib/transport/receiver/jsonp.js b/lib/transport/receiver/jsonp.js
new file mode 100644
index 0000000..83a9f61
--- /dev/null
+++ b/lib/transport/receiver/jsonp.js
@@ -0,0 +1,153 @@
+'use strict';
+
+var utils = require('../../utils')
+  , util = require('util')
+  , SimpleEvent = require('../../simpleevent')
+  , EventTarget = require('../../polyfills/eventtarget')
+  ;
+
+function JsonpReceiver(url) {
+  EventTarget.call(this);
+
+  utils.polluteGlobalNamespace();
+
+  this.id = 'a' + utils.randomString(6);
+  var urlId = url + '?c=' + encodeURIComponent(utils.WPrefix + '.' + this.id);
+
+  window[utils.WPrefix][this.id] = this.callback.bind(this);
+  this.createScript(urlId);
+}
+
+util.inherits(JsonpReceiver, EventTarget);
+
+JsonpReceiver.prototype.callback = function (data) {
+  this.deleteScript();
+  delete window[utils.WPrefix][this.id];
+  
+  if (this.aborting) {
+    return;
+  }
+
+  if (data) {
+    this.dispatchEvent(new SimpleEvent('message', { data: data }));
+  }
+  this.dispatchEvent(new SimpleEvent('close', { reason: 'network' }));
+};
+
+JsonpReceiver.prototype.abort = function () {
+  if (window[utils.WPrefix][this.id]) {
+    var err = new Error('JSONP user aborted read');
+    err.code = 1000;
+    this._abort(err);
+  }
+};
+
+module.exports = JsonpReceiver;
+
+JsonpReceiver.prototype._abort = function (err) {
+  this.deleteScript();
+  this.aborting = true;
+  this.dispatchEvent(new SimpleEvent('close', { reason: 'permanent' }));
+};
+
+JsonpReceiver.prototype.deleteScript = function () {
+  if (this.script2) {
+    this.script2.parentNode.removeChild(this.script2);
+    this.script2 = null;
+  }
+  if (this.script) {
+    var script = this.script;
+    clearTimeout(this.tref);
+    // Unfortunately, you can't really abort script loading of
+    // the script.
+    script.parentNode.removeChild(script);
+    script.onreadystatechange = script.onerror =
+        script.onload = script.onclick = null;
+    this.script = null;
+  }
+};
+
+JsonpReceiver.prototype.createScript = function (url) {
+  var self = this;
+  var script = this.script = global.document.createElement('script');
+  var script2;  // Opera synchronous load trick.
+
+  // IE9 fires 'error' event after orsc or before, in random order.
+  var loadedOkay = false;
+  var errorTimer = null;
+
+  script.id = 'a' + utils.randomString(8);
+  script.src = url;
+  script.type = 'text/javascript';
+  script.charset = 'UTF-8';
+  script.onerror = function() {
+    if (!errorTimer) {
+      // Delay firing closeScript.
+      errorTimer = setTimeout(function() {
+        if (!loadedOkay) {
+          self._abort(new Error('JSONP script loaded abnormally (onerror)'));
+        }
+      }, 1000);
+    }
+  };
+  script.onload = function() {
+    self._abort(new Error('JSONP script loaded abnormally (onload)'));
+  };
+
+  script.onreadystatechange = function() {
+    if (/loaded|closed/.test(script.readyState)) {
+      if (script && script.htmlFor && script.onclick) {
+        loadedOkay = true;
+        try {
+            // In IE, actually execute the script.
+            script.onclick();
+        } catch (x) {}
+      }
+      if (script) {
+        self._abort(new Error('JSONP script loaded abnormally (onreadystatechange)'));
+      }
+    }
+  };
+  // IE: event/htmlFor/onclick trick.
+  // One can't rely on proper order for onreadystatechange. In order to
+  // make sure, set a 'htmlFor' and 'event' properties, so that
+  // script code will be installed as 'onclick' handler for the
+  // script object. Later, onreadystatechange, manually execute this
+  // code. FF and Chrome doesn't work with 'event' and 'htmlFor'
+  // set. For reference see:
+  //   http://jaubourg.net/2010/07/loading-script-as-onclick-handler-of.html
+  // Also, read on that about script ordering:
+  //   http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order
+  if (typeof script.async === 'undefined' && document.attachEvent) {
+    // According to mozilla docs, in recent browsers script.async defaults
+    // to 'true', so we may use it to detect a good browser:
+    // https://developer.mozilla.org/en/HTML/Element/script
+    if (!/opera/i.test(navigator.userAgent)) {
+      // Naively assume we're in IE
+      try {
+          script.htmlFor = script.id;
+          script.event = 'onclick';
+      } catch (x) {}
+      script.async = true;
+    } else {
+      // Opera, second sync script hack
+      script2 = this.script2 = document.createElement('script');
+      script2.text = "try{var a = document.getElementById('" + script.id + "'); if(a)a.onerror();}catch(x){};";
+      script.async = script2.async = false;
+    }
+  }
+  if (typeof script.async !== 'undefined') {
+    script.async = true;
+  }
+
+  // Fallback mostly for Konqueror - stupid timer, 35 seconds shall be plenty.
+  this.tref = setTimeout(function() {
+    self._abort(new Error('JSONP script loaded abnormally (timeout)'));
+  }, 35000);
+
+  var head = document.getElementsByTagName('head')[0];
+  head.insertBefore(script, head.firstChild);
+  if (script2) {
+    head.insertBefore(script2, head.firstChild);
+  }
+};
diff --git a/lib/transport/sender/jsonp.js b/lib/transport/sender/jsonp.js
new file mode 100644
index 0000000..75a5bce
--- /dev/null
+++ b/lib/transport/sender/jsonp.js
@@ -0,0 +1,67 @@
+'use strict';
+
+var utils = require('../../utils');
+
+module.exports = function (url, payload, callback) {
+  var form = window._sendForm;
+  var area = window._sendArea;
+
+  if (!form) {
+    form = window._sendForm = document.createElement('form');
+    area = window._sendArea = document.createElement('textarea');
+    area.name = 'd';
+    form.style.display = 'none';
+    form.style.position = 'absolute';
+    form.method = 'POST';
+    form.enctype = 'application/x-www-form-urlencoded';
+    form.acceptCharset = 'UTF-8';
+    form.appendChild(area);
+    document.body.appendChild(form);
+  }
+  var id = 'a' + utils.randomString(8);
+  form.target = id;
+  form.action = url + '/jsonp_send?i=' + id;
+
+  var iframe;
+  try {
+    // ie6 dynamic iframes with target="" support (thanks Chris Lambacher)
+    iframe = document.createElement('<iframe name="' + id + '">');
+  } catch(x) {
+    iframe = document.createElement('iframe');
+    iframe.name = id;
+  }
+  iframe.id = id;
+  form.appendChild(iframe);
+  iframe.style.display = 'none';
+
+  try {
+    area.value = payload;
+  } catch(e) {
+    utils.log('Your browser is seriously broken. Go home! ' + e.message);
+  }
+  form.submit();
+
+  var completed = function() {
+    if (!iframe.onerror) {
+      return;
+    }
+    iframe.onreadystatechange = iframe.onerror = iframe.onload = null;
+    // Opera mini doesn't like if we GC iframe
+    // immediately, thus this timeout.
+    setTimeout(function() {
+                   iframe.parentNode.removeChild(iframe);
+                   iframe = null;
+               }, 500);
+    area.value = '';
+    // It is not possible to detect if the iframe succeeded or
+    // failed to submit our form.
+    callback();
+  };
+  iframe.onerror = iframe.onload = completed;
+  iframe.onreadystatechange = function() {
+    if (iframe.readyState === 'complete') {
+      completed();
+    }
+  };
+  return completed;
+};
diff --git a/lib/transport/sender/xhr-cors.js b/lib/transport/sender/xhr-cors.js
index 04d0052..cfc9bb4 100644
--- a/lib/transport/sender/xhr-cors.js
+++ b/lib/transport/sender/xhr-cors.js
@@ -1,7 +1,7 @@
 'use strict';
 
 var util = require('util')
-  , AbstractXHRObject = require('./abstract-xhr')
+  , XhrDriver = require('../driver/xhr')
   ;
 
 function XHRCorsObject(method, url, payload, opts) {
@@ -9,10 +9,12 @@ function XHRCorsObject(method, url, payload, opts) {
     , args = arguments
     ;
   process.nextTick(function(){
-    AbstractXHRObject.apply(self, args);
+    XhrDriver.apply(self, args);
   });
 }
 
-util.inherits(XHRCorsObject, AbstractXHRObject);
+util.inherits(XHRCorsObject, XhrDriver);
+
+XHRCorsObject.enabled = XhrDriver.enabled && XhrDriver.supportsCORS;
 
 module.exports = XHRCorsObject;
diff --git a/lib/transport/sender/xhr-fake.js b/lib/transport/sender/xhr-fake.js
index 360f08d..beabdfc 100644
--- a/lib/transport/sender/xhr-fake.js
+++ b/lib/transport/sender/xhr-fake.js
@@ -5,6 +5,7 @@ var EventEmitter = require('events').EventEmitter
   ;
 
 function XHRFake(method, url, payload, opts) {
+  var self = this;
   EventEmitter.call(this);
 
   setTimeout(function() {
diff --git a/lib/transport/sender/xhr-local.js b/lib/transport/sender/xhr-local.js
index 654da17..f047941 100644
--- a/lib/transport/sender/xhr-local.js
+++ b/lib/transport/sender/xhr-local.js
@@ -1,18 +1,20 @@
 'use strict';
 
 var util = require('util')
-  , AbstractXHRObject = require('./abstract-xhr')
+  , XhrDriver = require('../driver/xhr')
   ;
 
 function XHRLocalObject(method, url, payload) {
   var self = this;
   process.nextTick(function(){
-    AbstractXHRObject.call(self, method, url, payload, {
+    XhrDriver.call(self, method, url, payload, {
       noCredentials: true
     });
   });
 }
 
-util.inherits(XHRLocalObject, AbstractXHRObject);
+util.inherits(XHRLocalObject, XhrDriver);
+
+XHRLocalObject.enabled = XhrDriver.enabled;
 
 module.exports = XHRLocalObject;
diff --git a/lib/transport/xdr-polling.js b/lib/transport/xdr-polling.js
index 34f717d..cfdbf54 100644
--- a/lib/transport/xdr-polling.js
+++ b/lib/transport/xdr-polling.js
@@ -7,7 +7,7 @@ var util = require('util')
   , XDRObject = require('./sender/xdr')
   ;
 
-function XdrPollingTransport(ri, transUrl) {
+function XdrPollingTransport(transUrl) {
   AjaxBasedTransport.call(this, transUrl, '/xhr', XhrReceiver, XDRObject);
 }
 
diff --git a/lib/transport/xhr-polling.js b/lib/transport/xhr-polling.js
index d4822c5..6202b60 100644
--- a/lib/transport/xhr-polling.js
+++ b/lib/transport/xhr-polling.js
@@ -4,10 +4,11 @@ var util = require('util')
   , AjaxBasedTransport = require('./lib/ajax-based')
   , XhrReceiver = require('./receiver/xhr')
   , XHRCorsObject = require('./sender/xhr-cors')
+  , XHRLocalObject = require('./sender/xhr-local')
   , utils = require('../utils')
   ;
 
-function XhrPollingTransport(ri, transUrl) {
+function XhrPollingTransport(transUrl) {
   AjaxBasedTransport.call(this, transUrl, '/xhr', XhrReceiver, XHRCorsObject);
 }
 
@@ -17,10 +18,11 @@ XhrPollingTransport.enabled = function(url, info) {
   if (info.nullOrigin) {
     return false;
   }
-  if (global.XMLHttpRequest && utils.isSameOriginUrl(url)) {
+
+  if (XHRLocalObject.enabled && utils.isSameOriginUrl(url)) {
     return true;
   }
-  return utils.isXHRCorsCapable() === 1;
+  return XHRCorsObject.enabled;
 };
 
 XhrPollingTransport.transportName = 'xhr-polling';
diff --git a/lib/transport/xhr-streaming.js b/lib/transport/xhr-streaming.js
index c54809e..6cc2f3e 100644
--- a/lib/transport/xhr-streaming.js
+++ b/lib/transport/xhr-streaming.js
@@ -4,10 +4,11 @@ var util = require('util')
   , AjaxBasedTransport = require('./lib/ajax-based')
   , XhrReceiver = require('./receiver/xhr')
   , XHRCorsObject = require('./sender/xhr-cors')
+  , XHRLocalObject = require('./sender/xhr-local')
   , utils = require('../utils')
   ;
 
-function XhrStreamingTransport(ri, transUrl) {
+function XhrStreamingTransport(transUrl) {
   AjaxBasedTransport.call(this, transUrl, '/xhr_streaming', XhrReceiver, XHRCorsObject);
 }
 
@@ -18,14 +19,14 @@ XhrStreamingTransport.enabled = function(url, info) {
     return false;
   }
   // Opera doesn't support xhr-streaming
-  if (/opera/i.test(global.navigator.userAgent)) {
+  if (global.navigator && /opera/i.test(global.navigator.userAgent)) {
     return false;
   }
-  if (global.XMLHttpRequest && utils.isSameOriginUrl(url)) {
+  
+  if (XHRLocalObject.enabled && utils.isSameOriginUrl(url)) {
     return true;
   }
-
-  return utils.isXHRCorsCapable() === 1;
+  return XHRCorsObject.enabled;
 };
 
 XhrStreamingTransport.transportName = 'xhr-streaming';
diff --git a/package.json b/package.json
index c3619de..f909e3f 100644
--- a/package.json
+++ b/package.json
@@ -2,9 +2,10 @@
   "name": "sockjs-client",
   "description": "SockJS-client is a browser JavaScript library that provides a WebSocket-like object. SockJS gives you a coherent, cross-browser, Javascript API which creates a low latency, full duplex, cross-domain communication channel between the browser and the web server.",
   "version": "1.0.0-alpha1",
-  "author": "Marek Majkowski",
+  "author": "Bryce Kahle",
   "browser": {
-    "./lib/transport/driver/websocket": "./lib/transport/browser/websocket"
+    "./lib/transport/driver/websocket": "./lib/transport/browser/websocket",
+    "./lib/transport/driver/xhr": "./lib/transport/browser/abstract-xhr"
   },
   "bugs": {
     "url": "https://github.com/sockjs/sockjs-client/issues"
@@ -13,6 +14,10 @@
     {
       "name": "Bryce Kahle",
       "email": "bkahle at gmail.com"
+    },
+    {
+      "name": "Marek Majkowski",
+      "email": "deadbeef at popcount.org"
     }
   ],
   "dependencies": {

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/sockjs-client.git



More information about the Pkg-javascript-commits mailing list