-
Notifications
You must be signed in to change notification settings - Fork 2.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
URL Transform callback as a Map option #5021
Conversation
c2d6446
to
5cf7788
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @asheemmamoowala!
My main questions here are around the public API. See inline comments for specifics. Generally, I think this is a reasonable stopgap for custom sources, but we should replace it with custom sources when they're available, rather than maintaining two features with such substantial overlap.
bench/benchmarks/buffer.js
Outdated
@@ -24,7 +24,7 @@ module.exports = function run() { | |||
const evented = new Evented(); | |||
|
|||
const stylesheetURL = `https://api.mapbox.com/styles/v1/mapbox/streets-v9?access_token=${accessToken}`; | |||
ajax.getJSON(stylesheetURL, (err, stylesheet) => { | |||
ajax.getJSON({ url: stylesheetURL}, (err, stylesheet) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: either space after {
and before }
, or not -- not mixed (xN).
bench/benchmarks/buffer.js
Outdated
@@ -82,14 +82,24 @@ module.exports = function run() { | |||
return evented; | |||
}; | |||
|
|||
class StubMap extends Evented { | |||
constructor() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not necessary?
bench/benchmarks/buffer.js
Outdated
} | ||
|
||
_transformRequest(url) { | ||
return { url: url }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return { url };
src/source/load_tilejson.js
Outdated
module.exports = function(options, callback) { | ||
module.exports = function(options, requestTransformFn, callback) { | ||
if (!callback) { | ||
callback = requestTransformFn; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make requestTransformFn
a required argument.
test/suite_implementation.js
Outdated
@@ -126,7 +126,8 @@ function cached(data, callback) { | |||
}); | |||
} | |||
|
|||
sinon.stub(ajax, 'getJSON').callsFake((url, callback) => { | |||
sinon.stub(ajax, 'getJSON').callsFake((requestParameters, callback) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
({url}, callback) => {
(x3)
bench/benchmarks/buffer.js
Outdated
@@ -107,7 +117,7 @@ function preloadAssets(stylesheet, callback) { | |||
} | |||
|
|||
function getTile(url, callback) { | |||
ajax.getArrayBuffer(url, (err, response) => { | |||
ajax.getArrayBuffer({ url: url}, (err, response) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
{url}
src/source/raster_tile_source.js
Outdated
@@ -52,7 +52,7 @@ class RasterTileSource extends Evented implements Source { | |||
|
|||
load() { | |||
this.fire('dataloading', {dataType: 'source'}); | |||
loadTileJSON(this._options, (err, tileJSON) => { | |||
loadTileJSON(this._options, (url) => { return this.map._transformRequest(url, ajax.ResourceType.Source); }, (err, tileJSON) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
loadTileJSON(this._options, this.map._transformRequest, (err, tileJSON) => {
Let loadTileJSON
supply ajax.ResourceType.Source
.
src/source/worker_source.js
Outdated
@@ -7,7 +7,7 @@ import type {SerializedBucket} from '../data/bucket'; | |||
import type {SerializedFeatureIndex} from '../data/feature_index'; | |||
import type {SerializedCollisionTile} from '../symbol/collision_tile'; | |||
import type {SerializedStructArray} from '../util/struct_array'; | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: keep the whitespace between imports and exports.
src/source/geojson_source.js
Outdated
const EXTENT = require('../data/extent'); | ||
const resolveURL = require('../util/mapbox').resolveURL; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any particular reason for moving resolveURL
? If it does move, it should go in something like util.js
. mapbox.js
is for Mapbox-specific URL munging.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jfirebaugh util.js
already depends on window
, so putting resolveURL
in util.js
creates a cyclic dependency. resolveURL
could be moved to ajax.js
, or left in geojson_source.js
which was its only usage anyways
src/ui/map.js
Outdated
* } | ||
* }); | ||
*/ | ||
setRequestTransform(transform: Function) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Type transform
more specifically than Function
-- Function
is like any
: it turns off type checking.
Let's not make a setter for this, only a constructor option. This allows us to reduce internal coupling by passing a (normalized) transform function instead of the whole Map
object. (If someone really needs dynamic behavior, they can put it inside the transform. But it's still a questionable idea: network requests may be triggered at any time, and we don't guarantee exactly when the transform gets called.)
Normalization looks like:
this._transformRequest = transform ?
(url, type) => (transform(url, type || ajax.ResourceType.Unknown) || {url}) :
(url) => ({url});
No need for _transformRequestCallback
, and you can use map._transformRequest
as a standalone function unconditionally from anywhere.
Also, is there a reason for the resource type to be optional?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this suggestion. I didn't even consider the timing and order-of-execution issue with regards to Map#setRequestTransform.
reousrceType
is optional for catching calls that don't provide a type.
FWIW, the addition of this feature solves a big problem for me as I need to send an Authorization header with my requests. (I was on my way to implementing something like this, so thanks!) |
src/util/ajax.js
Outdated
export type RequestParameters = { | ||
url: string, | ||
headers?: Object, | ||
withCredentials? : Boolean |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's make this a bit more extensible, and consistent with the Fetch API (which we may eventually switch to internally):
credentials?: 'same-origin' | 'include'
(It doesn't look like it's possible to emulate Fetch's 'omit'
value using XHR, so I left that out.)
src/source/geojson_source.js
Outdated
@@ -170,7 +170,7 @@ class GeoJSONSource extends Evented implements Source { | |||
const options = util.extend({}, this.workerOptions); | |||
const data = this._data; | |||
if (typeof data === 'string') { | |||
options.url = resolveURL(data); | |||
options.request = this.map._transformRequest(resolveURL(data)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this the only place where the type isn't provided? Native uses the Source
type here; let's do the same and then make this parameter required.
src/style/image_sprite.js
Outdated
@@ -31,24 +31,26 @@ class ImageSprite extends Evented { | |||
imgData: ?HTMLImageElement; | |||
width: ?number; | |||
|
|||
constructor(base: string, eventedParent?: Evented) { | |||
constructor(base: string, eventedParent?: Evented, transformRequestCallback?: Function) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can the added parameter be required (in second position)?
… transform outgoing request.
293f965
to
e26c9bc
Compare
Any idea when this will be released? This looks like it'll fix some of the CloudFront Signed Cookies issues we're currently experiencing. |
@rayterrill It'll be part of the next GL JS release. We're typically releasing new versions ~6 weeks. Mapbox GL JS v0.39 was released on July 21, so the next release will likely be end of August/beginning of September. |
@kkaefer Thanks mate! |
Just a Question .. the Transformation of the URL seems to work ok .. but now I'm getting a "Error: Unimplemented type: 3" The Code looks like:
Do I have to set any type or something like that ? |
@volkergraf can you provide more context on the error you are seeing ? A reproducible case with jsfiddle would be helpful in debugging. |
It sounds like the response is zipped but not decompressed correctly. Why are you setting |
@kkaefer Well this was only a test, trying to get rid of the "Error: Unimplemented type: 3" which did not work =) |
@asheemmamoowala Ok .. well the Scenario is the following: We are developing an iOS Application using Apache-Cordova. WebKit has a Problem concerning AJAX-Calls using **file://..-**Urls .. but there is a workaround, using the cordova-file-plugin and the WXWebKitView (with a modified Initializer), allowing you to kinda use file://...-Urls to access the deployd files (that will reside in www/foo/bar), but you can NOT use the MapBox-GL.js source URL like "...www/foo/bar{z}/{x]/{y}.pbf, you have to transform it to a blob:file://var......11-22-33-66-767-88/1122.pbf blob-URL. Therefore I created an associative-Array, containing the Original-URLs that the mapbox-gl.js-map requests and it's corresponding blob:-URLs .. a_urls_to_blobs[url] I can definitively confirm that the mapbox-gl.js CAN load the Tiles trough the blob-URLs .. but it seems that using transformRequest: might require a few more Parameters to return .. to make the whole Thing run .. at the Moment I am returning simply the "blob:"-URLs .. perhapes I might have to add a type or something like that .. any Ideas ? |
|
I integrated this and implemented the transformRequest credentials functionality today using CloudFront signed cookies - Everything appears to be working great! Thanks all! |
We have quite a few tickets (#4740, #2918, #4917, and gl-native/#7455) related to modifying XHR requests made by mapbox-gl-js for various resources. While these tickets are each slightly different, they all include an element of inspecting and modifying the XHR request before it is sent.
The common use cases break down to:
This PR addresses all these concerns by providing a per-map option for a
transformRequest
callback.Example usage
Checklist
// cc @anandthakker @jfirebaugh @kkaefer