Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions src/source/load_tilejson.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,7 @@ export default function(options: any, requestManager: RequestManager, callback:
result.vectorLayerIds = result.vectorLayers.map((layer) => { return layer.id; });
}

// only canonicalize tile tileset if source is declared using a tilejson url
if (options.url) {
result.tiles = requestManager.canonicalizeTileset(result, options.url);
}
result.tiles = requestManager.canonicalizeTileset(result, options.url);
callback(null, result);
}
};
Expand Down
2 changes: 1 addition & 1 deletion src/source/raster_dem_tile_source.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class RasterDEMTileSource extends RasterTileSource implements Source {
}

loadTile(tile: Tile, callback: Callback<void>) {
const url = this.map._requestManager.normalizeTileURL(tile.tileID.canonical.url(this.tiles, this.scheme), this.url, this.tileSize);
const url = this.map._requestManager.normalizeTileURL(tile.tileID.canonical.url(this.tiles, this.scheme), this.tileSize);
tile.request = getImage(this.map._requestManager.transformRequest(url, ResourceType.Tile), imageLoaded.bind(this));

tile.neighboringTiles = this._getNeighboringTiles(tile.tileID);
Expand Down
2 changes: 1 addition & 1 deletion src/source/raster_tile_source.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ class RasterTileSource extends Evented implements Source {
}

loadTile(tile: Tile, callback: Callback<void>) {
const url = this.map._requestManager.normalizeTileURL(tile.tileID.canonical.url(this.tiles, this.scheme), this.url, this.tileSize);
const url = this.map._requestManager.normalizeTileURL(tile.tileID.canonical.url(this.tiles, this.scheme), this.tileSize);
tile.request = getImage(this.map._requestManager.transformRequest(url, ResourceType.Tile), (err, img) => {
delete tile.request;

Expand Down
2 changes: 1 addition & 1 deletion src/source/vector_tile_source.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ class VectorTileSource extends Evented implements Source {
}

loadTile(tile: Tile, callback: Callback<void>) {
const url = this.map._requestManager.normalizeTileURL(tile.tileID.canonical.url(this.tiles, this.scheme), this.url, null);
const url = this.map._requestManager.normalizeTileURL(tile.tileID.canonical.url(this.tiles, this.scheme));
const params = {
request: this.map._requestManager.transformRequest(url, ResourceType.Tile),
uid: tile.uid,
Expand Down
39 changes: 28 additions & 11 deletions src/util/mapbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,12 @@ export class RequestManager {
return this._makeAPIURL(urlObject, this._customAccessToken || accessToken);
}

normalizeTileURL(tileURL: string, sourceURL?: ?string, tileSize?: ?number): string {
normalizeTileURL(tileURL: string, tileSize?: ?number): string {
if (this._isSkuTokenExpired()) {
this._createSkuToken();
}

if (!sourceURL || !isMapboxURL(sourceURL)) return tileURL;
if (tileURL && !isMapboxURL(tileURL) && !isMapboxHTTPURL(tileURL)) return tileURL;

const urlObject = parseUrl(tileURL);
const imageExtensionRe = /(\.(png|jpg)\d*)(?=$)/;
Expand All @@ -121,14 +121,15 @@ export class RequestManager {
urlObject.path = urlObject.path.replace(tileURLAPIPrefixRe, '/');
urlObject.path = `/v4${urlObject.path}`;

if (config.REQUIRE_ACCESS_TOKEN && (config.ACCESS_TOKEN || this._customAccessToken) && this._skuToken) {
const accessToken = this._customAccessToken || getAccessToken(urlObject.params) || config.ACCESS_TOKEN;
if (config.REQUIRE_ACCESS_TOKEN && accessToken && this._skuToken) {
urlObject.params.push(`sku=${this._skuToken}`);
}

return this._makeAPIURL(urlObject, this._customAccessToken);
return this._makeAPIURL(urlObject, accessToken);
}

canonicalizeTileURL(url: string) {
canonicalizeTileURL(url: string, removeAccessToken: boolean) {
const version = "/v4/";
// matches any file extension specified by a dot and one or more alphanumeric characters
const extensionRe = /\.[\w]+$/;
Expand All @@ -145,17 +146,23 @@ export class RequestManager {
result += urlObject.path.replace(version, '');

// Append the query string, minus the access token parameter.
const params = urlObject.params.filter(p => !p.match(/^access_token=/));
let params = urlObject.params;
if (removeAccessToken) {
params = params.filter(p => !p.match(/^access_token=/));
}
if (params.length) result += `?${params.join('&')}`;
return result;
}

canonicalizeTileset(tileJSON: TileJSON, sourceURL: string) {
if (!isMapboxURL(sourceURL)) return tileJSON.tiles || [];
canonicalizeTileset(tileJSON: TileJSON, sourceURL?: string) {
const removeAccessToken = sourceURL ? isMapboxURL(sourceURL) : false;
const canonical = [];
for (const url of tileJSON.tiles) {
const canonicalUrl = this.canonicalizeTileURL(url);
canonical.push(canonicalUrl);
for (const url of tileJSON.tiles || []) {
if (isMapboxHTTPURL(url)) {
canonical.push(this.canonicalizeTileURL(url, removeAccessToken));
} else {
canonical.push(url);
}
}
return canonical;
}
Expand Down Expand Up @@ -197,6 +204,16 @@ function hasCacheDefeatingSku(url: string) {
return url.indexOf('sku=') > 0 && isMapboxHTTPURL(url);
}

function getAccessToken(params: Array<string>): string | null {
for (const param of params) {
const match = param.match(/^access_token=(.*)$/);
if (match) {
return match[1];
}
}
return null;
}

const urlRe = /^(\w+):\/\/([^/?]*)(\/[^?]+)?\??(.+)?/;

function parseUrl(url: string): UrlObject {
Expand Down
27 changes: 27 additions & 0 deletions test/unit/source/vector_tile_source.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,33 @@ test('VectorTileSource', (t) => {
window.server.respond();
});

t.test('canonicalizes tile URLs in inline TileJSON', (t) => {
const source = createSource({
minzoom: 1,
maxzoom: 10,
attribution: "Mapbox",
tiles: ["https://api.mapbox.com/v4/user.map/{z}/{x}/{y}.png?access_token=key"]
});
const transformSpy = t.spy(source.map._requestManager, 'transformRequest');
source.on('data', (e) => {
if (e.sourceDataType === 'metadata') {
t.deepEqual(source.tiles, ["mapbox://tiles/user.map/{z}/{x}/{y}.png?access_token=key"]);
const tile = {
tileID: new OverscaledTileID(10, 0, 10, 5, 5),
state: 'loading',
loadVectorData () {},
setExpiryData() {}
};
source.loadTile(tile, () => {});
t.ok(transformSpy.calledOnce);
t.equal(transformSpy.getCall(0).args[0], `https://api.mapbox.com/v4/user.map/10/5/5.png?sku=${source.map._requestManager._skuToken}&access_token=key`);
t.equal(transformSpy.getCall(0).args[1], 'Tile');
t.end();
}
});

});

t.test('reloads a loading tile properly', (t) => {
const source = createSource({
tiles: ["http://example.com/{z}/{x}/{y}.png"]
Expand Down
5 changes: 4 additions & 1 deletion test/unit/ui/control/logo.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ function createMap(t, logoPosition, logoRequired) {
function createSource(options, logoRequired) {
const source = new VectorTileSource('id', options, {send () {}});
source.onAdd({
_requestManager: {_skuToken: '1234567890123'},
_requestManager: {
_skuToken: '1234567890123',
canonicalizeTileset: tileJSON => tileJSON.tiles
},
transform: {angle: 0, pitch: 0, showCollisionBoxes: false},
_getMapId: () => 1
});
Expand Down
Loading