diff --git a/packages/core/src/sanitization/inert_body.ts b/packages/core/src/sanitization/inert_body.ts index c460c5dc65..4086956ac6 100644 --- a/packages/core/src/sanitization/inert_body.ts +++ b/packages/core/src/sanitization/inert_body.ts @@ -16,7 +16,8 @@ import {trustedHTMLFromString} from '../util/security/trusted_types'; * Fallback: InertDocument strategy */ export function getInertBodyHelper(defaultDoc: Document): InertBodyHelper { - return isDOMParserAvailable() ? new DOMParserHelper() : new InertDocumentHelper(defaultDoc); + const inertDocumentHelper = new InertDocumentHelper(defaultDoc); + return isDOMParserAvailable() ? new DOMParserHelper(inertDocumentHelper) : inertDocumentHelper; } export interface InertBodyHelper { @@ -31,6 +32,8 @@ export interface InertBodyHelper { * This is the default strategy used in browsers that support it. */ class DOMParserHelper implements InertBodyHelper { + constructor(private inertDocumentHelper: InertBodyHelper) {} + getInertBodyElement(html: string): HTMLElement|null { // We add these extra elements to ensure that the rest of the content is parsed as expected // e.g. leading whitespace is maintained and tags like `` do not get hoisted to the @@ -41,6 +44,12 @@ class DOMParserHelper implements InertBodyHelper { const body = new window.DOMParser() .parseFromString(trustedHTMLFromString(html) as string, 'text/html') .body as HTMLBodyElement; + if (body === null) { + // In some browsers (e.g. Mozilla/5.0 iPad AppleWebKit Mobile) the `body` property only + // becomes available in the following tick of the JS engine. In that case we fall back to + // the `inertDocumentHelper` instead. + return this.inertDocumentHelper.getInertBodyElement(html); + } body.removeChild(body.firstChild!); return body; } catch { diff --git a/packages/core/test/sanitization/html_sanitizer_spec.ts b/packages/core/test/sanitization/html_sanitizer_spec.ts index aae4a18421..01d805c9be 100644 --- a/packages/core/test/sanitization/html_sanitizer_spec.ts +++ b/packages/core/test/sanitization/html_sanitizer_spec.ts @@ -252,5 +252,14 @@ function sanitizeHtml(defaultDoc: any, unsafeHtmlInput: string): string { .toMatch(/CLICKME<\/a>/); }); } + + if (isDOMParserAvailable()) { + it('should work even if DOMParser returns a null body', () => { + // Simulate `DOMParser.parseFromString()` returning a null body. + // See https://github.com/angular/angular/issues/39834 + spyOn(window.DOMParser.prototype, 'parseFromString').and.returnValue({body: null} as any); + expect(sanitizeHtml(defaultDoc, 'Hello, World')).toEqual('Hello, World'); + }); + } }); }