From d49d7d7e0a26340fb3f6ff099c974df349bce325 Mon Sep 17 00:00:00 2001 From: Steve Sanderson Date: Thu, 8 Aug 2019 22:24:48 +0000 Subject: [PATCH] Merged PR 2262: Fix encoding used in JS generated by prerenderer Fix encoding used in JS generated by prerenderer --- .../src/Prerendering/RenderToStringResult.cs | 13 ++-- ...rosoft.AspNetCore.SpaServices.Tests.csproj | 11 +++ .../RenderToStringResultTest.cs | 71 +++++++++++++++++++ 3 files changed, 91 insertions(+), 4 deletions(-) create mode 100644 src/Middleware/SpaServices/test/Microsoft.AspNetCore.SpaServices.Tests/Microsoft.AspNetCore.SpaServices.Tests.csproj create mode 100644 src/Middleware/SpaServices/test/Microsoft.AspNetCore.SpaServices.Tests/RenderToStringResultTest.cs diff --git a/src/Middleware/SpaServices/src/Prerendering/RenderToStringResult.cs b/src/Middleware/SpaServices/src/Prerendering/RenderToStringResult.cs index 1a2e15635451..0cf02247a102 100644 --- a/src/Middleware/SpaServices/src/Prerendering/RenderToStringResult.cs +++ b/src/Middleware/SpaServices/src/Prerendering/RenderToStringResult.cs @@ -1,6 +1,7 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System.Text; +using System.Text.Encodings.Web; namespace Microsoft.AspNetCore.SpaServices.Prerendering { @@ -49,12 +50,16 @@ public string CreateGlobalsAssignmentScript() foreach (var property in Globals.Properties()) { - stringBuilder.AppendFormat("window.{0} = {1};", - property.Name, - property.Value.ToString(Formatting.None)); + var propertyNameJavaScriptString = JavaScriptEncoder.Default.Encode(property.Name); + var valueJson = property.Value.ToString(Formatting.None); + var valueJsonJavaScriptString = JavaScriptEncoder.Default.Encode(valueJson); + + stringBuilder.AppendFormat("window[\"{0}\"] = JSON.parse(\"{1}\");", + propertyNameJavaScriptString, + valueJsonJavaScriptString); } return stringBuilder.ToString(); } } -} \ No newline at end of file +} diff --git a/src/Middleware/SpaServices/test/Microsoft.AspNetCore.SpaServices.Tests/Microsoft.AspNetCore.SpaServices.Tests.csproj b/src/Middleware/SpaServices/test/Microsoft.AspNetCore.SpaServices.Tests/Microsoft.AspNetCore.SpaServices.Tests.csproj new file mode 100644 index 000000000000..db1160878bb0 --- /dev/null +++ b/src/Middleware/SpaServices/test/Microsoft.AspNetCore.SpaServices.Tests/Microsoft.AspNetCore.SpaServices.Tests.csproj @@ -0,0 +1,11 @@ + + + + netcoreapp2.0 + + + + + + + diff --git a/src/Middleware/SpaServices/test/Microsoft.AspNetCore.SpaServices.Tests/RenderToStringResultTest.cs b/src/Middleware/SpaServices/test/Microsoft.AspNetCore.SpaServices.Tests/RenderToStringResultTest.cs new file mode 100644 index 000000000000..77ce7a213c0e --- /dev/null +++ b/src/Middleware/SpaServices/test/Microsoft.AspNetCore.SpaServices.Tests/RenderToStringResultTest.cs @@ -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.Collections.Generic; +using Microsoft.AspNetCore.SpaServices.Prerendering; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Xunit; + +namespace Microsoft.AspNetCore.SpaServices.Tests +{ + public class RenderToStringResultTest + { + [Fact] + public void HandlesNullGlobals() + { + // Arrange + var renderToStringResult = new RenderToStringResult(); + renderToStringResult.Globals = null; + + // Act + var actualScript = renderToStringResult.CreateGlobalsAssignmentScript(); + + // Assert + Assert.Equal(string.Empty, actualScript); + } + + [Fact] + public void HandlesGlobalsWithMultipleProperties() + { + // Arrange + var renderToStringResult = new RenderToStringResult(); + renderToStringResult.Globals = ToJObject(new + { + FirstProperty = "first value", + SecondProperty = new[] { "Array entry 0", "Array entry 1" } + }); + + // Act + var actualScript = renderToStringResult.CreateGlobalsAssignmentScript(); + + // Assert + var expectedScript = @"window[""FirstProperty""] = JSON.parse(""\u0022first value\u0022"");" + + @"window[""SecondProperty""] = JSON.parse(""[\u0022Array entry 0\u0022,\u0022Array entry 1\u0022]"");"; + Assert.Equal(expectedScript, actualScript); + } + + [Fact] + public void HandlesGlobalsWithCorrectStringEncoding() + { + // Arrange + var renderToStringResult = new RenderToStringResult(); + renderToStringResult.Globals = ToJObject(new Dictionary + { + { "Va\"'}\u260E" } + }); + + // Act + var actualScript = renderToStringResult.CreateGlobalsAssignmentScript(); + + // Assert + var expectedScript = @"window[""Va\u003Cl\u0027u\u0022e""] = JSON.parse(""\u0022\u003C\/tag\u003E\\\u0022\u0027}\u260E\u0022"");"; + Assert.Equal(expectedScript, actualScript); + } + + private static JObject ToJObject(object value) + { + return JsonConvert.DeserializeObject(JsonConvert.SerializeObject(value)); + } + } +}