From f7f513a61a70567d87389110f61bf3b13ac05178 Mon Sep 17 00:00:00 2001 From: Raul Ochoa Date: Wed, 3 Jan 2018 20:53:03 +0000 Subject: [PATCH 1/3] Add urlTemplate URLs to metadata This is useful when using client libraries like leaflet. --- lib/cartodb/controllers/map.js | 11 +- lib/cartodb/models/resource-locator.js | 108 ++++++++++++------ test/acceptance/tilejson.js | 21 +++- .../cartodb/model/resource-locator.test.js | 71 ++++++++++++ 4 files changed, 173 insertions(+), 38 deletions(-) diff --git a/lib/cartodb/controllers/map.js b/lib/cartodb/controllers/map.js index 0985530d..5ec2a0ef 100644 --- a/lib/cartodb/controllers/map.js +++ b/lib/cartodb/controllers/map.js @@ -364,19 +364,26 @@ MapController.prototype.setTilejsonMetadataToLayergroup = function () { }); const tilejson = {}; + const url = {}; if (hasMapnikLayers) { + const vectorResource = `${layergroup.layergroupid}/{z}/{x}/{y}.mvt`; tilejson.vector = getTilejson( - this.resourceLocator.getTileUrls(user, `${layergroup.layergroupid}/{z}/{x}/{y}.mvt`) + this.resourceLocator.getTileUrls(user, vectorResource) ); + url.vector = this.resourceLocator.getTemplateUrls(user, vectorResource); + if (!isVectorOnlyMapConfig) { + const rasterResource = `${layergroup.layergroupid}/{z}/{x}/{y}.png`; tilejson.raster = getTilejson( - this.resourceLocator.getTileUrls(user, `${layergroup.layergroupid}/{z}/{x}/{y}.png`) + this.resourceLocator.getTileUrls(user, rasterResource) ); + url.raster = this.resourceLocator.getTemplateUrls(user, rasterResource); } } layergroup.metadata.tilejson = tilejson; + layergroup.metadata.url = url; next(); }.bind(this); diff --git a/lib/cartodb/models/resource-locator.js b/lib/cartodb/models/resource-locator.js index af777985..14a98431 100644 --- a/lib/cartodb/models/resource-locator.js +++ b/lib/cartodb/models/resource-locator.js @@ -40,6 +40,24 @@ ResourceLocator.prototype.getTileUrls = function(username, resourcePath) { } }; +ResourceLocator.prototype.getTemplateUrls = function(username, resourcePath) { + if (this.resourcesUrlTemplates) { + return this.getUrlsFromTemplate(username, new TemplateResource(resourcePath)); + } + var cdnUrls = getCdnUrls(this.environment.serverMetadata, username, new TemplateResource(resourcePath)); + if (cdnUrls) { + return cdnUrls; + } else { + var port = this.environment.port; + return { + http: { + urlTemplate: `http://${username}.localhost.lan:${port}/api/v1/map/${resourcePath}`, + subdomains: [] + } + }; + } +}; + ResourceLocator.prototype.getUrls = function(username, resourcePath) { if (this.resourcesUrlTemplates) { return this.getUrlsFromTemplate(username, new Resource(resourcePath)); @@ -55,45 +73,43 @@ ResourceLocator.prototype.getUrls = function(username, resourcePath) { } }; +function urlForTemplate(tpl, username, cdnDomain, resource) { + if (cdnDomain.hasOwnProperty('urlTemplate')) { + return { + urlTemplate: tpl({ + cdn_url: cdnDomain.urlTemplate, + user: username, + port: this.environment.port, + resource: resource.getPath() + }), + subdomains: cdnDomain.subdomains + }; + } else if (Array.isArray(cdnDomain)) { + return cdnDomain.map(d => tpl({ + cdn_url: d, + user: username, + port: this.environment.port, + resource: resource.getPath() + })); + } else { + return tpl({ + cdn_url: cdnDomain, + user: username, + port: this.environment.port, + resource: resource.getPath() + }); + } +} ResourceLocator.prototype.getUrlsFromTemplate = function(username, resource) { var urls = {}; var cdnDomain = getCdnDomain(this.environment.serverMetadata, resource) || {}; if (this.resourcesUrlTemplates.http) { - if (Array.isArray(cdnDomain.http)) { - urls.http = cdnDomain.http.map(d => this.resourcesUrlTemplates.http({ - cdn_url: d, - user: username, - port: this.environment.port, - resource: resource.getPath() - })); - } else { - urls.http = this.resourcesUrlTemplates.http({ - cdn_url: cdnDomain.http, - user: username, - port: this.environment.port, - resource: resource.getPath() - }); - } + urls.http = urlForTemplate(this.resourcesUrlTemplates.http, username, cdnDomain.http, resource); } - if (this.resourcesUrlTemplates.https) { - if (Array.isArray(cdnDomain.https)) { - urls.https = cdnDomain.https.map(d => this.resourcesUrlTemplates.https({ - cdn_url: d, - user: username, - port: this.environment.port, - resource: resource.getPath() - })); - } else { - urls.https = this.resourcesUrlTemplates.https({ - cdn_url: cdnDomain.https, - user: username, - port: this.environment.port, - resource: resource.getPath() - }); - } + urls.https = urlForTemplate(this.resourcesUrlTemplates.https, username, cdnDomain.https, resource); } return urls; @@ -109,6 +125,9 @@ class Resource { } getDomain (domain, subdomains) { + if (!subdomains) { + return domain; + } return domain.replace('{s}', subdomain(subdomains, this.resourcePath)); } @@ -127,6 +146,9 @@ class TileResource extends Resource { } getDomain (domain, subdomains) { + if (!subdomains) { + return domain; + } return subdomains.map(s => domain.replace('{s}', s)); } @@ -141,6 +163,26 @@ class TileResource extends Resource { } } +class TemplateResource extends Resource { + constructor (resourcePath) { + super(resourcePath); + } + + getDomain (domain, subdomains) { + return { + urlTemplate: domain, + subdomains: subdomains || [] + }; + } + + getUrl (baseUrl, username, subdomains) { + return { + urlTemplate: getUrl(baseUrl, username, this.resourcePath), + subdomains: subdomains || [] + }; + } +} + function getUrl(baseUrl, username, path) { return `${baseUrl}/${username}/api/v1/map/${path}`; } @@ -166,8 +208,8 @@ function getCdnUrls(serverMetadata, username, resource) { function getCdnDomain(serverMetadata, resource) { if (serverMetadata && serverMetadata.cdn_url) { var cdnUrl = serverMetadata.cdn_url; - var httpDomain = cdnUrl.http; - var httpsDomain = cdnUrl.https; + var httpDomain = resource.getDomain(cdnUrl.http); + var httpsDomain = resource.getDomain(cdnUrl.https); if (cdnUrl.templates) { var templates = cdnUrl.templates; var httpUrlTemplate = templates.http.url; diff --git a/test/acceptance/tilejson.js b/test/acceptance/tilejson.js index 56070e42..67b68d1c 100644 --- a/test/acceptance/tilejson.js +++ b/test/acceptance/tilejson.js @@ -8,7 +8,7 @@ describe('tilejson', function() { function tilejsonValidation(tilejson, shouldHaveGrid = false) { assert.equal(tilejson.tilejson, '2.2.0'); - assert.ok(Array.isArray(tilejson.tiles)); + assert.ok(Array.isArray(tilejson.tiles), JSON.stringify(tilejson)); assert.ok(tilejson.tiles.length > 0); if (shouldHaveGrid) { @@ -161,7 +161,7 @@ describe('tilejson', function() { describe('root tilejson', function() { - it('should expose just the `vector` tilejson when for vector only mapnik layers', function(done) { + it('should expose just the `vector` tilejson and URL when for vector only mapnik layers', function(done) { var testClient = new TestClient(mapConfig(VECTOR_LAYER)); testClient.getLayergroup(function(err, layergroupResult) { @@ -176,11 +176,17 @@ describe('tilejson', function() { tilejsonValidation(tilejson[k]); }); + const url = metadata.url; + assert.deepEqual(Object.keys(url), ['vector']); + + assert.ok(url.vector.http.urlTemplate); + assert.ok(url.vector.http.subdomains); + testClient.drain(done); }); }); - it('should expose just the `vector` and `raster` tilejson for mapnik layers', function(done) { + it('should expose just the `vector` and `raster` tilejson and urls for mapnik layers', function(done) { var testClient = new TestClient(mapConfig(RASTER_LAYER)); testClient.getLayergroup(function(err, layergroupResult) { @@ -195,6 +201,15 @@ describe('tilejson', function() { tilejsonValidation(tilejson[k]); }); + const url = metadata.url; + assert.deepEqual(Object.keys(url), ['vector', 'raster']); + + assert.ok(url.vector.http.urlTemplate); + assert.ok(url.vector.http.subdomains); + + assert.ok(url.raster.http.urlTemplate); + assert.ok(url.raster.http.subdomains); + testClient.drain(done); }); }); diff --git a/test/unit/cartodb/model/resource-locator.test.js b/test/unit/cartodb/model/resource-locator.test.js index 2f788d33..13ad5203 100644 --- a/test/unit/cartodb/model/resource-locator.test.js +++ b/test/unit/cartodb/model/resource-locator.test.js @@ -54,6 +54,24 @@ describe('ResourceLocator', function() { ); }); }); + + describe('getTemplateUrls', function() { + it('should return default urls when basic http and https domains are provided', function() { + var resourceLocator = new ResourceLocator(BASIC_ENVIRONMENT); + var urls = resourceLocator.getTemplateUrls(USERNAME, TILE_RESOURCE); + assert.ok(urls); + + assert.deepEqual(urls.http, { + urlTemplate: `http://cdn.carto.com/${USERNAME}/api/v1/map/${TILE_RESOURCE}`, + subdomains: [] + }); + assert.deepEqual(urls.https, { + urlTemplate: `https://cdn.ssl.carto.com/${USERNAME}/api/v1/map/${TILE_RESOURCE}`, + subdomains: [] + }); + }); + }); + }); describe('resource templates', function() { @@ -104,6 +122,24 @@ describe('ResourceLocator', function() { ); }); }); + + describe('getTemplateUrls', function() { + it('resources_url_templates should take precedence over http and https domains', function() { + var resourceLocator = new ResourceLocator(RESOURCE_TEMPLATES_ENVIRONMENT); + var urls = resourceLocator.getTemplateUrls(USERNAME, TILE_RESOURCE); + assert.ok(urls); + + assert.deepEqual(urls.http, { + urlTemplate: `http://${USERNAME}.localhost.lan/api/v1/map/${TILE_RESOURCE}`, + subdomains: [] + }); + assert.deepEqual(urls.https, { + urlTemplate: `https://${USERNAME}.ssl.localhost.lan/api/v1/map/${TILE_RESOURCE}`, + subdomains: [] + }); + }); + }); + }); describe('cdn templates', function() { @@ -126,6 +162,7 @@ describe('ResourceLocator', function() { } } }; + describe('getUrls', function() { it('cdn_url templates should take precedence over http and https domains', function() { var resourceLocator = new ResourceLocator(CDN_TEMPLATES_ENVIRONMENT); @@ -165,6 +202,23 @@ describe('ResourceLocator', function() { }); }); + describe('getTemplateUrls', function() { + it('cdn_url templates should take precedence over http and https domains', function() { + var resourceLocator = new ResourceLocator(CDN_TEMPLATES_ENVIRONMENT); + var urls = resourceLocator.getTemplateUrls(USERNAME, TILE_RESOURCE); + assert.ok(urls); + + assert.deepEqual(urls.http, { + urlTemplate: `http://{s}.cdn.carto.com/${USERNAME}/api/v1/map/${TILE_RESOURCE}`, + subdomains: HTTP_SUBDOMAINS + }); + assert.deepEqual(urls.https, { + urlTemplate: `https://cdn_{s}.ssl.cdn.carto.com/${USERNAME}/api/v1/map/${TILE_RESOURCE}`, + subdomains: HTTPS_SUBDOMAINS + }); + }); + }); + }); describe('cdn and resource templates', function() { @@ -231,6 +285,23 @@ describe('ResourceLocator', function() { }); }); + describe('getTemplateUrls', function() { + it('should mix cdn_url templates and resources_url_templates', function() { + var resourceLocator = new ResourceLocator(CDN_URL_AND_RESOURCE_TEMPLATES_ENVIRONMENT); + var urls = resourceLocator.getTemplateUrls(USERNAME, TILE_RESOURCE); + assert.ok(urls); + + assert.deepEqual(urls.http, { + urlTemplate: `http://{s}.cdn.carto.com/u/${USERNAME}/api/v1/map/${TILE_RESOURCE}`, + subdomains: HTTP_SUBDOMAINS + }); + assert.deepEqual(urls.https, { + urlTemplate: `https://cdn_{s}.ssl.cdn.carto.com/u/${USERNAME}/api/v1/map/${TILE_RESOURCE}`, + subdomains: HTTPS_SUBDOMAINS + }); + }); + }); + }); }); From 2cda43dc8d462f5c956949a3ea3a9cb611515eca Mon Sep 17 00:00:00 2001 From: Raul Ochoa Date: Wed, 3 Jan 2018 22:18:59 +0000 Subject: [PATCH 2/3] Promote https urls over http --- lib/cartodb/controllers/map.js | 7 +++++-- test/acceptance/tilejson.js | 12 ++++++------ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/cartodb/controllers/map.js b/lib/cartodb/controllers/map.js index 5ec2a0ef..34660ce0 100644 --- a/lib/cartodb/controllers/map.js +++ b/lib/cartodb/controllers/map.js @@ -314,6 +314,9 @@ MapController.prototype.augmentLayergroupData = function () { }; }; +function getTemplateUrl(url) { + return url.https || url.http; +} function getTilejson(tiles, grids) { const tilejson = { @@ -371,14 +374,14 @@ MapController.prototype.setTilejsonMetadataToLayergroup = function () { tilejson.vector = getTilejson( this.resourceLocator.getTileUrls(user, vectorResource) ); - url.vector = this.resourceLocator.getTemplateUrls(user, vectorResource); + url.vector = getTemplateUrl(this.resourceLocator.getTemplateUrls(user, vectorResource)); if (!isVectorOnlyMapConfig) { const rasterResource = `${layergroup.layergroupid}/{z}/{x}/{y}.png`; tilejson.raster = getTilejson( this.resourceLocator.getTileUrls(user, rasterResource) ); - url.raster = this.resourceLocator.getTemplateUrls(user, rasterResource); + url.raster = getTemplateUrl(this.resourceLocator.getTemplateUrls(user, rasterResource)); } } diff --git a/test/acceptance/tilejson.js b/test/acceptance/tilejson.js index 67b68d1c..0d3bc133 100644 --- a/test/acceptance/tilejson.js +++ b/test/acceptance/tilejson.js @@ -179,8 +179,8 @@ describe('tilejson', function() { const url = metadata.url; assert.deepEqual(Object.keys(url), ['vector']); - assert.ok(url.vector.http.urlTemplate); - assert.ok(url.vector.http.subdomains); + assert.ok(url.vector.urlTemplate); + assert.ok(url.vector.subdomains); testClient.drain(done); }); @@ -204,11 +204,11 @@ describe('tilejson', function() { const url = metadata.url; assert.deepEqual(Object.keys(url), ['vector', 'raster']); - assert.ok(url.vector.http.urlTemplate); - assert.ok(url.vector.http.subdomains); + assert.ok(url.vector.urlTemplate); + assert.ok(url.vector.subdomains); - assert.ok(url.raster.http.urlTemplate); - assert.ok(url.raster.http.subdomains); + assert.ok(url.raster.urlTemplate); + assert.ok(url.raster.subdomains); testClient.drain(done); }); From d5b5ef584df1947731776135db5522fbba155f7b Mon Sep 17 00:00:00 2001 From: Raul Ochoa Date: Wed, 3 Jan 2018 23:33:59 +0000 Subject: [PATCH 3/3] Be explicit about requesting urlTemplate+subdomains format --- lib/cartodb/models/resource-locator.js | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/lib/cartodb/models/resource-locator.js b/lib/cartodb/models/resource-locator.js index 14a98431..f9b1c1ad 100644 --- a/lib/cartodb/models/resource-locator.js +++ b/lib/cartodb/models/resource-locator.js @@ -42,7 +42,7 @@ ResourceLocator.prototype.getTileUrls = function(username, resourcePath) { ResourceLocator.prototype.getTemplateUrls = function(username, resourcePath) { if (this.resourcesUrlTemplates) { - return this.getUrlsFromTemplate(username, new TemplateResource(resourcePath)); + return this.getUrlsFromTemplate(username, new TemplateResource(resourcePath), true); } var cdnUrls = getCdnUrls(this.environment.serverMetadata, username, new TemplateResource(resourcePath)); if (cdnUrls) { @@ -73,18 +73,20 @@ ResourceLocator.prototype.getUrls = function(username, resourcePath) { } }; -function urlForTemplate(tpl, username, cdnDomain, resource) { - if (cdnDomain.hasOwnProperty('urlTemplate')) { +function urlForTemplate(tpl, username, cdnDomain, resource, templated) { + cdnDomain = cdnDomain || {}; + if (templated) { return { urlTemplate: tpl({ - cdn_url: cdnDomain.urlTemplate, + cdn_url: (cdnDomain.hasOwnProperty('urlTemplate') ? cdnDomain.urlTemplate : cdnDomain), user: username, port: this.environment.port, resource: resource.getPath() }), - subdomains: cdnDomain.subdomains + subdomains: cdnDomain.subdomains || [] }; - } else if (Array.isArray(cdnDomain)) { + } + if (Array.isArray(cdnDomain)) { return cdnDomain.map(d => tpl({ cdn_url: d, user: username, @@ -101,15 +103,14 @@ function urlForTemplate(tpl, username, cdnDomain, resource) { } } -ResourceLocator.prototype.getUrlsFromTemplate = function(username, resource) { +ResourceLocator.prototype.getUrlsFromTemplate = function(username, resource, templated) { var urls = {}; var cdnDomain = getCdnDomain(this.environment.serverMetadata, resource) || {}; - if (this.resourcesUrlTemplates.http) { - urls.http = urlForTemplate(this.resourcesUrlTemplates.http, username, cdnDomain.http, resource); + urls.http = urlForTemplate(this.resourcesUrlTemplates.http, username, cdnDomain.http, resource, templated); } if (this.resourcesUrlTemplates.https) { - urls.https = urlForTemplate(this.resourcesUrlTemplates.https, username, cdnDomain.https, resource); + urls.https = urlForTemplate(this.resourcesUrlTemplates.https, username, cdnDomain.https, resource, templated); } return urls;