From 5ddf2fa15b3faa2fca43f6c05d5d6e2c5e297bcf Mon Sep 17 00:00:00 2001 From: campersau Date: Wed, 9 Jun 2021 18:01:57 +0200 Subject: [PATCH 1/3] Unescape query parameter name --- src/Http/WebUtilities/src/QueryHelpers.cs | 5 ++++- src/Http/WebUtilities/test/QueryHelpersTests.cs | 8 ++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/Http/WebUtilities/src/QueryHelpers.cs b/src/Http/WebUtilities/src/QueryHelpers.cs index 137035b34076..64a2ba2db6ba 100644 --- a/src/Http/WebUtilities/src/QueryHelpers.cs +++ b/src/Http/WebUtilities/src/QueryHelpers.cs @@ -218,7 +218,10 @@ public static Dictionary ParseQuery(string? queryString) { if (delimiterIndex > scanIndex) { - accumulator.Append(queryString.Substring(scanIndex, delimiterIndex - scanIndex), string.Empty); + string name = queryString.Substring(scanIndex, delimiterIndex - scanIndex); + accumulator.Append( + Uri.UnescapeDataString(name.Replace('+', ' ')), + string.Empty); } } scanIndex = delimiterIndex + 1; diff --git a/src/Http/WebUtilities/test/QueryHelpersTests.cs b/src/Http/WebUtilities/test/QueryHelpersTests.cs index 1c9ed8666cba..29115af8915d 100644 --- a/src/Http/WebUtilities/test/QueryHelpersTests.cs +++ b/src/Http/WebUtilities/test/QueryHelpersTests.cs @@ -55,6 +55,14 @@ public void ParseQueryWithEmptyKeyWorks() Assert.Equal(new[] { "value1", "" }, collection[""]); } + [Fact] + public void ParseQueryWithEncodedKeyWorks() + { + var collection = QueryHelpers.ParseQuery("?fields%5BtodoItems%5D"); + Assert.Single(collection); + Assert.Equal("", collection["fields[todoItems]"].FirstOrDefault()); + } + [Theory] [InlineData("?")] [InlineData("")] From 539a1d9f4fc8f4c970060913abd4a61de675bd60 Mon Sep 17 00:00:00 2001 From: campersau Date: Wed, 9 Jun 2021 18:39:16 +0200 Subject: [PATCH 2/3] Add more tests for ParseQuery with encoded key and value --- .../WebUtilities/test/QueryHelpersTests.cs | 36 +++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/src/Http/WebUtilities/test/QueryHelpersTests.cs b/src/Http/WebUtilities/test/QueryHelpersTests.cs index 29115af8915d..9e50589d20b3 100644 --- a/src/Http/WebUtilities/test/QueryHelpersTests.cs +++ b/src/Http/WebUtilities/test/QueryHelpersTests.cs @@ -58,9 +58,41 @@ public void ParseQueryWithEmptyKeyWorks() [Fact] public void ParseQueryWithEncodedKeyWorks() { - var collection = QueryHelpers.ParseQuery("?fields%5BtodoItems%5D"); + var collection = QueryHelpers.ParseQuery("?fields+%5BtodoItems%5D"); Assert.Single(collection); - Assert.Equal("", collection["fields[todoItems]"].FirstOrDefault()); + Assert.Equal("", collection["fields [todoItems]"].FirstOrDefault()); + } + + [Fact] + public void ParseQueryWithEncodedValueWorks() + { + var collection = QueryHelpers.ParseQuery("?=fields+%5BtodoItems%5D"); + Assert.Single(collection); + Assert.Equal("fields [todoItems]", collection[""].FirstOrDefault()); + } + + [Fact] + public void ParseQueryWithEncodedKeyEmptyValueWorks() + { + var collection = QueryHelpers.ParseQuery("?fields+%5BtodoItems%5D="); + Assert.Single(collection); + Assert.Equal("", collection["fields [todoItems]"].FirstOrDefault()); + } + + [Fact] + public void ParseQueryWithEncodedKeyEncodedValueWorks() + { + var collection = QueryHelpers.ParseQuery("?fields+%5BtodoItems%5D=%5B+1+%5D"); + Assert.Single(collection); + Assert.Equal("[ 1 ]", collection["fields [todoItems]"].FirstOrDefault()); + } + + [Fact] + public void ParseQueryWithEncodedKeyEncodedValuesWorks() + { + var collection = QueryHelpers.ParseQuery("?fields+%5BtodoItems%5D=%5B+1+%5D&fields+%5BtodoItems%5D=%5B+2+%5D"); + Assert.Single(collection); + Assert.Equal(new[] { "[ 1 ]", "[ 2 ]" }, collection["fields [todoItems]"]); } [Theory] From b7acb2588c1368ea7309275e8109d83212c7c303 Mon Sep 17 00:00:00 2001 From: campersau Date: Fri, 18 Jun 2021 09:01:11 +0200 Subject: [PATCH 3/3] Unescape query parameter name in ParseNullableQueryInternal --- src/Http/Http/src/Features/QueryFeature.cs | 4 +- .../Http/test/Features/QueryFeatureTests.cs | 70 +++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/src/Http/Http/src/Features/QueryFeature.cs b/src/Http/Http/src/Features/QueryFeature.cs index bc7b1c7d2cf2..dd3a440202e8 100644 --- a/src/Http/Http/src/Features/QueryFeature.cs +++ b/src/Http/Http/src/Features/QueryFeature.cs @@ -143,7 +143,9 @@ public IQueryCollection Query { if (!querySegment.IsEmpty) { - accumulator.Append(querySegment); + var name = SpanHelper.ReplacePlusWithSpace(querySegment); + + accumulator.Append(Uri.UnescapeDataString(name)); } } diff --git a/src/Http/Http/test/Features/QueryFeatureTests.cs b/src/Http/Http/test/Features/QueryFeatureTests.cs index 04a0a7c8c462..321dc8bda3cd 100644 --- a/src/Http/Http/test/Features/QueryFeatureTests.cs +++ b/src/Http/Http/test/Features/QueryFeatureTests.cs @@ -150,5 +150,75 @@ public void ParseEmptyOrNullQueryWorks(string queryString) Assert.Empty(queryCollection); } + + [Fact] + public void ParseQueryWithEncodedKeyWorks() + { + var features = new FeatureCollection(); + features[typeof(IHttpRequestFeature)] = new HttpRequestFeature { QueryString = "?fields+%5BtodoItems%5D" }; + + var provider = new QueryFeature(features); + + var queryCollection = provider.Query; + + Assert.Single(queryCollection); + Assert.Equal("", queryCollection["fields [todoItems]"].FirstOrDefault()); + } + + [Fact] + public void ParseQueryWithEncodedValueWorks() + { + var features = new FeatureCollection(); + features[typeof(IHttpRequestFeature)] = new HttpRequestFeature { QueryString = "?=fields+%5BtodoItems%5D" }; + + var provider = new QueryFeature(features); + + var queryCollection = provider.Query; + + Assert.Single(queryCollection); + Assert.Equal("fields [todoItems]", queryCollection[""].FirstOrDefault()); + } + + [Fact] + public void ParseQueryWithEncodedKeyEmptyValueWorks() + { + var features = new FeatureCollection(); + features[typeof(IHttpRequestFeature)] = new HttpRequestFeature { QueryString = "?fields+%5BtodoItems%5D=" }; + + var provider = new QueryFeature(features); + + var queryCollection = provider.Query; + + Assert.Single(queryCollection); + Assert.Equal("", queryCollection["fields [todoItems]"].FirstOrDefault()); + } + + [Fact] + public void ParseQueryWithEncodedKeyEncodedValueWorks() + { + var features = new FeatureCollection(); + features[typeof(IHttpRequestFeature)] = new HttpRequestFeature { QueryString = "?fields+%5BtodoItems%5D=%5B+1+%5D" }; + + var provider = new QueryFeature(features); + + var queryCollection = provider.Query; + + Assert.Single(queryCollection); + Assert.Equal("[ 1 ]", queryCollection["fields [todoItems]"].FirstOrDefault()); + } + + [Fact] + public void ParseQueryWithEncodedKeyEncodedValuesWorks() + { + var features = new FeatureCollection(); + features[typeof(IHttpRequestFeature)] = new HttpRequestFeature { QueryString = "?fields+%5BtodoItems%5D=%5B+1+%5D&fields+%5BtodoItems%5D=%5B+2+%5D" }; + + var provider = new QueryFeature(features); + + var queryCollection = provider.Query; + + Assert.Single(queryCollection); + Assert.Equal(new[] { "[ 1 ]", "[ 2 ]" }, queryCollection["fields [todoItems]"]); + } } }