diff --git a/Fluid.Tests/MiscFiltersTests.cs b/Fluid.Tests/MiscFiltersTests.cs index 616ef56a..97d3aaed 100644 --- a/Fluid.Tests/MiscFiltersTests.cs +++ b/Fluid.Tests/MiscFiltersTests.cs @@ -1,10 +1,11 @@ -using System; -using System.Globalization; -using System.Linq; -using System.Threading.Tasks; using Fluid.Filters; using Fluid.Values; using Newtonsoft.Json.Linq; +using System; +using System.Globalization; +using System.Linq; +using System.Text.Encodings.Web; +using System.Threading.Tasks; using TimeZoneConverter; using Xunit; @@ -779,6 +780,29 @@ public async Task JsonShouldWriteValuesWithCorrectDataTypeForJObjectInput() Assert.Equal(expected, result.ToStringValue()); } + [Fact] + public async Task JsonShouldEncodeUnicodeChars() + { + var input = FluidValue.Create("你好,这是一条短信", TemplateOptions.Default); + var result = await MiscFilters.Json(input, new FilterArguments(), new TemplateContext(TemplateOptions.Default)); + var expected = @"""\u4F60\u597D\uFF0C\u8FD9\u662F\u4E00\u6761\u77ED\u4FE1"""; + Assert.Equal(expected, result.ToStringValue()); + } + + [Fact] + public async Task JsonShouldUseJsonSerializerOption() + { + var options = new TemplateOptions + { + JavaScriptEncoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + }; + + var input = FluidValue.Create("你好,这是一条短信", options); + var result = await MiscFilters.Json(input, new FilterArguments(), new TemplateContext(options)); + var expected = @"""你好,这是一条短信"""; + Assert.Equal(expected, result.ToStringValue()); + } + [Theory] [InlineData("", "", "", "0")] [InlineData(123456, "", "", "123456")] diff --git a/Fluid/Filters/MiscFilters.cs b/Fluid/Filters/MiscFilters.cs index b2bfd79b..4c248feb 100644 --- a/Fluid/Filters/MiscFilters.cs +++ b/Fluid/Filters/MiscFilters.cs @@ -774,7 +774,7 @@ private static async ValueTask WriteJson(Utf8JsonWriter writer, FluidValue input } break; case FluidValues.String: - writer.WriteStringValue(input.ToStringValue()); + writer.WriteStringValue(JsonEncodedText.Encode(input.ToStringValue(), ctx.Options.JavaScriptEncoder)); break; case FluidValues.Blank: writer.WriteStringValue(string.Empty); diff --git a/Fluid/TemplateOptions.cs b/Fluid/TemplateOptions.cs index cda8a0a5..92484740 100644 --- a/Fluid/TemplateOptions.cs +++ b/Fluid/TemplateOptions.cs @@ -2,6 +2,8 @@ using Fluid.Values; using Microsoft.Extensions.FileProviders; using System.Globalization; +using System.Text.Encodings.Web; +using System.Text.Json; namespace Fluid { @@ -21,6 +23,8 @@ public class TemplateOptions public static readonly TemplateOptions Default = new(); + private static readonly JavaScriptEncoder DefaultJavaScriptEncoder = JavaScriptEncoder.Default; + /// /// Gets ot sets the members than can be accessed in a template. /// @@ -89,6 +93,11 @@ public class TemplateOptions /// public AssignedDelegate Assigned { get; set; } + /// + /// Gets or sets the instance used by the json filter. + /// + public JavaScriptEncoder JavaScriptEncoder { get; set; } = DefaultJavaScriptEncoder; + /// /// Gets or sets the default trimming rules. /// @@ -99,7 +108,6 @@ public class TemplateOptions /// public bool Greedy { get; set; } = true; - public TemplateOptions() { Filters.WithArrayFilters() diff --git a/README.md b/README.md index dd7b38e5..4a2a89b1 100644 --- a/README.md +++ b/README.md @@ -335,16 +335,35 @@ Not encoded: {{ html | raw } When using `capture` blocks, the inner content is flagged as pre-encoded and won't be double-encoded if used in a `{{ }}` tag. -#### Source +### JSON encoding + +By default all JSON strings are encoded using the default `JavaScriptEncoder` instance. This can be changed by setting the `TemplateOptions.JavaScriptEncoder` property. + ```Liquid -{% capture breaktag %}
{% endcapture %} +{{ "你好,这是一条短信" | json" }} +``` + +#### Result + +```html +"\u4F60\u597D\uFF0C\u8FD9\u662F\u4E00\u6761\u77ED\u4FE1" +``` -{{ breaktag }} +Using the `JavaScriptEncoder.UnsafeRelaxedJsonEscaping` can be done this way: + +```csharp +// This variable should be static and reused for all templates +var options = new TemplateOptions +{ + JavaScriptEncoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping +}; + +var context = new TemplateContext(options); ``` #### Result ```html -
+"你好,这是一条短信" ```