Commit 6a1ad7c6 authored by Mark Nelson's avatar Mark Nelson
Browse files

MDL-65794 core: allow ajax calls to specify a cache key

This allows for better caching capabilities on servers. If a
cache key is passed and the web service call does not require
the user to be logged in we will attempt to use GET for the
request. This allows for things like proxy caching on URLs.
The cache key must be changed if we do not want to retrieve
what has been cached and want to perform the request again.
parent 7fa4e410
......@@ -28,4 +28,6 @@
*/
define('NO_MOODLE_COOKIES', true);
define('ALLOW_GET_PARAMETERS', true);
require_once('service.php');
......@@ -38,9 +38,24 @@ require_once($CFG->libdir . '/externallib.php');
define('PREFERRED_RENDERER_TARGET', RENDERER_TARGET_GENERAL);
$rawjson = file_get_contents('php://input');
$arguments = '';
$cacherequest = false;
if (defined('ALLOW_GET_PARAMETERS')) {
$arguments = optional_param('args', '', PARAM_RAW);
$cachekey = optional_param('cachekey', '', PARAM_INT);
if ($cachekey && $cachekey > 0 && $cachekey <= time()) {
$cacherequest = true;
}
}
// Either we are not allowing GET parameters or we didn't use GET because
// we did not pass a cache key or the URL was too long.
if (empty($arguments)) {
$arguments = file_get_contents('php://input');
}
$requests = json_decode($arguments, true);
$requests = json_decode($rawjson, true);
if ($requests === null) {
$lasterror = json_last_error_msg();
throw new coding_exception('Invalid json in request: ' . $lasterror);
......@@ -54,6 +69,7 @@ $settings->set_fileurl(true);
$settings->set_filter(true);
$settings->set_raw(false);
$haserror = false;
foreach ($requests as $request) {
$response = array();
$methodname = clean_param($request['methodname'], PARAM_ALPHANUMEXT);
......@@ -64,7 +80,19 @@ foreach ($requests as $request) {
$responses[$index] = $response;
if ($response['error']) {
// Do not process the remaining requests.
$haserror = true;
break;
}
}
if ($cacherequest && !$haserror) {
// 90 days only - based on Moodle point release cadence being every 3 months.
$lifetime = 60 * 60 * 24 * 90;
header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT');
header('Pragma: ');
header('Cache-Control: public, max-age=' . $lifetime . ', immutable');
header('Accept-Ranges: none');
}
echo json_encode($responses);
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
......@@ -137,9 +137,13 @@ define(['jquery', 'core/config', 'core/log', 'core/url'], function($, config, Lo
* @param {Boolean} nosessionupdate Optional, defaults to false.
* If true, the timemodified for the session will not be updated.
* @param {Integer} timeout number of milliseconds to wait for a response. Defaults to no limit.
* @param {Integer} cachekey This is used in order to identify the request. If this id changes then we
* will be sending a different URL and any caching (eg. browser, proxy) knows that it
* should perform another request and not use the cache. Note - this variable is only
* used when we are calling 'service-nologin.php'. See MDL-65794.
* @return {Promise[]} Array of promises that will be resolved when the ajax call returns.
*/
call: function(requests, async, loginrequired, nosessionupdate, timeout) {
call: function(requests, async, loginrequired, nosessionupdate, timeout, cachekey) {
$(window).bind('beforeunload', function() {
unloading = true;
});
......@@ -149,6 +153,8 @@ define(['jquery', 'core/config', 'core/log', 'core/url'], function($, config, Lo
methodInfo = [],
requestInfo = '';
var maxUrlLength = 2000;
if (typeof loginrequired === "undefined") {
loginrequired = true;
}
......@@ -158,6 +164,16 @@ define(['jquery', 'core/config', 'core/log', 'core/url'], function($, config, Lo
if (typeof timeout === 'undefined') {
timeout = 0;
}
if (typeof cachekey === 'undefined') {
cachekey = null;
} else {
cachekey = parseInt(cachekey);
if (cachekey <= 0) {
cachekey = null;
} else if (!cachekey) {
cachekey = null;
}
}
if (typeof nosessionupdate === "undefined") {
nosessionupdate = false;
......@@ -193,7 +209,6 @@ define(['jquery', 'core/config', 'core/log', 'core/url'], function($, config, Lo
ajaxRequestData = JSON.stringify(ajaxRequestData);
var settings = {
type: 'POST',
data: ajaxRequestData,
context: requests,
dataType: 'json',
processData: false,
......@@ -207,6 +222,10 @@ define(['jquery', 'core/config', 'core/log', 'core/url'], function($, config, Lo
if (!loginrequired) {
script = 'service-nologin.php';
url += script + '?info=' + requestInfo;
if (cachekey) {
url += '&cachekey=' + cachekey;
settings.type = 'GET';
}
} else {
url += script + '?sesskey=' + config.sesskey + '&info=' + requestInfo;
}
......@@ -215,6 +234,19 @@ define(['jquery', 'core/config', 'core/log', 'core/url'], function($, config, Lo
url += '&nosessionupdate=true';
}
if (settings.type === 'POST') {
settings.data = ajaxRequestData;
} else {
var urlUseGet = url + '&args=' + encodeURIComponent(ajaxRequestData);
if (urlUseGet.length > maxUrlLength) {
settings.type = 'POST';
settings.data = ajaxRequestData;
} else {
url = urlUseGet;
}
}
// Jquery deprecated done and fail with async=false so we need to do this 2 ways.
if (async) {
$.ajax(url, settings)
......
......@@ -3,6 +3,13 @@ information provided here is intended especially for developers.
This information is intended for authors of webservices, not people writing webservice clients.
=== 3.8 ===
* Ajax calls can now specify a cache key. This allows for better caching capabilities on servers. If a cache key
is passed and the web service call does not require the user to be logged in we will attempt to use GET for the
request. This allows for things like proxy caching on URLs. The cache key must be changed if we do not want to
retrieve what has been cached and want to perform the request again.
=== 3.7 ===
* External function core_webservice_external::get_site_info() now returns the current site theme (for the user).
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment