Disable cookie name encoding/decoding. (#23579)
This commit is contained in:
parent
36856ca8f9
commit
8182bb16a9
|
|
@ -57,6 +57,9 @@ namespace Microsoft.AspNetCore.Http
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RequestCookieCollection Parse(IList<string> values)
|
public static RequestCookieCollection Parse(IList<string> values)
|
||||||
|
=> ParseInternal(values, AppContext.TryGetSwitch(ResponseCookies.EnableCookieNameEncoding, out var enabled) && enabled);
|
||||||
|
|
||||||
|
internal static RequestCookieCollection ParseInternal(IList<string> values, bool enableCookieNameEncoding)
|
||||||
{
|
{
|
||||||
if (values.Count == 0)
|
if (values.Count == 0)
|
||||||
{
|
{
|
||||||
|
|
@ -75,7 +78,7 @@ 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 = enableCookieNameEncoding ? Uri.UnescapeDataString(cookie.Name.Value) : cookie.Name.Value;
|
||||||
var value = Uri.UnescapeDataString(cookie.Value.Value);
|
var value = Uri.UnescapeDataString(cookie.Value.Value);
|
||||||
store[name] = value;
|
store[name] = value;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,9 @@ namespace Microsoft.AspNetCore.Http
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal class ResponseCookies : IResponseCookies
|
internal class ResponseCookies : IResponseCookies
|
||||||
{
|
{
|
||||||
|
internal const string EnableCookieNameEncoding = "Microsoft.AspNetCore.Http.EnableCookieNameEncoding";
|
||||||
|
internal bool _enableCookieNameEncoding = AppContext.TryGetSwitch(EnableCookieNameEncoding, out var enabled) && enabled;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new wrapper.
|
/// Create a new wrapper.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -33,7 +36,7 @@ namespace Microsoft.AspNetCore.Http
|
||||||
public void Append(string key, string value)
|
public void Append(string key, string value)
|
||||||
{
|
{
|
||||||
var setCookieHeaderValue = new SetCookieHeaderValue(
|
var setCookieHeaderValue = new SetCookieHeaderValue(
|
||||||
Uri.EscapeDataString(key),
|
_enableCookieNameEncoding ? Uri.EscapeDataString(key) : key,
|
||||||
Uri.EscapeDataString(value))
|
Uri.EscapeDataString(value))
|
||||||
{
|
{
|
||||||
Path = "/"
|
Path = "/"
|
||||||
|
|
@ -52,7 +55,7 @@ namespace Microsoft.AspNetCore.Http
|
||||||
}
|
}
|
||||||
|
|
||||||
var setCookieHeaderValue = new SetCookieHeaderValue(
|
var setCookieHeaderValue = new SetCookieHeaderValue(
|
||||||
Uri.EscapeDataString(key),
|
_enableCookieNameEncoding ? Uri.EscapeDataString(key) : key,
|
||||||
Uri.EscapeDataString(value))
|
Uri.EscapeDataString(value))
|
||||||
{
|
{
|
||||||
Domain = options.Domain,
|
Domain = options.Domain,
|
||||||
|
|
@ -83,7 +86,7 @@ namespace Microsoft.AspNetCore.Http
|
||||||
throw new ArgumentNullException(nameof(options));
|
throw new ArgumentNullException(nameof(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
var encodedKeyPlusEquals = Uri.EscapeDataString(key) + "=";
|
var encodedKeyPlusEquals = (_enableCookieNameEncoding ? Uri.EscapeDataString(key) : key) + "=";
|
||||||
bool domainHasValue = !string.IsNullOrEmpty(options.Domain);
|
bool domainHasValue = !string.IsNullOrEmpty(options.Domain);
|
||||||
bool pathHasValue = !string.IsNullOrEmpty(options.Path);
|
bool pathHasValue = !string.IsNullOrEmpty(options.Path);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -175,7 +175,7 @@ namespace Microsoft.AspNetCore.Http
|
||||||
Assert.Null(cookies0["key0"]);
|
Assert.Null(cookies0["key0"]);
|
||||||
Assert.False(cookies0.ContainsKey("key0"));
|
Assert.False(cookies0.ContainsKey("key0"));
|
||||||
|
|
||||||
var newCookies = new[] { "name0=value0%2C", "%5Ename1=value1" };
|
var newCookies = new[] { "name0=value0%2C", "name1=value1" };
|
||||||
request.Headers["Cookie"] = newCookies;
|
request.Headers["Cookie"] = newCookies;
|
||||||
|
|
||||||
cookies0 = RequestCookieCollection.Parse(newCookies);
|
cookies0 = RequestCookieCollection.Parse(newCookies);
|
||||||
|
|
@ -183,7 +183,7 @@ namespace Microsoft.AspNetCore.Http
|
||||||
Assert.Equal(cookies0, cookies1);
|
Assert.Equal(cookies0, cookies1);
|
||||||
Assert.Equal(2, cookies1.Count);
|
Assert.Equal(2, cookies1.Count);
|
||||||
Assert.Equal("value0,", cookies1["name0"]);
|
Assert.Equal("value0,", cookies1["name0"]);
|
||||||
Assert.Equal("value1", cookies1["^name1"]);
|
Assert.Equal("value1", cookies1["name1"]);
|
||||||
Assert.Equal(newCookies, request.Headers["Cookie"]);
|
Assert.Equal(newCookies, request.Headers["Cookie"]);
|
||||||
|
|
||||||
var cookies2 = new RequestCookieCollection(new Dictionary<string,string>()
|
var cookies2 = new RequestCookieCollection(new Dictionary<string,string>()
|
||||||
|
|
|
||||||
|
|
@ -9,28 +9,13 @@ namespace Microsoft.AspNetCore.Http.Tests
|
||||||
{
|
{
|
||||||
public class RequestCookiesCollectionTests
|
public class RequestCookiesCollectionTests
|
||||||
{
|
{
|
||||||
public static TheoryData UnEscapesKeyValues_Data
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
// key, value, expected
|
|
||||||
return new TheoryData<string, string, string>
|
|
||||||
{
|
|
||||||
{ "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("key%2C=%21value", "key%2C", "!value")]
|
||||||
string input,
|
[InlineData("ke%23y%2C=val%5Eue", "ke%23y%2C", "val^ue")]
|
||||||
string expectedKey,
|
[InlineData("base64=QUI%2BREU%2FRw%3D%3D", "base64", "QUI+REU/Rw==")]
|
||||||
string expectedValue)
|
[InlineData("base64=QUI+REU/Rw==", "base64", "QUI+REU/Rw==")]
|
||||||
|
public void UnEscapesValues(string input, string expectedKey, string expectedValue)
|
||||||
{
|
{
|
||||||
var cookies = RequestCookieCollection.Parse(new StringValues(input));
|
var cookies = RequestCookieCollection.Parse(new StringValues(input));
|
||||||
|
|
||||||
|
|
@ -38,5 +23,20 @@ namespace Microsoft.AspNetCore.Http.Tests
|
||||||
Assert.Equal(expectedKey, cookies.Keys.Single());
|
Assert.Equal(expectedKey, cookies.Keys.Single());
|
||||||
Assert.Equal(expectedValue, cookies[expectedKey]);
|
Assert.Equal(expectedValue, cookies[expectedKey]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("key=value", "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 AppContextSwitchUnEscapesKeysAndValues(string input, string expectedKey, string expectedValue)
|
||||||
|
{
|
||||||
|
var cookies = RequestCookieCollection.ParseInternal(new StringValues(input), enableCookieNameEncoding: true);
|
||||||
|
|
||||||
|
Assert.Equal(1, cookies.Count);
|
||||||
|
Assert.Equal(expectedKey, cookies.Keys.Single());
|
||||||
|
Assert.Equal(expectedValue, cookies[expectedKey]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -88,31 +88,45 @@ namespace Microsoft.AspNetCore.Http.Tests
|
||||||
Assert.Contains($"max-age={maxAgeTime.TotalSeconds.ToString()}", cookieHeaderValues[0]);
|
Assert.Contains($"max-age={maxAgeTime.TotalSeconds.ToString()}", cookieHeaderValues[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TheoryData EscapesKeyValuesBeforeSettingCookieData
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
// key, value, object pool, expected
|
|
||||||
return new TheoryData<string, string, string>
|
|
||||||
{
|
|
||||||
{ "key", "value", "key=value" },
|
|
||||||
{ "key,", "!value", "key%2C=%21value" },
|
|
||||||
{ "ke#y,", "val^ue", "ke%23y%2C=val%5Eue" },
|
|
||||||
{ "base64", "QUI+REU/Rw==", "base64=QUI%2BREU%2FRw%3D%3D" },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[MemberData(nameof(EscapesKeyValuesBeforeSettingCookieData))]
|
[InlineData("value", "key=value")]
|
||||||
public void EscapesKeyValuesBeforeSettingCookie(
|
[InlineData("!value", "key=%21value")]
|
||||||
string key,
|
[InlineData("val^ue", "key=val%5Eue")]
|
||||||
string value,
|
[InlineData("QUI+REU/Rw==", "key=QUI%2BREU%2FRw%3D%3D")]
|
||||||
string expected)
|
public void EscapesValuesBeforeSettingCookie(string value, string expected)
|
||||||
{
|
{
|
||||||
var headers = new HeaderDictionary();
|
var headers = new HeaderDictionary();
|
||||||
var cookies = new ResponseCookies(headers);
|
var cookies = new ResponseCookies(headers);
|
||||||
|
|
||||||
|
cookies.Append("key", value);
|
||||||
|
|
||||||
|
var cookieHeaderValues = headers[HeaderNames.SetCookie];
|
||||||
|
Assert.Single(cookieHeaderValues);
|
||||||
|
Assert.StartsWith(expected, cookieHeaderValues[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("key,")]
|
||||||
|
[InlineData("ke@y")]
|
||||||
|
public void InvalidKeysThrow(string key)
|
||||||
|
{
|
||||||
|
var headers = new HeaderDictionary();
|
||||||
|
var cookies = new ResponseCookies(headers);
|
||||||
|
|
||||||
|
Assert.Throws<ArgumentException>(() => cookies.Append(key, "1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("key", "value", "key=value")]
|
||||||
|
[InlineData("key,", "!value", "key%2C=%21value")]
|
||||||
|
[InlineData("ke#y,", "val^ue", "ke%23y%2C=val%5Eue")]
|
||||||
|
[InlineData("base64", "QUI+REU/Rw==", "base64=QUI%2BREU%2FRw%3D%3D")]
|
||||||
|
public void AppContextSwitchEscapesKeysAndValuesBeforeSettingCookie(string key, string value, string expected)
|
||||||
|
{
|
||||||
|
var headers = new HeaderDictionary();
|
||||||
|
var cookies = new ResponseCookies(headers);
|
||||||
|
cookies._enableCookieNameEncoding = true;
|
||||||
|
|
||||||
cookies.Append(key, value);
|
cookies.Append(key, value);
|
||||||
|
|
||||||
var cookieHeaderValues = headers[HeaderNames.SetCookie];
|
var cookieHeaderValues = headers[HeaderNames.SetCookie];
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue