From 2e69497c130bde3626fd65f2c70a628c6c67ae33 Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Tue, 21 Jan 2020 10:37:42 +0100 Subject: [PATCH] MOBILE-3286 utils: Refactor CoreUrl and expose to plugins --- src/classes/utils/url.ts | 70 ++++++++++++++++++++++++--- src/core/compile/providers/compile.ts | 2 + src/core/login/pages/site/site.ts | 13 +++-- 3 files changed, 76 insertions(+), 9 deletions(-) diff --git a/src/classes/utils/url.ts b/src/classes/utils/url.ts index 1fb990b81..579d8cbb0 100644 --- a/src/classes/utils/url.ts +++ b/src/classes/utils/url.ts @@ -12,18 +12,76 @@ // See the License for the specific language governing permissions and // limitations under the License. -export class CoreUrl { +/** + * Parts contained within a url. + */ +interface UrlParts { /** - * Parse url domain. + * Url protocol. + */ + protocol?: string; + + /** + * Url domain. + */ + domain?: string; + + /** + * Url path. + */ + path?: string; + + /** + * Url query. + */ + query?: string; + + /** + * Url fragment. + */ + fragment?: string; + +} + +/** + * Singleton with helper functions for urls. + */ +export class CoreUrl { + + // Avoid creating singleton instances + private constructor() {} + + /** + * Parse parts of a url, using an implicit protocol if it is missing from the url. * * @param url Url. - * @return Url domain. + * @param implicitProtocol Protocol to be used if the url doesn't have any. + * @return Url parts. */ - static parseDomain(url: string): string | null { - const match = url.trim().match(/(https?:\/\/|^)([^/]+)/); + static parse(url: string, implicitProtocol?: string): UrlParts | null { + // Prepare url before parsing + url = url.trim(); - return match ? match[2] : null; + if (implicitProtocol && !url.match(/^[a-zA-Z]+:\/\//)) { + url = `${implicitProtocol}://${url}`; + } + + // Regular expression taken from RFC 3986: https://tools.ietf.org/html/rfc3986#appendix-B + const match = url.trim().match(/^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/); + + if (!match) { + return null; + } + + // Prepare parts replacing empty strings with undefined + return { + protocol: match[2] || undefined, + domain: match[4] || undefined, + path: match[5] || undefined, + query: match[7] || undefined, + fragment: match[9] || undefined, + }; } } diff --git a/src/core/compile/providers/compile.ts b/src/core/compile/providers/compile.ts index 8f0c7e1b6..74596aa20 100644 --- a/src/core/compile/providers/compile.ts +++ b/src/core/compile/providers/compile.ts @@ -55,6 +55,7 @@ import { Md5 } from 'ts-md5/dist/md5'; // Import core classes that can be useful for site plugins. import { CoreSyncBaseProvider } from '@classes/base-sync'; +import { CoreUrl } from '@classes/utils/url'; import { CoreCache } from '@classes/cache'; import { CoreDelegate } from '@classes/delegate'; import { CoreContentLinksHandlerBase } from '@core/contentlinks/classes/base-handler'; @@ -263,6 +264,7 @@ export class CoreCompileProvider { instance['moment'] = moment; instance['Md5'] = Md5; instance['CoreSyncBaseProvider'] = CoreSyncBaseProvider; + instance['CoreUrl'] = CoreUrl; instance['CoreCache'] = CoreCache; instance['CoreDelegate'] = CoreDelegate; instance['CoreContentLinksHandlerBase'] = CoreContentLinksHandlerBase; diff --git a/src/core/login/pages/site/site.ts b/src/core/login/pages/site/site.ts index b1b7dbd9b..27db57687 100644 --- a/src/core/login/pages/site/site.ts +++ b/src/core/login/pages/site/site.ts @@ -116,13 +116,13 @@ export class CoreLoginSitePage { // Attempt parsing the domain after initial check failed .catch((error) => { - const domain = CoreUrl.parseDomain(url); + const urlParts = CoreUrl.parse(url, 'http'); - if (!domain) { + if (!urlParts || !urlParts.domain) { throw error; } - return this.sitesProvider.checkSite(domain); + return this.sitesProvider.checkSite(urlParts.domain); }) .then((result) => this.login(result)) @@ -170,6 +170,13 @@ export class CoreLoginSitePage { modal.present(); } + /** + * Process login to a site. + * + * @param response Response obtained from the site check request. + * + * @return Promise resolved after logging in. + */ private async login(response: CoreSiteCheckResponse): Promise { return this.sitesProvider.checkRequiredMinimumVersion(response.config).then(() => { if (response.warning) {