Prevent newlines from being encoded in the output (dotnet/aspnetcore-tooling#374)
* Prevent newlines from being encoded in the output
\n\nCommit migrated from 5f74fae0d2
This commit is contained in:
parent
8a8e144653
commit
8bb16c28aa
|
|
@ -16,9 +16,9 @@ namespace __GeneratedComponent
|
|||
{
|
||||
builder.OpenElement(0, "div");
|
||||
builder.AddAttribute(1, "class", this.ToString());
|
||||
builder.AddContent(2, "\r\n Hello world\r\n ");
|
||||
builder.AddMarkupContent(2, "\r\n Hello world\r\n ");
|
||||
builder.AddContent(3, string.Format("{0}", "Hello"));
|
||||
builder.AddContent(4, "\r\n");
|
||||
builder.AddMarkupContent(4, "\r\n");
|
||||
builder.CloseElement();
|
||||
}
|
||||
#pragma warning restore 1998
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Razor.Language.Intermediate;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||
{
|
||||
internal class ComponentMarkupEncodingPass : ComponentIntermediateNodePassBase, IRazorOptimizationPass
|
||||
{
|
||||
// Runs after ComponentMarkupBlockPass
|
||||
public override int Order => 10010;
|
||||
|
||||
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
|
||||
{
|
||||
if (!IsComponentDocument(documentNode))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (documentNode.Options.DesignTime)
|
||||
{
|
||||
// Nothing to do during design time.
|
||||
return;
|
||||
}
|
||||
|
||||
var rewriter = new Rewriter();
|
||||
rewriter.Visit(documentNode);
|
||||
}
|
||||
|
||||
private class Rewriter : IntermediateNodeWalker
|
||||
{
|
||||
// Markup content in components are rendered in one of the following two ways,
|
||||
// AddContent - we encode it when used with prerendering and inserted into the DOM in a safe way (low perf impact)
|
||||
// AddMarkupContent - renders the content directly as markup (high perf impact)
|
||||
// Because of this, we want to use AddContent as much as possible.
|
||||
//
|
||||
// We want to use AddMarkupContent to avoid aggresive encoding during prerendering.
|
||||
// Specifically, when one of the following characters are in the content,
|
||||
// 1. New lines (\r, \n), tabs(\t) - so they get rendered as actual new lines, tabs instead of 

|
||||
// 2. Ampersands (&) - so that HTML entities are rendered correctly without getting encoded
|
||||
// 3. Any character outside the ASCII range
|
||||
|
||||
private static readonly char[] EncodedCharacters = new[] { '\r', '\n', '\t', '&' };
|
||||
|
||||
public override void VisitHtml(HtmlContentIntermediateNode node)
|
||||
{
|
||||
for (var i = 0; i < node.Children.Count; i++)
|
||||
{
|
||||
var child = node.Children[i];
|
||||
if (!(child is IntermediateToken token) || !token.IsHtml)
|
||||
{
|
||||
// We only care about Html tokens.
|
||||
continue;
|
||||
}
|
||||
|
||||
for (var j = 0; j < token.Content.Length; j++)
|
||||
{
|
||||
var ch = token.Content[j];
|
||||
// ASCII range is 0 - 127
|
||||
if (ch > 127 || EncodedCharacters.Contains(ch))
|
||||
{
|
||||
node.SetEncoded();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -98,7 +98,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
|||
// Since we're not in the middle of writing an element, this must evaluate as some
|
||||
// text to display
|
||||
context.CodeWriter
|
||||
.WriteStartMethodInvocation($"{_scopeStack.BuilderVarName}.{nameof(ComponentsApi.RenderTreeBuilder.AddContent)}")
|
||||
.WriteStartMethodInvocation($"{_scopeStack.BuilderVarName}.{ComponentsApi.RenderTreeBuilder.AddContent}")
|
||||
.Write((_sourceSequence++).ToString())
|
||||
.WriteParameterSeparator();
|
||||
|
||||
|
|
@ -158,7 +158,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
|||
}
|
||||
|
||||
context.CodeWriter
|
||||
.WriteStartMethodInvocation($"{_scopeStack.BuilderVarName}.{nameof(ComponentsApi.RenderTreeBuilder.AddMarkupContent)}")
|
||||
.WriteStartMethodInvocation($"{_scopeStack.BuilderVarName}.{ComponentsApi.RenderTreeBuilder.AddMarkupContent}")
|
||||
.Write((_sourceSequence++).ToString())
|
||||
.WriteParameterSeparator()
|
||||
.WriteStringLiteral(node.Content)
|
||||
|
|
@ -178,7 +178,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
|||
}
|
||||
|
||||
context.CodeWriter
|
||||
.WriteStartMethodInvocation($"{_scopeStack.BuilderVarName}.{nameof(ComponentsApi.RenderTreeBuilder.OpenElement)}")
|
||||
.WriteStartMethodInvocation($"{_scopeStack.BuilderVarName}.{ComponentsApi.RenderTreeBuilder.OpenElement}")
|
||||
.Write((_sourceSequence++).ToString())
|
||||
.WriteParameterSeparator()
|
||||
.WriteStringLiteral(node.TagName)
|
||||
|
|
@ -255,8 +255,15 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
|||
|
||||
// Text node
|
||||
var content = GetHtmlContent(node);
|
||||
var renderApi = ComponentsApi.RenderTreeBuilder.AddContent;
|
||||
if (node.IsEncoded())
|
||||
{
|
||||
// This content is already encoded.
|
||||
renderApi = ComponentsApi.RenderTreeBuilder.AddMarkupContent;
|
||||
}
|
||||
|
||||
context.CodeWriter
|
||||
.WriteStartMethodInvocation($"{_scopeStack.BuilderVarName}.{nameof(ComponentsApi.RenderTreeBuilder.AddContent)}")
|
||||
.WriteStartMethodInvocation($"{_scopeStack.BuilderVarName}.{renderApi}")
|
||||
.Write((_sourceSequence++).ToString())
|
||||
.WriteParameterSeparator()
|
||||
.WriteStringLiteral(content)
|
||||
|
|
@ -644,8 +651,8 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
|||
var codeWriter = context.CodeWriter;
|
||||
|
||||
var methodName = node.IsComponentCapture
|
||||
? nameof(ComponentsApi.RenderTreeBuilder.AddComponentReferenceCapture)
|
||||
: nameof(ComponentsApi.RenderTreeBuilder.AddElementReferenceCapture);
|
||||
? ComponentsApi.RenderTreeBuilder.AddComponentReferenceCapture
|
||||
: ComponentsApi.RenderTreeBuilder.AddElementReferenceCapture;
|
||||
codeWriter
|
||||
.WriteStartMethodInvocation($"{_scopeStack.BuilderVarName}.{methodName}")
|
||||
.Write((_sourceSequence++).ToString())
|
||||
|
|
@ -693,7 +700,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
|||
protected override void BeginWriteAttribute(CodeWriter codeWriter, string key)
|
||||
{
|
||||
codeWriter
|
||||
.WriteStartMethodInvocation($"{_scopeStack.BuilderVarName}.{nameof(ComponentsApi.RenderTreeBuilder.AddAttribute)}")
|
||||
.WriteStartMethodInvocation($"{_scopeStack.BuilderVarName}.{ComponentsApi.RenderTreeBuilder.AddAttribute}")
|
||||
.Write((_sourceSequence++).ToString())
|
||||
.WriteParameterSeparator()
|
||||
.WriteStringLiteral(key)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Language.Intermediate
|
||||
{
|
||||
internal static class HtmlContentIntermediateNodeExtensions
|
||||
{
|
||||
private static readonly string HasEncodedContent = "HasEncodedContent";
|
||||
|
||||
public static bool IsEncoded(this HtmlContentIntermediateNode node)
|
||||
{
|
||||
return ReferenceEquals(node.Annotations[HasEncodedContent], HasEncodedContent);
|
||||
}
|
||||
|
||||
public static void SetEncoded(this HtmlContentIntermediateNode node)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(node));
|
||||
}
|
||||
|
||||
node.Annotations[HasEncodedContent] = HasEncodedContent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -232,6 +232,7 @@ namespace Microsoft.AspNetCore.Razor.Language
|
|||
builder.Features.Add(new ComponentGenericTypePass());
|
||||
builder.Features.Add(new ComponentChildContentDiagnosticPass());
|
||||
builder.Features.Add(new ComponentMarkupBlockPass());
|
||||
builder.Features.Add(new ComponentMarkupEncodingPass());
|
||||
}
|
||||
|
||||
private static void LoadExtensions(RazorProjectEngineBuilder builder, IReadOnlyList<RazorExtension> extensions)
|
||||
|
|
|
|||
Loading…
Reference in New Issue