[Pkg-javascript-commits] [sockjs-client] 101/350: utils re-org
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 ea6d035e3a42842fd3432ebb916b3a7ca69be483
Author: Bryce Kahle <bkahle at gmail.com>
Date: Thu Oct 9 20:16:56 2014 -0400
utils re-org
---
lib/facade.js | 8 +-
lib/iframe-bootstrap.js | 16 +-
lib/info-receiver.js | 5 +-
lib/main.js | 41 ++-
lib/shims.js | 72 +++++
lib/transport/jsonp-polling.js | 7 +-
lib/transport/lib/frames.js | 9 +
lib/transport/lib/iframe-utils.js | 13 +
lib/transport/lib/iframe.js | 3 +-
lib/transport/receiver/htmlfile.js | 3 +-
lib/transport/sender/xhr-cors.js | 9 +
lib/transport/xdr-streaming.js | 3 +-
lib/transport/xhr-polling.js | 5 +-
lib/transport/xhr-streaming.js | 5 +-
lib/utils.js | 548 -------------------------------------
lib/utils/escape.js | 49 ++++
lib/utils/event.js | 73 +++++
lib/utils/iframe.js | 127 +++++++++
lib/utils/log.js | 7 +
lib/utils/origin.js | 28 ++
lib/utils/random.js | 43 +++
tests/html/lib/testutils.js | 57 ++--
22 files changed, 533 insertions(+), 598 deletions(-)
diff --git a/lib/facade.js b/lib/facade.js
index 75e4904..c7494d5 100644
--- a/lib/facade.js
+++ b/lib/facade.js
@@ -1,6 +1,8 @@
'use strict';
-var utils = require('./utils');
+var frameDefs = require('./lib/frames')
+ , iframeUtils = require('./transport/lib/iframe-utils')
+ ;
function FacadeJS(transport) {
this._transport = transport;
@@ -9,10 +11,10 @@ function FacadeJS(transport) {
}
FacadeJS.prototype._transportClose = function (code, reason) {
- utils.postMessage('t', utils.closeFrame(code, reason));
+ iframeUtils.postMessage('t', frameDefs.close(code, reason));
};
FacadeJS.prototype._transportMessage = function (frame) {
- utils.postMessage('t', frame);
+ iframeUtils.postMessage('t', frame);
};
FacadeJS.prototype._send = function (data) {
this._transport.send(data);
diff --git a/lib/iframe-bootstrap.js b/lib/iframe-bootstrap.js
index 8046579..2c67654 100644
--- a/lib/iframe-bootstrap.js
+++ b/lib/iframe-bootstrap.js
@@ -4,6 +4,8 @@ var utils = require('./utils')
, JSON3 = require('json3')
, FacadeJS = require('./facade')
, InfoIframeFacade = require('./transport/facade/info-receiver-iframe')
+ , iframeUtils = require('./transports/lib/iframe-utils')
+ , loc = require('./polyfills/location')
;
module.exports = function (SockJS, facadeTransports) {
@@ -19,7 +21,7 @@ module.exports = function (SockJS, facadeTransports) {
SockJS.bootstrap_iframe = function() {
/* eslint-enable camelcase */
var facade;
- utils.currentWindowId = global.location.hash.slice(1);
+ iframeUtils.currentWindowId = global.location.hash.slice(1);
var onMessage = function(e) {
if (e.source !== parent) {
return;
@@ -34,7 +36,7 @@ module.exports = function (SockJS, facadeTransports) {
var windowId = e.data.slice(0, 8);
var type = e.data.slice(8, 9);
var data = e.data.slice(9);
- if (windowId !== utils.currentWindowId) {
+ if (windowId !== iframeUtils.currentWindowId) {
return;
}
switch(type) {
@@ -50,13 +52,9 @@ module.exports = function (SockJS, facadeTransports) {
' "' + version + '", the iframe:' +
' "' + SockJS.version + '".');
}
- if (!utils.flatUrl(transUrl) || !utils.flatUrl(baseUrl)) {
- utils.log('Only basic urls are supported in SockJS');
- return;
- }
- if (!utils.isSameOriginUrl(transUrl) ||
- !utils.isSameOriginUrl(baseUrl)) {
+ if (!utils.isSameOriginUrl(transUrl, loc.href) ||
+ !utils.isSameOriginUrl(baseUrl, loc.href)) {
utils.log('Can\'t connect to different domain from within an ' +
'iframe. (' + JSON3.stringify([global.location.href, transUrl, baseUrl]) +
')');
@@ -79,6 +77,6 @@ module.exports = function (SockJS, facadeTransports) {
utils.attachMessage(onMessage);
// Start
- utils.postMessage('s');
+ iframeUtils.postMessage('s');
};
};
diff --git a/lib/info-receiver.js b/lib/info-receiver.js
index 11ab0ae..9c542f1 100644
--- a/lib/info-receiver.js
+++ b/lib/info-receiver.js
@@ -20,10 +20,11 @@ function InfoReceiver(baseUrl) {
EventEmitter.call(this);
var AjaxObject = XHRFake;
+ // determine method of CORS support (if needed)
if (utils.isSameOriginUrl(baseUrl, loc.href)) {
- AjaxObject = XHRCors;
- } else if (utils.isXHRCorsCapable() === 1) {
AjaxObject = XHRLocal;
+ } else if (XHRCors.capable()) {
+ AjaxObject = XHRCors;
} else if (XDRPolling.enabled(baseUrl)) {
AjaxObject = XDR;
} else if (IframeTransport.enabled()) {
diff --git a/lib/main.js b/lib/main.js
index 55fcb64..f7f1411 100644
--- a/lib/main.js
+++ b/lib/main.js
@@ -4,7 +4,7 @@ require('./shims');
var u = require('url')
, util = require('util')
- , utils = require('./utils')
+ , random = require('./utils/random')
, SecurityError = require('./error/securityerror')
, InvalidAccessError = require('./error/invalidaccesserror')
, InvalidStateError = require('./error/invalidstateerror')
@@ -72,13 +72,23 @@ function SockJS(url, protocols, transportsWhitelist) {
// Step 6 - convert origin
this._origin = loc.origin ? loc.origin.toLowerCase() : null;
- // Step 7 - start connection in background
- this.url = parsedUrl.href;
- // if we don't have any path component, remove the trailing slash to make code easier
- if (parsedUrl.path === '/') {
- this.url = this.url.slice(0, -1);
+ // TODO do we want to allow relative urls? Spec says no
+
+ // strip port numbers for 80 and 443 cases
+ // Issue #74
+ if (!secure && parsedUrl.port === '80') {
+ parsedUrl.host = parsedUrl.port = null;
+ } else if (secure && parsedUrl.port === '443') {
+ parsedUrl.host = parsedUrl.port = null;
}
+ // remove the trailing slash
+ parsedUrl.pathname = parsedUrl.pathname.replace(/[/]+$/, '');
+
+ // store the sanitized url
+ this.url = url.format(parsedUrl);
+
+ // Step 7 - start connection in background
// obtain server info
// http://sockjs.github.io/sockjs-protocol/sockjs-protocol-0.3.3.html#section-26
this._ir = new InfoReceiver(this.url);
@@ -131,7 +141,7 @@ SockJS.prototype._receiveInfo = function(info, rtt) {
// establish a round-trip timeout (RTO) based on the
// round-trip time (RTT)
- this._rto = utils.countRTO(rtt);
+ this._rto = this.countRTO(rtt);
// allow server to override url used for the actual transport
this._transUrl = info.base_url ? info.base_url : this.url;
info.nullOrigin = !document.domain;
@@ -160,7 +170,7 @@ SockJS.prototype._connect = function() {
var timeoutMs = (this._rto * Transport.roundTrips) || 5000;
this._transportTimeoutId = setTimeout(this._transportTimeout.bind(this), timeoutMs);
- var transportUrl = this._transUrl + '/' + this._server + '/' + utils.randomString(8);
+ var transportUrl = this._transUrl + '/' + this._server + '/' + random.string(8);
var transport = new Transport(transportUrl, this._transUrl);
transport.onmessage = this._transportMessage.bind(this);
transport.onclose = this._transportClose.bind(this);
@@ -264,6 +274,21 @@ SockJS.prototype._close = function(code, reason, wasClean) {
}.bind(this));
};
+// See: http://www.erg.abdn.ac.uk/~gerrit/dccp/notes/ccid2/rto_estimator/
+// and RFC 2988.
+SockJS.prototype.countRTO = function (rtt) {
+ // In a local environment, when using IE8/9 and the `jsonp-polling`
+ // transport the time needed to establish a connection (the time that pass
+ // from the opening of the transport to the call of `_dispatchOpen`) is
+ // around 200msec (the lower bound used in the article above) and this
+ // causes spurious timeouts. For this reason we calculate a value slightly
+ // larger than that used in the article.
+ if (rtt > 100) {
+ return 4 * rtt; // rto > 400msec
+ }
+ return 300 + rtt; // 300msec < rto <= 400msec
+};
+
module.exports = function (availableTransports) {
transports = require('./transports')(availableTransports);
return SockJS;
diff --git a/lib/shims.js b/lib/shims.js
index cd4f72f..b8e980d 100644
--- a/lib/shims.js
+++ b/lib/shims.js
@@ -31,3 +31,75 @@ if (!Function.prototype.bind) {
return Bound;
};
}
+
+if (!Array.isArray) {
+ Array.isArray = function(arg) {
+ return Object.prototype.toString.call(arg) === '[object Array]';
+ };
+}
+
+// Production steps of ECMA-262, Edition 5, 15.4.4.14
+// Reference: http://es5.github.io/#x15.4.4.14
+if (!Array.prototype.indexOf) {
+ Array.prototype.indexOf = function(searchElement, fromIndex) {
+
+ var k;
+
+ // 1. Let O be the result of calling ToObject passing
+ // the this value as the argument.
+ if (this == null) {
+ throw new TypeError('"this" is null or not defined');
+ }
+
+ var O = Object(this);
+
+ // 2. Let lenValue be the result of calling the Get
+ // internal method of O with the argument "length".
+ // 3. Let len be ToUint32(lenValue).
+ var len = O.length >>> 0;
+
+ // 4. If len is 0, return -1.
+ if (len === 0) {
+ return -1;
+ }
+
+ // 5. If argument fromIndex was passed let n be
+ // ToInteger(fromIndex); else let n be 0.
+ var n = +fromIndex || 0;
+
+ if (Math.abs(n) === Infinity) {
+ n = 0;
+ }
+
+ // 6. If n >= len, return -1.
+ if (n >= len) {
+ return -1;
+ }
+
+ // 7. If n >= 0, then Let k be n.
+ // 8. Else, n<0, Let k be len - abs(n).
+ // If k is less than 0, then let k be 0.
+ k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
+
+ // 9. Repeat, while k < len
+ while (k < len) {
+ // a. Let Pk be ToString(k).
+ // This is implicit for LHS operands of the in operator
+ // b. Let kPresent be the result of calling the
+ // HasProperty internal method of O with argument Pk.
+ // This step can be combined with c
+ // c. If kPresent is true, then
+ // i. Let elementK be the result of calling the Get
+ // internal method of O with the argument ToString(k).
+ // ii. Let same be the result of applying the
+ // Strict Equality Comparison Algorithm to
+ // searchElement and elementK.
+ // iii. If same is true, return k.
+ if (k in O && O[k] === searchElement) {
+ return k;
+ }
+ k++;
+ }
+ return -1;
+ };
+}
diff --git a/lib/transport/jsonp-polling.js b/lib/transport/jsonp-polling.js
index 492e872..5320986 100644
--- a/lib/transport/jsonp-polling.js
+++ b/lib/transport/jsonp-polling.js
@@ -10,13 +10,14 @@
var util = require('util')
, utils = require('../utils')
+ , random = require('../utils/random')
, BufferedSender = require('./lib/buffered-sender')
, TransportMessageEvent = require('./lib/trans-message-event')
;
// Abstract away code that handles global namespace pollution.
var jsonPReceiverWrapper = function(url, constructReceiver, userCallback) {
- var id = 'a' + utils.randomString(6);
+ var id = 'a' + random.string(6);
var urlId = url + '?c=' + encodeURIComponent(utils.WPrefix + '.' + id);
// Unfortunately it is not possible to abort loading of the
@@ -72,7 +73,7 @@ function jsonPGenericSender(url, payload, callback) {
form.appendChild(area);
document.body.appendChild(form);
}
- var id = 'a' + utils.randomString(8);
+ var id = 'a' + random.string(8);
form.target = id;
form.action = url + '/jsonp_send?i=' + id;
@@ -150,7 +151,7 @@ function jsonPGenericReceiver(url, callback) {
var loadedOkay = false;
var errorTimer = null;
- script.id = 'a' + utils.randomString(8);
+ script.id = 'a' + random.string(8);
script.src = url;
script.type = 'text/javascript';
script.charset = 'UTF-8';
diff --git a/lib/transport/lib/frames.js b/lib/transport/lib/frames.js
new file mode 100644
index 0000000..c0bbd90
--- /dev/null
+++ b/lib/transport/lib/frames.js
@@ -0,0 +1,9 @@
+'use strict';
+
+var JSON3 = require('JSON3');
+
+module.exports = {
+ close: function (code, reason) {
+ return 'c' + JSON3.stringify([code, reason]);
+ }
+};
diff --git a/lib/transport/lib/iframe-utils.js b/lib/transport/lib/iframe-utils.js
new file mode 100644
index 0000000..b724cb3
--- /dev/null
+++ b/lib/transport/lib/iframe-utils.js
@@ -0,0 +1,13 @@
+'use strict';
+
+// currentWindowId comes from SockJS.bootstrap_iframe()
+module.exports = {
+ currentWindowId: null
+, postMessage: function (type, data) {
+ if (global.parent !== global) {
+ global.parent.postMessage(this.currentWindowId + type + (data || ''), '*');
+ } else {
+ console.log('Cannot postMessage, no parent window.', type, data);
+ }
+ }
+};
diff --git a/lib/transport/lib/iframe.js b/lib/transport/lib/iframe.js
index be0ba00..c278f10 100644
--- a/lib/transport/lib/iframe.js
+++ b/lib/transport/lib/iframe.js
@@ -14,6 +14,7 @@ var util = require('util')
, TransportMessageEvent = require('./trans-message-event')
, JSON3 = require('json3')
, utils = require('../../utils')
+ , random = require('../../utils/random')
;
function IframeTransport(transport, transUrl, baseUrl) {
@@ -30,7 +31,7 @@ function IframeTransport(transport, transUrl, baseUrl) {
// if (this.ri._devel) {
// iframeUrl += '?t=' + Date.now();
// }
- this.windowId = utils.randomString(8);
+ this.windowId = random.string(8);
iframeUrl += '#' + this.windowId;
this.iframeObj = utils.createIframe(iframeUrl, function(r) {
diff --git a/lib/transport/receiver/htmlfile.js b/lib/transport/receiver/htmlfile.js
index 1727549..e23dc54 100644
--- a/lib/transport/receiver/htmlfile.js
+++ b/lib/transport/receiver/htmlfile.js
@@ -4,6 +4,7 @@ var util = require('util')
, utils = require('../../utils')
, SimpleEvent = require('../../simpleevent')
, EventTarget = require('../../polyfills/eventtarget')
+ , random = require('../../utils/random')
;
var _isIeHtmlfileCapable;
@@ -26,7 +27,7 @@ function HtmlfileReceiver(url) {
var self = this;
utils.polluteGlobalNamespace();
- this.id = 'a' + utils.randomString(6);
+ this.id = 'a' + random.string(6);
url += ((url.indexOf('?') === -1) ? '?' : '&') +
'c=' + decodeURIComponent(utils.WPrefix + '.' + this.id);
diff --git a/lib/transport/sender/xhr-cors.js b/lib/transport/sender/xhr-cors.js
index 04d0052..e98d658 100644
--- a/lib/transport/sender/xhr-cors.js
+++ b/lib/transport/sender/xhr-cors.js
@@ -15,4 +15,13 @@ function XHRCorsObject(method, url, payload, opts) {
util.inherits(XHRCorsObject, AbstractXHRObject);
+XHRCorsObject.capable = function () {
+ try {
+ if (global.XMLHttpRequest && 'withCredentials' in new XMLHttpRequest()) {
+ return true;
+ }
+ } catch (ignored) {}
+ return false;
+};
+
module.exports = XHRCorsObject;
diff --git a/lib/transport/xdr-streaming.js b/lib/transport/xdr-streaming.js
index 260a70c..2c934de 100644
--- a/lib/transport/xdr-streaming.js
+++ b/lib/transport/xdr-streaming.js
@@ -5,6 +5,7 @@ var util = require('util')
, XhrReceiver = require('./receiver/xhr')
, XDRObject = require('./sender/xdr')
, utils = require('../utils')
+ , loc = require('../polyfills/location')
;
// According to:
@@ -23,7 +24,7 @@ XdrStreamingTransport.enabled = function(url, info) {
}
// IE 8/9 if the request target uses the same scheme - #79
return !!(global.XDomainRequest && global.document &&
- global.document.domain && utils.isSameOriginScheme(url));
+ global.document.domain && utils.isSameOriginScheme(url, loc.href));
};
XdrStreamingTransport.transportName = 'xdr-streaming';
diff --git a/lib/transport/xhr-polling.js b/lib/transport/xhr-polling.js
index d4822c5..355b12e 100644
--- a/lib/transport/xhr-polling.js
+++ b/lib/transport/xhr-polling.js
@@ -5,6 +5,7 @@ var util = require('util')
, XhrReceiver = require('./receiver/xhr')
, XHRCorsObject = require('./sender/xhr-cors')
, utils = require('../utils')
+ , loc = require('../polyfills/location')
;
function XhrPollingTransport(ri, transUrl) {
@@ -17,10 +18,10 @@ XhrPollingTransport.enabled = function(url, info) {
if (info.nullOrigin) {
return false;
}
- if (global.XMLHttpRequest && utils.isSameOriginUrl(url)) {
+ if (global.XMLHttpRequest && utils.isSameOriginUrl(url, loc.href)) {
return true;
}
- return utils.isXHRCorsCapable() === 1;
+ return XHRCorsObject.capable();
};
XhrPollingTransport.transportName = 'xhr-polling';
diff --git a/lib/transport/xhr-streaming.js b/lib/transport/xhr-streaming.js
index c54809e..630b979 100644
--- a/lib/transport/xhr-streaming.js
+++ b/lib/transport/xhr-streaming.js
@@ -5,6 +5,7 @@ var util = require('util')
, XhrReceiver = require('./receiver/xhr')
, XHRCorsObject = require('./sender/xhr-cors')
, utils = require('../utils')
+ , loc = require('../polyfills/location')
;
function XhrStreamingTransport(ri, transUrl) {
@@ -21,11 +22,11 @@ XhrStreamingTransport.enabled = function(url, info) {
if (/opera/i.test(global.navigator.userAgent)) {
return false;
}
- if (global.XMLHttpRequest && utils.isSameOriginUrl(url)) {
+ if (global.XMLHttpRequest && utils.isSameOriginUrl(url, loc.href)) {
return true;
}
- return utils.isXHRCorsCapable() === 1;
+ return XHRCorsObject.capable();
};
XhrStreamingTransport.transportName = 'xhr-streaming';
diff --git a/lib/utils.js b/lib/utils.js
deleted file mode 100644
index 8646a08..0000000
--- a/lib/utils.js
+++ /dev/null
@@ -1,548 +0,0 @@
-'use strict';
-
-var JSON3 = require('json3');
-var IframeTransport = require('./transport/lib/iframe');
-var utils = {};
-
-var getRandomBytes;
-if (global && global.crypto && global.crypto.getRandomValues) {
- getRandomBytes = function (length) {
- var bytes = new Uint8Array(length);
- global.crypto.getRandomValues(bytes);
- return bytes;
- };
-} else {
- getRandomBytes = function (length) {
- var bytes = new Uint8Array(length);
- for (var i = 0; i < length; i++) {
- bytes[i] = Math.floor(Math.random() * 256);
- }
- return bytes;
- };
-}
-
-// This string has length 32, a power of 2, so the modulus doesn't introduce a
-// bias.
-var _randomStringChars = 'abcdefghijklmnopqrstuvwxyz012345';
-utils.randomString = function(length) {
- var max = _randomStringChars.length;
- var bytes = getRandomBytes(length);
- var ret = [];
- for (var i = 0; i < length; i++) {
- ret.push( _randomStringChars[bytes[i] % max] );
- }
- return ret.join('');
-};
-utils.randomNumber = function(max) {
- return Math.floor(Math.random() * max);
-};
-utils.randomNumberString = function(max) {
- var t = ('' + (max - 1)).length;
- var p = new Array(t + 1).join('0');
- return (p + utils.randomNumber(max)).slice(-t);
-};
-
-utils.getOrigin = function(url) {
- if (url.match(/^file:\/\//)) {
- // no origin when using file protocol
- return null;
- }
-
- var parts = url.split('/');
- var protocol = parts[0];
- var host = parts[2];
- var atSignIndex = host.lastIndexOf('@');
- var hostname;
- var port;
-
- if (~atSignIndex) {
- host = host.slice(atSignIndex + 1);
- }
-
- parts = host.split(':');
- hostname = parts[0];
- port = parts[1];
-
- if (!port) {
- port = (protocol === 'https:') ? 443 : 80;
- }
-
- return protocol + '//' + hostname + ':' + port;
-};
-
-utils.isSameOriginUrl = function(urlA, urlB) {
- // location.origin would do, but it's not always available.
- if (!urlB) {
- urlB = global.location.href;
- }
- return utils.getOrigin(urlA) === utils.getOrigin(urlB);
-};
-
-utils.isSameOriginScheme = function(urlA, urlB) {
- if (!urlB) {
- urlB = global.location.href;
- }
-
- return (urlA.split(':')[0] === urlB.split(':')[0]);
-};
-
-utils.getParentDomain = function(url) {
- // ipv4 ip address
- if (/^[0-9.]*$/.test(url)) {
- return url;
- }
- // ipv6 ip address
- if (/^\[/.test(url)) {
- return url;
- }
- // no dots
- if (!(/[.]/.test(url))) {
- return url;
- }
-
- var parts = url.split('.').slice(1);
- return parts.join('.');
-};
-
-utils.objectExtend = function(dst, src) {
- for (var k in src) {
- if (src.hasOwnProperty(k)) {
- dst[k] = src[k];
- }
- }
- return dst;
-};
-
-var WPrefix = utils.WPrefix = '_jp';
-
-utils.polluteGlobalNamespace = function() {
- if (!(WPrefix in global)) {
- global[WPrefix] = {};
- }
-};
-
-utils.closeFrame = function (code, reason) {
- return 'c' + JSON3.stringify([code, reason]);
-};
-
-utils.userSetCode = function (code) {
- return code === 1000 || (code >= 3000 && code <= 4999);
-};
-
-// See: http://www.erg.abdn.ac.uk/~gerrit/dccp/notes/ccid2/rto_estimator/
-// and RFC 2988.
-utils.countRTO = function (rtt) {
- // In a local environment, when using IE8/9 and the `jsonp-polling`
- // transport the time needed to establish a connection (the time that pass
- // from the opening of the transport to the call of `_dispatchOpen`) is
- // around 200msec (the lower bound used in the article above) and this
- // causes spurious timeouts. For this reason we calculate a value slightly
- // larger than that used in the article.
- if (rtt > 100) {
- return 4 * rtt; // rto > 400msec
- }
- return 300 + rtt; // 300msec < rto <= 400msec
-};
-
-utils.log = function() {
- if (window.console && console.log && console.log.apply) {
- console.log.apply(console, arguments);
- }
-};
-
-utils.bind = function(fun, that) {
- if (fun.bind) {
- return fun.bind(that);
- } else {
- return function() {
- return fun.apply(that, arguments);
- };
- }
-};
-
-utils.flatUrl = function(url) {
- return url.indexOf('?') === -1 && url.indexOf('#') === -1;
-};
-
-utils.amendUrl = function(url) {
- var dl = document.location;
- if (!url) {
- throw new Error('Wrong url for SockJS');
- }
- if (!utils.flatUrl(url)) {
- throw new Error('Only basic urls are supported in SockJS');
- }
-
- // '//abc' --> 'http://abc'
- if (url.indexOf('//') === 0) {
- url = dl.protocol + url;
- }
- // '/abc' --> 'http://localhost:1234/abc'
- if (url.indexOf('/') === 0) {
- url = dl.protocol + '//' + dl.host + url;
- }
- // strip trailing slashes
- url = url.replace(/[/]+$/,'');
-
- // We have a full url here, with proto and host. For some browsers
- // http://localhost:80/ is not in the same origin as http://localhost/
- // Remove explicit :80 or :443 in such cases. See #74
- var parts = url.split('/');
- if ((parts[0] === 'http:' && /:80$/.test(parts[2])) ||
- (parts[0] === 'https:' && /:443$/.test(parts[2]))) {
- parts[2] = parts[2].replace(/:(80|443)$/, '');
- }
- url = parts.join('/');
- return url;
-};
-
-// IE doesn't support [].indexOf.
-utils.arrIndexOf = function(arr, obj){
- for(var i = 0; i < arr.length; i++){
- if(arr[i] === obj){
- return i;
- }
- }
- return -1;
-};
-
-utils.arrSkip = function(arr, obj) {
- var idx = utils.arrIndexOf(arr, obj);
- if (idx === -1) {
- return arr.slice();
- } else {
- var dst = arr.slice(0, idx);
- return dst.concat(arr.slice(idx + 1));
- }
-};
-
-utils.isArray = Array.isArray || function(arg) {
- return Object.prototype.toString.call(arg) === '[object Array]';
-};
-
-// Chars worth escaping, as defined by Douglas Crockford:
-// https://github.com/douglascrockford/JSON-js/blob/47a9882cddeb1e8529e07af9736218075372b8ac/json2.js#L196
-var jsonEscapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
- jsonLookup = {
-'\u0000':'\\u0000','\u0001':'\\u0001','\u0002':'\\u0002','\u0003':'\\u0003',
-'\u0004':'\\u0004','\u0005':'\\u0005','\u0006':'\\u0006','\u0007':'\\u0007',
-'\b':'\\b','\t':'\\t','\n':'\\n','\u000b':'\\u000b','\f':'\\f','\r':'\\r',
-'\u000e':'\\u000e','\u000f':'\\u000f','\u0010':'\\u0010','\u0011':'\\u0011',
-'\u0012':'\\u0012','\u0013':'\\u0013','\u0014':'\\u0014','\u0015':'\\u0015',
-'\u0016':'\\u0016','\u0017':'\\u0017','\u0018':'\\u0018','\u0019':'\\u0019',
-'\u001a':'\\u001a','\u001b':'\\u001b','\u001c':'\\u001c','\u001d':'\\u001d',
-'\u001e':'\\u001e','\u001f':'\\u001f','\'':'\\\'','\\':'\\\\',
-'\u007f':'\\u007f','\u0080':'\\u0080','\u0081':'\\u0081','\u0082':'\\u0082',
-'\u0083':'\\u0083','\u0084':'\\u0084','\u0085':'\\u0085','\u0086':'\\u0086',
-'\u0087':'\\u0087','\u0088':'\\u0088','\u0089':'\\u0089','\u008a':'\\u008a',
-'\u008b':'\\u008b','\u008c':'\\u008c','\u008d':'\\u008d','\u008e':'\\u008e',
-'\u008f':'\\u008f','\u0090':'\\u0090','\u0091':'\\u0091','\u0092':'\\u0092',
-'\u0093':'\\u0093','\u0094':'\\u0094','\u0095':'\\u0095','\u0096':'\\u0096',
-'\u0097':'\\u0097','\u0098':'\\u0098','\u0099':'\\u0099','\u009a':'\\u009a',
-'\u009b':'\\u009b','\u009c':'\\u009c','\u009d':'\\u009d','\u009e':'\\u009e',
-'\u009f':'\\u009f','\u00ad':'\\u00ad','\u0600':'\\u0600','\u0601':'\\u0601',
-'\u0602':'\\u0602','\u0603':'\\u0603','\u0604':'\\u0604','\u070f':'\\u070f',
-'\u17b4':'\\u17b4','\u17b5':'\\u17b5','\u200c':'\\u200c','\u200d':'\\u200d',
-'\u200e':'\\u200e','\u200f':'\\u200f','\u2028':'\\u2028','\u2029':'\\u2029',
-'\u202a':'\\u202a','\u202b':'\\u202b','\u202c':'\\u202c','\u202d':'\\u202d',
-'\u202e':'\\u202e','\u202f':'\\u202f','\u2060':'\\u2060','\u2061':'\\u2061',
-'\u2062':'\\u2062','\u2063':'\\u2063','\u2064':'\\u2064','\u2065':'\\u2065',
-'\u2066':'\\u2066','\u2067':'\\u2067','\u2068':'\\u2068','\u2069':'\\u2069',
-'\u206a':'\\u206a','\u206b':'\\u206b','\u206c':'\\u206c','\u206d':'\\u206d',
-'\u206e':'\\u206e','\u206f':'\\u206f','\ufeff':'\\ufeff','\ufff0':'\\ufff0',
-'\ufff1':'\\ufff1','\ufff2':'\\ufff2','\ufff3':'\\ufff3','\ufff4':'\\ufff4',
-'\ufff5':'\\ufff5','\ufff6':'\\ufff6','\ufff7':'\\ufff7','\ufff8':'\\ufff8',
-'\ufff9':'\\ufff9','\ufffa':'\\ufffa','\ufffb':'\\ufffb','\ufffc':'\\ufffc',
-'\ufffd':'\\ufffd','\ufffe':'\\ufffe','\uffff':'\\uffff'};
-
-// Some extra characters that Chrome gets wrong, and substitutes with
-// something else on the wire.
-var extraEscapable = /[\x00-\x1f\ud800-\udfff\ufffe\uffff\u0300-\u0333\u033d-\u0346\u034a-\u034c\u0350-\u0352\u0357-\u0358\u035c-\u0362\u0374\u037e\u0387\u0591-\u05af\u05c4\u0610-\u0617\u0653-\u0654\u0657-\u065b\u065d-\u065e\u06df-\u06e2\u06eb-\u06ec\u0730\u0732-\u0733\u0735-\u0736\u073a\u073d\u073f-\u0741\u0743\u0745\u0747\u07eb-\u07f1\u0951\u0958-\u095f\u09dc-\u09dd\u09df\u0a33\u0a36\u0a59-\u0a5b\u0a5e\u0b5c-\u0b5d\u0e38-\u0e39\u0f43\u0f4d\u0f52\u0f57\u0f5c\u0f69\u0f72-\u0f76\u0f78\u0f [...]
- extraLookup;
-
-// JSON Quote string. Use native implementation when possible.
-var quoteJSON = (JSON3 && JSON3.stringify) || function(string) {
- jsonEscapable.lastIndex = 0;
- if (jsonEscapable.test(string)) {
- string = string.replace(jsonEscapable, function(a) {
- return jsonLookup[a];
- });
- }
- return '"' + string + '"';
-};
-
-// This may be quite slow, so let's delay until user actually uses bad
-// characters.
-var unrollLookup = function(escapable) {
- var i;
- var unrolled = {};
- var c = [];
- for(i = 0; i < 65536; i++) {
- c.push( String.fromCharCode(i) );
- }
- escapable.lastIndex = 0;
- c.join('').replace(escapable, function (a) {
- unrolled[ a ] = '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
- return '';
- });
- escapable.lastIndex = 0;
- return unrolled;
-};
-
-// Quote string, also taking care of unicode characters that browsers
-// often break. Especially, take care of unicode surrogates:
-// http://en.wikipedia.org/wiki/Mapping_of_Unicode_characters#Surrogates
-utils.quote = function(string) {
- var quoted = quoteJSON(string);
-
- // In most cases this should be very fast and good enough.
- extraEscapable.lastIndex = 0;
- if(!extraEscapable.test(quoted)) {
- return quoted;
- }
-
- if (!extraLookup) {
- extraLookup = unrollLookup(extraEscapable);
- }
-
- return quoted.replace(extraEscapable, function(a) {
- return extraLookup[a];
- });
-};
-
-// 1. Is natively via XHR
-// 2. Is natively via XDR
-// 3. Nope, but postMessage is there so it should work via the Iframe.
-// 4. Nope, sorry.
-utils.isXHRCorsCapable = function() {
- try {
- if (global.XMLHttpRequest && 'withCredentials' in new XMLHttpRequest()) {
- return 1;
- }
- } catch (ignored) {}
- // XDomainRequest doesn't work if page is served from file://
- if (global.XDomainRequest && global.document && global.document.domain) {
- return 2;
- }
- if (IframeTransport.enabled()) {
- return 3;
- }
- return 4;
-};
-
-// May be used by htmlfile jsonp and transports.
-var MPrefix = '_sockjs_global';
-utils.createHook = function() {
- var windowId = 'a' + utils.randomString(8);
- if (!(MPrefix in window)) {
- var map = {};
- window[MPrefix] = function(windowId) {
- if (!(windowId in map)) {
- map[windowId] = {
- id: windowId,
- del: function() {delete map[windowId];}
- };
- }
- return map[windowId];
- };
- }
- return window[MPrefix](windowId);
-};
-
-utils.attachMessage = function(listener) {
- utils.attachEvent('message', listener);
-};
-utils.attachEvent = function(event, listener) {
- if (typeof global.addEventListener !== 'undefined') {
- global.addEventListener(event, listener, false);
- } else {
- // IE quirks.
- // According to: http://stevesouders.com/misc/test-postmessage.php
- // the message gets delivered only to 'document', not 'window'.
- global.document.attachEvent('on' + event, listener);
- // I get 'window' for ie8.
- global.attachEvent('on' + event, listener);
- }
-};
-
-utils.detachMessage = function(listener) {
- utils.detachEvent('message', listener);
-};
-utils.detachEvent = function(event, listener) {
- if (typeof global.addEventListener !== 'undefined') {
- global.removeEventListener(event, listener, false);
- } else {
- document.detachEvent('on' + event, listener);
- global.detachEvent('on' + event, listener);
- }
-};
-
-
-var onUnload = {};
-// Things registered after beforeunload are to be called immediately.
-var afterUnload = false;
-
-var triggerUnloadCallbacks = function() {
- for(var ref in onUnload) {
- onUnload[ref]();
- delete onUnload[ref];
- }
-};
-
-var unloadTriggered = function() {
- if (afterUnload) {
- return;
- }
- afterUnload = true;
- triggerUnloadCallbacks();
-};
-
-// 'unload' alone is not reliable in opera within an iframe, but we
-// can't use `beforeunload` as IE fires it on javascript: links.
-
-// TODO see if we need to uncomment this
-//utils.attachEvent('unload', unloadTriggered);
-
-utils.unloadAdd = function(listener) {
- var ref = utils.randomString(8);
- onUnload[ref] = listener;
- if (afterUnload) {
- process.nextTick(triggerUnloadCallbacks);
- }
- return ref;
-};
-utils.unloadDel = function(ref) {
- if (ref in onUnload) {
- delete onUnload[ref];
- }
-};
-
-
-utils.createIframe = function (iframeUrl, errorCallback) {
- var iframe = document.createElement('iframe');
- var tref, unloadRef;
- var unattach = function() {
- clearTimeout(tref);
- // Explorer had problems with that.
- try {iframe.onload = null;} catch (x) {}
- iframe.onerror = null;
- };
- var cleanup = function() {
- if (iframe) {
- unattach();
- // This timeout makes chrome fire onbeforeunload event
- // within iframe. Without the timeout it goes straight to
- // onunload.
- setTimeout(function() {
- if(iframe) {
- iframe.parentNode.removeChild(iframe);
- }
- iframe = null;
- }, 0);
- utils.unloadDel(unloadRef);
- }
- };
- var onerror = function(r) {
- if (iframe) {
- cleanup();
- errorCallback(r);
- }
- };
- var post = function(msg, origin) {
- try {
- // When the iframe is not loaded, IE raises an exception
- // on 'contentWindow'.
- if (iframe && iframe.contentWindow) {
- setTimeout(function() {
- iframe.contentWindow.postMessage(msg, origin);
- }, 0);
- }
- } catch (x) {}
- };
-
- iframe.src = iframeUrl;
- iframe.style.display = 'none';
- iframe.style.position = 'absolute';
- iframe.onerror = function(){onerror('onerror');};
- iframe.onload = function() {
- // `onload` is triggered before scripts on the iframe are
- // executed. Give it few seconds to actually load stuff.
- clearTimeout(tref);
- tref = setTimeout(function(){onerror('onload timeout');}, 2000);
- };
- document.body.appendChild(iframe);
- tref = setTimeout(function(){onerror('timeout');}, 15000);
- unloadRef = utils.unloadAdd(cleanup);
- return {
- post: post,
- cleanup: cleanup,
- loaded: unattach
- };
-};
-
-/* jshint undef: false, newcap: false */
-/* eslint no-undef: [0], new-cap: [0] */
-utils.createHtmlfile = function (iframeUrl, errorCallback) {
- var doc = new ActiveXObject('htmlfile');
- var tref, unloadRef;
- var iframe;
- var unattach = function() {
- clearTimeout(tref);
- };
- var cleanup = function() {
- if (doc) {
- unattach();
- utils.unloadDel(unloadRef);
- iframe.parentNode.removeChild(iframe);
- iframe = doc = null;
- CollectGarbage();
- }
- };
- var onerror = function(r) {
- if (doc) {
- cleanup();
- errorCallback(r);
- }
- };
- var post = function(msg, origin) {
- try {
- // When the iframe is not loaded, IE raises an exception
- // on 'contentWindow'.
- if (iframe && iframe.contentWindow) {
- setTimeout(function() {
- iframe.contentWindow.postMessage(msg, origin);
- }, 0);
- }
- } catch (x) {}
- };
-
- doc.open();
- doc.write('<html><s' + 'cript>' +
- 'document.domain="' + document.domain + '";' +
- '</s' + 'cript></html>');
- doc.close();
- doc.parentWindow[utils.WPrefix] = window[utils.WPrefix];
- var c = doc.createElement('div');
- doc.body.appendChild(c);
- iframe = doc.createElement('iframe');
- c.appendChild(iframe);
- iframe.src = iframeUrl;
- tref = setTimeout(function(){onerror('timeout');}, 15000);
- unloadRef = utils.unloadAdd(cleanup);
- return {
- post: post,
- cleanup: cleanup,
- loaded: unattach
- };
-};
-
-// curr_window_id comes from SockJS.bootstrap_iframe()
-utils.postMessage = function (type, data) {
- if (parent !== window) {
- parent.postMessage(utils.currentWindowId + type + (data || ''), '*');
- } else {
- utils.log("Can't postMessage, no parent window.", type, data);
- }
-};
-
-module.exports = utils;
diff --git a/lib/utils/escape.js b/lib/utils/escape.js
new file mode 100644
index 0000000..1ecc8b6
--- /dev/null
+++ b/lib/utils/escape.js
@@ -0,0 +1,49 @@
+'use strict';
+
+var JSON3 = require('JSON3');
+
+// Some extra characters that Chrome gets wrong, and substitutes with
+// something else on the wire.
+var extraEscapable = /[\x00-\x1f\ud800-\udfff\ufffe\uffff\u0300-\u0333\u033d-\u0346\u034a-\u034c\u0350-\u0352\u0357-\u0358\u035c-\u0362\u0374\u037e\u0387\u0591-\u05af\u05c4\u0610-\u0617\u0653-\u0654\u0657-\u065b\u065d-\u065e\u06df-\u06e2\u06eb-\u06ec\u0730\u0732-\u0733\u0735-\u0736\u073a\u073d\u073f-\u0741\u0743\u0745\u0747\u07eb-\u07f1\u0951\u0958-\u095f\u09dc-\u09dd\u09df\u0a33\u0a36\u0a59-\u0a5b\u0a5e\u0b5c-\u0b5d\u0e38-\u0e39\u0f43\u0f4d\u0f52\u0f57\u0f5c\u0f69\u0f72-\u0f76\u0f78\u0f [...]
+ extraLookup;
+
+// This may be quite slow, so let's delay until user actually uses bad
+// characters.
+var unrollLookup = function(escapable) {
+ var i;
+ var unrolled = {};
+ var c = [];
+ for(i = 0; i < 65536; i++) {
+ c.push( String.fromCharCode(i) );
+ }
+ escapable.lastIndex = 0;
+ c.join('').replace(escapable, function (a) {
+ unrolled[ a ] = '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ return '';
+ });
+ escapable.lastIndex = 0;
+ return unrolled;
+};
+
+// Quote string, also taking care of unicode characters that browsers
+// often break. Especially, take care of unicode surrogates:
+// http://en.wikipedia.org/wiki/Mapping_of_Unicode_characters#Surrogates
+module.exports = {
+ quote: function(string) {
+ var quoted = JSON3.stringify(string);
+
+ // In most cases this should be very fast and good enough.
+ extraEscapable.lastIndex = 0;
+ if(!extraEscapable.test(quoted)) {
+ return quoted;
+ }
+
+ if (!extraLookup) {
+ extraLookup = unrollLookup(extraEscapable);
+ }
+
+ return quoted.replace(extraEscapable, function(a) {
+ return extraLookup[a];
+ });
+ }
+};
diff --git a/lib/utils/event.js b/lib/utils/event.js
new file mode 100644
index 0000000..cf2cec9
--- /dev/null
+++ b/lib/utils/event.js
@@ -0,0 +1,73 @@
+'use strict';
+
+module.exports = {
+ attachMessage: function(listener) {
+ this.attachEvent('message', listener);
+ }
+
+, attachEvent: function(event, listener) {
+ if (typeof global.addEventListener !== 'undefined') {
+ global.addEventListener(event, listener, false);
+ } else {
+ // IE quirks.
+ // According to: http://stevesouders.com/misc/test-postmessage.php
+ // the message gets delivered only to 'document', not 'window'.
+ global.document.attachEvent('on' + event, listener);
+ // I get 'window' for ie8.
+ global.attachEvent('on' + event, listener);
+ }
+ }
+
+, detachMessage: function(listener) {
+ this.detachEvent('message', listener);
+ }
+
+, detachEvent: function(event, listener) {
+ if (typeof global.addEventListener !== 'undefined') {
+ global.removeEventListener(event, listener, false);
+ } else {
+ global.document.detachEvent('on' + event, listener);
+ global.detachEvent('on' + event, listener);
+ }
+ }
+};
+
+
+var onUnload = {};
+// Things registered after beforeunload are to be called immediately.
+var afterUnload = false;
+
+var triggerUnloadCallbacks = function() {
+ for(var ref in onUnload) {
+ onUnload[ref]();
+ delete onUnload[ref];
+ }
+};
+
+var unloadTriggered = function() {
+ if (afterUnload) {
+ return;
+ }
+ afterUnload = true;
+ triggerUnloadCallbacks();
+};
+
+// 'unload' alone is not reliable in opera within an iframe, but we
+// can't use `beforeunload` as IE fires it on javascript: links.
+
+// TODO see if we need to uncomment this
+//utils.attachEvent('unload', unloadTriggered);
+
+utils.unloadAdd = function(listener) {
+ var ref = utils.randomString(8);
+ onUnload[ref] = listener;
+ if (afterUnload) {
+ process.nextTick(triggerUnloadCallbacks);
+ }
+ return ref;
+};
+utils.unloadDel = function(ref) {
+ if (ref in onUnload) {
+ delete onUnload[ref];
+ }
+};
diff --git a/lib/utils/iframe.js b/lib/utils/iframe.js
new file mode 100644
index 0000000..d5fad06
--- /dev/null
+++ b/lib/utils/iframe.js
@@ -0,0 +1,127 @@
+'use strict';
+
+var WPrefix = utils.WPrefix = '_jp';
+
+utils.polluteGlobalNamespace = function() {
+ if (!(WPrefix in global)) {
+ global[WPrefix] = {};
+ }
+};
+
+utils.createIframe = function (iframeUrl, errorCallback) {
+ var iframe = document.createElement('iframe');
+ var tref, unloadRef;
+ var unattach = function() {
+ clearTimeout(tref);
+ // Explorer had problems with that.
+ try {iframe.onload = null;} catch (x) {}
+ iframe.onerror = null;
+ };
+ var cleanup = function() {
+ if (iframe) {
+ unattach();
+ // This timeout makes chrome fire onbeforeunload event
+ // within iframe. Without the timeout it goes straight to
+ // onunload.
+ setTimeout(function() {
+ if(iframe) {
+ iframe.parentNode.removeChild(iframe);
+ }
+ iframe = null;
+ }, 0);
+ utils.unloadDel(unloadRef);
+ }
+ };
+ var onerror = function(r) {
+ if (iframe) {
+ cleanup();
+ errorCallback(r);
+ }
+ };
+ var post = function(msg, origin) {
+ try {
+ // When the iframe is not loaded, IE raises an exception
+ // on 'contentWindow'.
+ if (iframe && iframe.contentWindow) {
+ setTimeout(function() {
+ iframe.contentWindow.postMessage(msg, origin);
+ }, 0);
+ }
+ } catch (x) {}
+ };
+
+ iframe.src = iframeUrl;
+ iframe.style.display = 'none';
+ iframe.style.position = 'absolute';
+ iframe.onerror = function(){onerror('onerror');};
+ iframe.onload = function() {
+ // `onload` is triggered before scripts on the iframe are
+ // executed. Give it few seconds to actually load stuff.
+ clearTimeout(tref);
+ tref = setTimeout(function(){onerror('onload timeout');}, 2000);
+ };
+ document.body.appendChild(iframe);
+ tref = setTimeout(function(){onerror('timeout');}, 15000);
+ unloadRef = utils.unloadAdd(cleanup);
+ return {
+ post: post,
+ cleanup: cleanup,
+ loaded: unattach
+ };
+};
+
+/* jshint undef: false, newcap: false */
+/* eslint no-undef: [0], new-cap: [0] */
+utils.createHtmlfile = function (iframeUrl, errorCallback) {
+ var doc = new ActiveXObject('htmlfile');
+ var tref, unloadRef;
+ var iframe;
+ var unattach = function() {
+ clearTimeout(tref);
+ };
+ var cleanup = function() {
+ if (doc) {
+ unattach();
+ utils.unloadDel(unloadRef);
+ iframe.parentNode.removeChild(iframe);
+ iframe = doc = null;
+ CollectGarbage();
+ }
+ };
+ var onerror = function(r) {
+ if (doc) {
+ cleanup();
+ errorCallback(r);
+ }
+ };
+ var post = function(msg, origin) {
+ try {
+ // When the iframe is not loaded, IE raises an exception
+ // on 'contentWindow'.
+ if (iframe && iframe.contentWindow) {
+ setTimeout(function() {
+ iframe.contentWindow.postMessage(msg, origin);
+ }, 0);
+ }
+ } catch (x) {}
+ };
+
+ doc.open();
+ doc.write('<html><s' + 'cript>' +
+ 'document.domain="' + document.domain + '";' +
+ '</s' + 'cript></html>');
+ doc.close();
+ doc.parentWindow[utils.WPrefix] = window[utils.WPrefix];
+ var c = doc.createElement('div');
+ doc.body.appendChild(c);
+ iframe = doc.createElement('iframe');
+ c.appendChild(iframe);
+ iframe.src = iframeUrl;
+ tref = setTimeout(function(){onerror('timeout');}, 15000);
+ unloadRef = utils.unloadAdd(cleanup);
+ return {
+ post: post,
+ cleanup: cleanup,
+ loaded: unattach
+ };
+};
diff --git a/lib/utils/log.js b/lib/utils/log.js
new file mode 100644
index 0000000..c4fc960
--- /dev/null
+++ b/lib/utils/log.js
@@ -0,0 +1,7 @@
+'use strict';
+
+utils.log = function() {
+ if (global.console && console.log && console.log.apply) {
+ console.log.apply(console, arguments);
+ }
+};
diff --git a/lib/utils/origin.js b/lib/utils/origin.js
new file mode 100644
index 0000000..6aa216a
--- /dev/null
+++ b/lib/utils/origin.js
@@ -0,0 +1,28 @@
+'use strict';
+
+var u = require('url');
+
+module.exports = {
+ getOrigin: function (url) {
+ var p = u.parse(url);
+ if (p.protocol === 'file:') {
+ return null;
+ }
+
+ var port = p.port;
+ if (!port) {
+ port = (p.protocol === 'https:') ? '443' : '80';
+ }
+
+ return p.protocol + '//' + p.hostname + ':' + port;
+ }
+
+, isSameOriginUrl: function(urlA, urlB) {
+ // location.origin would do, but it's not always available.
+ return this.getOrigin(urlA) === this.getOrigin(urlB);
+ }
+
+, isSameOriginScheme: function(urlA, urlB) {
+ return (urlA.split(':')[0] === urlB.split(':')[0]);
+ }
+};
diff --git a/lib/utils/random.js b/lib/utils/random.js
new file mode 100644
index 0000000..0e66e09
--- /dev/null
+++ b/lib/utils/random.js
@@ -0,0 +1,43 @@
+'use strict';
+
+var getRandomBytes;
+if (global && global.crypto && global.crypto.getRandomValues) {
+ getRandomBytes = function (length) {
+ var bytes = new Uint8Array(length);
+ global.crypto.getRandomValues(bytes);
+ return bytes;
+ };
+} else {
+ getRandomBytes = function (length) {
+ var bytes = new Uint8Array(length);
+ for (var i = 0; i < length; i++) {
+ bytes[i] = Math.floor(Math.random() * 256);
+ }
+ return bytes;
+ };
+}
+
+// This string has length 32, a power of 2, so the modulus doesn't introduce a
+// bias.
+var _randomStringChars = 'abcdefghijklmnopqrstuvwxyz012345';
+module.exports = {
+ string: function(length) {
+ var max = _randomStringChars.length;
+ var bytes = getRandomBytes(length);
+ var ret = [];
+ for (var i = 0; i < length; i++) {
+ ret.push( _randomStringChars[bytes[i] % max] );
+ }
+ return ret.join('');
+ }
+
+, number: function(max) {
+ return Math.floor(Math.random() * max);
+ }
+
+, numberString: function(max) {
+ var t = ('' + (max - 1)).length;
+ var p = new Array(t + 1).join('0');
+ return (p + this.number(max)).slice(-t);
+ }
+};
diff --git a/tests/html/lib/testutils.js b/tests/html/lib/testutils.js
index aebc051..a13bb2a 100644
--- a/tests/html/lib/testutils.js
+++ b/tests/html/lib/testutils.js
@@ -1,27 +1,48 @@
'use strict';
/* global jQuery, client_opts, SockJS */
-var u = require('../../../lib/utils');
+var random = require('../../../lib/utils/random');
+
+// May be used by htmlfile jsonp and transports.
+var MPrefix = '_sockjs_global';
+var createHook = function() {
+ var windowId = 'a' + random.string(8);
+ if (!(MPrefix in window)) {
+ var map = {};
+ window[MPrefix] = function(windowId) {
+ if (!(windowId in map)) {
+ map[windowId] = {
+ id: windowId,
+ del: function() {delete map[windowId];}
+ };
+ }
+ return map[windowId];
+ };
+ }
+ return window[MPrefix](windowId);
+};
module.exports = {
-newIframe: function(path) {
- var err, hook;
- if (!path) path = '/iframe.html';
- hook = u.createHook();
- err = function() {
- return u.log('iframe error. bad.');
- };
- hook.iobj = u.createIframe(path + '?a=' + Math.random() + '#' + hook.id, err);
- return hook;
-},
+ newIframe: function(path) {
+ var err, hook;
+ if (!path) {
+ path = '/iframe.html';
+ }
+ hook = createHook();
+ err = function() {
+ return u.log('iframe error. bad.');
+ };
+ hook.iobj = u.createIframe(path + '?a=' + Math.random() + '#' + hook.id, err);
+ return hook;
+ },
-newSockJS: function(path, protocol) {
- var options, url;
- url = /^http/.test(path) ? path : client_opts.url + path;
- options = jQuery.extend({}, client_opts.sockjs_opts);
- if (protocol) options.protocols_whitelist = [protocol];
- return new SockJS(url, null, options);
-}
+ newSockJS: function(path, protocol) {
+ var options, url;
+ url = /^http/.test(path) ? path : client_opts.url + path;
+ options = jQuery.extend({}, client_opts.sockjs_opts);
+ if (protocol) options.protocols_whitelist = [protocol];
+ return new SockJS(url, null, options);
+ }
};
\ No newline at end of file
--
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