This commit is contained in:
Joe Canero 2017-11-13 13:04:50 +00:00 committed by GitHub
commit c7a1dccf57
5 changed files with 101 additions and 50 deletions

View file

@ -180,7 +180,7 @@ module.exports = function(options, repo, params, id, styles) {
info.tiles = utils.getTileUrls(req, info.tiles, info.tiles = utils.getTileUrls(req, info.tiles,
'data/' + id, info.format, { 'data/' + id, info.format, {
'pbf': options.pbfAlias 'pbf': options.pbfAlias
}); }, options);
return res.send(info); return res.send(info);
}); });

View file

@ -747,7 +747,7 @@ module.exports = function(options, repo, params, id, dataResolver) {
app.get('/' + id + '.json', function(req, res, next) { app.get('/' + id + '.json', function(req, res, next) {
var info = clone(tileJSON); var info = clone(tileJSON);
info.tiles = utils.getTileUrls(req, info.tiles, info.tiles = utils.getTileUrls(req, info.tiles,
'styles/' + id, info.format); 'styles/' + id, info.format, null, options);
return res.send(info); return res.send(info);
}); });

View file

@ -1,25 +1,27 @@
'use strict'; 'use strict';
var path = require('path'), var path = require('path'),
fs = require('fs'); fs = require('fs'),
nodeUrl = require('url'),
querystring = require('querystring');
var clone = require('clone'), var clone = require('clone'),
express = require('express'); express = require('express');
module.exports = function(options, repo, params, id, reportTiles, reportFont) { module.exports = function (options, repo, params, id, reportTiles, reportFont) {
var app = express().disable('x-powered-by'); var app = express().disable('x-powered-by');
var styleFile = path.resolve(options.paths.styles, params.style); var styleFile = path.resolve(options.paths.styles, params.style);
var styleJSON = clone(require(styleFile)); var styleJSON = clone(require(styleFile));
Object.keys(styleJSON.sources).forEach(function(name) { Object.keys(styleJSON.sources).forEach(function (name) {
var source = styleJSON.sources[name]; var source = styleJSON.sources[name];
var url = source.url; var url = source.url;
if (url && url.lastIndexOf('mbtiles:', 0) === 0) { if (url && url.lastIndexOf('mbtiles:', 0) === 0) {
var mbtilesFile = url.substring('mbtiles://'.length); var mbtilesFile = url.substring('mbtiles://'.length);
var fromData = mbtilesFile[0] == '{' && var fromData = mbtilesFile[0] == '{' &&
mbtilesFile[mbtilesFile.length - 1] == '}'; mbtilesFile[mbtilesFile.length - 1] == '}';
if (fromData) { if (fromData) {
mbtilesFile = mbtilesFile.substr(1, mbtilesFile.length - 2); mbtilesFile = mbtilesFile.substr(1, mbtilesFile.length - 2);
@ -33,7 +35,7 @@ module.exports = function(options, repo, params, id, reportTiles, reportFont) {
} }
}); });
styleJSON.layers.forEach(function(obj) { styleJSON.layers.forEach(function (obj) {
if (obj['type'] == 'symbol') { if (obj['type'] == 'symbol') {
var fonts = (obj['layout'] || {})['text-font']; var fonts = (obj['layout'] || {})['text-font'];
if (fonts && fonts.length) { if (fonts && fonts.length) {
@ -45,51 +47,94 @@ module.exports = function(options, repo, params, id, reportTiles, reportFont) {
} }
}); });
var normalizeSpritePath = function (intermediatePath) {
return path.join(options.paths.sprites,
intermediatePath
.replace('{style}', path.basename(styleFile, '.json'))
.replace('{styleJsonFolder}', path.relative(options.paths.sprites, path.dirname(styleFile)))
);
}
var spritePath; var spritePath;
var httpTester = /^(http(s)?:)?\/\//; var httpTester = /^(http(s)?:)?\/\//;
// if the current style JSON has a sprite path referencing some local sprites,
// replace placeholders, use that as our sprite path for this style, and
// then update the sprite path in the styleJSON to reference the sprite url.
if (styleJSON.sprite && !httpTester.test(styleJSON.sprite)) { if (styleJSON.sprite && !httpTester.test(styleJSON.sprite)) {
spritePath = path.join(options.paths.sprites, spritePath = normalizeSpritePath(styleJSON.sprite);
styleJSON.sprite
.replace('{style}', path.basename(styleFile, '.json'))
.replace('{styleJsonFolder}', path.relative(options.paths.sprites, path.dirname(styleFile)))
);
styleJSON.sprite = 'local://styles/' + id + '/sprite'; styleJSON.sprite = 'local://styles/' + id + '/sprite';
// if there are still sprites for this style, serve them according to the config setting
} else if (params.serveSprites && typeof params.serveSprites === 'object') {
spritePath = normalizeSpritePath(params.serveSprites.file);
} }
if (styleJSON.glyphs && !httpTester.test(styleJSON.glyphs)) { if (styleJSON.glyphs && !httpTester.test(styleJSON.glyphs)) {
styleJSON.glyphs = 'local://fonts/{fontstack}/{range}.pbf'; styleJSON.glyphs = 'local://fonts/{fontstack}/{range}.pbf';
} }
repo[id] = styleJSON; repo[id] = styleJSON;
app.get('/' + id + '/style.json', function(req, res, next) { var isWhitelistedUrl = function (url) {
var fixUrl = function(url, opt_nokey, opt_nostyle) { if (!options.auth || !Array.isArray(options.auth.keyDomains) || options.auth.keyDomains.length === 0) {
if (!url || (typeof url !== 'string') || url.indexOf('local://') !== 0) { return false;
}
for (var i = 0; i < options.auth.keyDomains.length; i++) {
var keyDomain = options.auth.keyDomains[i];
if (!keyDomain || (typeof keyDomain !== 'string') || keyDomain.length === 0) {
continue;
}
if (url.includes(keyDomain)) {
return true;
}
}
return false;
}
app.get('/' + id + '/style.json', function (req, res, next) {
var fixUrl = function (url, opt_nokey, opt_nostyle) {
if (!url || (typeof url !== 'string') || (url.indexOf('local://') !== 0 && !isWhitelistedUrl(url))) {
return url; return url;
} }
var queryParams = [];
var queryParams = {};
if (!opt_nostyle && global.addStyleParam) { if (!opt_nostyle && global.addStyleParam) {
queryParams.push('style=' + id); queryParams.style = id;
} }
if (!opt_nokey && req.query.key) { if (!opt_nokey && req.query[options.auth.keyName]) {
queryParams.unshift('key=' + req.query.key); queryParams[options.auth.keyName] = req.query[options.auth.keyName];
} }
var query = '';
if (queryParams.length) { if (url.indexOf('local://') === 0) {
query = '?' + queryParams.join('&'); var query = querystring.stringify(queryParams);
} if (query.length) {
return url.replace( query = '?' + query;
}
return url.replace(
'local://', req.protocol + '://' + req.headers.host + '/') + query; 'local://', req.protocol + '://' + req.headers.host + '/') + query;
} else { // whitelisted url. might have existing parameters
var parsedUrl = nodeUrl.parse(url);
var parsedQS = querystring.parse(parsedUrl.query);
var newParams = Object.assign(parsedQS, queryParams);
parsedUrl.search = querystring.stringify(parsedQS);
return querystring.unescape(nodeUrl.format(parsedUrl));
}
}; };
var styleJSON_ = clone(styleJSON); var styleJSON_ = clone(styleJSON);
Object.keys(styleJSON_.sources).forEach(function(name) { Object.keys(styleJSON_.sources).forEach(function (name) {
var source = styleJSON_.sources[name]; var source = styleJSON_.sources[name];
source.url = fixUrl(source.url); source.url = fixUrl(source.url);
}); });
// mapbox-gl-js viewer cannot handle sprite urls with query // mapbox-gl-js viewer cannot handle sprite urls with query
if (styleJSON_.sprite) { if (styleJSON_.sprite) {
styleJSON_.sprite = fixUrl(styleJSON_.sprite, true, true); var forceKeyParameter = options.auth.forceSpriteKey === true;
styleJSON_.sprite = fixUrl(styleJSON_.sprite, !forceKeyParameter, true);
} }
if (styleJSON_.glyphs) { if (styleJSON_.glyphs) {
styleJSON_.glyphs = fixUrl(styleJSON_.glyphs, false, true); styleJSON_.glyphs = fixUrl(styleJSON_.glyphs, false, true);
@ -98,24 +143,24 @@ module.exports = function(options, repo, params, id, reportTiles, reportFont) {
}); });
app.get('/' + id + '/sprite:scale(@[23]x)?\.:format([\\w]+)', app.get('/' + id + '/sprite:scale(@[23]x)?\.:format([\\w]+)',
function(req, res, next) { function (req, res, next) {
if (!spritePath) { if (!spritePath) {
return res.status(404).send('File not found');
}
var scale = req.params.scale,
format = req.params.format;
var filename = spritePath + (scale || '') + '.' + format;
return fs.readFile(filename, function(err, data) {
if (err) {
console.log('Sprite load error:', filename);
return res.status(404).send('File not found'); return res.status(404).send('File not found');
} else {
if (format == 'json') res.header('Content-type', 'application/json');
if (format == 'png') res.header('Content-type', 'image/png');
return res.send(data);
} }
var scale = req.params.scale,
format = req.params.format;
var filename = spritePath + (scale || '') + '.' + format;
return fs.readFile(filename, function (err, data) {
if (err) {
console.log('Sprite load error:', filename);
return res.status(404).send('File not found');
} else {
if (format == 'json') res.header('Content-type', 'application/json');
if (format == 'png') res.header('Content-type', 'image/png');
return res.send(data);
}
});
}); });
});
return Promise.resolve(app); return Promise.resolve(app);
}; };

View file

@ -66,6 +66,12 @@ function start(opts) {
} }
var options = config.options || {}; var options = config.options || {};
options.auth = options.auth || {};
options.auth.keyName = options.auth.keyName || 'key';
options.auth.keyDomains = options.auth.keyDomains || [];
options.auth.forceSpriteKey = options.auth.forceSpriteKey || false;
var paths = options.paths || {}; var paths = options.paths || {};
options.paths = paths; options.paths = paths;
paths.root = path.resolve( paths.root = path.resolve(
@ -212,7 +218,7 @@ function start(opts) {
} }
info.tiles = utils.getTileUrls(req, info.tiles, path, info.format, { info.tiles = utils.getTileUrls(req, info.tiles, path, info.format, {
'pbf': options.pbfAlias 'pbf': options.pbfAlias
}); }, options);
arr.push(info); arr.push(info);
}); });
return arr; return arr;
@ -299,7 +305,7 @@ function start(opts) {
var tiles = utils.getTileUrls( var tiles = utils.getTileUrls(
req, style.serving_rendered.tiles, req, style.serving_rendered.tiles,
'styles/' + id, style.serving_rendered.format); 'styles/' + id, style.serving_rendered.format, null, options);
style.xyz_link = tiles[0]; style.xyz_link = tiles[0];
} }
}); });
@ -327,9 +333,9 @@ function start(opts) {
'/data/' + id + '.json' + query) + '/wmts'; '/data/' + id + '.json' + query) + '/wmts';
var tiles = utils.getTileUrls( var tiles = utils.getTileUrls(
req, data_.tiles, 'data/' + id, data_.format, { req, data_.tiles, 'data/' + id, data_.format, {
'pbf': options.pbfAlias 'pbf': options.pbfAlias
}); }, options);
data_.xyz_link = tiles[0]; data_.xyz_link = tiles[0];
} }
if (data_.filesize) { if (data_.filesize) {

View file

@ -6,7 +6,7 @@ var path = require('path'),
var clone = require('clone'), var clone = require('clone'),
glyphCompose = require('glyph-pbf-composite'); glyphCompose = require('glyph-pbf-composite');
module.exports.getTileUrls = function(req, domains, path, format, aliases) { module.exports.getTileUrls = function(req, domains, path, format, aliases, options) {
if (domains) { if (domains) {
if (domains.constructor === String && domains.length > 0) { if (domains.constructor === String && domains.length > 0) {
@ -36,8 +36,8 @@ module.exports.getTileUrls = function(req, domains, path, format, aliases) {
var key = req.query.key; var key = req.query.key;
var queryParams = []; var queryParams = [];
if (req.query.key) { if (req.query[options.auth.keyName]) {
queryParams.push('key=' + req.query.key); queryParams.push(options.auth.keyName + '=' + req.query[options.auth.keyName]);
} }
if (req.query.style) { if (req.query.style) {
queryParams.push('style=' + req.query.style); queryParams.push('style=' + req.query.style);