Skip to content

Commit 43a46af

Browse files
authored
Unescape query parameter name (#33401)
1 parent 54449b3 commit 43a46af

File tree

4 files changed

+117
-2
lines changed

4 files changed

+117
-2
lines changed

src/Http/Http/src/Features/QueryFeature.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,9 @@ public IQueryCollection Query
143143
{
144144
if (!querySegment.IsEmpty)
145145
{
146-
accumulator.Append(querySegment);
146+
var name = SpanHelper.ReplacePlusWithSpace(querySegment);
147+
148+
accumulator.Append(Uri.UnescapeDataString(name));
147149
}
148150
}
149151

src/Http/Http/test/Features/QueryFeatureTests.cs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,5 +150,75 @@ public void ParseEmptyOrNullQueryWorks(string queryString)
150150

151151
Assert.Empty(queryCollection);
152152
}
153+
154+
[Fact]
155+
public void ParseQueryWithEncodedKeyWorks()
156+
{
157+
var features = new FeatureCollection();
158+
features[typeof(IHttpRequestFeature)] = new HttpRequestFeature { QueryString = "?fields+%5BtodoItems%5D" };
159+
160+
var provider = new QueryFeature(features);
161+
162+
var queryCollection = provider.Query;
163+
164+
Assert.Single(queryCollection);
165+
Assert.Equal("", queryCollection["fields [todoItems]"].FirstOrDefault());
166+
}
167+
168+
[Fact]
169+
public void ParseQueryWithEncodedValueWorks()
170+
{
171+
var features = new FeatureCollection();
172+
features[typeof(IHttpRequestFeature)] = new HttpRequestFeature { QueryString = "?=fields+%5BtodoItems%5D" };
173+
174+
var provider = new QueryFeature(features);
175+
176+
var queryCollection = provider.Query;
177+
178+
Assert.Single(queryCollection);
179+
Assert.Equal("fields [todoItems]", queryCollection[""].FirstOrDefault());
180+
}
181+
182+
[Fact]
183+
public void ParseQueryWithEncodedKeyEmptyValueWorks()
184+
{
185+
var features = new FeatureCollection();
186+
features[typeof(IHttpRequestFeature)] = new HttpRequestFeature { QueryString = "?fields+%5BtodoItems%5D=" };
187+
188+
var provider = new QueryFeature(features);
189+
190+
var queryCollection = provider.Query;
191+
192+
Assert.Single(queryCollection);
193+
Assert.Equal("", queryCollection["fields [todoItems]"].FirstOrDefault());
194+
}
195+
196+
[Fact]
197+
public void ParseQueryWithEncodedKeyEncodedValueWorks()
198+
{
199+
var features = new FeatureCollection();
200+
features[typeof(IHttpRequestFeature)] = new HttpRequestFeature { QueryString = "?fields+%5BtodoItems%5D=%5B+1+%5D" };
201+
202+
var provider = new QueryFeature(features);
203+
204+
var queryCollection = provider.Query;
205+
206+
Assert.Single(queryCollection);
207+
Assert.Equal("[ 1 ]", queryCollection["fields [todoItems]"].FirstOrDefault());
208+
}
209+
210+
[Fact]
211+
public void ParseQueryWithEncodedKeyEncodedValuesWorks()
212+
{
213+
var features = new FeatureCollection();
214+
features[typeof(IHttpRequestFeature)] = new HttpRequestFeature { QueryString = "?fields+%5BtodoItems%5D=%5B+1+%5D&fields+%5BtodoItems%5D=%5B+2+%5D" };
215+
216+
var provider = new QueryFeature(features);
217+
218+
var queryCollection = provider.Query;
219+
220+
Assert.Single(queryCollection);
221+
Assert.Equal(new[] { "[ 1 ]", "[ 2 ]" }, queryCollection["fields [todoItems]"]);
222+
}
153223
}
154224
}

src/Http/WebUtilities/src/QueryHelpers.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,10 @@ public static Dictionary<string, StringValues> ParseQuery(string? queryString)
218218
{
219219
if (delimiterIndex > scanIndex)
220220
{
221-
accumulator.Append(queryString.Substring(scanIndex, delimiterIndex - scanIndex), string.Empty);
221+
string name = queryString.Substring(scanIndex, delimiterIndex - scanIndex);
222+
accumulator.Append(
223+
Uri.UnescapeDataString(name.Replace('+', ' ')),
224+
string.Empty);
222225
}
223226
}
224227
scanIndex = delimiterIndex + 1;

src/Http/WebUtilities/test/QueryHelpersTests.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,46 @@ public void ParseQueryWithEmptyKeyWorks()
5555
Assert.Equal(new[] { "value1", "" }, collection[""]);
5656
}
5757

58+
[Fact]
59+
public void ParseQueryWithEncodedKeyWorks()
60+
{
61+
var collection = QueryHelpers.ParseQuery("?fields+%5BtodoItems%5D");
62+
Assert.Single(collection);
63+
Assert.Equal("", collection["fields [todoItems]"].FirstOrDefault());
64+
}
65+
66+
[Fact]
67+
public void ParseQueryWithEncodedValueWorks()
68+
{
69+
var collection = QueryHelpers.ParseQuery("?=fields+%5BtodoItems%5D");
70+
Assert.Single(collection);
71+
Assert.Equal("fields [todoItems]", collection[""].FirstOrDefault());
72+
}
73+
74+
[Fact]
75+
public void ParseQueryWithEncodedKeyEmptyValueWorks()
76+
{
77+
var collection = QueryHelpers.ParseQuery("?fields+%5BtodoItems%5D=");
78+
Assert.Single(collection);
79+
Assert.Equal("", collection["fields [todoItems]"].FirstOrDefault());
80+
}
81+
82+
[Fact]
83+
public void ParseQueryWithEncodedKeyEncodedValueWorks()
84+
{
85+
var collection = QueryHelpers.ParseQuery("?fields+%5BtodoItems%5D=%5B+1+%5D");
86+
Assert.Single(collection);
87+
Assert.Equal("[ 1 ]", collection["fields [todoItems]"].FirstOrDefault());
88+
}
89+
90+
[Fact]
91+
public void ParseQueryWithEncodedKeyEncodedValuesWorks()
92+
{
93+
var collection = QueryHelpers.ParseQuery("?fields+%5BtodoItems%5D=%5B+1+%5D&fields+%5BtodoItems%5D=%5B+2+%5D");
94+
Assert.Single(collection);
95+
Assert.Equal(new[] { "[ 1 ]", "[ 2 ]" }, collection["fields [todoItems]"]);
96+
}
97+
5898
[Theory]
5999
[InlineData("?")]
60100
[InlineData("")]

0 commit comments

Comments
 (0)