perf(core): make sanitization tree-shakable in Ivy mode (#31934)

In VE the `Sanitizer` is always available in `BrowserModule` because the VE retrieves it using injection.

In Ivy the injection is optional and we have instructions instead of component definition arrays. The implication of this is that in Ivy the instructions can pull in the sanitizer only when they are working with a property which is known to be unsafe. Because the Injection is optional this works even if no Sanitizer is present. So in Ivy we first use the sanitizer which is pulled in by the instruction, unless one is available through the `Injector` then we use that one instead.

This PR does few things:
1) It makes `Sanitizer` optional in Ivy.
2) It makes `DomSanitizer` tree shakable.
3) It aligns the semantics of Ivy `Sanitizer` with that of the Ivy sanitization rules.
4) It refactors `DomSanitizer` to use same functions as Ivy sanitization for consistency.

PR Close #31934
This commit is contained in:
Miško Hevery
2019-07-31 13:15:50 -07:00
committed by Andrew Kushnir
parent 40b28742a9
commit 2e4d17f3a9
31 changed files with 269 additions and 214 deletions

View File

@ -10,7 +10,7 @@
// correctly implementing its interfaces for backwards compatibility.
import {Type} from '../core';
import {Injector} from '../di/injector';
import {Sanitizer} from '../sanitization/security';
import {Sanitizer} from '../sanitization/sanitizer';
import {assertDataInRange} from '../util/assert';
import {assertComponentType} from './assert';

View File

@ -16,7 +16,7 @@ import {ComponentFactoryResolver as viewEngine_ComponentFactoryResolver} from '.
import {ElementRef as viewEngine_ElementRef} from '../linker/element_ref';
import {NgModuleRef as viewEngine_NgModuleRef} from '../linker/ng_module_factory';
import {RendererFactory2} from '../render/api';
import {Sanitizer} from '../sanitization/security';
import {Sanitizer} from '../sanitization/sanitizer';
import {VERSION} from '../version';
import {NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR} from '../view/provider';

View File

@ -9,7 +9,7 @@ import {Injector} from '../../di';
import {ErrorHandler} from '../../error_handler';
import {CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA, SchemaMetadata} from '../../metadata/schema';
import {validateAgainstEventAttributes, validateAgainstEventProperties} from '../../sanitization/sanitization';
import {Sanitizer} from '../../sanitization/security';
import {Sanitizer} from '../../sanitization/sanitizer';
import {assertDataInRange, assertDefined, assertDomNode, assertEqual, assertGreaterThan, assertNotEqual, assertNotSame} from '../../util/assert';
import {createNamedArrayType} from '../../util/named_array_type';
import {normalizeDebugBindingName, normalizeDebugBindingValue} from '../../util/ng_reflect';

View File

@ -10,7 +10,7 @@ import {InjectionToken} from '../../di/injection_token';
import {Injector} from '../../di/injector';
import {Type} from '../../interface/type';
import {SchemaMetadata} from '../../metadata';
import {Sanitizer} from '../../sanitization/security';
import {Sanitizer} from '../../sanitization/sanitizer';
import {LContainer} from './container';
import {ComponentDef, ComponentTemplate, DirectiveDef, DirectiveDefList, HostBindingsFunction, PipeDef, PipeDefList, ViewQueriesFunction} from './definition';

View File

@ -5,6 +5,7 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {SafeValue} from '../../sanitization/bypass';
import {StyleSanitizeFn, StyleSanitizeMode} from '../../sanitization/style_sanitizer';
import {ProceduralRenderer3, RElement, Renderer3, RendererStyleFlags3, isProceduralRenderer} from '../interfaces/renderer';
@ -110,7 +111,7 @@ export function updateClassBinding(
*/
export function updateStyleBinding(
context: TStylingContext, data: LStylingData, element: RElement, prop: string | null,
bindingIndex: number, value: String | string | number | null | undefined | StylingMapArray,
bindingIndex: number, value: string | number | SafeValue | null | undefined | StylingMapArray,
sanitizer: StyleSanitizeFn | null, deferRegistration: boolean, forceUpdate: boolean): boolean {
const isMapBased = !prop;
const state = getStylingState(element, stateIsPersisted(context));
@ -149,7 +150,7 @@ export function updateStyleBinding(
function updateBindingData(
context: TStylingContext, data: LStylingData, counterIndex: number, prop: string | null,
bindingIndex: number,
value: string | String | number | boolean | null | undefined | StylingMapArray,
value: string | SafeValue | number | boolean | null | undefined | StylingMapArray,
deferRegistration: boolean, forceUpdate: boolean, sanitizationRequired: boolean): boolean {
if (!isContextLocked(context)) {
if (deferRegistration) {

View File

@ -5,6 +5,7 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {SafeValue} from '../../sanitization/bypass';
import {StyleSanitizeFn} from '../../sanitization/style_sanitizer';
import {setInputsForProperty} from '../instructions/shared';
import {AttributeMarker, TAttributes, TNode, TNodeType} from '../interfaces/node';
@ -96,12 +97,12 @@ export function ɵɵstyleSanitizer(sanitizer: StyleSanitizeFn | null): void {
* @codeGenApi
*/
export function ɵɵstyleProp(
prop: string, value: string | number | String | null, suffix?: string | null): void {
prop: string, value: string | number | SafeValue | null, suffix?: string | null): void {
stylePropInternal(getSelectedIndex(), prop, value, suffix);
}
export function stylePropInternal(
elementIndex: number, prop: string, value: string | number | String | null,
elementIndex: number, prop: string, value: string | number | SafeValue | null,
suffix?: string | null | undefined) {
const lView = getLView();
@ -161,8 +162,8 @@ export function ɵɵclassProp(className: string, value: boolean | null): void {
*/
function _stylingProp(
elementIndex: number, bindingIndex: number, prop: string,
value: boolean | number | String | string | null | undefined | NO_CHANGE, isClassBased: boolean,
defer: boolean): boolean {
value: boolean | number | SafeValue | string | null | undefined | NO_CHANGE,
isClassBased: boolean, defer: boolean): boolean {
const lView = getLView();
const tNode = getTNode(elementIndex, lView);
const native = getNativeByTNode(tNode, lView) as RElement;
@ -176,8 +177,8 @@ function _stylingProp(
} else {
const sanitizer = getCurrentStyleSanitizer();
updated = updateStyleBinding(
getStylesContext(tNode), lView, native, prop, bindingIndex, value as string | null,
sanitizer, defer, false);
getStylesContext(tNode), lView, native, prop, bindingIndex,
value as string | SafeValue | null, sanitizer, defer, false);
}
}
@ -508,8 +509,8 @@ function getContext(tNode: TNode, isClassBased: boolean) {
}
function resolveStylePropValue(
value: string | number | String | null | NO_CHANGE, suffix: string | null | undefined): string|
null|undefined|NO_CHANGE {
value: string | number | SafeValue | null | NO_CHANGE,
suffix: string | null | undefined): string|SafeValue|null|undefined|NO_CHANGE {
if (value === NO_CHANGE) return value;
let resolvedValue: string|null = null;
@ -519,7 +520,7 @@ function resolveStylePropValue(
// sanitization entirely (b/c a new string is created)
resolvedValue = renderStringify(value) + suffix;
} else {
// sanitization happens by dealing with a String value
// sanitization happens by dealing with a string value
// this means that the string value will be passed through
// into the style rendering later (which is where the value
// will be sanitized before it is applied)