Merge pull request #1167 from CartoDB/dgaubert/ch77050/data-in-headers

Add 'Carto-Stat-Tag', 'Carto-User-Id', and 'Carto-Client' headers
This commit is contained in:
Daniel G. Aubert 2020-05-26 17:14:32 +02:00 committed by GitHub
commit bf7e8a6ec6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 134 additions and 23 deletions

View File

@ -57,6 +57,7 @@ const user = require('./middlewares/user');
const sendResponse = require('./middlewares/send-response');
const syntaxError = require('./middlewares/syntax-error');
const errorMiddleware = require('./middlewares/error-middleware');
const clientHeader = require('./middlewares/client-header');
const MapRouter = require('./map/map-router');
const TemplateRouter = require('./template/template-router');
@ -208,6 +209,7 @@ module.exports = class ApiRouter {
apiRouter.use(initializeStatusCode());
apiRouter.use(bodyParser.json());
apiRouter.use(servedByHostHeader());
apiRouter.use(clientHeader());
apiRouter.use(stats({
enabled: this.serverOptions.useProfiler,
statsClient: global.statsClient

View File

@ -353,6 +353,8 @@ function incrementMapViews ({ metadataBackend }) {
const statTag = mapConfig.obj().stat_tag;
res.set('Carto-Stat-Tag', `${statTag}`);
metadataBackend.incMapviewCount(user, statTag, (err) => {
if (err) {
global.logger.log(incrementMapViewsError({ user, err }));

View File

@ -0,0 +1,13 @@
'use strict';
module.exports = function clientHeader () {
return function clientHeaderMiddleware (req, res, next) {
const { client } = req.query;
if (client) {
res.set('Carto-Client', client);
}
return next();
};
};

View File

@ -3,9 +3,12 @@
module.exports = function incrementMapViewCount (metadataBackend) {
return function incrementMapViewCountMiddleware (req, res, next) {
const { mapConfig, user } = res.locals;
const statTag = mapConfig.obj().stat_tag;
res.set('Carto-Stat-Tag', `${statTag}`);
// Error won't blow up, just be logged.
metadataBackend.incMapviewCount(user, mapConfig.obj().stat_tag, (err) => {
metadataBackend.incMapviewCount(user, statTag, (err) => {
req.profiler.done('incMapviewCount');
if (err) {

View File

@ -14,6 +14,7 @@ module.exports = function user (metadataBackend) {
}
res.locals.userId = userId;
res.set('Carto-User-Id', `${userId}`);
return next();
});
};

View File

@ -17,7 +17,7 @@ describe('layergroup metadata', function () {
serverOptions.renderer.mvt.usePostGIS = originalUsePostGIS;
});
[1234, 'default_public', false].forEach(apiKey => {
[1234, 'default_public', undefined].forEach(apiKey => {
it(`tiles base urls ${apiKey ? `with api key: ${apiKey}` : 'without api key'}`, function (done) {
const mapConfig = {
version: '1.7.0',

View File

@ -0,0 +1,97 @@
'use strict';
require('../support/test-helper');
const assert = require('../support/assert');
const TestClient = require('../support/test-client');
const defaultLayers = [{
type: 'cartodb',
options: {
sql: TestClient.SQL.ONE_POINT
}
}];
const defaultStatTag = 'wadus';
function createMapConfig (layers = defaultLayers, statTag = defaultStatTag) {
return {
version: '1.8.0',
layers: layers,
stat_tag: defaultStatTag
};
}
describe('map view headers', function () {
it('anonymous map instantiation should respond with map-view headers', function (done) {
const mapConfig = createMapConfig();
const testClient = new TestClient(mapConfig);
const params = { client: 'test' };
testClient.getLayergroup(params, (err, body, res) => {
if (err) {
return done(err);
}
assert.strictEqual(res.headers['carto-stat-tag'], defaultStatTag);
assert.strictEqual(res.headers['carto-client'], params.client);
assert.strictEqual(res.headers['carto-user-id'], '1');
testClient.drain(done);
});
});
it('named map instantiation should respond with map-view headers', function (done) {
const templateid = `map-view-headers-test-${Date.now()}`;
const template = {
version: '0.0.1',
name: templateid,
layergroup: createMapConfig()
};
const testClient = new TestClient(template, 1234);
const params = { client: 'test' };
testClient.getLayergroup(params, (err, body, res) => {
if (err) {
return done(err);
}
assert.strictEqual(res.headers['carto-stat-tag'], defaultStatTag);
assert.strictEqual(res.headers['carto-client'], params.client);
assert.strictEqual(res.headers['carto-user-id'], '1');
testClient.drain(done);
});
});
it('preview should respond with map-view headers', function (done) {
const templateid = `map-view-headers-test-${Date.now()}`;
const template = {
version: '0.0.1',
name: templateid,
layergroup: createMapConfig([{
type: 'cartodb',
options: {
sql: TestClient.SQL.ONE_POINT,
cartocss: TestClient.CARTOCSS.POINTS,
cartocss_version: '2.3.0'
}
}])
};
const testClient = new TestClient(template, 1234);
const params = { client: 'test' };
testClient.getPreview(640, 480, params, (err, res) => {
if (err) {
return done(err);
}
assert.strictEqual(res.headers['carto-stat-tag'], defaultStatTag);
assert.strictEqual(res.headers['carto-client'], params.client);
assert.strictEqual(res.headers['carto-user-id'], '1');
testClient.drain(done);
});
});
});

View File

@ -942,24 +942,8 @@ TestClient.prototype.getLayergroup = function (params, callback) {
params = {};
}
let url = '/api/v1/map';
const urlNamed = url + '/named';
const headers = Object.assign({ host: 'localhost', 'Content-Type': 'application/json' }, self.extraHeaders);
const queryParams = {};
if (self.apiKey) {
queryParams.api_key = self.apiKey;
}
if (params.aggregation !== undefined) {
queryParams.aggregation = params.aggregation;
}
if (Object.keys(queryParams).length) {
url += '?' + qs.stringify(queryParams);
}
var layergroupId;
if (params.layergroupid) {
@ -982,7 +966,7 @@ TestClient.prototype.getLayergroup = function (params, callback) {
assert.response(self.server,
{
url: urlNamed + '?' + qs.stringify({ api_key: self.apiKey }),
url: `/api/v1/map/named?${qs.stringify({ api_key: self.apiKey })}`,
method: 'POST',
headers,
data: JSON.stringify(self.template)
@ -1023,9 +1007,10 @@ TestClient.prototype.getLayergroup = function (params, callback) {
};
}
const url = '/api/v1/map';
const queryParams = {};
if (self.apiKey) {
if (self.apiKey !== undefined) {
queryParams.api_key = self.apiKey;
}
@ -1033,9 +1018,14 @@ TestClient.prototype.getLayergroup = function (params, callback) {
queryParams.aggregation = params.aggregation;
}
if (params.client !== undefined) {
queryParams.client = params.client;
}
const query = Object.keys(queryParams).length ? `?${qs.stringify(queryParams)}` : '';
const path = templateId
? urlNamed + '/' + templateId + '?' + qs.stringify(queryParams)
: url;
? `${url}/named/${templateId}${query}`
: `${url}${query}`;
assert.response(self.server,
{
@ -1058,12 +1048,15 @@ TestClient.prototype.getLayergroup = function (params, callback) {
if (res.statusCode === 200 && self.template && self.template.layergroup && self.template.layergroup.stat_tag) {
self.keysToDelete[`user:localhost:mapviews:stat_tag:${self.template.layergroup.stat_tag}`] = 5;
}
if (res.statusCode === 200 && self.mapConfig && self.mapConfig.stat_tag) {
self.keysToDelete[`user:localhost:mapviews:stat_tag:${self.mapConfig.stat_tag}`] = 5;
}
}
if (err) {
return callback(err);
}
return callback(null, parsedBody);
return callback(null, parsedBody, res);
}
);
}