diff --git a/src/app/app.module.ts b/src/app/app.module.ts index ce8413a28..b6f4a6ed4 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -15,7 +15,7 @@ import { BrowserModule } from '@angular/platform-browser'; import { ErrorHandler, NgModule } from '@angular/core'; import { IonicApp, IonicErrorHandler, IonicModule, Platform } from 'ionic-angular'; -import { HttpClient, HttpClientModule } from '@angular/common/http'; +import { HttpClient, HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; import { SplashScreen } from '@ionic-native/splash-screen'; import { StatusBar } from '@ionic-native/status-bar'; @@ -25,6 +25,7 @@ import { TranslateModule, TranslateLoader } from '@ngx-translate/core'; import { TranslateHttpLoader } from '@ngx-translate/http-loader'; import { MyApp } from './app.component'; +import { CoreInterceptor } from '../classes/interceptor'; import { CoreLoggerProvider } from '../providers/logger'; import { CoreDbProvider } from '../providers/db'; import { CoreAppProvider } from '../providers/app'; @@ -80,6 +81,11 @@ export function createTranslateLoader(http: HttpClient) { MyApp ], providers: [ + { + provide: HTTP_INTERCEPTORS, + useClass: CoreInterceptor, + multi: true, + }, StatusBar, SplashScreen, SQLite, diff --git a/src/classes/interceptor.ts b/src/classes/interceptor.ts new file mode 100644 index 000000000..ad78e5d95 --- /dev/null +++ b/src/classes/interceptor.ts @@ -0,0 +1,79 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Injectable } from '@angular/core'; +import { HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +/** + * Interceptor for Http calls. Adds the header 'Content-Type'='application/x-www-form-urlencoded' + * and serializes the parameters if needed. + */ +@Injectable() +export class CoreInterceptor implements HttpInterceptor { + + constructor() {} + + intercept(req: HttpRequest, next: HttpHandler): Observable { + // Add the header and serialize the body if needed. + const newReq = req.clone({ + headers: req.headers.set('Content-Type', 'application/x-www-form-urlencoded'), + body: typeof req.body == 'object' && String(req.body) != '[object File]' ? + CoreInterceptor.serialize(req.body) : req.body + }); + + // Pass on the cloned request instead of the original request. + return next.handle(newReq); + } + + /** + * Serialize an object to be used in a request. + * + * @param {any} obj Object to serialize. + * @param {boolean} [addNull] Add null values to the serialized as empty parameters. + * @return {string} Serialization of the object. + */ + public static serialize(obj: any, addNull?: boolean) : string { + let query = '', + fullSubName, + subValue, + innerObj; + + for (let name in obj) { + let value = obj[name]; + + if (value instanceof Array) { + for (let i = 0; i < value.length; ++i) { + subValue = value[i]; + fullSubName = name + '[' + i + ']'; + innerObj = {}; + innerObj[fullSubName] = subValue; + query += this.serialize(innerObj) + '&'; + } + } else if (value instanceof Object) { + for (let subName in value) { + subValue = value[subName]; + fullSubName = name + '[' + subName + ']'; + innerObj = {}; + innerObj[fullSubName] = subValue; + query += this.serialize(innerObj) + '&'; + } + } else if (addNull || (typeof value != 'undefined' && value !== null)) { + query += encodeURIComponent(name) + '=' + encodeURIComponent(value) + '&'; + } + } + + return query.length ? query.substr(0, query.length - 1) : query; + } +} diff --git a/src/providers/utils/utils.ts b/src/providers/utils/utils.ts index d1c650fd8..3a642ab79 100644 --- a/src/providers/utils/utils.ts +++ b/src/providers/utils/utils.ts @@ -1036,46 +1036,6 @@ export class CoreUtilsProvider { return value1 === value2; } - /** - * Serialize an object to be used in a request. - * - * @param {any} obj Object to serialize. - * @param {boolean} [addNull] Add null values to the serialized as empty parameters. - * @return {string} Serialization of the object. - */ - serialize(obj: any, addNull?: boolean) : string { - let query = '', - fullSubName, - subValue, - innerObj; - - for (let name in obj) { - let value = obj[name]; - - if (value instanceof Array) { - for (let i = 0; i < value.length; ++i) { - subValue = value[i]; - fullSubName = name + '[' + i + ']'; - innerObj = {}; - innerObj[fullSubName] = subValue; - query += this.serialize(innerObj) + '&'; - } - } else if (value instanceof Object) { - for (let subName in value) { - subValue = value[subName]; - fullSubName = name + '[' + subName + ']'; - innerObj = {}; - innerObj[fullSubName] = subValue; - query += this.serialize(innerObj) + '&'; - } - } else if (addNull || (typeof value != 'undefined' && value !== null)) { - query += encodeURIComponent(name) + '=' + encodeURIComponent(value) + '&'; - } - } - - return query.length ? query.substr(0, query.length - 1) : query; - } - /** * Stringify an object, sorting the properties. It doesn't sort arrays, only object properties. E.g.: * {b: 2, a: 1} -> '{"a":1,"b":2}' diff --git a/src/providers/ws.ts b/src/providers/ws.ts index c554a1422..2673f4626 100644 --- a/src/providers/ws.ts +++ b/src/providers/ws.ts @@ -24,6 +24,7 @@ import { CoreTextUtilsProvider } from './utils/text'; import { CoreUtilsProvider } from './utils/utils'; import { CoreConstants } from '../core/constants'; import { Md5 } from 'ts-md5/dist/md5'; +import { CoreInterceptor } from '../classes/interceptor'; /** * Interface of the presets accepted by the WS call. @@ -416,7 +417,7 @@ export class CoreWSProvider { */ protected getQueueItemId(method: string, url: string, params?: any) : string { if (params) { - url += '###' + this.utils.serialize(params); + url += '###' + CoreInterceptor.serialize(params); } return method + '#' + Md5.hashAsciiStr(url); } @@ -595,7 +596,7 @@ export class CoreWSProvider { siteUrl = preSets.siteUrl + '/webservice/rest/server.php?moodlewsrestformat=json'; // Serialize data. - data = this.utils.serialize(data); + data = CoreInterceptor.serialize(data); // Perform sync request using XMLHttpRequest. xhr = new (window).XMLHttpRequest();