Skip to content

Commit 97f003c

Browse files
kkaefermike-unearth
authored andcommitted
Canonicalize Mapbox tile URLs from inline TileJSON as well (mapbox#9217)
1 parent 25421a0 commit 97f003c

8 files changed

+117
-74
lines changed

src/source/load_tilejson.js

+1-4
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,7 @@ export default function(options: any, requestManager: RequestManager, callback:
2626
result.vectorLayerIds = result.vectorLayers.map((layer) => { return layer.id; });
2727
}
2828

29-
// only canonicalize tile tileset if source is declared using a tilejson url
30-
if (options.url) {
31-
result.tiles = requestManager.canonicalizeTileset(result, options.url);
32-
}
29+
result.tiles = requestManager.canonicalizeTileset(result, options.url);
3330
callback(null, result);
3431
}
3532
};

src/source/raster_dem_tile_source.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class RasterDEMTileSource extends RasterTileSource implements Source {
4040
}
4141

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

4646
tile.neighboringTiles = this._getNeighboringTiles(tile.tileID);

src/source/raster_tile_source.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ class RasterTileSource extends Evented implements Source {
110110
}
111111

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

src/source/vector_tile_source.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ class VectorTileSource extends Evented implements Source {
115115
}
116116

117117
loadTile(tile: Tile, callback: Callback<void>) {
118-
const url = this.map._requestManager.normalizeTileURL(tile.tileID.canonical.url(this.tiles, this.scheme), this.url, null);
118+
const url = this.map._requestManager.normalizeTileURL(tile.tileID.canonical.url(this.tiles, this.scheme));
119119
const params = {
120120
request: this.map._requestManager.transformRequest(url, ResourceType.Tile),
121121
uid: tile.uid,

src/util/mapbox.js

+28-11
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,12 @@ export class RequestManager {
101101
return this._makeAPIURL(urlObject, this._customAccessToken || accessToken);
102102
}
103103

104-
normalizeTileURL(tileURL: string, sourceURL?: ?string, tileSize?: ?number): string {
104+
normalizeTileURL(tileURL: string, tileSize?: ?number): string {
105105
if (this._isSkuTokenExpired()) {
106106
this._createSkuToken();
107107
}
108108

109-
if (!sourceURL || !isMapboxURL(sourceURL)) return tileURL;
109+
if (tileURL && !isMapboxURL(tileURL) && !isMapboxHTTPURL(tileURL)) return tileURL;
110110

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

124-
if (config.REQUIRE_ACCESS_TOKEN && (config.ACCESS_TOKEN || this._customAccessToken) && this._skuToken) {
124+
const accessToken = this._customAccessToken || getAccessToken(urlObject.params) || config.ACCESS_TOKEN;
125+
if (config.REQUIRE_ACCESS_TOKEN && accessToken && this._skuToken) {
125126
urlObject.params.push(`sku=${this._skuToken}`);
126127
}
127128

128-
return this._makeAPIURL(urlObject, this._customAccessToken);
129+
return this._makeAPIURL(urlObject, accessToken);
129130
}
130131

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

147148
// Append the query string, minus the access token parameter.
148-
const params = urlObject.params.filter(p => !p.match(/^access_token=/));
149+
let params = urlObject.params;
150+
if (removeAccessToken) {
151+
params = params.filter(p => !p.match(/^access_token=/));
152+
}
149153
if (params.length) result += `?${params.join('&')}`;
150154
return result;
151155
}
152156

153-
canonicalizeTileset(tileJSON: TileJSON, sourceURL: string) {
154-
if (!isMapboxURL(sourceURL)) return tileJSON.tiles || [];
157+
canonicalizeTileset(tileJSON: TileJSON, sourceURL?: string) {
158+
const removeAccessToken = sourceURL ? isMapboxURL(sourceURL) : false;
155159
const canonical = [];
156-
for (const url of tileJSON.tiles) {
157-
const canonicalUrl = this.canonicalizeTileURL(url);
158-
canonical.push(canonicalUrl);
160+
for (const url of tileJSON.tiles || []) {
161+
if (isMapboxHTTPURL(url)) {
162+
canonical.push(this.canonicalizeTileURL(url, removeAccessToken));
163+
} else {
164+
canonical.push(url);
165+
}
159166
}
160167
return canonical;
161168
}
@@ -197,6 +204,16 @@ function hasCacheDefeatingSku(url: string) {
197204
return url.indexOf('sku=') > 0 && isMapboxHTTPURL(url);
198205
}
199206

207+
function getAccessToken(params: Array<string>): string | null {
208+
for (const param of params) {
209+
const match = param.match(/^access_token=(.*)$/);
210+
if (match) {
211+
return match[1];
212+
}
213+
}
214+
return null;
215+
}
216+
200217
const urlRe = /^(\w+):\/\/([^/?]*)(\/[^?]+)?\??(.+)?/;
201218

202219
function parseUrl(url: string): UrlObject {

test/unit/source/vector_tile_source.test.js

+27
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,33 @@ test('VectorTileSource', (t) => {
200200
window.server.respond();
201201
});
202202

203+
t.test('canonicalizes tile URLs in inline TileJSON', (t) => {
204+
const source = createSource({
205+
minzoom: 1,
206+
maxzoom: 10,
207+
attribution: "Mapbox",
208+
tiles: ["https://api.mapbox.com/v4/user.map/{z}/{x}/{y}.png?access_token=key"]
209+
});
210+
const transformSpy = t.spy(source.map._requestManager, 'transformRequest');
211+
source.on('data', (e) => {
212+
if (e.sourceDataType === 'metadata') {
213+
t.deepEqual(source.tiles, ["mapbox://tiles/user.map/{z}/{x}/{y}.png?access_token=key"]);
214+
const tile = {
215+
tileID: new OverscaledTileID(10, 0, 10, 5, 5),
216+
state: 'loading',
217+
loadVectorData () {},
218+
setExpiryData() {}
219+
};
220+
source.loadTile(tile, () => {});
221+
t.ok(transformSpy.calledOnce);
222+
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`);
223+
t.equal(transformSpy.getCall(0).args[1], 'Tile');
224+
t.end();
225+
}
226+
});
227+
228+
});
229+
203230
t.test('reloads a loading tile properly', (t) => {
204231
const source = createSource({
205232
tiles: ["http://example.com/{z}/{x}/{y}.png"]

test/unit/ui/control/logo.test.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@ function createMap(t, logoPosition, logoRequired) {
2525
function createSource(options, logoRequired) {
2626
const source = new VectorTileSource('id', options, {send () {}});
2727
source.onAdd({
28-
_requestManager: {_skuToken: '1234567890123'},
28+
_requestManager: {
29+
_skuToken: '1234567890123',
30+
canonicalizeTileset: tileJSON => tileJSON.tiles
31+
},
2932
transform: {angle: 0, pitch: 0, showCollisionBoxes: false},
3033
_getMapId: () => 1
3134
});

0 commit comments

Comments
 (0)