mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
Share URL-munging code
Still to do:
* Share more code
* Deal with this error:
Uncaught Error: INVALID_STATE_ERR sockjs-0.3.4.js:1054
SockJS._didClose sockjs-0.3.4.js:1054
(anonymous function) sockjs-0.3.4.js:1330
xo.onfinish sockjs-0.3.4.js:1412
EventEmitter.emit sockjs-0.3.4.js:150
that.xhr.onreadystatechange
This commit is contained in:
@@ -16,6 +16,7 @@ Package.on_use(function (api) {
|
||||
api.add_files(['sockjs-0.3.4.js',
|
||||
'stream_client_sockjs.js'], 'client');
|
||||
api.add_files('stream_client_nodejs.js', 'server');
|
||||
api.add_files('urls.js', ['client', 'server']);
|
||||
api.add_files('stream_server.js', 'server');
|
||||
|
||||
// livedata_connection.js uses a Minimongo collection internally to
|
||||
|
||||
@@ -27,6 +27,11 @@ Meteor._DdpClientStream = function (endpoint) {
|
||||
return self._onConnect(connection);
|
||||
});
|
||||
|
||||
self.client.on('connectFailed', function (error) {
|
||||
// XXX: Make this do something better than make the tests hang if it does not work.
|
||||
return self._lostConnection();
|
||||
});
|
||||
|
||||
//// Constants
|
||||
|
||||
// how long to wait until we declare the connection attempt
|
||||
@@ -69,16 +74,6 @@ Meteor._DdpClientStream = function (endpoint) {
|
||||
self._launchConnection();
|
||||
};
|
||||
|
||||
_.extend(Meteor._DdpClientStream, {
|
||||
_endpointToUrl: function (endpoint) {
|
||||
// XXX should be secure!
|
||||
// among other problems
|
||||
endpoint = endpoint.replace(/^http(s)?:\/\//, "");
|
||||
endpoint = endpoint.replace(/\/$/, "");
|
||||
return 'ws://' + endpoint + '/websocket';
|
||||
}
|
||||
});
|
||||
|
||||
_.extend(Meteor._DdpClientStream.prototype, {
|
||||
// Register for callbacks.
|
||||
on: function (name, callback) {
|
||||
@@ -303,7 +298,7 @@ _.extend(Meteor._DdpClientStream.prototype, {
|
||||
// a protocol and the server doesn't send one back (and sockjs
|
||||
// doesn't). also, related: I guess we have to accept that
|
||||
// 'stream' is ddp-specific
|
||||
self.client.connect(Meteor._DdpClientStream._endpointToUrl(self.endpoint));
|
||||
self.client.connect(Meteor._DdpClientStream._toWebsocketUrl(self.endpoint));
|
||||
|
||||
if (self.connectionTimer)
|
||||
clearTimeout(self.connectionTimer);
|
||||
|
||||
@@ -62,56 +62,6 @@ Meteor._DdpClientStream = function (url) {
|
||||
self._launch_connection();
|
||||
};
|
||||
|
||||
_.extend(Meteor._DdpClientStream, {
|
||||
// @param url {String} URL to Meteor app, eg:
|
||||
// "/" or "madewith.meteor.com" or "https://foo.meteor.com"
|
||||
// or "ddp+sockjs://ddp--****-foo.meteor.com/sockjs"
|
||||
// @returns {String} URL to the sockjs endpoint, e.g.
|
||||
// "http://subdomain.meteor.com/sockjs" or "/sockjs"
|
||||
// or "https://ddp--1234-foo.meteor.com/sockjs"
|
||||
_toSockjsUrl: function(url) {
|
||||
// XXX from Underscore.String (http://epeli.github.com/underscore.string/)
|
||||
var startsWith = function(str, starts) {
|
||||
return str.length >= starts.length &&
|
||||
str.substring(0, starts.length) === starts;
|
||||
};
|
||||
var endsWith = function(str, ends) {
|
||||
return str.length >= ends.length &&
|
||||
str.substring(str.length - ends.length) === ends;
|
||||
};
|
||||
|
||||
var ddpUrlMatch = url.match(/^ddp(i?)\+sockjs:\/\//);
|
||||
if (ddpUrlMatch) {
|
||||
// Remove scheme and split off the host.
|
||||
var urlAfterDDP = url.substr(ddpUrlMatch[0].length);
|
||||
var newScheme = ddpUrlMatch[1] === 'i' ? 'http' : 'https';
|
||||
var slashPos = urlAfterDDP.indexOf('/');
|
||||
var host =
|
||||
slashPos === -1 ? urlAfterDDP : urlAfterDDP.substr(0, slashPos);
|
||||
var rest = slashPos === -1 ? '' : urlAfterDDP.substr(slashPos);
|
||||
|
||||
// In the host (ONLY!), change '*' characters into random digits. This
|
||||
// allows different stream connections to connect to different hostnames
|
||||
// and avoid browser per-hostname connection limits.
|
||||
host = host.replace(/\*/g, function () {
|
||||
return Math.floor(Random.fraction()*10);
|
||||
});
|
||||
|
||||
return newScheme + '://' + host + rest;
|
||||
}
|
||||
|
||||
// Prefix FQDNs but not relative URLs
|
||||
if (url.indexOf("://") === -1 && !startsWith(url, "/")) {
|
||||
url = "http://" + url;
|
||||
}
|
||||
|
||||
if (endsWith(url, "/"))
|
||||
return url + "sockjs";
|
||||
else
|
||||
return url + "/sockjs";
|
||||
}
|
||||
});
|
||||
|
||||
_.extend(Meteor._DdpClientStream.prototype, {
|
||||
// Register for callbacks.
|
||||
on: function (name, callback) {
|
||||
|
||||
@@ -37,7 +37,7 @@ Tinytest.add("stream - sockjs urls are computed correctly", function(test) {
|
||||
var testHasSockjsUrl = function(raw, expectedSockjsUrl) {
|
||||
var actual = Meteor._DdpClientStream._toSockjsUrl(raw);
|
||||
if (expectedSockjsUrl instanceof RegExp)
|
||||
test.isTrue(actual.match(expectedSockjsUrl));
|
||||
test.isTrue(actual.match(expectedSockjsUrl), actual);
|
||||
else
|
||||
test.equal(actual, expectedSockjsUrl);
|
||||
};
|
||||
|
||||
70
packages/livedata/urls.js
Normal file
70
packages/livedata/urls.js
Normal file
@@ -0,0 +1,70 @@
|
||||
|
||||
// XXX from Underscore.String (http://epeli.github.com/underscore.string/)
|
||||
var startsWith = function(str, starts) {
|
||||
return str.length >= starts.length &&
|
||||
str.substring(0, starts.length) === starts;
|
||||
};
|
||||
var endsWith = function(str, ends) {
|
||||
return str.length >= ends.length &&
|
||||
str.substring(str.length - ends.length) === ends;
|
||||
};
|
||||
|
||||
// @param url {String} URL to Meteor app, eg:
|
||||
// "/" or "madewith.meteor.com" or "https://foo.meteor.com"
|
||||
// or "ddp+sockjs://ddp--****-foo.meteor.com/sockjs"
|
||||
// @returns {String} URL to the endpoint with the specific scheme and subPath, e.g.
|
||||
// for scheme "http" and subPath "sockjs"
|
||||
// "http://subdomain.meteor.com/sockjs" or "/sockjs"
|
||||
// or "https://ddp--1234-foo.meteor.com/sockjs"
|
||||
var translateUrl = function(url, newSchemeBase, subPath) {
|
||||
if (! newSchemeBase) {
|
||||
newSchemeBase = "http";
|
||||
}
|
||||
|
||||
var ddpUrlMatch = url.match(/^ddp(i?)\+sockjs:\/\//);
|
||||
var httpUrlMatch = url.match(/^http(s?):\/\//);
|
||||
var newScheme;
|
||||
if (ddpUrlMatch) {
|
||||
// Remove scheme and split off the host.
|
||||
var urlAfterDDP = url.substr(ddpUrlMatch[0].length);
|
||||
newScheme = ddpUrlMatch[1] === "i" ? newSchemeBase : newSchemeBase + "s";
|
||||
var slashPos = urlAfterDDP.indexOf('/');
|
||||
var host =
|
||||
slashPos === -1 ? urlAfterDDP : urlAfterDDP.substr(0, slashPos);
|
||||
var rest = slashPos === -1 ? '' : urlAfterDDP.substr(slashPos);
|
||||
|
||||
// In the host (ONLY!), change '*' characters into random digits. This
|
||||
// allows different stream connections to connect to different hostnames
|
||||
// and avoid browser per-hostname connection limits.
|
||||
host = host.replace(/\*/g, function () {
|
||||
return Math.floor(Random.fraction()*10);
|
||||
});
|
||||
|
||||
return newScheme + '://' + host + rest;
|
||||
} else if (httpUrlMatch) {
|
||||
newScheme = !httpUrlMatch[1] ? newSchemeBase : newSchemeBase + "s";
|
||||
var urlAfterHttp = url.substr(httpUrlMatch[0].length);
|
||||
url = newScheme + "://" + urlAfterHttp;
|
||||
}
|
||||
|
||||
// Prefix FQDNs but not relative URLs
|
||||
if (url.indexOf("://") === -1 && !startsWith(url, "/")) {
|
||||
url = newSchemeBase + "://" + url;
|
||||
}
|
||||
|
||||
if (endsWith(url, "/"))
|
||||
return url + subPath;
|
||||
else
|
||||
return url + "/" + subPath;
|
||||
};
|
||||
|
||||
_.extend(Meteor._DdpClientStream, {
|
||||
_toSockjsUrl: function (url) {
|
||||
return translateUrl(url, "http", "sockjs");
|
||||
},
|
||||
|
||||
_toWebsocketUrl: function (url) {
|
||||
var ret = translateUrl(url, "ws", "websocket");
|
||||
return ret;
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user