The `inertDocument` member is only needed when using the InertDocument strategy. By separating the DOMParser and InertDocument strategies into separate classes, we can easily avoid creating the inert document unnecessarily when using DOMParser. PR Close #36578
This commit is contained in:
parent
b950d4675f
commit
d4544da804
|
@ -9,7 +9,7 @@ import '../util/ng_i18n_closure_mode';
|
|||
|
||||
import {DEFAULT_LOCALE_ID, getPluralCase} from '../i18n/localization';
|
||||
import {getTemplateContent, SRCSET_ATTRS, URI_ATTRS, VALID_ATTRS, VALID_ELEMENTS} from '../sanitization/html_sanitizer';
|
||||
import {InertBodyHelper} from '../sanitization/inert_body';
|
||||
import {getInertBodyHelper} from '../sanitization/inert_body';
|
||||
import {_sanitizeUrl, sanitizeSrcset} from '../sanitization/url_sanitizer';
|
||||
import {addAllToArray} from '../util/array_utils';
|
||||
import {assertDataInRange, assertDefined, assertEqual} from '../util/assert';
|
||||
|
@ -1233,7 +1233,7 @@ function icuStart(
|
|||
function parseIcuCase(
|
||||
unsafeHtml: string, parentIndex: number, nestedIcus: IcuExpression[], tIcus: TIcu[],
|
||||
expandoStartIndex: number): IcuCase {
|
||||
const inertBodyHelper = new InertBodyHelper(getDocument());
|
||||
const inertBodyHelper = getInertBodyHelper(getDocument());
|
||||
const inertBodyElement = inertBodyHelper.getInertBodyElement(unsafeHtml);
|
||||
if (!inertBodyElement) {
|
||||
throw new Error('Unable to generate inert body element');
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
import {isDevMode} from '../util/is_dev_mode';
|
||||
import {InertBodyHelper} from './inert_body';
|
||||
import {getInertBodyHelper, InertBodyHelper} from './inert_body';
|
||||
import {_sanitizeUrl, sanitizeSrcset} from './url_sanitizer';
|
||||
|
||||
function tagSet(tags: string): {[k: string]: boolean} {
|
||||
|
@ -245,7 +245,7 @@ let inertBodyHelper: InertBodyHelper;
|
|||
export function _sanitizeHtml(defaultDoc: any, unsafeHtmlInput: string): string {
|
||||
let inertBodyElement: HTMLElement|null = null;
|
||||
try {
|
||||
inertBodyHelper = inertBodyHelper || new InertBodyHelper(defaultDoc);
|
||||
inertBodyHelper = inertBodyHelper || getInertBodyHelper(defaultDoc);
|
||||
// Make sure unsafeHtml is actually a string (TypeScript types are not enforced at runtime).
|
||||
let unsafeHtml = unsafeHtmlInput ? String(unsafeHtmlInput) : '';
|
||||
inertBodyElement = inertBodyHelper.getInertBodyElement(unsafeHtml);
|
||||
|
|
|
@ -7,40 +7,29 @@
|
|||
*/
|
||||
|
||||
/**
|
||||
* This helper class is used to get hold of an inert tree of DOM elements containing dirty HTML
|
||||
* This helper is used to get hold of an inert tree of DOM elements containing dirty HTML
|
||||
* that needs sanitizing.
|
||||
* Depending upon browser support we use one of two strategies for doing this.
|
||||
* Default: DomParser strategy
|
||||
* Default: DOMParser strategy
|
||||
* Fallback: InertDocument strategy
|
||||
*/
|
||||
export class InertBodyHelper {
|
||||
private inertDocument: Document;
|
||||
|
||||
constructor(private defaultDoc: Document) {
|
||||
this.inertDocument = this.defaultDoc.implementation.createHTMLDocument('sanitization-inert');
|
||||
if (this.inertDocument.body == null) {
|
||||
// usually there should be only one body element in the document, but IE doesn't have any, so
|
||||
// we need to create one.
|
||||
const inertHtml = this.inertDocument.createElement('html');
|
||||
this.inertDocument.appendChild(inertHtml);
|
||||
const inertBodyElement = this.inertDocument.createElement('body');
|
||||
inertHtml.appendChild(inertBodyElement);
|
||||
}
|
||||
|
||||
this.getInertBodyElement = isDOMParserAvailable() ? this.getInertBodyElement_DOMParser :
|
||||
this.getInertBodyElement_InertDocument;
|
||||
export function getInertBodyHelper(defaultDoc: Document): InertBodyHelper {
|
||||
return isDOMParserAvailable() ? new DOMParserHelper() : new InertDocumentHelper(defaultDoc);
|
||||
}
|
||||
|
||||
export interface InertBodyHelper {
|
||||
/**
|
||||
* Get an inert DOM element containing DOM created from the dirty HTML string provided.
|
||||
* The implementation of this is determined in the constructor, when the class is instantiated.
|
||||
*/
|
||||
getInertBodyElement: (html: string) => HTMLElement | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use DOMParser to create and fill an inert body element in browsers that support it.
|
||||
* Uses DOMParser to create and fill an inert body element.
|
||||
* This is the default strategy used in browsers that support it.
|
||||
*/
|
||||
private getInertBodyElement_DOMParser(html: string) {
|
||||
class DOMParserHelper implements 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 `<meta>` do not get hoisted to the
|
||||
// `<head>` tag.
|
||||
|
@ -54,13 +43,30 @@ export class InertBodyHelper {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Use an HTML5 `template` element, if supported, or an inert body element created via
|
||||
* `createHtmlDocument` to create and fill an inert DOM element.
|
||||
* This is the fallback strategy if the browser does not support DOMParser.
|
||||
*/
|
||||
private getInertBodyElement_InertDocument(html: string) {
|
||||
class InertDocumentHelper implements InertBodyHelper {
|
||||
private inertDocument: Document;
|
||||
|
||||
constructor(private defaultDoc: Document) {
|
||||
this.inertDocument = this.defaultDoc.implementation.createHTMLDocument('sanitization-inert');
|
||||
|
||||
if (this.inertDocument.body == null) {
|
||||
// usually there should be only one body element in the document, but IE doesn't have any, so
|
||||
// we need to create one.
|
||||
const inertHtml = this.inertDocument.createElement('html');
|
||||
this.inertDocument.appendChild(inertHtml);
|
||||
const inertBodyElement = this.inertDocument.createElement('body');
|
||||
inertHtml.appendChild(inertBodyElement);
|
||||
}
|
||||
}
|
||||
|
||||
getInertBodyElement(html: string): HTMLElement|null {
|
||||
// Prefer using <template> element if supported.
|
||||
const templateEl = this.inertDocument.createElement('template');
|
||||
if ('content' in templateEl) {
|
||||
|
|
Loading…
Reference in New Issue