From fdabaf00a6720d852ec3120b7bbe4b14de2f3ccf Mon Sep 17 00:00:00 2001 From: Safia Abdalla Date: Mon, 17 May 2021 00:40:31 -0700 Subject: [PATCH] Avoid adding CSS scope to elements in HEAD (#32709) * Avoid adding CSS scope to elements in HEAD * Set StringComparison type for comparison --- .../RazorView_Layout_WithCssScope.codegen.cs | 2 +- .../RazorView_Layout_WithCssScope.ir.txt | 5 ---- .../src/Extensions/ViewCssScopePass.cs | 29 +++++++++++++++++-- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/RazorView_Layout_WithCssScope.codegen.cs b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/RazorView_Layout_WithCssScope.codegen.cs index 282f05793985..488d55f68690 100644 --- a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/RazorView_Layout_WithCssScope.codegen.cs +++ b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/RazorView_Layout_WithCssScope.codegen.cs @@ -18,7 +18,7 @@ public class TestFiles_IntegrationTests_CodeGenerationIntegrationTest_test : glo #pragma warning disable 1998 public async override global::System.Threading.Tasks.Task ExecuteAsync() { - WriteLiteral("\r\n\r\n\r\n\r\n \r\n \r\n "); + WriteLiteral("\r\n<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n <meta charset=\"utf-8\" />\r\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\r\n <title>"); #nullable restore #line 7 "TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml" Write(ViewData["Title"]); diff --git a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/RazorView_Layout_WithCssScope.ir.txt b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/RazorView_Layout_WithCssScope.ir.txt index c7db330e79b4..258748bf6e49 100644 --- a/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/RazorView_Layout_WithCssScope.ir.txt +++ b/src/Razor/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/RazorView_Layout_WithCssScope.ir.txt @@ -15,29 +15,24 @@ Document - LazyIntermediateToken - (0:0,0 [2] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml) - Html - \n LazyIntermediateToken - (2:1,0 [17] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml) - Html - <!DOCTYPE html>\n LazyIntermediateToken - (19:2,0 [5] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml) - Html - <html - IntermediateToken - - Html - TestCssScope LazyIntermediateToken - (24:2,5 [10] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml) - Html - lang="en" LazyIntermediateToken - (34:2,15 [1] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml) - Html - > LazyIntermediateToken - (35:2,16 [2] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml) - Html - \n LazyIntermediateToken - (37:3,0 [5] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml) - Html - <head - IntermediateToken - - Html - TestCssScope LazyIntermediateToken - (42:3,5 [1] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml) - Html - > LazyIntermediateToken - (43:3,6 [6] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml) - Html - \n LazyIntermediateToken - (49:4,4 [5] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml) - Html - <meta - IntermediateToken - - Html - TestCssScope LazyIntermediateToken - (54:4,9 [16] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml) - Html - charset="utf-8" LazyIntermediateToken - (70:4,25 [1] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml) - Html - LazyIntermediateToken - (71:4,26 [2] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml) - Html - /> LazyIntermediateToken - (73:4,28 [6] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml) - Html - \n LazyIntermediateToken - (79:5,4 [5] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml) - Html - <meta - IntermediateToken - - Html - TestCssScope LazyIntermediateToken - (84:5,9 [16] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml) - Html - name="viewport" LazyIntermediateToken - (100:5,25 [48] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml) - Html - content="width=device-width, initial-scale=1.0" LazyIntermediateToken - (148:5,73 [1] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml) - Html - LazyIntermediateToken - (149:5,74 [2] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml) - Html - /> LazyIntermediateToken - (151:5,76 [6] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml) - Html - \n LazyIntermediateToken - (157:6,4 [6] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml) - Html - <title - IntermediateToken - - Html - TestCssScope LazyIntermediateToken - (163:6,10 [1] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml) - Html - > CSharpExpression - (165:6,12 [17] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml) LazyIntermediateToken - (165:6,12 [17] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml) - CSharp - ViewData["Title"] diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Extensions/ViewCssScopePass.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Extensions/ViewCssScopePass.cs index ae20b386c243..23dd233a3100 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Extensions/ViewCssScopePass.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Extensions/ViewCssScopePass.cs @@ -41,9 +41,7 @@ private void ProcessElement(HtmlContentIntermediateNode node, string cssScope) var child = node.Children[i]; if (child is IntermediateToken token && token.IsHtml) { - var content = token.Content; - var isValidToken = content.StartsWith("<", StringComparison.Ordinal) && !content.StartsWith("</", StringComparison.Ordinal) && !content.StartsWith("<!", StringComparison.Ordinal); - if (isValidToken) + if (IsValidElement(token)) { node.Children.Insert(i + 1, new IntermediateToken() { @@ -55,6 +53,31 @@ private void ProcessElement(HtmlContentIntermediateNode node, string cssScope) } } } + + bool IsValidElement(IntermediateToken token) + { + var content = token.Content; + var isValidToken = content.StartsWith("<", StringComparison.Ordinal) + && !content.StartsWith("</", StringComparison.Ordinal) + && !content.StartsWith("<!", StringComparison.Ordinal); + /// <remarks> + /// We want to avoid adding the CSS scope to elements that do not appear + /// within the body element of the document. When this pass executes over the + /// nodes, we don't have the ability to store whether we are a descandant of a + /// `head` or `body` element so it is not possible to discern whether the tag + /// is valid this way. Instead, we go for a straight-forward check on the tag + /// name that we are currently inspecting. + /// </remarks> + var isInvalidTag = content.IndexOf("head", StringComparison.OrdinalIgnoreCase) >= 0 + || content.IndexOf("meta", StringComparison.OrdinalIgnoreCase) >= 0 + || content.IndexOf("title", StringComparison.OrdinalIgnoreCase) >= 0 + || content.IndexOf("link", StringComparison.OrdinalIgnoreCase) >= 0 + || content.IndexOf("base", StringComparison.OrdinalIgnoreCase) >= 0 + || content.IndexOf("script", StringComparison.OrdinalIgnoreCase) >= 0 + || content.IndexOf("style", StringComparison.OrdinalIgnoreCase) >= 0 + || content.IndexOf("html", StringComparison.OrdinalIgnoreCase) >= 0; + return isValidToken && !isInvalidTag; + } } } }