Compare commits
88 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
47217909f6 | ||
|
|
3a0a366230 | ||
|
|
787ca1607a | ||
|
|
7179c0a5f1 | ||
|
|
b739db1023 | ||
|
|
66a898cdc2 | ||
|
|
ac94118798 | ||
|
|
1a197bb9cf | ||
|
|
5b96db2ba2 | ||
|
|
3b687ce09a | ||
|
|
7bb039b13c | ||
|
|
0ac53db73a | ||
|
|
36e9239056 | ||
|
|
4e6e267f10 | ||
|
|
2c235b6629 | ||
|
|
6bd7537467 | ||
|
|
8426dd00f1 | ||
|
|
567928a7f5 | ||
|
|
ae9e211f30 | ||
|
|
b5b75df91a | ||
|
|
8ddccc0b0c | ||
|
|
95195fff6f | ||
|
|
93b77dc4c1 | ||
|
|
4aee7fb1b8 | ||
|
|
a6d68dba5e | ||
|
|
883f87c7c8 | ||
|
|
14d37268d6 | ||
|
|
4b6181039d | ||
|
|
47944671c6 | ||
|
|
f33a7dd665 | ||
|
|
781e5a71bf | ||
|
|
c4ff884ad0 | ||
|
|
02b9f85b16 | ||
|
|
2756252368 | ||
|
|
a386abf5a5 | ||
|
|
e5c2c35a81 | ||
|
|
227112c7aa | ||
|
|
a4ed37bdfc | ||
|
|
c6a62cee61 | ||
|
|
891bc818b2 | ||
|
|
ebe25d6f20 | ||
|
|
92ec17218b | ||
|
|
e8a0f6b7b6 | ||
|
|
125c39967c | ||
|
|
4132bc755d | ||
|
|
9707881bf9 | ||
|
|
fa6493ae44 | ||
|
|
0c387cf6d9 | ||
|
|
5e4d1d5c1c | ||
|
|
4d82fd65f6 | ||
|
|
6d3644f13b | ||
|
|
7a5aa7ba35 | ||
|
|
9c9609eb2b | ||
|
|
418d3c074f | ||
|
|
6bbda3d41e | ||
|
|
25669bb3f2 | ||
|
|
508d495a23 | ||
|
|
06427dc009 | ||
|
|
c325df1414 | ||
|
|
07447160e3 | ||
|
|
ededc73fd7 | ||
|
|
cad02bfad7 | ||
|
|
94299f0452 | ||
|
|
ae5d82c41d | ||
|
|
6468822295 | ||
|
|
777ae31426 | ||
|
|
1ca56fb81c | ||
|
|
5d74e1eafe | ||
|
|
f3fdd7ff25 | ||
|
|
fbbe69dac0 | ||
|
|
ac54179f14 | ||
|
|
50d296e46c | ||
|
|
616ba6500c | ||
|
|
d9968f2c91 | ||
|
|
8ca9c5bcf7 | ||
|
|
a7b0618f91 | ||
|
|
e9896e34e1 | ||
|
|
28bd03765a | ||
|
|
24a86ae8df | ||
|
|
f5c349e105 | ||
|
|
e8d2e28dba | ||
|
|
e0c2423ace | ||
|
|
5e429ba71f | ||
|
|
64dfdba94d | ||
|
|
3866413504 | ||
|
|
2da834784f | ||
|
|
d6181da32b | ||
|
|
8694c120bc |
111
NEWS.md
111
NEWS.md
@@ -1,5 +1,116 @@
|
||||
# Changelog
|
||||
|
||||
## 3.6.7
|
||||
Released 2017-09-01
|
||||
|
||||
Announcements:
|
||||
- Adding a new cartodb-psql fixing a pg vulnerability.
|
||||
|
||||
|
||||
## 3.6.6
|
||||
Released 2017-05-11
|
||||
|
||||
Announcements:
|
||||
- Upgrades camshaft to [0.54.4](https://github.com/CartoDB/camshaft/releases/tag/0.54.4).
|
||||
|
||||
|
||||
## 3.6.5
|
||||
Released 2017-05-09
|
||||
|
||||
Announcements:
|
||||
- Upgrades camshaft to [0.54.3](https://github.com/CartoDB/camshaft/releases/tag/0.54.3).
|
||||
|
||||
|
||||
## 3.6.4
|
||||
Released 2017-05-05
|
||||
|
||||
Announcements:
|
||||
- Upgrade cartodb-psql to [0.8.0](https://github.com/CartoDB/node-cartodb-psql/releases/tag/0.8.0).
|
||||
- Upgrades camshaft to [0.54.2](https://github.com/CartoDB/camshaft/releases/tag/0.54.2).
|
||||
- Upgrades windshaft to [3.1.2](https://github.com/CartoDB/windshaft/releases/tag/3.1.2).
|
||||
|
||||
|
||||
## 3.6.3
|
||||
Released 2017-04-25
|
||||
|
||||
Announcements:
|
||||
- Upgrades windshaft to [3.1.1](https://github.com/CartoDB/windshaft/releases/tag/3.1.1).
|
||||
|
||||
|
||||
## 3.6.2
|
||||
Released 2017-04-24
|
||||
|
||||
Announcements:
|
||||
- Upgrades grainstore to [1.6.3](https://github.com/CartoDB/grainstore/releases/tag/1.6.3).
|
||||
|
||||
|
||||
## 3.6.1
|
||||
Released 2017-04-24
|
||||
|
||||
Announcements:
|
||||
- Upgrades camshaft to [0.54.1](https://github.com/CartoDB/camshaft/releases/tag/0.54.1).
|
||||
|
||||
|
||||
## 3.6.0
|
||||
Released 2017-04-20
|
||||
|
||||
Announcements:
|
||||
- Upgrades camshaft to [0.54.0](https://github.com/CartoDB/camshaft/releases/tag/0.54.0).
|
||||
|
||||
|
||||
## 3.5.1
|
||||
Released 2017-04-11
|
||||
|
||||
Announcements:
|
||||
- Upgrades camshaft to [0.53.1](https://github.com/CartoDB/camshaft/releases/tag/0.53.1).
|
||||
|
||||
|
||||
## 3.5.0
|
||||
Released 2017-04-10
|
||||
|
||||
Bug fixes:
|
||||
- Fix invalidation of cache for maps with analyses #638.
|
||||
|
||||
Announcements:
|
||||
- Upgrades camshaft to [0.53.0](https://github.com/CartoDB/camshaft/releases/tag/0.53.0).
|
||||
|
||||
|
||||
## 3.4.0
|
||||
Released 2017-04-03
|
||||
|
||||
Announcements:
|
||||
- Upgrades camshaft to [0.51.0](https://github.com/CartoDB/camshaft/releases/tag/0.51.0).
|
||||
|
||||
|
||||
## 3.3.0
|
||||
Released 2017-04-03
|
||||
|
||||
New features:
|
||||
- Static map endpoints allow specifying the layers to render #653.
|
||||
|
||||
|
||||
## 3.2.0
|
||||
Released 2017-03-30
|
||||
|
||||
Announcements:
|
||||
- Upgrades windshaft to [3.1.0](https://github.com/CartoDB/windshaft/releases/tag/3.1.0).
|
||||
- Active GC interval.
|
||||
|
||||
|
||||
## 3.1.1
|
||||
Released 2017-03-23
|
||||
|
||||
Bug fixes:
|
||||
- Use crc32 instead of md5 for computing subdomain candidate #642
|
||||
|
||||
|
||||
## 3.1.0
|
||||
Released 2017-03-22
|
||||
|
||||
Features:
|
||||
- Generate URLs for resources based on CDN and template rules
|
||||
|
||||
|
||||
## 3.0.2
|
||||
Released 2017-03-22
|
||||
|
||||
|
||||
14
app.js
14
app.js
@@ -136,3 +136,17 @@ process.on('SIGHUP', function() {
|
||||
process.on('uncaughtException', function(err) {
|
||||
global.logger.error('Uncaught exception: ' + err.stack);
|
||||
});
|
||||
|
||||
if (global.gc) {
|
||||
var gcInterval = Number.isFinite(global.environment.gc_interval) ?
|
||||
global.environment.gc_interval :
|
||||
10000;
|
||||
|
||||
if (gcInterval > 0) {
|
||||
setInterval(function gcForcedCycle() {
|
||||
var start = Date.now();
|
||||
global.gc();
|
||||
global.statsClient.timing('windshaft.gc', Date.now() - start);
|
||||
}, gcInterval);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,9 @@ var config = {
|
||||
// Its default size is 4, but it can be changed at startup time (the absolute maximum is 128).
|
||||
// See http://docs.libuv.org/en/latest/threadpool.html
|
||||
,uv_threadpool_size: undefined
|
||||
// Time in milliseconds to force GC cycle.
|
||||
// Disable by using <=0 value.
|
||||
,gc_interval: 10000
|
||||
// Regular expression pattern to extract username
|
||||
// from hostname. Must have a single grabbing block.
|
||||
,user_from_host: '^(.*)\\.localhost'
|
||||
|
||||
@@ -6,6 +6,9 @@ var config = {
|
||||
// Its default size is 4, but it can be changed at startup time (the absolute maximum is 128).
|
||||
// See http://docs.libuv.org/en/latest/threadpool.html
|
||||
,uv_threadpool_size: undefined
|
||||
// Time in milliseconds to force GC cycle.
|
||||
// Disable by using <=0 value.
|
||||
,gc_interval: 10000
|
||||
// Regular expression pattern to extract username
|
||||
// from hostname. Must have a single grabbing block.
|
||||
,user_from_host: '^(.*)\\.cartodb\\.com$'
|
||||
|
||||
@@ -6,6 +6,9 @@ var config = {
|
||||
// Its default size is 4, but it can be changed at startup time (the absolute maximum is 128).
|
||||
// See http://docs.libuv.org/en/latest/threadpool.html
|
||||
,uv_threadpool_size: undefined
|
||||
// Time in milliseconds to force GC cycle.
|
||||
// Disable by using <=0 value.
|
||||
,gc_interval: 10000
|
||||
// Regular expression pattern to extract username
|
||||
// from hostname. Must have a single grabbing block.
|
||||
,user_from_host: '^(.*)\\.cartodb\\.com$'
|
||||
|
||||
@@ -6,6 +6,9 @@ var config = {
|
||||
// Its default size is 4, but it can be changed at startup time (the absolute maximum is 128).
|
||||
// See http://docs.libuv.org/en/latest/threadpool.html
|
||||
,uv_threadpool_size: undefined
|
||||
// Time in milliseconds to force GC cycle.
|
||||
// Disable by using <=0 value.
|
||||
,gc_interval: 10000
|
||||
// Regular expression pattern to extract username
|
||||
// from hostname. Must have a single grabbing block.
|
||||
,user_from_host: '(.*)'
|
||||
|
||||
@@ -124,7 +124,7 @@ view (optional) | extra keys to specify the view area for the map. It can be use
|
||||
|
||||
### Placeholder Format
|
||||
|
||||
Placeholders are variables that can be placed in your template.json file. Placeholders need to be defined with a `type` and a default value for MapConfigs. See details about defining a MapConfig `type` for [Layergoup configurations](http://docs.carto.com/carto-engine/maps-api/mapconfig/#layergroup-configurations).
|
||||
Placeholders are variables that can be placed in your template.json file. Placeholders need to be defined with a `type` and a default value for MapConfigs. See details about defining a MapConfig `type` for [Layergroup configurations](http://docs.carto.com/carto-engine/maps-api/mapconfig/#layergroup-configurations).
|
||||
|
||||
Valid placeholder names start with a letter and can only contain letters, numbers, or underscores. They have to be written between the `<%=` and `%>` strings in order to be replaced inside the Named Maps API.
|
||||
|
||||
@@ -527,11 +527,11 @@ If you are creating a Torque layer in a Named Map without using the Torque.js li
|
||||
|
||||
#### Examples of Named Maps created with CARTO.js
|
||||
|
||||
- [Named Map selectors with interaction](http://bl.ocks.org/ohasselblad/515a8af1f99d5e690484)
|
||||
- [Named Map selectors with interaction](http://bl.ocks.org/andy-esch/515a8af1f99d5e690484)
|
||||
|
||||
- [Named Map with interactivity](http://bl.ocks.org/ohasselblad/d1a45b8ff5e7bd90cd68)
|
||||
- [Named Map with interactivity](http://bl.ocks.org/andy-esch/d1a45b8ff5e7bd90cd68)
|
||||
|
||||
- [Toggling sublayers in a Named Map](http://bl.ocks.org/ohasselblad/c1a0f4913610eec53cd3)
|
||||
- [Toggling sublayers in a Named Map](http://bl.ocks.org/andy-esch/c1a0f4913610eec53cd3)
|
||||
|
||||
## Fetching XYZ Tiles for Named Maps
|
||||
|
||||
|
||||
@@ -150,6 +150,10 @@ It is important to note that generated images are cached from the live data refe
|
||||
* Image resolution is set to 72 DPI
|
||||
* JPEG quality is 85%
|
||||
* Timeout limits for generating static maps are the same across CARTO Builder and CARTO Engine. It is important to ensure timely processing of queries.
|
||||
* If you are publishing your map as a static image with the API, you must manually add [attributions](https://carto.com/attribution) for your static map image. For example, add the following attribution code:
|
||||
|
||||
{% highlight javascript %}attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, © <a href="https://carto.com/attributions">CARTO</a>
|
||||
{% endhighlight %}
|
||||
|
||||
## Examples
|
||||
|
||||
|
||||
@@ -95,9 +95,7 @@ AuthApi.prototype.authorize = function(req, callback) {
|
||||
self.authorizedByAPIKey(user, req, this);
|
||||
},
|
||||
function checkApiKey(err, authorized){
|
||||
if (req.profiler) {
|
||||
req.profiler.done('authorizedByAPIKey');
|
||||
}
|
||||
req.profiler.done('authorizedByAPIKey');
|
||||
assert.ifError(err);
|
||||
|
||||
// if not authorized by api_key, continue
|
||||
@@ -131,9 +129,7 @@ AuthApi.prototype.authorize = function(req, callback) {
|
||||
}
|
||||
|
||||
self.pgConnection.setDBAuth(user, req.params, function(err) {
|
||||
if (req.profiler) {
|
||||
req.profiler.done('setDBAuth');
|
||||
}
|
||||
req.profiler.done('setDBAuth');
|
||||
callback(err, true); // authorized (or error)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ function BaseController(authApi, pgConnection) {
|
||||
|
||||
module.exports = BaseController;
|
||||
|
||||
// jshint maxcomplexity:9
|
||||
// jshint maxcomplexity:10
|
||||
/**
|
||||
* Whitelist input and get database name & default geometry type from
|
||||
* subdomain/user metadata held in CartoDB Redis
|
||||
@@ -61,9 +61,7 @@ BaseController.prototype.req2params = function(req, callback){
|
||||
lzmaWorker.decompress(
|
||||
lzma,
|
||||
function(result) {
|
||||
if (req.profiler) {
|
||||
req.profiler.done('lzma');
|
||||
}
|
||||
req.profiler.done('lzma');
|
||||
try {
|
||||
delete req.query.lzma;
|
||||
_.extend(req.query, JSON.parse(result));
|
||||
@@ -77,7 +75,11 @@ BaseController.prototype.req2params = function(req, callback){
|
||||
return;
|
||||
}
|
||||
|
||||
req.query = _.pick(req.query, REQUEST_QUERY_PARAMS_WHITELIST);
|
||||
var allowedQueryParams = REQUEST_QUERY_PARAMS_WHITELIST;
|
||||
if (Array.isArray(req.context.allowedQueryParams)) {
|
||||
allowedQueryParams = allowedQueryParams.concat(req.context.allowedQueryParams);
|
||||
}
|
||||
req.query = _.pick(req.query, allowedQueryParams);
|
||||
req.params = _.extend({}, req.params); // shuffle things as request is a strange array/object
|
||||
|
||||
var user = req.context.user;
|
||||
@@ -115,18 +117,14 @@ BaseController.prototype.req2params = function(req, callback){
|
||||
// bring all query values onto req.params object
|
||||
_.extend(req.params, req.query);
|
||||
|
||||
if (req.profiler) {
|
||||
req.profiler.done('req2params.setup');
|
||||
}
|
||||
req.profiler.done('req2params.setup');
|
||||
|
||||
step(
|
||||
function getPrivacy(){
|
||||
self.authApi.authorize(req, this);
|
||||
},
|
||||
function validateAuthorization(err, authorized) {
|
||||
if (req.profiler) {
|
||||
req.profiler.done('authorize');
|
||||
}
|
||||
req.profiler.done('authorize');
|
||||
assert.ifError(err);
|
||||
if(!authorized) {
|
||||
err = new Error("Sorry, you are unauthorized (permission denied)");
|
||||
@@ -167,9 +165,7 @@ BaseController.prototype.send = function(req, res, body, status, headers) {
|
||||
res.set('X-Served-By-DB-Host', req.params.dbhost);
|
||||
}
|
||||
|
||||
if (req.profiler) {
|
||||
res.set('X-Tiler-Profiler', req.profiler.toJSONString());
|
||||
}
|
||||
res.set('X-Tiler-Profiler', req.profiler.toJSONString());
|
||||
|
||||
if (headers) {
|
||||
res.set(headers);
|
||||
@@ -187,14 +183,12 @@ BaseController.prototype.send = function(req, res, body, status, headers) {
|
||||
res.send(body);
|
||||
}
|
||||
|
||||
if (req.profiler) {
|
||||
try {
|
||||
// May throw due to dns, see
|
||||
// See http://github.com/CartoDB/Windshaft/issues/166
|
||||
req.profiler.sendStats();
|
||||
} catch (err) {
|
||||
debug("error sending profiling stats: " + err);
|
||||
}
|
||||
try {
|
||||
// May throw due to dns, see
|
||||
// See http://github.com/CartoDB/Windshaft/issues/166
|
||||
req.profiler.sendStats();
|
||||
} catch (err) {
|
||||
debug("error sending profiling stats: " + err);
|
||||
}
|
||||
};
|
||||
// jshint maxcomplexity:6
|
||||
|
||||
@@ -6,6 +6,7 @@ var BaseController = require('./base');
|
||||
|
||||
var cors = require('../middleware/cors');
|
||||
var userMiddleware = require('../middleware/user');
|
||||
var allowQueryParams = require('../middleware/allow-query-params');
|
||||
|
||||
var DataviewBackend = require('../backends/dataview');
|
||||
var AnalysisStatusBackend = require('../backends/analysis-status');
|
||||
@@ -67,11 +68,13 @@ LayergroupController.prototype.register = function(app) {
|
||||
this.attributes.bind(this));
|
||||
|
||||
app.get(app.base_url_mapconfig +
|
||||
'/static/center/:token/:z/:lat/:lng/:width/:height.:format', cors(), userMiddleware,
|
||||
'/static/center/:token/:z/:lat/:lng/:width/:height.:format',
|
||||
cors(), userMiddleware, allowQueryParams(['layer']),
|
||||
this.center.bind(this));
|
||||
|
||||
app.get(app.base_url_mapconfig +
|
||||
'/static/bbox/:token/:west,:south,:east,:north/:width/:height.:format', cors(), userMiddleware,
|
||||
'/static/bbox/:token/:west,:south,:east,:north/:width/:height.:format',
|
||||
cors(), userMiddleware, allowQueryParams(['layer']),
|
||||
this.bbox.bind(this));
|
||||
|
||||
// Undocumented/non-supported API endpoint methods.
|
||||
@@ -388,13 +391,15 @@ LayergroupController.prototype.getAffectedTables = function(user, dbName, layerg
|
||||
function getSQL(err, mapConfig) {
|
||||
assert.ifError(err);
|
||||
|
||||
var queries = mapConfig.getLayers()
|
||||
.map(function(lyr) {
|
||||
return lyr.options.sql;
|
||||
})
|
||||
.filter(function(sql) {
|
||||
return !!sql;
|
||||
});
|
||||
var queries = [];
|
||||
mapConfig.getLayers().forEach(function(layer) {
|
||||
queries.push(layer.options.sql);
|
||||
if (layer.options.affected_tables) {
|
||||
layer.options.affected_tables.map(function(table) {
|
||||
queries.push('SELECT * FROM ' + table + ' LIMIT 0');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return queries.length ? queries.join(';') : null;
|
||||
},
|
||||
|
||||
@@ -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);
|
||||
@@ -100,9 +87,7 @@ MapController.prototype.createPost = function(req, res) {
|
||||
};
|
||||
|
||||
MapController.prototype.instantiate = function(req, res) {
|
||||
if (req.profiler) {
|
||||
req.profiler.start('windshaft-cartodb.instance_template_post');
|
||||
}
|
||||
req.profiler.start('windshaft-cartodb.instance_template_post');
|
||||
|
||||
this.instantiateTemplate(req, res, function prepareTemplateParams(callback) {
|
||||
if (!req.is('application/json')) {
|
||||
@@ -113,9 +98,7 @@ MapController.prototype.instantiate = function(req, res) {
|
||||
};
|
||||
|
||||
MapController.prototype.jsonp = function(req, res) {
|
||||
if (req.profiler) {
|
||||
req.profiler.start('windshaft-cartodb.instance_template_get');
|
||||
}
|
||||
req.profiler.start('windshaft-cartodb.instance_template_get');
|
||||
|
||||
this.instantiateTemplate(req, res, function prepareJsonTemplateParams(callback) {
|
||||
var err = null;
|
||||
@@ -316,18 +299,22 @@ MapController.prototype.afterLayergroupCreate = function(req, res, mapconfig, la
|
||||
// take place before proceeding. Error will be logged
|
||||
// asynchronously
|
||||
this.metadataBackend.incMapviewCount(username, mapconfig.obj().stat_tag, function(err) {
|
||||
if (req.profiler) {
|
||||
req.profiler.done('incMapviewCount');
|
||||
}
|
||||
req.profiler.done('incMapviewCount');
|
||||
if ( err ) {
|
||||
global.logger.log("ERROR: failed to increment mapview count for user '" + username + "': " + err);
|
||||
}
|
||||
done();
|
||||
});
|
||||
|
||||
var sql = mapconfig.getLayers().map(function(layer) {
|
||||
return layer.options.sql;
|
||||
}).join(';');
|
||||
var sql = [];
|
||||
mapconfig.getLayers().forEach(function(layer) {
|
||||
sql.push(layer.options.sql);
|
||||
if (layer.options.affected_tables) {
|
||||
layer.options.affected_tables.map(function(table) {
|
||||
sql.push('SELECT * FROM ' + table + ' LIMIT 0');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var dbName = req.params.dbname;
|
||||
var layergroupId = layergroup.layergroupid;
|
||||
@@ -338,12 +325,10 @@ MapController.prototype.afterLayergroupCreate = function(req, res, mapconfig, la
|
||||
},
|
||||
function getAffectedTablesAndLastUpdatedTime(err, connection) {
|
||||
assert.ifError(err);
|
||||
QueryTables.getAffectedTablesFromQuery(connection, sql, this);
|
||||
QueryTables.getAffectedTablesFromQuery(connection, sql.join(';'), this);
|
||||
},
|
||||
function handleAffectedTablesAndLastUpdatedTime(err, result) {
|
||||
if (req.profiler) {
|
||||
req.profiler.done('queryTablesAndLastUpdated');
|
||||
}
|
||||
req.profiler.done('queryTablesAndLastUpdated');
|
||||
assert.ifError(err);
|
||||
// feed affected tables cache so it can be reused from, for instance, layergroup controller
|
||||
self.layergroupAffectedTables.set(dbName, layergroupId, result);
|
||||
@@ -399,7 +384,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 +414,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 +429,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 +437,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;
|
||||
};
|
||||
|
||||
@@ -8,6 +8,7 @@ var BaseController = require('./base');
|
||||
|
||||
var cors = require('../middleware/cors');
|
||||
var userMiddleware = require('../middleware/user');
|
||||
var allowQueryParams = require('../middleware/allow-query-params');
|
||||
|
||||
function NamedMapsController(authApi, pgConnection, namedMapProviderCache, tileBackend, previewBackend,
|
||||
surrogateKeysCache, tablesExtentApi, metadataBackend) {
|
||||
@@ -31,7 +32,7 @@ NamedMapsController.prototype.register = function(app) {
|
||||
this.tile.bind(this));
|
||||
|
||||
app.get(app.base_url_mapconfig +
|
||||
'/static/named/:template_id/:width/:height.:format', cors(), userMiddleware,
|
||||
'/static/named/:template_id/:width/:height.:format', cors(), userMiddleware, allowQueryParams(['layer']),
|
||||
this.staticMap.bind(this));
|
||||
};
|
||||
|
||||
@@ -100,9 +101,7 @@ NamedMapsController.prototype.tile = function(req, res) {
|
||||
self.tileBackend.getTile(namedMapProvider, req.params, this);
|
||||
},
|
||||
function handleImage(err, tile, headers, stats) {
|
||||
if (req.profiler) {
|
||||
req.profiler.add(stats);
|
||||
}
|
||||
req.profiler.add(stats);
|
||||
if (err) {
|
||||
self.sendError(req, res, err, 'NAMED_MAP_TILE');
|
||||
} else {
|
||||
@@ -176,10 +175,8 @@ NamedMapsController.prototype.staticMap = function(req, res) {
|
||||
});
|
||||
},
|
||||
function handleImage(err, image, headers, stats) {
|
||||
if (req.profiler) {
|
||||
req.profiler.done('render-' + format);
|
||||
req.profiler.add(stats || {});
|
||||
}
|
||||
req.profiler.done('render-' + format);
|
||||
req.profiler.add(stats || {});
|
||||
|
||||
if (err) {
|
||||
self.sendError(req, res, err, 'STATIC_VIZ_MAP');
|
||||
|
||||
@@ -91,9 +91,7 @@ NamedMapsAdminController.prototype.update = function(req, res) {
|
||||
NamedMapsAdminController.prototype.retrieve = function(req, res) {
|
||||
var self = this;
|
||||
|
||||
if (req.profiler) {
|
||||
req.profiler.start('windshaft-cartodb.get_template');
|
||||
}
|
||||
req.profiler.start('windshaft-cartodb.get_template');
|
||||
|
||||
var cdbuser = req.context.user;
|
||||
var tpl_id;
|
||||
@@ -127,9 +125,7 @@ NamedMapsAdminController.prototype.retrieve = function(req, res) {
|
||||
NamedMapsAdminController.prototype.destroy = function(req, res) {
|
||||
var self = this;
|
||||
|
||||
if (req.profiler) {
|
||||
req.profiler.start('windshaft-cartodb.delete_template');
|
||||
}
|
||||
req.profiler.start('windshaft-cartodb.delete_template');
|
||||
|
||||
var cdbuser = req.context.user;
|
||||
var tpl_id;
|
||||
@@ -154,9 +150,7 @@ NamedMapsAdminController.prototype.destroy = function(req, res) {
|
||||
|
||||
NamedMapsAdminController.prototype.list = function(req, res) {
|
||||
var self = this;
|
||||
if ( req.profiler ) {
|
||||
req.profiler.start('windshaft-cartodb.get_template_list');
|
||||
}
|
||||
req.profiler.start('windshaft-cartodb.get_template_list');
|
||||
|
||||
var cdbuser = req.context.user;
|
||||
|
||||
|
||||
9
lib/cartodb/middleware/allow-query-params.js
Normal file
9
lib/cartodb/middleware/allow-query-params.js
Normal file
@@ -0,0 +1,9 @@
|
||||
module.exports = function allowQueryParams(params) {
|
||||
if (!Array.isArray(params)) {
|
||||
throw new Error('allowQueryParams must receive an Array of params');
|
||||
}
|
||||
return function allowQueryParamsMiddleware(req, res, next) {
|
||||
req.context.allowedQueryParams = params;
|
||||
next();
|
||||
};
|
||||
};
|
||||
@@ -115,6 +115,7 @@ AnalysisMapConfigAdapter.prototype.getMapConfig = function(user, requestMapConfi
|
||||
}
|
||||
layer.options.sql = analysisSql;
|
||||
layer.options.columns = getDataviewsColumns(getLayerDataviews(layer, dataviews));
|
||||
layer.options.affected_tables = getAllAffectedTablesFromSourceNodes(layerNode);
|
||||
} else {
|
||||
missingNodesErrors.push(
|
||||
new Error('Missing analysis node.id="' + layerSourceId +'" for layer='+layerIndex)
|
||||
@@ -330,4 +331,13 @@ function AnalysisError(message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
function getAllAffectedTablesFromSourceNodes(node) {
|
||||
var affectedTables = node.getAllInputNodes(function (node) {
|
||||
return node.getType() === 'source';
|
||||
}).reduce(function(list, node) {
|
||||
return list.concat(node.getAffectedTables());
|
||||
},[]);
|
||||
return affectedTables;
|
||||
}
|
||||
|
||||
require('util').inherits(AnalysisError, Error);
|
||||
|
||||
119
lib/cartodb/models/resource-locator.js
Normal file
119
lib/cartodb/models/resource-locator.js
Normal file
@@ -0,0 +1,119 @@
|
||||
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;
|
||||
}
|
||||
|
||||
// ref https://jsperf.com/js-crc32
|
||||
function crcTable() {
|
||||
var c;
|
||||
var table = [];
|
||||
for (var n = 0; n < 256; n++) {
|
||||
c = n;
|
||||
for (var k = 0; k < 8; k++) {
|
||||
c = ((c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1));
|
||||
}
|
||||
table[n] = c;
|
||||
}
|
||||
return table;
|
||||
}
|
||||
var CRC_TABLE = crcTable();
|
||||
|
||||
function crc32(str) {
|
||||
var crc = 0 ^ (-1);
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
crc = (crc >>> 8) ^ CRC_TABLE[(crc ^ str.charCodeAt(i)) & 0xFF];
|
||||
}
|
||||
return (crc ^ (-1)) >>> 0;
|
||||
}
|
||||
|
||||
function subdomain(subdomains, resource) {
|
||||
var index = crc32(resource) % subdomains.length;
|
||||
return subdomains[index];
|
||||
}
|
||||
module.exports.subdomain = subdomain;
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "windshaft-cartodb",
|
||||
"version": "3.0.2",
|
||||
"version": "3.6.7",
|
||||
"description": "A map tile server for CartoDB",
|
||||
"keywords": [
|
||||
"cartodb"
|
||||
@@ -20,8 +20,8 @@
|
||||
],
|
||||
"dependencies": {
|
||||
"body-parser": "~1.14.0",
|
||||
"camshaft": "0.50.3",
|
||||
"cartodb-psql": "~0.7.1",
|
||||
"camshaft": "0.54.4",
|
||||
"cartodb-psql": "0.10.1",
|
||||
"cartodb-query-tables": "0.2.0",
|
||||
"cartodb-redis": "0.13.2",
|
||||
"debug": "~2.2.0",
|
||||
@@ -39,7 +39,7 @@
|
||||
"step-profiler": "~0.3.0",
|
||||
"turbo-carto": "0.19.0",
|
||||
"underscore": "~1.6.0",
|
||||
"windshaft": "3.0.1",
|
||||
"windshaft": "3.1.2",
|
||||
"yargs": "~5.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -373,5 +373,70 @@ describe('analysis-layers error cases', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('should return "function does not exist" indicating the node_id and context', function(done) {
|
||||
var mapConfig = createMapConfig([{
|
||||
"type": "cartodb",
|
||||
"options": {
|
||||
"source": {
|
||||
"id": "HEAD"
|
||||
},
|
||||
"cartocss": '#polygons { polygon-fill: red; }',
|
||||
"cartocss_version": "2.3.0"
|
||||
}
|
||||
}], {}, [{
|
||||
"id": "HEAD",
|
||||
"type": "buffer",
|
||||
"params": {
|
||||
"source": {
|
||||
"id": "HEAD2",
|
||||
"type": "buffer",
|
||||
"params": {
|
||||
"source": {
|
||||
"id": "HEAD3",
|
||||
"type": 'deprecated-sql-function',
|
||||
"params": {
|
||||
"id": "HEAD4",
|
||||
"function_name": 'DEP_EXT_does_not_exist_fn',
|
||||
"primary_source": {
|
||||
"type": 'source',
|
||||
"params": {
|
||||
"query": "select * from populated_places_simple_reduced"
|
||||
}
|
||||
},
|
||||
"function_args": ['wadus']
|
||||
}
|
||||
},
|
||||
"radius": 10
|
||||
}
|
||||
},
|
||||
"radius": 10
|
||||
}
|
||||
}]);
|
||||
|
||||
var testClient = new TestClient(mapConfig, 1234);
|
||||
|
||||
testClient.getLayergroup(ERROR_RESPONSE, function(err, layergroupResult) {
|
||||
assert.ok(!err, err);
|
||||
|
||||
assert.equal(layergroupResult.errors.length, 1);
|
||||
assert.equal(
|
||||
layergroupResult.errors[0],
|
||||
'function dep_ext_does_not_exist_fn(unknown, unknown, unknown, text[], unknown) does not exist'
|
||||
);
|
||||
|
||||
assert.equal(layergroupResult.errors_with_context[0].type, 'analysis');
|
||||
assert.equal(
|
||||
layergroupResult.errors_with_context[0].message,
|
||||
'function dep_ext_does_not_exist_fn(unknown, unknown, unknown, text[], unknown) does not exist'
|
||||
);
|
||||
assert.equal(layergroupResult.errors_with_context[0].analysis.id, 'HEAD');
|
||||
assert.equal(layergroupResult.errors_with_context[0].analysis.type, 'buffer');
|
||||
assert.equal(layergroupResult.errors_with_context[0].analysis.node_id, 'HEAD3');
|
||||
|
||||
testClient.drain(done);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
393
test/acceptance/cache/cache_headers.js
vendored
Normal file
393
test/acceptance/cache/cache_headers.js
vendored
Normal file
@@ -0,0 +1,393 @@
|
||||
var testHelper = require('../../support/test_helper');
|
||||
|
||||
var assert = require('../../support/assert');
|
||||
var qs = require('querystring');
|
||||
|
||||
var CartodbWindshaft = require('../../../lib/cartodb/server');
|
||||
var serverOptions = require('../../../lib/cartodb/server_options');
|
||||
var server = new CartodbWindshaft(serverOptions);
|
||||
server.setMaxListeners(0);
|
||||
|
||||
var LayergroupToken = require('../../support/layergroup-token');
|
||||
|
||||
describe('get requests with cache headers', function() {
|
||||
|
||||
var keysToDelete;
|
||||
beforeEach(function() {
|
||||
keysToDelete = {};
|
||||
});
|
||||
|
||||
afterEach(function(done) {
|
||||
testHelper.deleteRedisKeys(keysToDelete, done);
|
||||
});
|
||||
|
||||
var statusOkResponse = {
|
||||
status: 200
|
||||
};
|
||||
|
||||
var mapConfigs = [
|
||||
{
|
||||
"description": "cache headers should be present",
|
||||
"cache_headers": {
|
||||
"x_cache_channel": {
|
||||
"db_name": "test_windshaft_cartodb_user_1_db",
|
||||
"tables": ["public.test_table"]
|
||||
},
|
||||
"surrogate_keys": "t:77pJnX"
|
||||
},
|
||||
"data":
|
||||
{
|
||||
version: '1.5.0',
|
||||
layers: [
|
||||
{
|
||||
options: {
|
||||
source: {
|
||||
id: "2570e105-7b37-40d2-bdf4-1af889598745"
|
||||
},
|
||||
sql: 'select * from test_table limit 2',
|
||||
cartocss: '#layer { marker-fill:red; }',
|
||||
cartocss_version: '2.3.0',
|
||||
attributes: {
|
||||
id:'cartodb_id',
|
||||
columns: [
|
||||
'name',
|
||||
'address'
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
analyses: [
|
||||
{
|
||||
"id": "2570e105-7b37-40d2-bdf4-1af889598745",
|
||||
"type": "source",
|
||||
"params": {
|
||||
"query": "select * from test_table limit 2"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
},
|
||||
{
|
||||
"description": "cache headers should be present and be composed with source table name",
|
||||
"cache_headers": {
|
||||
"x_cache_channel": {
|
||||
"db_name": "test_windshaft_cartodb_user_1_db",
|
||||
"tables": ["public.analysis_2f13a3dbd7_9eb239903a1afd8a69130d1ece0fc8b38de8592d",
|
||||
"public.test_table"]
|
||||
},
|
||||
"surrogate_keys": "t:77pJnX t:iL4eth"
|
||||
},
|
||||
"data":
|
||||
{
|
||||
version: '1.5.0',
|
||||
layers: [
|
||||
{
|
||||
options: {
|
||||
source: {
|
||||
id: "2570e105-7b37-40d2-bdf4-1af889598745"
|
||||
},
|
||||
sql: 'select * from test_table limit 2',
|
||||
cartocss: '#layer { marker-fill:red; }',
|
||||
cartocss_version: '2.3.0',
|
||||
attributes: {
|
||||
id:'cartodb_id',
|
||||
columns: [
|
||||
'name',
|
||||
'address'
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
analyses: [
|
||||
{
|
||||
"id": "2570e105-7b37-40d2-bdf4-1af889598745",
|
||||
"type": "buffer",
|
||||
"params": {
|
||||
"source": {
|
||||
"type": "source",
|
||||
"params": {
|
||||
"query": "select * from test_table limit 2"
|
||||
}
|
||||
},
|
||||
"radius": 50000
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}];
|
||||
|
||||
var layergroupRequest = function(mapConfig) {
|
||||
return {
|
||||
url: '/api/v1/map?api_key=1234&config=' + encodeURIComponent(JSON.stringify(mapConfig)),
|
||||
method: 'GET',
|
||||
headers: {
|
||||
host: 'localhost'
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
function getRequest(url, addApiKey, callbackName) {
|
||||
var params = {};
|
||||
if (!!addApiKey) {
|
||||
params.api_key = '1234';
|
||||
}
|
||||
if (!!callbackName) {
|
||||
params.callback = callbackName;
|
||||
}
|
||||
|
||||
return {
|
||||
url: url + '?' + qs.stringify(params),
|
||||
method: 'GET',
|
||||
headers: {
|
||||
host: 'localhost',
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function validateCacheHeaders(done, expectedCacheHeaders) {
|
||||
return function(res, err) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
assert.ok(res.headers['x-cache-channel']);
|
||||
assert.ok(res.headers['surrogate-key']);
|
||||
if (expectedCacheHeaders) {
|
||||
validateXChannelHeaders(res.headers, expectedCacheHeaders);
|
||||
assert.equal(res.headers['surrogate-key'], expectedCacheHeaders.surrogate_keys);
|
||||
}
|
||||
|
||||
done();
|
||||
};
|
||||
}
|
||||
|
||||
function validateXChannelHeaders(headers, expectedCacheHeaders) {
|
||||
var dbName = headers['x-cache-channel'].split(':')[0];
|
||||
var tables = headers['x-cache-channel'].split(':')[1].split(',').sort();
|
||||
assert.equal(dbName, expectedCacheHeaders.x_cache_channel.db_name);
|
||||
assert.deepEqual(tables, expectedCacheHeaders.x_cache_channel.tables.sort());
|
||||
}
|
||||
|
||||
function noCacheHeaders(done) {
|
||||
return function(res, err) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
assert.ok(
|
||||
!res.headers['x-cache-channel'],
|
||||
'did not expect x-cache-channel header, got: `' + res.headers['x-cache-channel'] + '`'
|
||||
);
|
||||
assert.ok(
|
||||
!res.headers['surrogate-key'],
|
||||
'did not expect surrogate-key header, got: `' + res.headers['surrogate-key'] + '`'
|
||||
);
|
||||
done();
|
||||
};
|
||||
}
|
||||
|
||||
function withLayergroupId(mapConfig, callback) {
|
||||
assert.response(
|
||||
server,
|
||||
layergroupRequest(mapConfig),
|
||||
statusOkResponse,
|
||||
function(res, err) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
var layergroupId = JSON.parse(res.body).layergroupid;
|
||||
keysToDelete['map_cfg|' + LayergroupToken.parse(layergroupId).token] = 0;
|
||||
keysToDelete['user:localhost:mapviews:global'] = 5;
|
||||
callback(null, layergroupId, res);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
mapConfigs.forEach(function(mapConfigData) {
|
||||
describe(mapConfigData.description, function() {
|
||||
var mapConfig = mapConfigData.data;
|
||||
var expectedCacheHeaders = mapConfigData.cache_headers;
|
||||
it('/api/v1/map Map instantiation', function(done) {
|
||||
var testFn = validateCacheHeaders(done, expectedCacheHeaders);
|
||||
withLayergroupId(mapConfig, function(err, layergroupId, res) {
|
||||
testFn(res);
|
||||
});
|
||||
});
|
||||
|
||||
it ('/api/v1/map/:token/:z/:x/:y@:scale_factor?x.:format Mapnik retina tiles', function(done) {
|
||||
withLayergroupId(mapConfig, function(err, layergroupId) {
|
||||
assert.response(
|
||||
server,
|
||||
getRequest('/api/v1/map/' + layergroupId + '/0/0/0@2x.png', true),
|
||||
validateCacheHeaders(done, expectedCacheHeaders)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it ('/api/v1/map/:token/:z/:x/:y@:scale_factor?x.:format Mapnik tiles', function(done) {
|
||||
withLayergroupId(mapConfig, function(err, layergroupId) {
|
||||
assert.response(
|
||||
server,
|
||||
getRequest('/api/v1/map/' + layergroupId + '/0/0/0.png', true),
|
||||
validateCacheHeaders(done, expectedCacheHeaders)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it ('/api/v1/map/:token/:layer/:z/:x/:y.(:format) Per :layer rendering', function(done) {
|
||||
withLayergroupId(mapConfig, function(err, layergroupId) {
|
||||
assert.response(
|
||||
server,
|
||||
getRequest('/api/v1/map/' + layergroupId + '/0/0/0/0.png', true),
|
||||
validateCacheHeaders(done, expectedCacheHeaders)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it ('/api/v1/map/:token/:layer/attributes/:fid endpoint for info windows', function(done) {
|
||||
withLayergroupId(mapConfig, function(err, layergroupId) {
|
||||
assert.response(
|
||||
server,
|
||||
getRequest('/api/v1/map/' + layergroupId + '/0/attributes/1', true),
|
||||
validateCacheHeaders(done, expectedCacheHeaders)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it ('/api/v1/map/static/center/:token/:z/:lat/:lng/:width/:height.:format static maps', function(done) {
|
||||
withLayergroupId(mapConfig, function(err, layergroupId) {
|
||||
assert.response(
|
||||
server,
|
||||
getRequest('/api/v1/map/static/center/' + layergroupId + '/0/0/0/400/300.png', true),
|
||||
validateCacheHeaders(done, expectedCacheHeaders)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it ('/api/v1/map/static/bbox/:token/:bbox/:width/:height.:format static maps', function(done) {
|
||||
withLayergroupId(mapConfig, function(err, layergroupId) {
|
||||
assert.response(
|
||||
server,
|
||||
getRequest('/api/v1/map/static/bbox/' + layergroupId + '/-45,-45,45,45/400/300.png', true),
|
||||
validateCacheHeaders(done, expectedCacheHeaders)
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('cache headers should NOT be present', function() {
|
||||
|
||||
it('/', function(done) {
|
||||
assert.response(
|
||||
server,
|
||||
getRequest('/'),
|
||||
statusOkResponse,
|
||||
noCacheHeaders(done)
|
||||
);
|
||||
});
|
||||
|
||||
it('/version', function(done) {
|
||||
assert.response(
|
||||
server,
|
||||
getRequest('/version'),
|
||||
statusOkResponse,
|
||||
noCacheHeaders(done)
|
||||
);
|
||||
});
|
||||
|
||||
it('/health', function(done) {
|
||||
assert.response(
|
||||
server,
|
||||
getRequest('/health'),
|
||||
statusOkResponse,
|
||||
noCacheHeaders(done)
|
||||
);
|
||||
});
|
||||
|
||||
it('/api/v1/map/named list named maps', function(done) {
|
||||
assert.response(
|
||||
server,
|
||||
getRequest('/api/v1/map/named', true),
|
||||
statusOkResponse,
|
||||
noCacheHeaders(done)
|
||||
);
|
||||
});
|
||||
|
||||
describe('with named maps', function() {
|
||||
|
||||
var templateName = 'x_cache';
|
||||
|
||||
beforeEach(function(done) {
|
||||
var template = {
|
||||
version: '0.0.1',
|
||||
name: templateName,
|
||||
auth: {
|
||||
method: 'open'
|
||||
},
|
||||
layergroup: mapConfigs[0].data
|
||||
};
|
||||
|
||||
var namedMapRequest = {
|
||||
url: '/api/v1/map/named?api_key=1234',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
host: 'localhost',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
data: JSON.stringify(template)
|
||||
};
|
||||
|
||||
assert.response(
|
||||
server,
|
||||
namedMapRequest,
|
||||
statusOkResponse,
|
||||
function(res, err) {
|
||||
done(err);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(function(done) {
|
||||
assert.response(
|
||||
server,
|
||||
{
|
||||
url: '/api/v1/map/named/' + templateName + '?api_key=1234',
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
host: 'localhost'
|
||||
}
|
||||
},
|
||||
{
|
||||
status: 204
|
||||
},
|
||||
function(res, err) {
|
||||
done(err);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
it('/api/v1/map/named/:template_id Named map retrieval', function(done) {
|
||||
assert.response(
|
||||
server,
|
||||
getRequest('/api/v1/map/named/' + templateName, true),
|
||||
statusOkResponse,
|
||||
noCacheHeaders(done)
|
||||
);
|
||||
});
|
||||
|
||||
it('/api/v1/map/named/:template_id/jsonp Named map retrieval', function(done) {
|
||||
assert.response(
|
||||
server,
|
||||
getRequest('/api/v1/map/named/' + templateName, true, 'cb'),
|
||||
statusOkResponse,
|
||||
noCacheHeaders(done)
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -21,7 +21,7 @@ describe('named maps static view', function() {
|
||||
|
||||
var IMAGE_TOLERANCE = 20;
|
||||
|
||||
function createTemplate(view) {
|
||||
function createTemplate(view, layers) {
|
||||
return {
|
||||
version: '0.0.1',
|
||||
name: templateName,
|
||||
@@ -36,7 +36,7 @@ describe('named maps static view', function() {
|
||||
},
|
||||
view: view,
|
||||
layergroup: {
|
||||
layers: [
|
||||
layers: layers || [
|
||||
{
|
||||
type: 'mapnik',
|
||||
options: {
|
||||
@@ -198,4 +198,43 @@ describe('named maps static view', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow to select the layers to render', function (done) {
|
||||
var view = {
|
||||
bounds: {
|
||||
west: 0,
|
||||
south: 0,
|
||||
east: 45,
|
||||
north: 45
|
||||
}
|
||||
};
|
||||
|
||||
var layers = [
|
||||
{
|
||||
type: 'mapnik',
|
||||
options: {
|
||||
sql: 'select * from populated_places_simple_reduced',
|
||||
cartocss: '#layer { marker-fill: <%= color %>; }',
|
||||
cartocss_version: '2.3.0'
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'mapnik',
|
||||
options: {
|
||||
sql: 'select ST_Transform(ST_MakeEnvelope(-45, -45, 45, 45, 4326), 3857) the_geom_webmercator',
|
||||
cartocss: '#layer { polygon-fill: <%= color %>; }',
|
||||
cartocss_version: '2.3.0'
|
||||
}
|
||||
}
|
||||
];
|
||||
templateMaps.addTemplate(username, createTemplate(view, layers), function (err) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
getStaticMap({ layer: 0 }, function(err, img) {
|
||||
assert.ok(!err);
|
||||
assert.imageIsSimilarToFile(img, previewFixture('bounds'), IMAGE_TOLERANCE, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -1052,8 +1052,9 @@ describe('template_api', function() {
|
||||
'Unexpected error for authorized instance: ' + res.statusCode + ' -- ' + res.body);
|
||||
assert.equal(res.headers['content-type'], "application/json; charset=utf-8");
|
||||
var cc = res.headers['x-cache-channel'];
|
||||
var expectedCC = 'test_windshaft_cartodb_user_1_db:public.test_table_private_1';
|
||||
assert.ok(cc);
|
||||
assert.ok(cc.match, /ciao/, cc);
|
||||
assert.equal(cc, expectedCC);
|
||||
// hack simulating restart...
|
||||
server.layergroupAffectedTablesCache.cache.reset(); // need to clean channel cache
|
||||
var get_request = {
|
||||
@@ -1072,8 +1073,9 @@ describe('template_api', function() {
|
||||
'Unexpected error for authorized instance: ' + res.statusCode + ' -- ' + res.body);
|
||||
assert.equal(res.headers['content-type'], "application/json; charset=utf-8");
|
||||
var cc = res.headers['x-cache-channel'];
|
||||
var expectedCC = 'test_windshaft_cartodb_user_1_db:public.test_table_private_1';
|
||||
assert.ok(cc, "Missing X-Cache-Channel on fetch-after-restart");
|
||||
assert.ok(cc.match, /ciao/, cc);
|
||||
assert.equal(cc, expectedCC);
|
||||
return null;
|
||||
},
|
||||
function deleteTemplate(err)
|
||||
|
||||
@@ -1,307 +0,0 @@
|
||||
var testHelper = require('../support/test_helper');
|
||||
|
||||
var assert = require('../support/assert');
|
||||
var qs = require('querystring');
|
||||
|
||||
var CartodbWindshaft = require('../../lib/cartodb/server');
|
||||
var serverOptions = require('../../lib/cartodb/server_options');
|
||||
var server = new CartodbWindshaft(serverOptions);
|
||||
server.setMaxListeners(0);
|
||||
|
||||
var LayergroupToken = require('../support/layergroup-token');
|
||||
|
||||
describe('get requests x-cache-channel', function() {
|
||||
|
||||
var keysToDelete;
|
||||
beforeEach(function() {
|
||||
keysToDelete = {};
|
||||
});
|
||||
|
||||
afterEach(function(done) {
|
||||
testHelper.deleteRedisKeys(keysToDelete, done);
|
||||
});
|
||||
|
||||
var statusOkResponse = {
|
||||
status: 200
|
||||
};
|
||||
|
||||
var mapConfig = {
|
||||
version: '1.3.0',
|
||||
layers: [
|
||||
{
|
||||
options: {
|
||||
sql: 'select * from test_table limit 2',
|
||||
cartocss: '#layer { marker-fill:red; }',
|
||||
cartocss_version: '2.3.0',
|
||||
attributes: {
|
||||
id:'cartodb_id',
|
||||
columns: [
|
||||
'name',
|
||||
'address'
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
var layergroupRequest = {
|
||||
url: '/api/v1/map?config=' + encodeURIComponent(JSON.stringify(mapConfig)),
|
||||
method: 'GET',
|
||||
headers: {
|
||||
host: 'localhost'
|
||||
}
|
||||
};
|
||||
|
||||
function getRequest(url, addApiKey, callbackName) {
|
||||
var params = {};
|
||||
if (!!addApiKey) {
|
||||
params.api_key = '1234';
|
||||
}
|
||||
if (!!callbackName) {
|
||||
params.callback = callbackName;
|
||||
}
|
||||
|
||||
return {
|
||||
url: url + '?' + qs.stringify(params),
|
||||
method: 'GET',
|
||||
headers: {
|
||||
host: 'localhost',
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function validateXCacheChannel(done, expectedCacheChannel) {
|
||||
return function(res, err) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
assert.ok(res.headers['x-cache-channel']);
|
||||
if (expectedCacheChannel) {
|
||||
assert.equal(res.headers['x-cache-channel'], expectedCacheChannel);
|
||||
}
|
||||
|
||||
done();
|
||||
};
|
||||
}
|
||||
|
||||
function noXCacheChannelHeader(done) {
|
||||
return function(res, err) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
assert.ok(
|
||||
!res.headers['x-cache-channel'],
|
||||
'did not expect x-cache-channel header, got: `' + res.headers['x-cache-channel'] + '`'
|
||||
);
|
||||
done();
|
||||
};
|
||||
}
|
||||
|
||||
function withLayergroupId(callback) {
|
||||
assert.response(
|
||||
server,
|
||||
layergroupRequest,
|
||||
statusOkResponse,
|
||||
function(res, err) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
var layergroupId = JSON.parse(res.body).layergroupid;
|
||||
keysToDelete['map_cfg|' + LayergroupToken.parse(layergroupId).token] = 0;
|
||||
keysToDelete['user:localhost:mapviews:global'] = 5;
|
||||
callback(null, layergroupId, res);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
describe('header should be present', function() {
|
||||
|
||||
it('/api/v1/map Map instantiation', function(done) {
|
||||
var testFn = validateXCacheChannel(done, 'test_windshaft_cartodb_user_1_db:public.test_table');
|
||||
withLayergroupId(function(err, layergroupId, res) {
|
||||
testFn(res);
|
||||
});
|
||||
});
|
||||
|
||||
it ('/api/v1/map/:token/:z/:x/:y@:scale_factor?x.:format Mapnik retina tiles', function(done) {
|
||||
withLayergroupId(function(err, layergroupId) {
|
||||
assert.response(
|
||||
server,
|
||||
getRequest('/api/v1/map/' + layergroupId + '/0/0/0@2x.png'),
|
||||
validateXCacheChannel(done, 'test_windshaft_cartodb_user_1_db:public.test_table')
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it ('/api/v1/map/:token/:z/:x/:y@:scale_factor?x.:format Mapnik tiles', function(done) {
|
||||
withLayergroupId(function(err, layergroupId) {
|
||||
assert.response(
|
||||
server,
|
||||
getRequest('/api/v1/map/' + layergroupId + '/0/0/0.png'),
|
||||
validateXCacheChannel(done, 'test_windshaft_cartodb_user_1_db:public.test_table')
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it ('/api/v1/map/:token/:layer/:z/:x/:y.(:format) Per :layer rendering', function(done) {
|
||||
withLayergroupId(function(err, layergroupId) {
|
||||
assert.response(
|
||||
server,
|
||||
getRequest('/api/v1/map/' + layergroupId + '/0/0/0/0.png'),
|
||||
validateXCacheChannel(done, 'test_windshaft_cartodb_user_1_db:public.test_table')
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it ('/api/v1/map/:token/:layer/attributes/:fid endpoint for info windows', function(done) {
|
||||
withLayergroupId(function(err, layergroupId) {
|
||||
assert.response(
|
||||
server,
|
||||
getRequest('/api/v1/map/' + layergroupId + '/0/attributes/1'),
|
||||
validateXCacheChannel(done, 'test_windshaft_cartodb_user_1_db:public.test_table')
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it ('/api/v1/map/static/center/:token/:z/:lat/:lng/:width/:height.:format static maps', function(done) {
|
||||
withLayergroupId(function(err, layergroupId) {
|
||||
assert.response(
|
||||
server,
|
||||
getRequest('/api/v1/map/static/center/' + layergroupId + '/0/0/0/400/300.png'),
|
||||
validateXCacheChannel(done, 'test_windshaft_cartodb_user_1_db:public.test_table')
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it ('/api/v1/map/static/bbox/:token/:bbox/:width/:height.:format static maps', function(done) {
|
||||
withLayergroupId(function(err, layergroupId) {
|
||||
assert.response(
|
||||
server,
|
||||
getRequest('/api/v1/map/static/bbox/' + layergroupId + '/-45,-45,45,45/400/300.png'),
|
||||
validateXCacheChannel(done, 'test_windshaft_cartodb_user_1_db:public.test_table')
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('header should NOT be present', function() {
|
||||
|
||||
it('/', function(done) {
|
||||
assert.response(
|
||||
server,
|
||||
getRequest('/'),
|
||||
statusOkResponse,
|
||||
noXCacheChannelHeader(done)
|
||||
);
|
||||
});
|
||||
|
||||
it('/version', function(done) {
|
||||
assert.response(
|
||||
server,
|
||||
getRequest('/version'),
|
||||
statusOkResponse,
|
||||
noXCacheChannelHeader(done)
|
||||
);
|
||||
});
|
||||
|
||||
it('/health', function(done) {
|
||||
assert.response(
|
||||
server,
|
||||
getRequest('/health'),
|
||||
statusOkResponse,
|
||||
noXCacheChannelHeader(done)
|
||||
);
|
||||
});
|
||||
|
||||
it('/api/v1/map/named list named maps', function(done) {
|
||||
assert.response(
|
||||
server,
|
||||
getRequest('/api/v1/map/named', true),
|
||||
statusOkResponse,
|
||||
noXCacheChannelHeader(done)
|
||||
);
|
||||
});
|
||||
|
||||
describe('with named maps', function() {
|
||||
|
||||
var templateName = 'x_cache';
|
||||
|
||||
beforeEach(function(done) {
|
||||
var template = {
|
||||
version: '0.0.1',
|
||||
name: templateName,
|
||||
auth: {
|
||||
method: 'open'
|
||||
},
|
||||
layergroup: mapConfig
|
||||
};
|
||||
|
||||
var namedMapRequest = {
|
||||
url: '/api/v1/map/named?api_key=1234',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
host: 'localhost',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
data: JSON.stringify(template)
|
||||
};
|
||||
|
||||
assert.response(
|
||||
server,
|
||||
namedMapRequest,
|
||||
statusOkResponse,
|
||||
function(res, err) {
|
||||
done(err);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(function(done) {
|
||||
assert.response(
|
||||
server,
|
||||
{
|
||||
url: '/api/v1/map/named/' + templateName + '?api_key=1234',
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
host: 'localhost'
|
||||
}
|
||||
},
|
||||
{
|
||||
status: 204
|
||||
},
|
||||
function(res, err) {
|
||||
done(err);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
it('/api/v1/map/named/:template_id Named map retrieval', function(done) {
|
||||
assert.response(
|
||||
server,
|
||||
getRequest('/api/v1/map/named/' + templateName, true),
|
||||
statusOkResponse,
|
||||
noXCacheChannelHeader(done)
|
||||
);
|
||||
});
|
||||
|
||||
it('/api/v1/map/named/:template_id/jsonp Named map retrieval', function(done) {
|
||||
assert.response(
|
||||
server,
|
||||
getRequest('/api/v1/map/named/' + templateName, true, 'cb'),
|
||||
statusOkResponse,
|
||||
noXCacheChannelHeader(done)
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
@@ -75,7 +75,7 @@ if test x"$PREPARE_PGSQL" = xyes; then
|
||||
dropdb "${TEST_DB}"
|
||||
createdb -Ttemplate_postgis -EUTF8 "${TEST_DB}" || die "Could not create test database"
|
||||
|
||||
LOCAL_SQL_SCRIPTS='analysis_catalog windshaft.test gadm4 ported/populated_places_simple_reduced cdb_analysis_check'
|
||||
LOCAL_SQL_SCRIPTS='analysis_catalog windshaft.test gadm4 ported/populated_places_simple_reduced cdb_analysis_check cdb_invalidate_varnish'
|
||||
REMOTE_SQL_SCRIPTS='CDB_QueryStatements CDB_QueryTables CDB_CartodbfyTable CDB_TableMetadata CDB_ForeignTable CDB_UserTables CDB_ColumnNames CDB_ZoomFromScale CDB_OverviewsSupport CDB_Overviews CDB_QuantileBins CDB_JenksBins CDB_HeadsTailsBins CDB_EqualIntervalBins CDB_Hexagon CDB_XYZ'
|
||||
|
||||
CURL_ARGS=""
|
||||
|
||||
6
test/support/sql/cdb_invalidate_varnish.sql
Normal file
6
test/support/sql/cdb_invalidate_varnish.sql
Normal file
@@ -0,0 +1,6 @@
|
||||
CREATE OR REPLACE FUNCTION CDB_Invalidate_Varnish(table_name TEXT)
|
||||
RETURNS void AS
|
||||
$$
|
||||
BEGIN
|
||||
END;
|
||||
$$ LANGUAGE PLPGSQL;
|
||||
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('/')
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -26,12 +26,14 @@ describe('tile stats', function() {
|
||||
var layergroupController = new LayergroupController();
|
||||
|
||||
var reqMock = {
|
||||
profiler: { toJSONString:function() {} },
|
||||
params: {
|
||||
format: invalidFormat
|
||||
}
|
||||
};
|
||||
var resMock = {
|
||||
status: function() { return this; },
|
||||
set: function() {},
|
||||
json: function() {},
|
||||
jsonp: function() {},
|
||||
send: function() {}
|
||||
@@ -54,12 +56,14 @@ describe('tile stats', function() {
|
||||
}
|
||||
});
|
||||
var reqMock = {
|
||||
profiler: { toJSONString:function() {} },
|
||||
params: {
|
||||
format: validFormat
|
||||
}
|
||||
};
|
||||
var resMock = {
|
||||
status: function() { return this; },
|
||||
set: function() {},
|
||||
json: function() {},
|
||||
jsonp: function() {},
|
||||
send: function() {}
|
||||
|
||||
Reference in New Issue
Block a user