diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/PathHelpers.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/PathHelpers.cs index d46314c148..f0afedb60e 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Internal/PathHelpers.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Internal/PathHelpers.cs @@ -2,23 +2,24 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.AspNetCore.JsonPatch.Exceptions; +using System; namespace Microsoft.AspNetCore.JsonPatch.Internal { internal static class PathHelpers { - internal static string NormalizePath(string path) + internal static string ValidateAndNormalizePath(string path) { // check for most common path errors on create. This is not // absolutely necessary, but it allows us to already catch mistakes // on creation of the patch document rather than on execute. - if (path.Contains("//") || path.Contains(" ") || path.Contains("\\")) + if (path.Contains("//")) { throw new JsonPatchException(Resources.FormatInvalidValueForPath(path), null); } - if (!(path.StartsWith("/"))) + if (!path.StartsWith("/", StringComparison.Ordinal)) { return "/" + path; } diff --git a/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocument.cs b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocument.cs index 4420e576bf..b6539caae8 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocument.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocument.cs @@ -60,7 +60,7 @@ namespace Microsoft.AspNetCore.JsonPatch throw new ArgumentNullException(nameof(path)); } - Operations.Add(new Operation("add", PathHelpers.NormalizePath(path), null, value)); + Operations.Add(new Operation("add", PathHelpers.ValidateAndNormalizePath(path), null, value)); return this; } @@ -77,7 +77,7 @@ namespace Microsoft.AspNetCore.JsonPatch throw new ArgumentNullException(nameof(path)); } - Operations.Add(new Operation("remove", PathHelpers.NormalizePath(path), null, null)); + Operations.Add(new Operation("remove", PathHelpers.ValidateAndNormalizePath(path), null, null)); return this; } @@ -95,7 +95,7 @@ namespace Microsoft.AspNetCore.JsonPatch throw new ArgumentNullException(nameof(path)); } - Operations.Add(new Operation("replace", PathHelpers.NormalizePath(path), null, value)); + Operations.Add(new Operation("replace", PathHelpers.ValidateAndNormalizePath(path), null, value)); return this; } @@ -113,7 +113,7 @@ namespace Microsoft.AspNetCore.JsonPatch throw new ArgumentNullException(nameof(path)); } - Operations.Add(new Operation("test", PathHelpers.NormalizePath(path), null, value)); + Operations.Add(new Operation("test", PathHelpers.ValidateAndNormalizePath(path), null, value)); return this; } @@ -136,7 +136,7 @@ namespace Microsoft.AspNetCore.JsonPatch throw new ArgumentNullException(nameof(path)); } - Operations.Add(new Operation("move", PathHelpers.NormalizePath(path), PathHelpers.NormalizePath(from))); + Operations.Add(new Operation("move", PathHelpers.ValidateAndNormalizePath(path), PathHelpers.ValidateAndNormalizePath(from))); return this; } @@ -159,7 +159,7 @@ namespace Microsoft.AspNetCore.JsonPatch throw new ArgumentNullException(nameof(path)); } - Operations.Add(new Operation("copy", PathHelpers.NormalizePath(path), PathHelpers.NormalizePath(from))); + Operations.Add(new Operation("copy", PathHelpers.ValidateAndNormalizePath(path), PathHelpers.ValidateAndNormalizePath(from))); return this; } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs index f5d6377989..a9c3d8500b 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs @@ -24,6 +24,23 @@ namespace Microsoft.AspNetCore.JsonPatch Assert.Equal("/AnotherName", pathToCheck); } + [Fact] + public void Add_RespectsJsonPropertyAttribute_WithDotWhitespaceAndBackslashInName() + { + // Arrange + var obj = new JsonPropertyObjectWithStrangeNames(); + var patchDocument = new JsonPatchDocument(); + + // Act + patchDocument.Add("/First Name.", "John"); + patchDocument.Add("Last\\Name", "Doe"); + patchDocument.ApplyTo(obj); + + // Assert + Assert.Equal("John", obj.FirstName); + Assert.Equal("Doe", obj.LastName); + } + [Fact] public void Move_FallsbackToPropertyName_WhenJsonPropertyAttributeName_IsEmpty() { @@ -46,6 +63,15 @@ namespace Microsoft.AspNetCore.JsonPatch public string Name { get; set; } } + private class JsonPropertyObjectWithStrangeNames + { + [JsonProperty("First Name.")] + public string FirstName { get; set; } + + [JsonProperty("Last\\Name")] + public string LastName { get; set; } + } + private class JsonPropertyWithNoPropertyName { [JsonProperty]