kopia lustrzana https://github.com/c9/core
Merge pull request +7998 from c9/multi-domain-part-deux
Multiple-domain/cs50 support part 2: change backendpull/117/merge
commit
f8fc34c531
|
@ -0,0 +1,94 @@
|
||||||
|
/**
|
||||||
|
* Base URL utilities for the Ajax.org Cloud IDE
|
||||||
|
*
|
||||||
|
* Access via require("c9/urls").
|
||||||
|
*
|
||||||
|
* @copyright 2015, Ajax.org B.V.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var plugin = module.exports = main;
|
||||||
|
var assert = require("assert");
|
||||||
|
|
||||||
|
plugin.consumes = ["error.logger"];
|
||||||
|
plugin.provides = ["urls"];
|
||||||
|
|
||||||
|
var errorLogger = mockErrorLogger;
|
||||||
|
|
||||||
|
function main(options, imports, register) {
|
||||||
|
errorLogger = imports["error.logger"];
|
||||||
|
|
||||||
|
register(null, {
|
||||||
|
urls: plugin
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a desired base URL, given some context.
|
||||||
|
*
|
||||||
|
* @param req The current request object or URL
|
||||||
|
* @param {String} [sourceUrlPattern] The source URL pattern, e.g. https://ide.$DOMAIN
|
||||||
|
* @param {String} targetBaseUrlPattern The target URL pattern, e.g. https://$DOMAIN
|
||||||
|
*/
|
||||||
|
plugin.getBaseUrl = function(req, sourceBaseUrlPattern, targetBaseUrlPattern) {
|
||||||
|
var sourceHost = req.headers && req.headers.host
|
||||||
|
|| req.host
|
||||||
|
|| req.url && req.url.replace(/^https?:\/\/([^/]*).*/, "$1")
|
||||||
|
|| req;
|
||||||
|
if (typeof sourceHost !== "string")
|
||||||
|
throw new Error("Not a valid request object: " + req);
|
||||||
|
|
||||||
|
var sourceHostMatcher = sourceBaseUrlPattern
|
||||||
|
.replace(/^https?:\/\//, "")
|
||||||
|
.replace(/\/.*/, "")
|
||||||
|
.replace(/\./, "\\.")
|
||||||
|
.replace("$DOMAIN", "([^/]+)");
|
||||||
|
var hostMatch = sourceHost.match(sourceHostMatcher);
|
||||||
|
var targetHost;
|
||||||
|
if (hostMatch) {
|
||||||
|
targetHost = hostMatch[1];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
errorLogger.log(new Error("Could not construct URL: request host "
|
||||||
|
+ sourceHost + " should match " + sourceBaseUrlPattern));
|
||||||
|
targetHost = "c9.io";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetHost.match(/^(ide|vfs)./) && !targetBaseUrlPattern)
|
||||||
|
errorLogger.log(new Error("Warning: no targetBaseUrlPattern specified, will stay at " + targetHost), { sourceBaseUrlPattern: sourceBaseUrlPattern });
|
||||||
|
if (targetHost.match(/^(ide|vfs)./))
|
||||||
|
console.trace("Warning: possibly incorrect baseUrl constructed, with 'ide.' in the hostname: " + targetHost);
|
||||||
|
return replaceDomain(targetBaseUrlPattern || sourceBaseUrlPattern, targetHost)
|
||||||
|
.replace(/\/$/, "");
|
||||||
|
};
|
||||||
|
|
||||||
|
plugin.replaceDomains = function(settings, domains) {
|
||||||
|
domains = Array.isArray(domains) ? domains : domains.split(",");
|
||||||
|
var primaryDomain = domains[0];
|
||||||
|
settings.domains = domains;
|
||||||
|
settings.primaryDomain = replaceDomain(settings.primaryDomain || "$DOMAIN", primaryDomain);
|
||||||
|
settings.primaryBaseUrl = replaceDomain(settings.primaryBaseUrl || "https://$DOMAIN", primaryDomain);
|
||||||
|
for (var s in settings) {
|
||||||
|
if (!settings[s])
|
||||||
|
continue;
|
||||||
|
if (settings[s].baseUrl)
|
||||||
|
settings[s].baseUrl = replaceDomain(settings[s].baseUrl, primaryDomain);
|
||||||
|
if (settings[s].primaryBaseUrl)
|
||||||
|
settings[s].primaryBaseUrl = replaceDomain(settings[s].primaryBaseUrl, primaryDomain);
|
||||||
|
if (settings[s].baseUrls) {
|
||||||
|
assert(settings[s].baseUrls.length === 1);
|
||||||
|
settings[s].baseUrls = domains.map(function(d) {
|
||||||
|
return replaceDomain(settings[s].baseUrls[0], d);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function replaceDomain(url, domain) {
|
||||||
|
return url.replace("$DOMAIN", domain);
|
||||||
|
}
|
||||||
|
|
||||||
|
function mockErrorLogger() {}
|
||||||
|
mockErrorLogger.log = function(err) {
|
||||||
|
console.error(err.stack);
|
||||||
|
};
|
||||||
|
plugin.mockErrorLogger = mockErrorLogger;
|
|
@ -0,0 +1,129 @@
|
||||||
|
/*global describe it beforeEach afterEach*/
|
||||||
|
"use strict";
|
||||||
|
"use server";
|
||||||
|
"use mocha";
|
||||||
|
|
||||||
|
require("c9/inline-mocha")(module);
|
||||||
|
if (typeof define === "undefined") {
|
||||||
|
require("amd-loader");
|
||||||
|
require("../../test/setup_paths");
|
||||||
|
}
|
||||||
|
|
||||||
|
var assert = require("assert");
|
||||||
|
var urls = require("./urls");
|
||||||
|
var url = require("url");
|
||||||
|
var sinon = require("sinon");
|
||||||
|
|
||||||
|
describe("urls", function() {
|
||||||
|
|
||||||
|
this.timeout(15000);
|
||||||
|
|
||||||
|
it("can do basic domain substitution in settings", function() {
|
||||||
|
var settings = {
|
||||||
|
domains: ["c9.io"],
|
||||||
|
preview: {
|
||||||
|
baseUrl: "https://preview.$DOMAIN"
|
||||||
|
},
|
||||||
|
ide: {
|
||||||
|
baseUrlPattern: "https://ide.$DOMAIN"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
urls.replaceDomains(settings, "cloud9beta.com");
|
||||||
|
assert.equal(settings.primaryDomain, "cloud9beta.com");
|
||||||
|
assert.equal(settings.preview.baseUrl, "https://preview.cloud9beta.com");
|
||||||
|
assert.equal(settings.ide.baseUrlPattern, "https://ide.$DOMAIN");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can do basic domain substitution in settings a list of domains", function() {
|
||||||
|
var settings = {
|
||||||
|
domains: ["c9.io"],
|
||||||
|
preview: {
|
||||||
|
baseUrl: "https://preview.$DOMAIN"
|
||||||
|
},
|
||||||
|
ide: {
|
||||||
|
baseUrlPattern: "https://ide.$DOMAIN"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
urls.replaceDomains(settings, "cloud9beta.com,cs50.me");
|
||||||
|
assert.equal(settings.primaryDomain, "cloud9beta.com");
|
||||||
|
assert.deepEqual(settings.domains, ["cloud9beta.com", "cs50.me"]);
|
||||||
|
assert.equal(settings.preview.baseUrl, "https://preview.cloud9beta.com");
|
||||||
|
assert.equal(settings.ide.baseUrlPattern, "https://ide.$DOMAIN");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("behaves like an architect plugin", function(next) {
|
||||||
|
urls({}, { "error.logger": urls.mockErrorLogger }, function(err, result) {
|
||||||
|
assert(!err, err);
|
||||||
|
assert(result.urls.getBaseUrl);
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can get the base url for a request", function() {
|
||||||
|
var mockRequest = {
|
||||||
|
host: "preview.c9.io"
|
||||||
|
};
|
||||||
|
var baseUrl = urls.getBaseUrl(mockRequest, "https://preview.$DOMAIN", "https://ide.$DOMAIN");
|
||||||
|
assert.equal(baseUrl, "https://ide.c9.io");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can get the base url for a request with root domain source", function() {
|
||||||
|
var mockRequest = {
|
||||||
|
host: "c9.io"
|
||||||
|
};
|
||||||
|
var baseUrl = urls.getBaseUrl(mockRequest, "https://$DOMAIN", "https://ide.$DOMAIN");
|
||||||
|
assert.equal(baseUrl, "https://ide.c9.io");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can get the base url for a request with root domain target", function() {
|
||||||
|
var mockRequest = {
|
||||||
|
host: "preview.cloud9beta.com"
|
||||||
|
};
|
||||||
|
var baseUrl = urls.getBaseUrl(mockRequest, "https://preview.$DOMAIN", "https://$DOMAIN");
|
||||||
|
assert.equal(baseUrl, "https://cloud9beta.com");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("gracefully copes with source domain mismatch", function() {
|
||||||
|
var mockRequest = {
|
||||||
|
host: "preview.cloud9beta.com"
|
||||||
|
};
|
||||||
|
urls.mockErrorLogger.log = sinon.spy();
|
||||||
|
var baseUrl = urls.getBaseUrl(mockRequest, "https://ide.$DOMAIN", "https://$DOMAIN");
|
||||||
|
assert.equal(baseUrl, "https://c9.io");
|
||||||
|
assert(urls.mockErrorLogger.log.called);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can get the base url in dogfooding mode", function() {
|
||||||
|
var mockRequest = {
|
||||||
|
host: "newclient-lennartcl.c9.io"
|
||||||
|
};
|
||||||
|
var baseUrl = urls.getBaseUrl(mockRequest, "https://$DOMAIN", "https://ide.$DOMAIN");
|
||||||
|
assert.equal(baseUrl, "https://ide.newclient-lennartcl.c9.io");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can get the base url in dogfooding mode (2)", function() {
|
||||||
|
var mockRequest = {
|
||||||
|
host: "preview.newclient-lennartcl.c9.io"
|
||||||
|
};
|
||||||
|
var baseUrl = urls.getBaseUrl(mockRequest, "https://preview.$DOMAIN", "https://ide.$DOMAIN");
|
||||||
|
assert.equal(baseUrl, "https://ide.newclient-lennartcl.c9.io");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("even works with URL objects", function() {
|
||||||
|
var input = url.parse("https://preview.newclient-lennartcl.c9.io");
|
||||||
|
var baseUrl = urls.getBaseUrl(input, "https://preview.$DOMAIN", "https://ide.$DOMAIN");
|
||||||
|
assert.equal(baseUrl, "https://ide.newclient-lennartcl.c9.io");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("even works with strings", function() {
|
||||||
|
var input = "https://preview.newclient-lennartcl.c9.io";
|
||||||
|
var baseUrl = urls.getBaseUrl(input, "https://preview.$DOMAIN", "https://ide.$DOMAIN");
|
||||||
|
assert.equal(baseUrl, "https://ide.newclient-lennartcl.c9.io");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("targetBaseUrlPattern is optional", function() {
|
||||||
|
var input = "https://preview.newclient-lennartcl.c9.io";
|
||||||
|
var baseUrl = urls.getBaseUrl(input, "https://preview.$DOMAIN");
|
||||||
|
assert.equal(baseUrl, "https://preview.newclient-lennartcl.c9.io");
|
||||||
|
});
|
||||||
|
});
|
32
server.js
32
server.js
|
@ -10,8 +10,8 @@ var path = require("path");
|
||||||
var architect = require("architect");
|
var architect = require("architect");
|
||||||
var optimist = require("optimist");
|
var optimist = require("optimist");
|
||||||
var async = require("async");
|
var async = require("async");
|
||||||
var assert = require("assert");
|
|
||||||
var os = require("os");
|
var os = require("os");
|
||||||
|
var urls = require("c9/urls");
|
||||||
require("c9/setup_paths.js");
|
require("c9/setup_paths.js");
|
||||||
|
|
||||||
if (process.version.match(/^v0/) && parseFloat(process.version.substr(3)) < 10) {
|
if (process.version.match(/^v0/) && parseFloat(process.version.substr(3)) < 10) {
|
||||||
|
@ -63,7 +63,7 @@ function main(argv, config, onLoaded) {
|
||||||
.describe("dump", "dump config file as JSON")
|
.describe("dump", "dump config file as JSON")
|
||||||
.describe("domains", "Primary and any secondary top-level domains to use (e.g, c9.io,c9.dev)")
|
.describe("domains", "Primary and any secondary top-level domains to use (e.g, c9.io,c9.dev)")
|
||||||
.describe("exclude", "Exclude specified service")
|
.describe("exclude", "Exclude specified service")
|
||||||
.default("domains", inContainer && process.env.C9_HOSTNAME)
|
.default("domains", inContainer && process.env.C9_HOSTNAME || process.env.C9_DOMAINS)
|
||||||
.boolean("help")
|
.boolean("help")
|
||||||
.describe("help", "Show command line options.");
|
.describe("help", "Show command line options.");
|
||||||
|
|
||||||
|
@ -127,7 +127,7 @@ function start(configName, options, callback) {
|
||||||
|
|
||||||
argv.domains = argv.domains || settings.domains;
|
argv.domains = argv.domains || settings.domains;
|
||||||
if (settings.c9 && argv.domains)
|
if (settings.c9 && argv.domains)
|
||||||
replaceDomains(settings, argv.domains);
|
urls.replaceDomains(settings, argv.domains);
|
||||||
|
|
||||||
var plugins = require(configPath)(settings, options);
|
var plugins = require(configPath)(settings, options);
|
||||||
|
|
||||||
|
@ -173,29 +173,3 @@ function start(configName, options, callback) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function replaceDomains(settings, domains) {
|
|
||||||
domains = Array.isArray(domains) ? domains : [domains];
|
|
||||||
var primaryDomain = domains[0];
|
|
||||||
settings.domains = domains;
|
|
||||||
settings.primaryDomain = replaceDomain(settings.primaryDomain, primaryDomain);
|
|
||||||
settings.primaryBaseUrl = replaceDomain(settings.primaryBaseUrl, primaryDomain);
|
|
||||||
for (var s in settings) {
|
|
||||||
if (!settings[s])
|
|
||||||
continue;
|
|
||||||
if (settings[s].baseUrl)
|
|
||||||
settings[s].baseUrl = replaceDomain(settings[s].baseUrl, primaryDomain);
|
|
||||||
if (settings[s].primaryBaseUrl)
|
|
||||||
settings[s].primaryBaseUrl = replaceDomain(settings[s].primaryBaseUrl, primaryDomain);
|
|
||||||
if (settings[s].baseUrls) {
|
|
||||||
assert(settings[s].baseUrls.length === 1);
|
|
||||||
settings[s].baseUrls = domains.map(function(d) {
|
|
||||||
return replaceDomain(settings[s].baseUrls[0], d);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function replaceDomain(url, domain) {
|
|
||||||
return url.replace("$DOMAIN", domain);
|
|
||||||
}
|
|
Ładowanie…
Reference in New Issue