From a11b5ce602d5755e2935f3fa5754e1dc97a52065 Mon Sep 17 00:00:00 2001 From: Aiosa Date: Wed, 8 Dec 2021 09:54:14 +0100 Subject: [PATCH 1/5] Support for POST data in the ajax requests. --- src/dzitilesource.js | 3 ++- src/iiiftilesource.js | 4 +++- src/imageloader.js | 4 ++++ src/imagetilesource.js | 3 ++- src/legacytilesource.js | 3 ++- src/openseadragon.js | 8 ++++++-- src/osmtilesource.js | 3 ++- src/tile.js | 10 +++++++++- src/tiledimage.js | 4 ++++ src/tilesource.js | 27 +++++++++++++++++++++++++-- src/tmstilesource.js | 3 ++- src/zoomifytilesource.js | 3 ++- 12 files changed, 63 insertions(+), 12 deletions(-) diff --git a/src/dzitilesource.js b/src/dzitilesource.js index f600a4d1..633c0371 100644 --- a/src/dzitilesource.js +++ b/src/dzitilesource.js @@ -124,10 +124,11 @@ $.extend( $.DziTileSource.prototype, $.TileSource.prototype, /** @lends OpenSead * @function * @param {Object|XMLDocument} data - the raw configuration * @param {String} url - the url the data was retrieved from if any. + * @param {String} postData - data for the post request or null * @return {Object} options - A dictionary of keyword arguments sufficient * to configure this tile sources constructor. */ - configure: function( data, url ){ + configure: function( data, url, postData ){ var options; diff --git a/src/iiiftilesource.js b/src/iiiftilesource.js index 76479e76..5450b612 100644 --- a/src/iiiftilesource.js +++ b/src/iiiftilesource.js @@ -183,6 +183,8 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea * * @function * @param {Object} data - the raw configuration + * @param {String} url - the url configuration was retrieved from + * @param {String} postData - data for the post request or null * @example IIIF 1.1 Info Looks like this * { * "@context" : "http://library.stanford.edu/iiif/image-api/1.1/context.json", @@ -197,7 +199,7 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea * "profile" : "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level0" * } */ - configure: function( data, url ){ + configure: function( data, url, postData ){ // Try to deduce our version and fake it upwards if needed if ( !$.isPlainObject(data) ) { var options = configureFromXml10( data ); diff --git a/src/imageloader.js b/src/imageloader.js index faa1fac8..b48e1d55 100644 --- a/src/imageloader.js +++ b/src/imageloader.js @@ -43,6 +43,7 @@ * @param {String} [options.loadWithAjax] - Whether to load this image with AJAX. * @param {String} [options.ajaxHeaders] - Headers to add to the image request if using AJAX. * @param {String} [options.crossOriginPolicy] - CORS policy to use for downloads + * @param {String} [options.postData] - POST parameters or null * @param {Function} [options.callback] - Called once image has been downloaded. * @param {Function} [options.abort] - Called when this image job is aborted. * @param {Number} [options.timeout] - The max number of milliseconds that this image job may take to complete. @@ -96,6 +97,7 @@ ImageJob.prototype = { withCredentials: this.ajaxWithCredentials, headers: this.ajaxHeaders, responseType: "arraybuffer", + postData: this.postData, success: function(request) { var blb; // Make the raw data into a blob. @@ -196,6 +198,7 @@ $.ImageLoader.prototype = { * @param {String} [options.loadWithAjax] - Whether to load this image with AJAX. * @param {String} [options.ajaxHeaders] - Headers to add to the image request if using AJAX. * @param {String|Boolean} [options.crossOriginPolicy] - CORS policy to use for downloads + * @param {String} [options.postData] - POST parameters in k=v&k2=v2... form or null * @param {Boolean} [options.ajaxWithCredentials] - Whether to set withCredentials on AJAX * requests. * @param {Function} [options.callback] - Called once image has been downloaded. @@ -212,6 +215,7 @@ $.ImageLoader.prototype = { ajaxHeaders: options.loadWithAjax ? options.ajaxHeaders : null, crossOriginPolicy: options.crossOriginPolicy, ajaxWithCredentials: options.ajaxWithCredentials, + postData: options.postData, callback: complete, abort: options.abort, timeout: this.timeout diff --git a/src/imagetilesource.js b/src/imagetilesource.js index 25f67988..cc0d2619 100644 --- a/src/imagetilesource.js +++ b/src/imagetilesource.js @@ -89,10 +89,11 @@ * @function * @param {Object} options - the options * @param {String} dataUrl - the url the image was retrieved from, if any. + * @param {String} postData - data for the post request or null * @return {Object} options - A dictionary of keyword arguments sufficient * to configure this tile sources constructor. */ - configure: function (options, dataUrl) { + configure: function (options, dataUrl, postData) { return options; }, /** diff --git a/src/legacytilesource.js b/src/legacytilesource.js index c1c5e253..cdf0cbc9 100644 --- a/src/legacytilesource.js +++ b/src/legacytilesource.js @@ -122,10 +122,11 @@ $.extend( $.LegacyTileSource.prototype, $.TileSource.prototype, /** @lends OpenS * @function * @param {Object|XMLDocument} configuration - the raw configuration * @param {String} dataUrl - the url the data was retrieved from if any. + * @param {String} postData - data for the post request or null * @return {Object} options - A dictionary of keyword arguments sufficient * to configure this tile sources constructor. */ - configure: function( configuration, dataUrl ){ + configure: function( configuration, dataUrl, postData ){ var options; diff --git a/src/openseadragon.js b/src/openseadragon.js index 5b0accb0..68761635 100644 --- a/src/openseadragon.js +++ b/src/openseadragon.js @@ -2273,6 +2273,7 @@ function OpenSeadragon( options ){ * @param {Function} options.error - a function to call on when an error occurs * @param {Object} options.headers - headers to add to the AJAX request * @param {String} options.responseType - the response type of the the AJAX request + * @param {String} options.postData - HTTP POST data in k=v&k2=v2... form, GET method used if null * @param {Boolean} [options.withCredentials=false] - whether to set the XHR's withCredentials * @throws {Error} * @returns {XMLHttpRequest} @@ -2281,6 +2282,7 @@ function OpenSeadragon( options ){ var withCredentials; var headers; var responseType; + var postData; // Note that our preferred API is that you pass in a single object; the named // arguments are for legacy support. @@ -2290,6 +2292,7 @@ function OpenSeadragon( options ){ withCredentials = url.withCredentials; headers = url.headers; responseType = url.responseType || null; + postData = url.postData || null; url = url.url; } @@ -2322,8 +2325,9 @@ function OpenSeadragon( options ){ } }; + var method = postData ? "POST" : "GET"; try { - request.open( "GET", url, true ); + request.open( method, url, true ); if (responseType) { request.responseType = responseType; @@ -2341,7 +2345,7 @@ function OpenSeadragon( options ){ request.withCredentials = true; } - request.send(null); + request.send(postData); } catch (e) { $.console.log( "%s while making AJAX request: %s", e.name, e.message ); diff --git a/src/osmtilesource.js b/src/osmtilesource.js index c28945bb..d5a11163 100644 --- a/src/osmtilesource.js +++ b/src/osmtilesource.js @@ -122,10 +122,11 @@ $.extend( $.OsmTileSource.prototype, $.TileSource.prototype, /** @lends OpenSead * @function * @param {Object} data - the raw configuration * @param {String} url - the url the data was retrieved from if any. + * @param {String} postData - data for the post request or null * @return {Object} options - A dictionary of keyword arguments sufficient * to configure this tile sources constructor. */ - configure: function( data, url ){ + configure: function( data, url, postData ){ return data; }, diff --git a/src/tile.js b/src/tile.js index 701db750..e8a97da9 100644 --- a/src/tile.js +++ b/src/tile.js @@ -45,6 +45,7 @@ * @param {Boolean} exists Is this tile a part of a sparse image? ( Also has * this tile failed to load? ) * @param {String} url The URL of this tile's image. + * @param {String} postData post parameters or null * @param {CanvasRenderingContext2D} context2D The context2D of this tile if it * is provided directly by the tile source. * @param {Boolean} loadWithAjax Whether this tile image should be loaded with an AJAX request . @@ -53,7 +54,7 @@ * drawing operation, in pixels. Note that this only works when drawing with canvas; when drawing * with HTML the entire tile is always used. */ -$.Tile = function(level, x, y, bounds, exists, url, context2D, loadWithAjax, ajaxHeaders, sourceBounds) { +$.Tile = function(level, x, y, bounds, exists, url, postData, context2D, loadWithAjax, ajaxHeaders, sourceBounds) { /** * The zoom level this tile belongs to. * @member {Number} level @@ -97,6 +98,13 @@ $.Tile = function(level, x, y, bounds, exists, url, context2D, loadWithAjax, aja * @memberof OpenSeadragon.Tile# */ this.url = url; + /** + * Post parameters for this tile. Either it is an URL-encoded string + * in k1=v1&k2=v2... format or null + * @member {String} postData + * @memberof OpenSeadragon.Tile# + */ + this.postData = postData; /** * The context2D of this tile if it is provided directly by the tile source. * @member {CanvasRenderingContext2D} context2D diff --git a/src/tiledimage.js b/src/tiledimage.js index 82e35ed7..39f195f2 100644 --- a/src/tiledimage.js +++ b/src/tiledimage.js @@ -1490,6 +1490,7 @@ function getTile( sourceBounds, exists, url, + post, ajaxHeaders, context2D, tile; @@ -1508,6 +1509,7 @@ function getTile( sourceBounds = tileSource.getTileBounds( level, xMod, yMod, true ); exists = tileSource.tileExists( level, xMod, yMod ); url = tileSource.getTileUrl( level, xMod, yMod ); + post = tileSource.getTilePostData( level, xMod, yMod ); // Headers are only applicable if loadTilesWithAjax is set if (tiledImage.loadTilesWithAjax) { @@ -1530,6 +1532,7 @@ function getTile( bounds, exists, url, + post, context2D, tiledImage.loadTilesWithAjax, ajaxHeaders, @@ -1573,6 +1576,7 @@ function loadTile( tiledImage, tile, time ) { tile.loading = true; tiledImage._imageLoader.addJob({ src: tile.url, + postData: tile.postData, loadWithAjax: tile.loadWithAjax, ajaxHeaders: tile.ajaxHeaders, crossOriginPolicy: tiledImage.crossOriginPolicy, diff --git a/src/tilesource.js b/src/tilesource.js index aab7f134..8c66258e 100644 --- a/src/tilesource.js +++ b/src/tilesource.js @@ -426,6 +426,13 @@ $.TileSource.prototype = { } } + var postData = null; + var hashIdx = url.indexOf("#"); + if (hashIdx !== -1) { + postData = url.substring(hashIdx + 1); + url = url.substr(0, hashIdx - 1); + } + callback = function( data ){ if( typeof (data) === "string" ) { data = $.parseXml( data ); @@ -447,7 +454,7 @@ $.TileSource.prototype = { return; } - options = $TileSource.prototype.configure.apply( _this, [ data, url ]); + options = $TileSource.prototype.configure.apply( _this, [ data, url, postData ]); if (options.ajaxWithCredentials === undefined) { options.ajaxWithCredentials = _this.ajaxWithCredentials; } @@ -482,6 +489,7 @@ $.TileSource.prototype = { // request info via xhr asynchronously. $.makeAjaxRequest( { url: url, + postData: postData, withCredentials: this.ajaxWithCredentials, headers: this.ajaxHeaders, success: function( xhr ) { @@ -559,11 +567,12 @@ $.TileSource.prototype = { * @param {String|Object|Array|Document} data * @param {String} url - the url the data was loaded * from if any. + * @param {String} postData value obtained from the url after '#' sign or null * @return {Object} options - A dictionary of keyword arguments sufficient * to configure this tile sources constructor. * @throws {Error} */ - configure: function( data, url ) { + configure: function( data, url, postData ) { throw new Error( "Method not implemented." ); }, @@ -584,6 +593,20 @@ $.TileSource.prototype = { throw new Error( "Method not implemented." ); }, + /** + * Must use AJAX in order to work, i.e. loadTilesWithAjax = true is set. + * It should return url-encoded string with the following structure: + * key=value&key2=value2... + * or null in case GET is used instead. + * @param level + * @param x + * @param y + * @return {string || null} post data to send with tile configuration request + */ + getTilePostData: function( level, x, y ) { + return null; + }, + /** * Responsible for retrieving the headers which will be attached to the image request for the * region specified by the given x, y, and level components. diff --git a/src/tmstilesource.js b/src/tmstilesource.js index abb8f2db..355ffa99 100644 --- a/src/tmstilesource.js +++ b/src/tmstilesource.js @@ -111,10 +111,11 @@ $.extend( $.TmsTileSource.prototype, $.TileSource.prototype, /** @lends OpenSead * @function * @param {Object} data - the raw configuration * @param {String} url - the url the data was retrieved from if any. + * @param {String} postData - data for the post request or null * @return {Object} options - A dictionary of keyword arguments sufficient * to configure this tile sources constructor. */ - configure: function( data, url ){ + configure: function( data, url, postData ){ return data; }, diff --git a/src/zoomifytilesource.js b/src/zoomifytilesource.js index 9ffa4988..540b2695 100644 --- a/src/zoomifytilesource.js +++ b/src/zoomifytilesource.js @@ -122,10 +122,11 @@ * @function * @param {Object} data - the raw configuration * @param {String} url - the url the data was retrieved from if any. + * @param {String} postData - data for the post request or null * @return {Object} options - A dictionary of keyword arguments sufficient * to configure this tile sources constructor. */ - configure: function(data, url) { + configure: function(data, url, postData) { return data; }, From aacae1ca3fd010f050bf1715fd1ce21685dc0fef Mon Sep 17 00:00:00 2001 From: Jirka Date: Wed, 12 Jan 2022 22:31:13 +0100 Subject: [PATCH 2/5] Reverted .json configuration changes made by npm. Added tests for PUSH functionality, new flag 'allowPost' to explicitly enable POST data, remove (-1) in the URL splitting. --- src/openseadragon.js | 10 ++ src/tile.js | 4 +- src/tiledimage.js | 4 +- src/tilesource.js | 24 ++- src/viewer.js | 1 + test/coverage.html | 1 + test/modules/ajax-post-data.js | 276 +++++++++++++++++++++++++++++++++ test/test.html | 1 + 8 files changed, 311 insertions(+), 10 deletions(-) create mode 100644 test/modules/ajax-post-data.js diff --git a/src/openseadragon.js b/src/openseadragon.js index 30663b4b..73fb912b 100644 --- a/src/openseadragon.js +++ b/src/openseadragon.js @@ -659,6 +659,15 @@ * @property {Object} [ajaxHeaders={}] * A set of headers to include when making AJAX requests for tile sources or tiles. * + * @property {Boolean} [splitHashDataForPost=false] + * Allows to treat _first_ hash ('#') symbol as a separator for POST data: + * URL to be opened by a {@link OpenSeadragon.TileSource} can thus look like: http://some.url#postdata=here . + * The URL is split to 'http://some.url' and 'postdata=here'; post data is given to the + * {@link OpenSeadragon.TileSource} of the choice and can be further used within tile requests + * (see TileSource methods). {@link OpenSeadragon.TileSource.prototype.configure} return value + * should contain the post data so that it is given to its subclass in the constructor. + * NOTE: post data is expected to be ampersand-separated (just like GET parameters), and is not used + * to fetch tile image data if loadTilesWithAjax=false (but it is still used for the initial request). */ /** @@ -1140,6 +1149,7 @@ function OpenSeadragon( options ){ ajaxWithCredentials: false, loadTilesWithAjax: false, ajaxHeaders: {}, + splitHashDataForPost: false, //PAN AND ZOOM SETTINGS AND CONSTRAINTS panHorizontal: true, diff --git a/src/tile.js b/src/tile.js index c0740eb4..ba4a5575 100644 --- a/src/tile.js +++ b/src/tile.js @@ -45,16 +45,16 @@ * @param {Boolean} exists Is this tile a part of a sparse image? ( Also has * this tile failed to load? ) * @param {String} url The URL of this tile's image. - * @param {String} postData post parameters or null * @param {CanvasRenderingContext2D} context2D The context2D of this tile if it * is provided directly by the tile source. * @param {Boolean} loadWithAjax Whether this tile image should be loaded with an AJAX request . * @param {Object} ajaxHeaders The headers to send with this tile's AJAX request (if applicable). * @param {OpenSeadragon.Rect} sourceBounds The portion of the tile to use as the source of the + * @param {String} postData post parameters or null * drawing operation, in pixels. Note that this only works when drawing with canvas; when drawing * with HTML the entire tile is always used. */ -$.Tile = function(level, x, y, bounds, exists, url, postData, context2D, loadWithAjax, ajaxHeaders, sourceBounds) { +$.Tile = function(level, x, y, bounds, exists, url, context2D, loadWithAjax, ajaxHeaders, sourceBounds, postData) { /** * The zoom level this tile belongs to. * @member {Number} level diff --git a/src/tiledimage.js b/src/tiledimage.js index f1b28fa2..76f3eead 100644 --- a/src/tiledimage.js +++ b/src/tiledimage.js @@ -1542,11 +1542,11 @@ function getTile( bounds, exists, url, - post, context2D, tiledImage.loadTilesWithAjax, ajaxHeaders, - sourceBounds + sourceBounds, + post ); if (tiledImage.getFlip()) { diff --git a/src/tilesource.js b/src/tilesource.js index a915ac2c..4d24070d 100644 --- a/src/tilesource.js +++ b/src/tilesource.js @@ -69,6 +69,9 @@ * the XHR's withCredentials (for accessing secure data). * @param {Object} [options.ajaxHeaders] * A set of headers to include in AJAX requests. + * @param {Boolean} [options.splitHashDataForPost] + * First occurrence of '#' in the options.url is used to split URL + * and the latter part is treated as POST data (applies to getImageInfo(...)) * @param {Number} [options.width] * Width of the source image at max resolution in pixels. * @param {Number} [options.height] @@ -446,10 +449,16 @@ $.TileSource.prototype = { } var postData = null; - var hashIdx = url.indexOf("#"); - if (hashIdx !== -1) { - postData = url.substring(hashIdx + 1); - url = url.substr(0, hashIdx - 1); + if (this.allowPost) { + if (!this.loadTilesWithAjax) { + console.warn("Ajax is not enabled, but post data are used. Post data is ignored " + + "without ajax in subsequent tile requests."); + } + var hashIdx = url.indexOf("#"); + if (hashIdx !== -1) { + postData = url.substring(hashIdx + 1); + url = url.substr(0, hashIdx); + } } callback = function( data ){ @@ -545,11 +554,13 @@ $.TileSource.prototype = { * @property {OpenSeadragon.TileSource} eventSource - A reference to the TileSource which raised the event. * @property {String} message * @property {String} source + * @property {String} postData or null * @property {?Object} userData - Arbitrary subscriber-defined object. */ _this.raiseEvent( 'open-failed', { message: msg, - source: url + source: url, + postData: postData }); } }); @@ -588,7 +599,8 @@ $.TileSource.prototype = { * from if any. * @param {String} postData value obtained from the url after '#' sign or null * @return {Object} options - A dictionary of keyword arguments sufficient - * to configure this tile sources constructor. + * to configure the tile source constructor (include all values you want to + * instantiate the TileSource subclass with - what _options_ object should contain). * @throws {Error} */ configure: function( data, url, postData ) { diff --git a/src/viewer.js b/src/viewer.js index b1a60446..b4199a42 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -2432,6 +2432,7 @@ function getTileSourceImplementation( viewer, tileSource, imgOptions, successCal ajaxWithCredentials: viewer.ajaxWithCredentials, ajaxHeaders: imgOptions.ajaxHeaders ? imgOptions.ajaxHeaders : viewer.ajaxHeaders, + splitHashDataForPost: viewer.splitHashDataForPost, useCanvas: viewer.useCanvas, success: function( event ) { successCallback( event.tileSource ); diff --git a/test/coverage.html b/test/coverage.html index df0e9781..6d392209 100644 --- a/test/coverage.html +++ b/test/coverage.html @@ -86,6 +86,7 @@ +