Generate URLs for resources based on CDN + template rules
This commit is contained in:
parent
d6181da32b
commit
2da834784f
@ -1,11 +1,11 @@
|
||||
var _ = require('underscore');
|
||||
var dot = require('dot');
|
||||
dot.templateSettings.strip = false;
|
||||
var assert = require('assert');
|
||||
var step = require('step');
|
||||
var windshaft = require('windshaft');
|
||||
var QueryTables = require('cartodb-query-tables');
|
||||
|
||||
var ResourceLocator = require('../models/resource-locator');
|
||||
|
||||
var util = require('util');
|
||||
var BaseController = require('./base');
|
||||
|
||||
@ -46,20 +46,7 @@ function MapController(authApi, pgConnection, templateMaps, mapBackend, metadata
|
||||
this.layergroupAffectedTables = layergroupAffectedTables;
|
||||
|
||||
this.mapConfigAdapter = mapConfigAdapter;
|
||||
|
||||
this.resourcesUrlTemplates = null;
|
||||
if (global.environment.resources_url_templates) {
|
||||
var templates = global.environment.resources_url_templates;
|
||||
|
||||
if (templates.http) {
|
||||
this.resourcesUrlTemplates = this.resourcesUrlTemplates || {};
|
||||
this.resourcesUrlTemplates.http = dot.template(templates.http + '/{{=it.resource}}');
|
||||
}
|
||||
if (templates.https) {
|
||||
this.resourcesUrlTemplates = this.resourcesUrlTemplates || {};
|
||||
this.resourcesUrlTemplates.https = dot.template(templates.https + '/{{=it.resource}}');
|
||||
}
|
||||
}
|
||||
this.resourceLocator = new ResourceLocator(global.environment);
|
||||
}
|
||||
|
||||
util.inherits(MapController, BaseController);
|
||||
@ -399,7 +386,7 @@ MapController.prototype.addAnalysesMetadata = function(username, layergroup, ana
|
||||
var nodeResource = layergroup.layergroupid + '/analysis/node/' + node.id();
|
||||
var nodeRepr = {
|
||||
status: node.getStatus(),
|
||||
url: this.getUrls(username, nodeResource)
|
||||
url: this.resourceLocator.getUrls(username, nodeResource)
|
||||
};
|
||||
if (includeQuery) {
|
||||
nodeRepr.query = node.getQuery();
|
||||
@ -429,7 +416,7 @@ MapController.prototype.addDataviewsUrls = function(username, layergroup, mapCon
|
||||
Object.keys(dataviews).forEach(function(dataviewName) {
|
||||
var resource = layergroup.layergroupid + '/dataview/' + dataviewName;
|
||||
layergroup.metadata.dataviews[dataviewName] = {
|
||||
url: this.getUrls(username, resource)
|
||||
url: this.resourceLocator.getUrls(username, resource)
|
||||
};
|
||||
}.bind(this));
|
||||
};
|
||||
@ -444,7 +431,7 @@ MapController.prototype.addWidgetsUrl = function(username, layergroup, mapConfig
|
||||
var resource = layergroup.layergroupid + '/' + layerIndex + '/widget/' + widgetName;
|
||||
layer.widgets[widgetName] = {
|
||||
type: mapConfigLayer.options.widgets[widgetName].type,
|
||||
url: this.getUrls(username, resource)
|
||||
url: this.resourceLocator.getUrls(username, resource)
|
||||
};
|
||||
}.bind(this));
|
||||
}
|
||||
@ -452,46 +439,3 @@ MapController.prototype.addWidgetsUrl = function(username, layergroup, mapConfig
|
||||
}.bind(this));
|
||||
}
|
||||
};
|
||||
|
||||
MapController.prototype.getUrls = function(username, resource) {
|
||||
if (this.resourcesUrlTemplates) {
|
||||
return this.getUrlsFromTemplate(username, resource);
|
||||
}
|
||||
var cdnUrl = global.environment.serverMetadata && global.environment.serverMetadata.cdn_url;
|
||||
if (cdnUrl) {
|
||||
return {
|
||||
http: 'http://' + cdnUrl.http + '/' + username + '/api/v1/map/' + resource,
|
||||
https: 'https://' + cdnUrl.https + '/' + username + '/api/v1/map/' + resource
|
||||
};
|
||||
} else {
|
||||
var port = global.environment.port;
|
||||
return {
|
||||
http: 'http://' + username + '.' + 'localhost.lan:' + port + '/api/v1/map/' + resource
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
MapController.prototype.getUrlsFromTemplate = function(username, resource) {
|
||||
var urls = {};
|
||||
var cdnUrl = global.environment.serverMetadata && global.environment.serverMetadata.cdn_url || {};
|
||||
|
||||
if (this.resourcesUrlTemplates.http) {
|
||||
urls.http = this.resourcesUrlTemplates.http({
|
||||
cdn_url: cdnUrl.http,
|
||||
user: username,
|
||||
port: global.environment.port,
|
||||
resource: resource
|
||||
});
|
||||
}
|
||||
|
||||
if (this.resourcesUrlTemplates.https) {
|
||||
urls.https = this.resourcesUrlTemplates.https({
|
||||
cdn_url: cdnUrl.https,
|
||||
user: username,
|
||||
port: global.environment.port,
|
||||
resource: resource
|
||||
});
|
||||
}
|
||||
|
||||
return urls;
|
||||
};
|
||||
|
99
lib/cartodb/models/resource-locator.js
Normal file
99
lib/cartodb/models/resource-locator.js
Normal file
@ -0,0 +1,99 @@
|
||||
var crypto = require('crypto');
|
||||
|
||||
var dot = require('dot');
|
||||
dot.templateSettings.strip = false;
|
||||
|
||||
function ResourceLocator(environment) {
|
||||
this.environment = environment;
|
||||
|
||||
this.resourcesUrlTemplates = null;
|
||||
if (this.environment.resources_url_templates) {
|
||||
var templates = environment.resources_url_templates;
|
||||
|
||||
if (templates.http) {
|
||||
this.resourcesUrlTemplates = this.resourcesUrlTemplates || {};
|
||||
this.resourcesUrlTemplates.http = dot.template(templates.http + '/{{=it.resource}}');
|
||||
}
|
||||
if (templates.https) {
|
||||
this.resourcesUrlTemplates = this.resourcesUrlTemplates || {};
|
||||
this.resourcesUrlTemplates.https = dot.template(templates.https + '/{{=it.resource}}');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ResourceLocator;
|
||||
|
||||
ResourceLocator.prototype.getUrls = function(username, resource) {
|
||||
if (this.resourcesUrlTemplates) {
|
||||
return this.getUrlsFromTemplate(username, resource);
|
||||
}
|
||||
var cdnDomain = getCdnDomain(this.environment.serverMetadata, resource);
|
||||
if (cdnDomain) {
|
||||
return {
|
||||
http: 'http://' + cdnDomain.http + '/' + username + '/api/v1/map/' + resource,
|
||||
https: 'https://' + cdnDomain.https + '/' + username + '/api/v1/map/' + resource
|
||||
};
|
||||
} else {
|
||||
var port = this.environment.port;
|
||||
return {
|
||||
http: 'http://' + username + '.' + 'localhost.lan:' + port + '/api/v1/map/' + resource
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
ResourceLocator.prototype.getUrlsFromTemplate = function(username, resource) {
|
||||
var urls = {};
|
||||
var cdnDomain = getCdnDomain(this.environment.serverMetadata, resource) || {};
|
||||
|
||||
if (this.resourcesUrlTemplates.http) {
|
||||
urls.http = this.resourcesUrlTemplates.http({
|
||||
cdn_url: cdnDomain.http,
|
||||
user: username,
|
||||
port: this.environment.port,
|
||||
resource: resource
|
||||
});
|
||||
}
|
||||
|
||||
if (this.resourcesUrlTemplates.https) {
|
||||
urls.https = this.resourcesUrlTemplates.https({
|
||||
cdn_url: cdnDomain.https,
|
||||
user: username,
|
||||
port: this.environment.port,
|
||||
resource: resource
|
||||
});
|
||||
}
|
||||
|
||||
return urls;
|
||||
};
|
||||
|
||||
function getCdnDomain(serverMetadata, resource) {
|
||||
if (serverMetadata && serverMetadata.cdn_url) {
|
||||
var cdnUrl = serverMetadata.cdn_url;
|
||||
var http = cdnUrl.http;
|
||||
var https = cdnUrl.https;
|
||||
if (cdnUrl.templates) {
|
||||
var templates = cdnUrl.templates;
|
||||
var httpUrlTemplate = templates.http.url;
|
||||
var httpsUrlTemplate = templates.https.url;
|
||||
http = httpUrlTemplate
|
||||
.replace(/^(http[s]*:\/\/)/, '')
|
||||
.replace('{s}', subdomain(templates.http.subdomains, resource));
|
||||
https = httpsUrlTemplate
|
||||
.replace(/^(http[s]*:\/\/)/, '')
|
||||
.replace('{s}', subdomain(templates.https.subdomains, resource));
|
||||
}
|
||||
return {
|
||||
http: http,
|
||||
https: https,
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function subdomain(subdomains, resource) {
|
||||
var resourceHash = crypto.createHash('md5').update(resource, 'binary').digest('hex');
|
||||
var index = parseInt(resourceHash, 16) % subdomains.length;
|
||||
return subdomains[index];
|
||||
}
|
||||
module.exports.subdomain = subdomain;
|
132
test/unit/cartodb/model/resource-locator.test.js
Normal file
132
test/unit/cartodb/model/resource-locator.test.js
Normal file
@ -0,0 +1,132 @@
|
||||
require('../../../support/test_helper');
|
||||
|
||||
var assert = require('../../../support/assert');
|
||||
var ResourceLocator = require('../../../../lib/cartodb/models/resource-locator');
|
||||
|
||||
describe('ResourceLocator.getUrls', function() {
|
||||
var USERNAME = 'username';
|
||||
var RESOURCE = 'wadus';
|
||||
var HTTP_SUBDOMAINS = ['1', '2', '3', '4'];
|
||||
var HTTPS_SUBDOMAINS = ['a', 'b', 'c', 'd'];
|
||||
|
||||
it('should return default urls when no serverMetadata is in environment', function() {
|
||||
var resourceLocator = new ResourceLocator({});
|
||||
var urls = resourceLocator.getUrls(USERNAME, RESOURCE);
|
||||
assert.ok(urls);
|
||||
});
|
||||
|
||||
var BASIC_ENVIRONMENT = {
|
||||
serverMetadata: {
|
||||
cdn_url: {
|
||||
http: 'cdn.carto.com',
|
||||
https: 'cdn.ssl.carto.com'
|
||||
}
|
||||
}
|
||||
};
|
||||
it('should return default urls when basic http and https domains are provided', function() {
|
||||
var resourceLocator = new ResourceLocator(BASIC_ENVIRONMENT);
|
||||
var urls = resourceLocator.getUrls(USERNAME, RESOURCE);
|
||||
assert.ok(urls);
|
||||
|
||||
assert.equal(urls.http, ['http://cdn.carto.com', USERNAME, 'api/v1/map', RESOURCE].join('/'));
|
||||
assert.equal(urls.https, ['https://cdn.ssl.carto.com', USERNAME, 'api/v1/map', RESOURCE].join('/'));
|
||||
});
|
||||
|
||||
var RESOURCE_TEMPLATES_ENVIRONMENT = {
|
||||
serverMetadata: {
|
||||
cdn_url: {
|
||||
http: 'cdn.carto.com',
|
||||
https: 'cdn.ssl.carto.com'
|
||||
}
|
||||
},
|
||||
resources_url_templates: {
|
||||
http: 'http://{{=it.user}}.localhost.lan/api/v1/map',
|
||||
https: 'https://{{=it.user}}.ssl.localhost.lan/api/v1/map'
|
||||
}
|
||||
};
|
||||
it('resources_url_templates should take precedence over http and https domains', function() {
|
||||
var resourceLocator = new ResourceLocator(RESOURCE_TEMPLATES_ENVIRONMENT);
|
||||
var urls = resourceLocator.getUrls(USERNAME, RESOURCE);
|
||||
assert.ok(urls);
|
||||
|
||||
assert.equal(urls.http, ['http://' + USERNAME + '.localhost.lan', 'api/v1/map', RESOURCE].join('/'));
|
||||
assert.equal(urls.https, ['https://' + USERNAME + '.ssl.localhost.lan', 'api/v1/map', RESOURCE].join('/'));
|
||||
});
|
||||
|
||||
var CDN_TEMPLATES_ENVIRONMENT = {
|
||||
serverMetadata: {
|
||||
cdn_url: {
|
||||
http: 'cdn.carto.com',
|
||||
https: 'cdn.ssl.carto.com',
|
||||
templates: {
|
||||
http: {
|
||||
url: "http://{s}.cdn.carto.com",
|
||||
subdomains: HTTP_SUBDOMAINS
|
||||
},
|
||||
https: {
|
||||
url: "https://cdn_{s}.ssl.cdn.carto.com",
|
||||
subdomains: HTTPS_SUBDOMAINS
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
it('cdn_url templates should take precedence over http and https domains', function() {
|
||||
var resourceLocator = new ResourceLocator(CDN_TEMPLATES_ENVIRONMENT);
|
||||
var urls = resourceLocator.getUrls(USERNAME, RESOURCE);
|
||||
assert.ok(urls);
|
||||
|
||||
var httpSubdomain = ResourceLocator.subdomain(HTTP_SUBDOMAINS, RESOURCE);
|
||||
var httpsSubdomain = ResourceLocator.subdomain(HTTPS_SUBDOMAINS, RESOURCE);
|
||||
|
||||
assert.equal(
|
||||
urls.http,
|
||||
['http://' + httpSubdomain + '.cdn.carto.com', USERNAME, 'api/v1/map', RESOURCE].join('/')
|
||||
);
|
||||
assert.equal(
|
||||
urls.https,
|
||||
['https://cdn_' + httpsSubdomain + '.ssl.cdn.carto.com', USERNAME, 'api/v1/map', RESOURCE].join('/')
|
||||
);
|
||||
});
|
||||
|
||||
var CDN_URL_AND_RESOURCE_TEMPLATES_ENVIRONMENT = {
|
||||
serverMetadata: {
|
||||
cdn_url: {
|
||||
http: 'cdn.carto.com',
|
||||
https: 'cdn.ssl.carto.com',
|
||||
templates: {
|
||||
http: {
|
||||
url: "http://{s}.cdn.carto.com",
|
||||
subdomains: HTTP_SUBDOMAINS
|
||||
},
|
||||
https: {
|
||||
url: "https://cdn_{s}.ssl.cdn.carto.com",
|
||||
subdomains: HTTPS_SUBDOMAINS
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
resources_url_templates: {
|
||||
http: 'http://{{=it.cdn_url}}/u/{{=it.user}}/api/v1/map',
|
||||
https: 'https://{{=it.cdn_url}}/u/{{=it.user}}/api/v1/map'
|
||||
}
|
||||
};
|
||||
it('should mix cdn_url templates and resources_url_templates', function() {
|
||||
var resourceLocator = new ResourceLocator(CDN_URL_AND_RESOURCE_TEMPLATES_ENVIRONMENT);
|
||||
var urls = resourceLocator.getUrls(USERNAME, RESOURCE);
|
||||
assert.ok(urls);
|
||||
|
||||
var httpSubdomain = ResourceLocator.subdomain(HTTP_SUBDOMAINS, RESOURCE);
|
||||
var httpsSubdomain = ResourceLocator.subdomain(HTTPS_SUBDOMAINS, RESOURCE);
|
||||
|
||||
assert.equal(
|
||||
urls.http,
|
||||
['http://' + httpSubdomain + '.cdn.carto.com', 'u', USERNAME, 'api/v1/map', RESOURCE].join('/')
|
||||
);
|
||||
assert.equal(
|
||||
urls.https,
|
||||
['https://cdn_' + httpsSubdomain + '.ssl.cdn.carto.com', 'u', USERNAME, 'api/v1/map', RESOURCE].join('/')
|
||||
);
|
||||
});
|
||||
|
||||
});
|
Loading…
Reference in New Issue
Block a user