Skip to content
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

Enqueue requests made from QuickIcon plugins #38019

Merged
merged 5 commits into from
Jun 12, 2022
Merged
Show file tree
Hide file tree
Changes from 3 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
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
Joomla.request({
url: badgeurl,
method: 'POST',
queued: true,
onSuccess: (resp) => {
let response;
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,17 @@
}
};

/**
* DO NOT use fetch() for QuickIcon requests. They must be queued.
*
* @see https://github.com/joomla/joomla-cms/issues/38001
*/
Joomla.request({
url: options.ajaxUrl,
method: 'GET',
data: '',
perform: true,
queued: true,
onSuccess: (response) => {
const updateInfoList = JSON.parse(response);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,36 +21,43 @@ if (Joomla && Joomla.getOptions('js-extensions-update')) {
const fetchUpdate = () => {
const options = Joomla.getOptions('js-joomla-update');

fetch(options.ajaxUrl, { method: 'GET' })
.then((response) => {
response.json().then((updateInfoList) => {
if (Array.isArray(updateInfoList)) {
if (updateInfoList.length === 0) {
// No updates
update('success', Joomla.Text._('PLG_QUICKICON_JOOMLAUPDATE_UPTODATE'));
} else {
const updateInfo = updateInfoList.shift();
/**
* DO NOT use fetch() for QuickIcon requests. They must be queued.
*
* @see https://github.com/joomla/joomla-cms/issues/38001
*/
Joomla.request({
url: options.ajaxUrl,
method: 'GET',
data: '',
perform: true,
queued: true,
onSuccess: (response) => {
const updateInfoList = JSON.parse(response);

if (updateInfo.version !== options.version) {
update('danger', Joomla.Text._('PLG_QUICKICON_JOOMLAUPDATE_UPDATEFOUND').replace('%s', `<span class="badge text-dark bg-light"> \u200E ${updateInfo.version}</span>`));
} else {
update('success', Joomla.Text._('PLG_QUICKICON_JOOMLAUPDATE_UPTODATE'));
}
}
if (Array.isArray(updateInfoList)) {
if (updateInfoList.length === 0) {
// No updates
update('success', Joomla.Text._('PLG_QUICKICON_JOOMLAUPDATE_UPTODATE'));
} else {
// An error occurred
update('danger', Joomla.Text._('PLG_QUICKICON_JOOMLAUPDATE_ERROR'));
const updateInfo = updateInfoList.shift();

if (updateInfo.version !== options.version) {
update('danger', Joomla.Text._('PLG_QUICKICON_JOOMLAUPDATE_UPDATEFOUND').replace('%s', `<span class="badge text-dark bg-light"> \u200E ${updateInfo.version}</span>`));
} else {
update('success', Joomla.Text._('PLG_QUICKICON_JOOMLAUPDATE_UPTODATE'));
}
}
})
.catch(() => {
// An error occurred
update('danger', Joomla.Text._('PLG_QUICKICON_JOOMLAUPDATE_ERROR'));
});
})
.catch(() => {
} else {
// An error occurred
update('danger', Joomla.Text._('PLG_QUICKICON_JOOMLAUPDATE_ERROR'));
}
},
onError: () => {
// An error occurred
update('danger', Joomla.Text._('PLG_QUICKICON_JOOMLAUPDATE_ERROR'));
});
},
});
};

// Give some times to the layout and other scripts to settle their stuff
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,17 @@
}
};

/**
* DO NOT use fetch() for QuickIcon requests. They must be queued.
*
* @see https://github.com/joomla/joomla-cms/issues/38001
*/
Joomla.request({
url: options.ajaxUrl,
method: 'GET',
data: '',
perform: true,
queued: true,
onSuccess: (response) => {
const updateInfoList = JSON.parse(response);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,17 @@
const quickicon = document.getElementById('plg_quickicon_privacycheck');
const link = quickicon.querySelector('span.j-links-link');

/**
* DO NOT use fetch() for QuickIcon requests. They must be queued.
*
* @see https://github.com/joomla/joomla-cms/issues/38001
*/
Joomla.request({
url: ajaxUrl,
method: 'GET',
data: '',
perform: true,
queued: true,
onSuccess: (response) => {
try {
const request = JSON.parse(response);
Expand Down
59 changes: 58 additions & 1 deletion build/media_source/system/js/core.es6.js
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,27 @@ window.Joomla.Modal = window.Joomla.Modal || {
});
};

/**
* Joomla Request queue.
*
* A FIFO queue of requests to execute serially. Used to prevent simultaneous execution of
* multiple requests against the server which could trigger its Denial of Service protection.
*
* @type {Array}
*
* @since __DEPLOY_VERSION__
*/
const requestQueue = [];

/**
* Flag to indicate whether Joomla is performing a queued Request.
*
* @type {boolean}
*
* @since __DEPLOY_VERSION__
*/
let performingQueuedRequest = false;

/**
* Method to perform AJAX request
*
Expand All @@ -576,6 +597,8 @@ window.Joomla.Modal = window.Joomla.Modal || {
* https://developer.mozilla.org/docs/Web/API/XMLHttpRequest/send
* perform: true, Perform the request immediately
* or return XMLHttpRequest instance and perform it later
* queued: false, Put the request in a FIFO queue; prevents simultaneous execution of
* multiple requests to avoid triggering the server's Denial of Service protection.
* headers: null, Object of custom headers, eg {'X-Foo': 'Bar', 'X-Bar': 'Foo'}
*
* onBefore: (xhr) => {} // Callback on before the request
Expand All @@ -598,13 +621,32 @@ window.Joomla.Modal = window.Joomla.Modal || {
* @see https://developer.mozilla.org/docs/Web/API/XMLHttpRequest
*/
Joomla.request = (options) => {
/**
* Processes queued Request objects.
*
* @since __DEPLOY_VERSION__
*/
const processQueuedRequests = () => {
if (performingQueuedRequest || requestQueue.length === 0) {
return;
}

performingQueuedRequest = true;

const nextRequest = requestQueue.shift();

nextRequest.xhr.send(nextRequest.data);
};

let xhr;

// Prepare the options
const newOptions = Joomla.extend({
url: '',
method: 'GET',
data: null,
perform: true,
queued: false,
}, options);

// Set up XMLHttpRequest instance
Expand Down Expand Up @@ -648,6 +690,12 @@ window.Joomla.Modal = window.Joomla.Modal || {
return;
}

// The request is finished; step through any more queued requests
if (newOptions.queued) {
performingQueuedRequest = false;
processQueuedRequests();
}

// Request finished and response is ready
if (xhr.status === 200) {
if (newOptions.onSuccess) {
Expand All @@ -663,14 +711,23 @@ window.Joomla.Modal = window.Joomla.Modal || {
};

// Do request
if (newOptions.perform) {
if (newOptions.perform && !newOptions.queued) {
if (newOptions.onBefore && newOptions.onBefore.call(window, xhr) === false) {
// Request interrupted
return xhr;
}

xhr.send(newOptions.data);
}

// Enqueue request and try to process the queue
if (newOptions.queued) {
requestQueue.push({
xhr,
data: newOptions.data,
});
processQueuedRequests();
}
} catch (error) {
// eslint-disable-next-line no-unused-expressions,no-console
window.console ? console.log(error) : null;
Expand Down