Remove cookie name decoding (#24389)
This commit is contained in:
parent
a8e8fe2ab3
commit
ad4f0a0cb6
|
|
@ -37,6 +37,7 @@ namespace Microsoft.AspNetCore.Http
|
||||||
public bool ContainsKey(string key) { throw null; }
|
public bool ContainsKey(string key) { throw null; }
|
||||||
public Microsoft.AspNetCore.Http.RequestCookieCollection.Enumerator GetEnumerator() { throw null; }
|
public Microsoft.AspNetCore.Http.RequestCookieCollection.Enumerator GetEnumerator() { throw null; }
|
||||||
public static Microsoft.AspNetCore.Http.RequestCookieCollection Parse(System.Collections.Generic.IList<string> values) { throw null; }
|
public static Microsoft.AspNetCore.Http.RequestCookieCollection Parse(System.Collections.Generic.IList<string> values) { throw null; }
|
||||||
|
internal static RequestCookieCollection ParseInternal(System.Collections.Generic.IList<string> values, bool enableCookieNameDecoding) { throw null; }
|
||||||
System.Collections.Generic.IEnumerator<System.Collections.Generic.KeyValuePair<string, string>> System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<System.String,System.String>>.GetEnumerator() { throw null; }
|
System.Collections.Generic.IEnumerator<System.Collections.Generic.KeyValuePair<string, string>> System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<System.String,System.String>>.GetEnumerator() { throw null; }
|
||||||
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; }
|
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; }
|
||||||
public bool TryGetValue(string key, out string value) { throw null; }
|
public bool TryGetValue(string key, out string value) { throw null; }
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,9 @@ namespace Microsoft.AspNetCore.Http
|
||||||
{
|
{
|
||||||
internal class RequestCookieCollection : IRequestCookieCollection
|
internal class RequestCookieCollection : IRequestCookieCollection
|
||||||
{
|
{
|
||||||
|
private const string EnableCookieNameDecoding = "Microsoft.AspNetCore.Http.EnableCookieNameDecoding";
|
||||||
|
private bool _enableCookieNameDecoding;
|
||||||
|
|
||||||
public static readonly RequestCookieCollection Empty = new RequestCookieCollection();
|
public static readonly RequestCookieCollection Empty = new RequestCookieCollection();
|
||||||
private static readonly string[] EmptyKeys = Array.Empty<string>();
|
private static readonly string[] EmptyKeys = Array.Empty<string>();
|
||||||
private static readonly Enumerator EmptyEnumerator = new Enumerator();
|
private static readonly Enumerator EmptyEnumerator = new Enumerator();
|
||||||
|
|
@ -21,14 +24,15 @@ namespace Microsoft.AspNetCore.Http
|
||||||
|
|
||||||
public RequestCookieCollection()
|
public RequestCookieCollection()
|
||||||
{
|
{
|
||||||
|
_enableCookieNameDecoding = AppContext.TryGetSwitch(EnableCookieNameDecoding, out var enabled) && enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RequestCookieCollection(Dictionary<string, string> store)
|
public RequestCookieCollection(Dictionary<string, string> store) : this()
|
||||||
{
|
{
|
||||||
Store = store;
|
Store = store;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RequestCookieCollection(int capacity)
|
public RequestCookieCollection(int capacity) : this()
|
||||||
{
|
{
|
||||||
Store = new Dictionary<string, string>(capacity, StringComparer.OrdinalIgnoreCase);
|
Store = new Dictionary<string, string>(capacity, StringComparer.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
@ -57,6 +61,9 @@ namespace Microsoft.AspNetCore.Http
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RequestCookieCollection Parse(IList<string> values)
|
public static RequestCookieCollection Parse(IList<string> values)
|
||||||
|
=> ParseInternal(values, AppContext.TryGetSwitch(EnableCookieNameDecoding, out var enabled) && enabled);
|
||||||
|
|
||||||
|
internal static RequestCookieCollection ParseInternal(IList<string> values, bool enableCookieNameDecoding)
|
||||||
{
|
{
|
||||||
if (values.Count == 0)
|
if (values.Count == 0)
|
||||||
{
|
{
|
||||||
|
|
@ -76,7 +83,11 @@ namespace Microsoft.AspNetCore.Http
|
||||||
for (var i = 0; i < cookies.Count; i++)
|
for (var i = 0; i < cookies.Count; i++)
|
||||||
{
|
{
|
||||||
var cookie = cookies[i];
|
var cookie = cookies[i];
|
||||||
var name = Uri.UnescapeDataString(cookie.Name.Value);
|
var name = cookie.Name.Value;
|
||||||
|
if (enableCookieNameDecoding)
|
||||||
|
{
|
||||||
|
name = Uri.UnescapeDataString(name);
|
||||||
|
}
|
||||||
var value = Uri.UnescapeDataString(cookie.Value.Value);
|
var value = Uri.UnescapeDataString(cookie.Value.Value);
|
||||||
store[name] = value;
|
store[name] = value;
|
||||||
}
|
}
|
||||||
|
|
@ -116,7 +127,8 @@ namespace Microsoft.AspNetCore.Http
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return Store.ContainsKey(key);
|
return Store.ContainsKey(key)
|
||||||
|
|| !_enableCookieNameDecoding && Store.ContainsKey(Uri.EscapeDataString(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetValue(string key, out string value)
|
public bool TryGetValue(string key, out string value)
|
||||||
|
|
@ -126,7 +138,9 @@ namespace Microsoft.AspNetCore.Http
|
||||||
value = null;
|
value = null;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return Store.TryGetValue(key, out value);
|
|
||||||
|
return Store.TryGetValue(key, out value)
|
||||||
|
|| !_enableCookieNameDecoding && Store.TryGetValue(Uri.EscapeDataString(key), out value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.Extensions.Primitives;
|
using Microsoft.Extensions.Primitives;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
@ -9,30 +10,32 @@ namespace Microsoft.AspNetCore.Http.Tests
|
||||||
{
|
{
|
||||||
public class RequestCookiesCollectionTests
|
public class RequestCookiesCollectionTests
|
||||||
{
|
{
|
||||||
public static TheoryData UnEscapesKeyValues_Data
|
[Theory]
|
||||||
|
[InlineData("key=value", "key", "value")]
|
||||||
|
[InlineData("__secure-key=value", "__secure-key", "value")]
|
||||||
|
[InlineData("key%2C=%21value", "key,", "!value")]
|
||||||
|
[InlineData("ke%23y%2C=val%5Eue", "ke#y,", "val^ue")]
|
||||||
|
[InlineData("base64=QUI%2BREU%2FRw%3D%3D", "base64", "QUI+REU/Rw==")]
|
||||||
|
[InlineData("base64=QUI+REU/Rw==", "base64", "QUI+REU/Rw==")]
|
||||||
|
public void UnEscapesValues(string input, string expectedKey, string expectedValue)
|
||||||
{
|
{
|
||||||
get
|
var cookies = RequestCookieCollection.Parse(new StringValues(input));
|
||||||
{
|
|
||||||
// key, value, expected
|
Assert.Equal(1, cookies.Count);
|
||||||
return new TheoryData<string, string, string>
|
Assert.Equal(Uri.EscapeDataString(expectedKey), cookies.Keys.Single());
|
||||||
{
|
Assert.Equal(expectedValue, cookies[expectedKey]);
|
||||||
{ "key=value", "key", "value" },
|
|
||||||
{ "key%2C=%21value", "key,", "!value" },
|
|
||||||
{ "ke%23y%2C=val%5Eue", "ke#y,", "val^ue" },
|
|
||||||
{ "base64=QUI%2BREU%2FRw%3D%3D", "base64", "QUI+REU/Rw==" },
|
|
||||||
{ "base64=QUI+REU/Rw==", "base64", "QUI+REU/Rw==" },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[MemberData(nameof(UnEscapesKeyValues_Data))]
|
[InlineData("key=value", "key", "value")]
|
||||||
public void UnEscapesKeyValues(
|
[InlineData("__secure-key=value", "__secure-key", "value")]
|
||||||
string input,
|
[InlineData("key%2C=%21value", "key,", "!value")]
|
||||||
string expectedKey,
|
[InlineData("ke%23y%2C=val%5Eue", "ke#y,", "val^ue")]
|
||||||
string expectedValue)
|
[InlineData("base64=QUI%2BREU%2FRw%3D%3D", "base64", "QUI+REU/Rw==")]
|
||||||
|
[InlineData("base64=QUI+REU/Rw==", "base64", "QUI+REU/Rw==")]
|
||||||
|
public void AppContextSwitchUnEscapesKeyValues(string input, string expectedKey, string expectedValue)
|
||||||
{
|
{
|
||||||
var cookies = RequestCookieCollection.Parse(new StringValues(input));
|
var cookies = RequestCookieCollection.ParseInternal(new StringValues(input), enableCookieNameDecoding: true);
|
||||||
|
|
||||||
Assert.Equal(1, cookies.Count);
|
Assert.Equal(1, cookies.Count);
|
||||||
Assert.Equal(expectedKey, cookies.Keys.Single());
|
Assert.Equal(expectedKey, cookies.Keys.Single());
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue