Skip to content

Commit a37d632

Browse files
committed
Remove cookie name decoding
1 parent cb4e0ce commit a37d632

File tree

4 files changed

+77
-27
lines changed

4 files changed

+77
-27
lines changed

src/Http/Http/src/Internal/RequestCookieCollection.cs

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ namespace Microsoft.AspNetCore.Http.Internal
1010
{
1111
public class RequestCookieCollection : IRequestCookieCollection
1212
{
13+
private const string EnableCookieNameDecoding = "Microsoft.AspNetCore.Http.EnableCookieNameDecoding";
14+
private bool _enableCookieNameDecoding;
15+
1316
public static readonly RequestCookieCollection Empty = new RequestCookieCollection();
1417
private static readonly string[] EmptyKeys = Array.Empty<string>();
1518
private static readonly Enumerator EmptyEnumerator = new Enumerator();
@@ -21,14 +24,15 @@ public class RequestCookieCollection : IRequestCookieCollection
2124

2225
public RequestCookieCollection()
2326
{
27+
_enableCookieNameDecoding = AppContext.TryGetSwitch(EnableCookieNameDecoding, out var enabled) && enabled;
2428
}
2529

26-
public RequestCookieCollection(Dictionary<string, string> store)
30+
public RequestCookieCollection(Dictionary<string, string> store) : this()
2731
{
2832
Store = store;
2933
}
3034

31-
public RequestCookieCollection(int capacity)
35+
public RequestCookieCollection(int capacity) : this()
3236
{
3337
Store = new Dictionary<string, string>(capacity, StringComparer.OrdinalIgnoreCase);
3438
}
@@ -57,6 +61,9 @@ public string this[string key]
5761
}
5862

5963
public static RequestCookieCollection Parse(IList<string> values)
64+
=> ParseInternal(values, AppContext.TryGetSwitch(EnableCookieNameDecoding, out var enabled) && enabled);
65+
66+
internal static RequestCookieCollection ParseInternal(IList<string> values, bool enableCookieNameDecoding)
6067
{
6168
if (values.Count == 0)
6269
{
@@ -76,7 +83,11 @@ public static RequestCookieCollection Parse(IList<string> values)
7683
for (var i = 0; i < cookies.Count; i++)
7784
{
7885
var cookie = cookies[i];
79-
var name = Uri.UnescapeDataString(cookie.Name.Value);
86+
var name = cookie.Name.Value;
87+
if (enableCookieNameDecoding)
88+
{
89+
name = Uri.UnescapeDataString(name);
90+
}
8091
var value = Uri.UnescapeDataString(cookie.Value.Value);
8192
store[name] = value;
8293
}
@@ -116,17 +127,20 @@ public bool ContainsKey(string key)
116127
{
117128
return false;
118129
}
119-
return Store.ContainsKey(key);
130+
return Store.ContainsKey(key)
131+
|| !_enableCookieNameDecoding && Store.ContainsKey(Uri.EscapeDataString(key));
120132
}
121133

122134
public bool TryGetValue(string key, out string value)
123135
{
124-
if (Store == null)
136+
if (Store == null || key == null)
125137
{
126138
value = null;
127139
return false;
128140
}
129-
return Store.TryGetValue(key, out value);
141+
142+
return Store.TryGetValue(key, out value)
143+
|| !_enableCookieNameDecoding && Store.TryGetValue(Uri.EscapeDataString(key), out value);
130144
}
131145

132146
/// <summary>
@@ -229,4 +243,4 @@ public void Reset()
229243
}
230244
}
231245
}
232-
}
246+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
using System.Runtime.CompilerServices;
2+
3+
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Http.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]

src/Http/Http/test/RequestCookiesCollectionTests.cs

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
// Copyright (c) .NET Foundation. All rights reserved.
1+
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4+
using System;
45
using System.Linq;
56
using Microsoft.AspNetCore.Http.Internal;
67
using Microsoft.Extensions.Primitives;
@@ -10,30 +11,32 @@ namespace Microsoft.AspNetCore.Http.Tests
1011
{
1112
public class RequestCookiesCollectionTests
1213
{
13-
public static TheoryData UnEscapesKeyValues_Data
14+
[Theory]
15+
[InlineData("key=value", "key", "value")]
16+
[InlineData("__secure-key=value", "__secure-key", "value")]
17+
[InlineData("key%2C=%21value", "key,", "!value")]
18+
[InlineData("ke%23y%2C=val%5Eue", "ke#y,", "val^ue")]
19+
[InlineData("base64=QUI%2BREU%2FRw%3D%3D", "base64", "QUI+REU/Rw==")]
20+
[InlineData("base64=QUI+REU/Rw==", "base64", "QUI+REU/Rw==")]
21+
public void UnEscapesValues(string input, string expectedKey, string expectedValue)
1422
{
15-
get
16-
{
17-
// key, value, expected
18-
return new TheoryData<string, string, string>
19-
{
20-
{ "key=value", "key", "value" },
21-
{ "key%2C=%21value", "key,", "!value" },
22-
{ "ke%23y%2C=val%5Eue", "ke#y,", "val^ue" },
23-
{ "base64=QUI%2BREU%2FRw%3D%3D", "base64", "QUI+REU/Rw==" },
24-
{ "base64=QUI+REU/Rw==", "base64", "QUI+REU/Rw==" },
25-
};
26-
}
23+
var cookies = RequestCookieCollection.Parse(new StringValues(input));
24+
25+
Assert.Equal(1, cookies.Count);
26+
Assert.Equal(Uri.EscapeDataString(expectedKey), cookies.Keys.Single());
27+
Assert.Equal(expectedValue, cookies[expectedKey]);
2728
}
2829

2930
[Theory]
30-
[MemberData(nameof(UnEscapesKeyValues_Data))]
31-
public void UnEscapesKeyValues(
32-
string input,
33-
string expectedKey,
34-
string expectedValue)
31+
[InlineData("key=value", "key", "value")]
32+
[InlineData("__secure-key=value", "__secure-key", "value")]
33+
[InlineData("key%2C=%21value", "key,", "!value")]
34+
[InlineData("ke%23y%2C=val%5Eue", "ke#y,", "val^ue")]
35+
[InlineData("base64=QUI%2BREU%2FRw%3D%3D", "base64", "QUI+REU/Rw==")]
36+
[InlineData("base64=QUI+REU/Rw==", "base64", "QUI+REU/Rw==")]
37+
public void AppContextSwitchUnEscapesKeyValues(string input, string expectedKey, string expectedValue)
3538
{
36-
var cookies = RequestCookieCollection.Parse(new StringValues(input));
39+
var cookies = RequestCookieCollection.ParseInternal(new StringValues(input), enableCookieNameDecoding: true);
3740

3841
Assert.Equal(1, cookies.Count);
3942
Assert.Equal(expectedKey, cookies.Keys.Single());

src/Http/HttpAbstractions.sln

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RoutingSample.Web", "Routin
8181
EndProject
8282
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dependencies", "dependencies", "{793FFE24-138A-4C3D-81AB-18D625E36230}"
8383
EndProject
84+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.IISIntegration", "..\Servers\IIS\IISIntegration\src\Microsoft.AspNetCore.Server.IISIntegration.csproj", "{58817E6B-145C-47B7-AC13-513127074AC7}"
85+
EndProject
86+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.Kestrel", "..\Servers\Kestrel\Kestrel\src\Microsoft.AspNetCore.Server.Kestrel.csproj", "{0BDB21AA-5F81-4F91-86E0-8435110A3017}"
87+
EndProject
8488
Global
8589
GlobalSection(SolutionConfigurationPlatforms) = preSolution
8690
Debug|Any CPU = Debug|Any CPU
@@ -403,6 +407,30 @@ Global
403407
{F4F5D8AF-FBD1-463F-9473-B63AA820A6C4}.Release|x64.Build.0 = Release|Any CPU
404408
{F4F5D8AF-FBD1-463F-9473-B63AA820A6C4}.Release|x86.ActiveCfg = Release|Any CPU
405409
{F4F5D8AF-FBD1-463F-9473-B63AA820A6C4}.Release|x86.Build.0 = Release|Any CPU
410+
{58817E6B-145C-47B7-AC13-513127074AC7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
411+
{58817E6B-145C-47B7-AC13-513127074AC7}.Debug|Any CPU.Build.0 = Debug|Any CPU
412+
{58817E6B-145C-47B7-AC13-513127074AC7}.Debug|x64.ActiveCfg = Debug|Any CPU
413+
{58817E6B-145C-47B7-AC13-513127074AC7}.Debug|x64.Build.0 = Debug|Any CPU
414+
{58817E6B-145C-47B7-AC13-513127074AC7}.Debug|x86.ActiveCfg = Debug|Any CPU
415+
{58817E6B-145C-47B7-AC13-513127074AC7}.Debug|x86.Build.0 = Debug|Any CPU
416+
{58817E6B-145C-47B7-AC13-513127074AC7}.Release|Any CPU.ActiveCfg = Release|Any CPU
417+
{58817E6B-145C-47B7-AC13-513127074AC7}.Release|Any CPU.Build.0 = Release|Any CPU
418+
{58817E6B-145C-47B7-AC13-513127074AC7}.Release|x64.ActiveCfg = Release|Any CPU
419+
{58817E6B-145C-47B7-AC13-513127074AC7}.Release|x64.Build.0 = Release|Any CPU
420+
{58817E6B-145C-47B7-AC13-513127074AC7}.Release|x86.ActiveCfg = Release|Any CPU
421+
{58817E6B-145C-47B7-AC13-513127074AC7}.Release|x86.Build.0 = Release|Any CPU
422+
{0BDB21AA-5F81-4F91-86E0-8435110A3017}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
423+
{0BDB21AA-5F81-4F91-86E0-8435110A3017}.Debug|Any CPU.Build.0 = Debug|Any CPU
424+
{0BDB21AA-5F81-4F91-86E0-8435110A3017}.Debug|x64.ActiveCfg = Debug|Any CPU
425+
{0BDB21AA-5F81-4F91-86E0-8435110A3017}.Debug|x64.Build.0 = Debug|Any CPU
426+
{0BDB21AA-5F81-4F91-86E0-8435110A3017}.Debug|x86.ActiveCfg = Debug|Any CPU
427+
{0BDB21AA-5F81-4F91-86E0-8435110A3017}.Debug|x86.Build.0 = Debug|Any CPU
428+
{0BDB21AA-5F81-4F91-86E0-8435110A3017}.Release|Any CPU.ActiveCfg = Release|Any CPU
429+
{0BDB21AA-5F81-4F91-86E0-8435110A3017}.Release|Any CPU.Build.0 = Release|Any CPU
430+
{0BDB21AA-5F81-4F91-86E0-8435110A3017}.Release|x64.ActiveCfg = Release|Any CPU
431+
{0BDB21AA-5F81-4F91-86E0-8435110A3017}.Release|x64.Build.0 = Release|Any CPU
432+
{0BDB21AA-5F81-4F91-86E0-8435110A3017}.Release|x86.ActiveCfg = Release|Any CPU
433+
{0BDB21AA-5F81-4F91-86E0-8435110A3017}.Release|x86.Build.0 = Release|Any CPU
406434
EndGlobalSection
407435
GlobalSection(SolutionProperties) = preSolution
408436
HideSolutionNode = FALSE
@@ -435,6 +463,8 @@ Global
435463
{E4AC79A3-625B-421B-9F91-EFCBD9BEB37F} = {24D19E8E-25FD-4C0B-8865-697878B67BE0}
436464
{BF8DC0FF-96F9-4705-8CFA-F42BE989AB6A} = {793FFE24-138A-4C3D-81AB-18D625E36230}
437465
{F4F5D8AF-FBD1-463F-9473-B63AA820A6C4} = {14A7B3DE-46C8-4245-B0BD-9AFF3795C163}
466+
{58817E6B-145C-47B7-AC13-513127074AC7} = {793FFE24-138A-4C3D-81AB-18D625E36230}
467+
{0BDB21AA-5F81-4F91-86E0-8435110A3017} = {793FFE24-138A-4C3D-81AB-18D625E36230}
438468
EndGlobalSection
439469
GlobalSection(ExtensibilityGlobals) = postSolution
440470
SolutionGuid = {85B5E151-2E9D-419C-83DD-0DDCF446C83A}

0 commit comments

Comments
 (0)