Skip to content

Commit 5452ce6

Browse files
committed
MOBILE-3571 core: Split calls with too many parameters
1 parent 8d95636 commit 5452ce6

File tree

4 files changed

+106
-5
lines changed

4 files changed

+106
-5
lines changed

src/classes/site.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ import { CoreDbProvider } from '@providers/db';
2020
import { CoreEventsProvider } from '@providers/events';
2121
import { CoreFileProvider } from '@providers/file';
2222
import { CoreLoggerProvider } from '@providers/logger';
23-
import { CoreWSProvider, CoreWSPreSets, CoreWSFileUploadOptions, CoreWSAjaxPreSets } from '@providers/ws';
23+
import {
24+
CoreWSProvider, CoreWSPreSets, CoreWSFileUploadOptions, CoreWSAjaxPreSets, CoreWSPreSetsSplitRequest
25+
} from '@providers/ws';
2426
import { CoreDomUtilsProvider } from '@providers/utils/dom';
2527
import { CoreTextUtilsProvider } from '@providers/utils/text';
2628
import { CoreTimeUtilsProvider } from '@providers/utils/time';
@@ -138,6 +140,12 @@ export interface CoreSiteWSPreSets {
138140
* Component id. Optionally included when 'component' is set.
139141
*/
140142
componentId?: number;
143+
144+
/**
145+
* Whether to split a request if it has too many parameters. Sending too many parameters to the site
146+
* can cause the request to fail (see PHP's max_input_vars).
147+
*/
148+
splitRequest?: CoreWSPreSetsSplitRequest;
141149
}
142150

143151
/**
@@ -650,7 +658,8 @@ export class CoreSite {
650658
siteUrl: this.siteUrl,
651659
cleanUnicode: this.cleanUnicode,
652660
typeExpected: preSets.typeExpected,
653-
responseExpected: preSets.responseExpected
661+
responseExpected: preSets.responseExpected,
662+
splitRequest: preSets.splitRequest,
654663
};
655664

656665
if (wsPreSets.cleanUnicode && this.textUtils.hasUnicodeData(data)) {

src/core/course/providers/module-prefetch-delegate.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,11 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
471471
preSets: CoreSiteWSPreSets = {
472472
cacheKey: this.getCourseUpdatesCacheKey(courseId),
473473
emergencyCache: false, // If downloaded data has changed and offline, just fail. See MOBILE-2085.
474-
uniqueCacheKey: true
474+
uniqueCacheKey: true,
475+
splitRequest: {
476+
param: 'tocheck',
477+
maxLength: 10,
478+
},
475479
};
476480

477481
return site.read('core_course_check_updates', params, preSets).then((response) => {

src/core/filter/providers/filter.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,11 @@ export class CoreFilterProvider {
272272
},
273273
preSets = {
274274
cacheKey: this.getAvailableInContextsCacheKey(contextsToSend),
275-
updateFrequency: CoreSite.FREQUENCY_RARELY
275+
updateFrequency: CoreSite.FREQUENCY_RARELY,
276+
splitRequest: {
277+
param: 'contexts',
278+
maxLength: 300,
279+
},
276280
};
277281

278282
return site.read('core_filters_get_available_in_context', data, preSets)

src/providers/ws.ts

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,34 @@ export interface CoreWSPreSets {
5757
* Defaults to false. Clean multibyte Unicode chars from data.
5858
*/
5959
cleanUnicode?: boolean;
60+
61+
/**
62+
* Whether to split a request if it has too many parameters. Sending too many parameters to the site
63+
* can cause the request to fail (see PHP's max_input_vars).
64+
*/
65+
splitRequest?: CoreWSPreSetsSplitRequest;
6066
}
6167

68+
/**
69+
* Options to split a request.
70+
*/
71+
export type CoreWSPreSetsSplitRequest = {
72+
/**
73+
* Name of the parameter used to split the request if too big. Must be an array parameter.
74+
*/
75+
param: string;
76+
77+
/**
78+
* Max number of entries sent per request.
79+
*/
80+
maxLength: number;
81+
82+
/**
83+
* Callback to combine the results. If not supplied, arrays in the result will be concatenated.
84+
*/
85+
combineCallback?: (previousValue: any, currentValue: any, currentIndex: number, array: any[]) => any;
86+
};
87+
6288
/**
6389
* PreSets accepted by AJAX WS calls.
6490
*/
@@ -622,7 +648,7 @@ export class CoreWSProvider {
622648
}
623649

624650
/**
625-
* Perform the post call and save the promise while waiting to be resolved.
651+
* Perform the post call. It can be split into several requests.
626652
*
627653
* @param method The WebService method to be called.
628654
* @param siteUrl Complete site url to perform the call.
@@ -639,6 +665,64 @@ export class CoreWSProvider {
639665
options['responseType'] = 'text';
640666
}
641667

668+
if (!preSets.splitRequest || !ajaxData[preSets.splitRequest.param]) {
669+
return this.performSinglePost(method, siteUrl, ajaxData, preSets, options);
670+
}
671+
672+
// Split the request into several requests if needed.
673+
const promises: Promise<any>[] = [];
674+
675+
for (let i = 0; i < ajaxData[preSets.splitRequest.param].length; i += preSets.splitRequest.maxLength) {
676+
// Limit the array sent.
677+
const limitedData = Object.assign({}, ajaxData);
678+
limitedData[preSets.splitRequest.param] =
679+
ajaxData[preSets.splitRequest.param].slice(i, i + preSets.splitRequest.maxLength);
680+
681+
promises.push(this.performSinglePost(method, siteUrl, limitedData, preSets, options));
682+
}
683+
684+
return Promise.all(promises).then((results) => {
685+
// Combine the results.
686+
const firstResult = results.shift();
687+
688+
if (preSets.splitRequest.combineCallback) {
689+
return results.reduce(preSets.splitRequest.combineCallback, firstResult);
690+
}
691+
692+
return results.reduce(this.combineObjectsArrays, firstResult);
693+
});
694+
}
695+
696+
/**
697+
* Combine the arrays of two objects.
698+
*
699+
* @param object1 First object.
700+
* @param object2 Second object.
701+
* @return Combined object.
702+
*/
703+
protected combineObjectsArrays(object1: any, object2: any): any {
704+
for (const name in object2) {
705+
if (Array.isArray(object2[name])) {
706+
object1[name] = object1[name].concat(object2[name]);
707+
}
708+
}
709+
710+
return object1;
711+
}
712+
713+
/**
714+
* Perform a single post request.
715+
*
716+
* @param method The WebService method to be called.
717+
* @param siteUrl Complete site url to perform the call.
718+
* @param ajaxData Arguments to pass to the method.
719+
* @param preSets Extra settings and information.
720+
* @param options Request options.
721+
* @return Promise resolved with the response data in success and rejected with CoreWSError if it fails.
722+
*/
723+
protected performSinglePost(method: string, siteUrl: string, ajaxData: any, preSets: CoreWSPreSets, options: any)
724+
: Promise<any> {
725+
642726
// We add the method name to the URL purely to help with debugging.
643727
// This duplicates what is in the ajaxData, but that does no harm.
644728
// POST variables take precedence over GET.

0 commit comments

Comments
 (0)