From c25aadf599b4de61879ffc7f40cded23a36bc9e7 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Thu, 20 Apr 2017 13:44:14 -0700 Subject: [PATCH] Enable page directive to handle malformed text. - Made a targeted fix to PageDirective that stops it from crashing Visual Studio when its malformed. - Added unit test to validate PageDirective didn't throw when attempting to determine if something was a page. - Added an integration test to validate malformed page tags can make their way through the entire Razor pipeline and don't destroy the rest of the content. #1247 --- .../PageDirective.cs | 11 +++- .../CodeGenerationIntegrationTest.cs | 33 ++++++++++- .../PageDirectiveTest.cs | 19 +++++++ .../MalformedPageDirective.cshtml | 4 ++ ...lformedPageDirective_DesignTime.codegen.cs | 41 ++++++++++++++ .../MalformedPageDirective_DesignTime.ir.txt | 56 +++++++++++++++++++ .../MalformedPageDirective_Runtime.codegen.cs | 35 ++++++++++++ .../MalformedPageDirective_Runtime.ir.txt | 34 +++++++++++ 8 files changed, 229 insertions(+), 4 deletions(-) create mode 100644 test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective.cshtml create mode 100644 test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective_DesignTime.codegen.cs create mode 100644 test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective_DesignTime.ir.txt create mode 100644 test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective_Runtime.codegen.cs create mode 100644 test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective_Runtime.ir.txt diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/PageDirective.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/PageDirective.cs index 48db33bc17..014587d2c1 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/PageDirective.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/PageDirective.cs @@ -67,10 +67,15 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions private static string TrimQuotes(string content) { - Debug.Assert(content.StartsWith("\"", StringComparison.Ordinal)); - Debug.Assert(content.EndsWith("\"", StringComparison.Ordinal)); + if (content.Length >= 2 && + content.StartsWith("\"", StringComparison.Ordinal) && + content.EndsWith("\"", StringComparison.Ordinal)) + { + return content.Substring(1, content.Length - 2); + } - return content.Substring(1, content.Length - 2); + // The extensible directive system handed us invalid content. There's already an error logged. + return null; } private class Visitor : RazorIRNodeWalker diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/IntegrationTests/CodeGenerationIntegrationTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/IntegrationTests/CodeGenerationIntegrationTest.cs index a195666fad..b434d7591f 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/IntegrationTests/CodeGenerationIntegrationTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/IntegrationTests/CodeGenerationIntegrationTest.cs @@ -24,7 +24,22 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.IntegrationTests private static readonly RazorSourceDocument DefaultImports = MvcRazorTemplateEngine.GetDefaultImports(); #region Runtime - + + [Fact] + public void MalformedPageDirective_Runtime() + { + // Arrange + var engine = CreateRuntimeEngine(); + var document = CreateCodeDocument(); + + // Act + engine.Process(document); + + // Assert + AssertIRMatchesBaseline(document.GetIRDocument()); + AssertCSharpDocumentMatchesBaseline(document.GetCSharpDocument()); + } + [Fact] public void Basic_Runtime() { @@ -192,6 +207,22 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.IntegrationTests #endregion #region DesignTime + + [Fact] + public void MalformedPageDirective_DesignTime() + { + // Arrange + var engine = CreateDesignTimeEngine(); + var document = CreateCodeDocument(); + + // Act + engine.Process(document); + + // Assert + AssertIRMatchesBaseline(document.GetIRDocument()); + AssertCSharpDocumentMatchesBaseline(document.GetCSharpDocument()); + } + [Fact] public void Basic_DesignTime() { diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/PageDirectiveTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/PageDirectiveTest.cs index 580651bdc2..f94bbf8559 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/PageDirectiveTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/PageDirectiveTest.cs @@ -9,6 +9,25 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions { public class PageDirectiveTest { + [Fact] + public void TryGetPageDirective_CanHandleMalformedPageDirectives() + { + // Arrange + var content = "@page \""; + var sourceDocument = RazorSourceDocument.Create(content, "file"); + var codeDocument = RazorCodeDocument.Create(sourceDocument); + var engine = CreateEngine(); + var irDocument = CreateIRDocument(engine, codeDocument); + + // Act + var result = PageDirective.TryGetPageDirective(irDocument, out var pageDirective); + + // Assert + Assert.True(result); + Assert.Null(pageDirective.RouteTemplate); + Assert.Null(pageDirective.PageName); + } + [Fact] public void TryGetPageDirective_ReturnsFalse_IfPageDoesNotHaveDirective() { diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective.cshtml b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective.cshtml new file mode 100644 index 0000000000..9b4f9d5559 --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective.cshtml @@ -0,0 +1,4 @@ +@page "foo + +

About Us

+

We are awesome.

\ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective_DesignTime.codegen.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective_DesignTime.codegen.cs new file mode 100644 index 0000000000..26ffa461cd --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective_DesignTime.codegen.cs @@ -0,0 +1,41 @@ +namespace AspNetCore +{ + #line hidden + using TModel = global::System.Object; + using System; + using System.Threading.Tasks; + using System.Linq; + using System.Collections.Generic; + using Microsoft.AspNetCore.Mvc; + using Microsoft.AspNetCore.Mvc.Rendering; + using Microsoft.AspNetCore.Mvc.ViewFeatures; + public class TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml : global::Microsoft.AspNetCore.Mvc.RazorPages.Page + { + #pragma warning disable 219 + private void __RazorDirectiveTokenHelpers__() { + ((System.Action)(() => { +global::System.Object __typeHelper = "foo; + } + ))(); + } + #pragma warning restore 219 + private static System.Object __o = null; + #pragma warning disable 1998 + public async override global::System.Threading.Tasks.Task ExecuteAsync() + { + } + #pragma warning restore 1998 + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper Html { get; private set; } + public global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary ViewData => (global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary)PageContext?.ViewData; + public TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml Model => ViewData.Model; + } +} diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective_DesignTime.ir.txt b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective_DesignTime.ir.txt new file mode 100644 index 0000000000..a8b90ab1ff --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective_DesignTime.ir.txt @@ -0,0 +1,56 @@ +Document - + Checksum - + NamespaceDeclaration - - AspNetCore + UsingStatement - - TModel = global::System.Object + UsingStatement - (1:0,1 [12] ) - System + UsingStatement - - System.Threading.Tasks + UsingStatement - (16:1,1 [17] ) - System.Linq + UsingStatement - (36:2,1 [32] ) - System.Collections.Generic + UsingStatement - (71:3,1 [30] ) - Microsoft.AspNetCore.Mvc + UsingStatement - (104:4,1 [40] ) - Microsoft.AspNetCore.Mvc.Rendering + UsingStatement - (147:5,1 [43] ) - Microsoft.AspNetCore.Mvc.ViewFeatures + ClassDeclaration - - public - TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml - global::Microsoft.AspNetCore.Mvc.RazorPages.Page - + DirectiveTokenHelper - + CSharpStatement - + RazorIRToken - - CSharp - #pragma warning disable 219 + CSharpStatement - + RazorIRToken - - CSharp - private void __RazorDirectiveTokenHelpers__() { + DirectiveToken - (200:6,8 [62] ) - global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper + DirectiveToken - (263:6,71 [4] ) - Html + DirectiveToken - (277:7,8 [54] ) - global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper + DirectiveToken - (332:7,63 [4] ) - Json + DirectiveToken - (346:8,8 [53] ) - global::Microsoft.AspNetCore.Mvc.IViewComponentHelper + DirectiveToken - (400:8,62 [9] ) - Component + DirectiveToken - (419:9,8 [43] ) - global::Microsoft.AspNetCore.Mvc.IUrlHelper + DirectiveToken - (463:9,52 [3] ) - Url + DirectiveToken - (476:10,8 [70] ) - global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider + DirectiveToken - (547:10,79 [23] ) - ModelExpressionProvider + DirectiveToken - (586:11,14 [96] ) - Microsoft.AspNetCore.Mvc.Razor.TagHelpers.UrlResolutionTagHelper, Microsoft.AspNetCore.Mvc.Razor + DirectiveToken - (698:12,14 [87] ) - Microsoft.AspNetCore.Mvc.Razor.TagHelpers.HeadTagHelper, Microsoft.AspNetCore.Mvc.Razor + DirectiveToken - (801:13,14 [87] ) - Microsoft.AspNetCore.Mvc.Razor.TagHelpers.BodyTagHelper, Microsoft.AspNetCore.Mvc.Razor + DirectiveToken - (6:0,6 [4] MalformedPageDirective.cshtml) - "foo + CSharpStatement - + RazorIRToken - - CSharp - } + CSharpStatement - + RazorIRToken - - CSharp - #pragma warning restore 219 + CSharpStatement - + RazorIRToken - - CSharp - private static System.Object __o = null; + RazorMethodDeclaration - - public - async, override - global::System.Threading.Tasks.Task - ExecuteAsync + HtmlContent - (12:1,0 [43] MalformedPageDirective.cshtml) + RazorIRToken - (12:1,0 [2] MalformedPageDirective.cshtml) - Html - \n + RazorIRToken - (14:2,0 [4] MalformedPageDirective.cshtml) - Html -

+ RazorIRToken - (18:2,4 [8] MalformedPageDirective.cshtml) - Html - About Us + RazorIRToken - (26:2,12 [5] MalformedPageDirective.cshtml) - Html -

+ RazorIRToken - (31:2,17 [2] MalformedPageDirective.cshtml) - Html - \n + RazorIRToken - (33:3,0 [3] MalformedPageDirective.cshtml) - Html -

+ RazorIRToken - (36:3,3 [15] MalformedPageDirective.cshtml) - Html - We are awesome. + RazorIRToken - (51:3,18 [4] MalformedPageDirective.cshtml) - Html -

+ InjectDirective - + InjectDirective - + InjectDirective - + InjectDirective - + InjectDirective - + CSharpStatement - + RazorIRToken - - CSharp - public global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary ViewData => (global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary)PageContext?.ViewData; + CSharpStatement - + RazorIRToken - - CSharp - public TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml Model => ViewData.Model; diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective_Runtime.codegen.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective_Runtime.codegen.cs new file mode 100644 index 0000000000..77f9668a85 --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective_Runtime.codegen.cs @@ -0,0 +1,35 @@ +#pragma checksum "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "5a9ff8440150c6746e4a8ba63bc633ea84930405" +namespace AspNetCore +{ + #line hidden + using System; + using System.Threading.Tasks; + using System.Linq; + using System.Collections.Generic; + using Microsoft.AspNetCore.Mvc; + using Microsoft.AspNetCore.Mvc.Rendering; + using Microsoft.AspNetCore.Mvc.ViewFeatures; + public class TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml : global::Microsoft.AspNetCore.Mvc.RazorPages.Page + { + #pragma warning disable 1998 + public async override global::System.Threading.Tasks.Task ExecuteAsync() + { + BeginContext(12, 43, true); + WriteLiteral("\r\n

About Us

\r\n

We are awesome.

"); + EndContext(); + } + #pragma warning restore 1998 + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper Html { get; private set; } + public global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary ViewData => (global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary)PageContext?.ViewData; + public TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml Model => ViewData.Model; + } +} diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective_Runtime.ir.txt b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective_Runtime.ir.txt new file mode 100644 index 0000000000..4553832fcd --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective_Runtime.ir.txt @@ -0,0 +1,34 @@ +Document - + Checksum - + NamespaceDeclaration - - AspNetCore + UsingStatement - (1:0,1 [14] ) - System + UsingStatement - - System.Threading.Tasks + UsingStatement - (16:1,1 [19] ) - System.Linq + UsingStatement - (36:2,1 [34] ) - System.Collections.Generic + UsingStatement - (71:3,1 [32] ) - Microsoft.AspNetCore.Mvc + UsingStatement - (104:4,1 [42] ) - Microsoft.AspNetCore.Mvc.Rendering + UsingStatement - (147:5,1 [45] ) - Microsoft.AspNetCore.Mvc.ViewFeatures + ClassDeclaration - - public - TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml - global::Microsoft.AspNetCore.Mvc.RazorPages.Page - + RazorMethodDeclaration - - public - async, override - global::System.Threading.Tasks.Task - ExecuteAsync + CSharpStatement - + RazorIRToken - - CSharp - BeginContext(12, 43, true); + HtmlContent - (12:1,0 [43] MalformedPageDirective.cshtml) + RazorIRToken - (12:1,0 [2] MalformedPageDirective.cshtml) - Html - \n + RazorIRToken - (14:2,0 [4] MalformedPageDirective.cshtml) - Html -

+ RazorIRToken - (18:2,4 [8] MalformedPageDirective.cshtml) - Html - About Us + RazorIRToken - (26:2,12 [5] MalformedPageDirective.cshtml) - Html -

+ RazorIRToken - (31:2,17 [2] MalformedPageDirective.cshtml) - Html - \n + RazorIRToken - (33:3,0 [3] MalformedPageDirective.cshtml) - Html -

+ RazorIRToken - (36:3,3 [15] MalformedPageDirective.cshtml) - Html - We are awesome. + RazorIRToken - (51:3,18 [4] MalformedPageDirective.cshtml) - Html -

+ CSharpStatement - + RazorIRToken - - CSharp - EndContext(); + InjectDirective - + InjectDirective - + InjectDirective - + InjectDirective - + InjectDirective - + CSharpStatement - + RazorIRToken - - CSharp - public global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary ViewData => (global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary)PageContext?.ViewData; + CSharpStatement - + RazorIRToken - - CSharp - public TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml Model => ViewData.Model;