Skip to content

Commit

Permalink
Remove cookie name decoding (#368)
Browse files Browse the repository at this point in the history
  • Loading branch information
Tratcher committed Aug 12, 2020
1 parent 635c92f commit 535ab4c
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 15 deletions.
23 changes: 15 additions & 8 deletions src/Microsoft.Owin/Infrastructure/OwinHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -530,13 +530,13 @@ internal static partial class OwinHelpers
if (request.Get<string>("Microsoft.Owin.Cookies#text") != text)
{
cookies.Clear();
ParseDelimited(text, SemicolonAndComma, AddCookieCallback, cookies);
ParseDelimited(text, SemicolonAndComma, AddCookieCallback, decodePlus: false, decodeKey: false, state: cookies);
request.Set("Microsoft.Owin.Cookies#text", text);
}
return cookies;
}

internal static void ParseDelimited(string text, char[] delimiters, Action<string, string, object> callback, object state)
internal static void ParseDelimited(string text, char[] delimiters, Action<string, string, object> callback, bool decodePlus, bool decodeKey, object state)
{
int textLength = text.Length;
int equalIndex = text.IndexOf('=');
Expand All @@ -560,10 +560,17 @@ internal static void ParseDelimited(string text, char[] delimiters, Action<strin
}
string name = text.Substring(scanIndex, equalIndex - scanIndex);
string value = text.Substring(equalIndex + 1, delimiterIndex - equalIndex - 1);
callback(
Uri.UnescapeDataString(name.Replace('+', ' ')),
Uri.UnescapeDataString(value.Replace('+', ' ')),
state);
if (decodePlus)
{
name.Replace('+', ' ');
value.Replace('+', ' ');
}
if (decodeKey)
{
name = Uri.UnescapeDataString(name);
}
value = Uri.UnescapeDataString(value);
callback(name, value, state);
equalIndex = text.IndexOf('=', delimiterIndex);
if (equalIndex == -1)
{
Expand Down Expand Up @@ -799,7 +806,7 @@ internal static partial class OwinHelpers
{
query.Clear();
var accumulator = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
ParseDelimited(text, AmpersandAndSemicolon, AppendItemCallback, accumulator);
ParseDelimited(text, AmpersandAndSemicolon, AppendItemCallback, decodePlus: true, decodeKey: true, state: accumulator);
foreach (var kv in accumulator)
{
query.Add(kv.Key, kv.Value.ToArray());
Expand All @@ -813,7 +820,7 @@ internal static IFormCollection GetForm(string text)
{
IDictionary<string, string[]> form = new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase);
var accumulator = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
ParseDelimited(text, new[] { '&' }, AppendItemCallback, accumulator);
ParseDelimited(text, new[] { '&' }, AppendItemCallback, decodePlus: false, decodeKey: true, state: accumulator);
foreach (var kv in accumulator)
{
form.Add(kv.Key, kv.Value.ToArray());
Expand Down
7 changes: 5 additions & 2 deletions src/Microsoft.Owin/RequestCookieCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,11 @@ public RequestCookieCollection(IDictionary<string, string> store)
get
{
string value;
Store.TryGetValue(key, out value);
return value;
if (Store.TryGetValue(key, out value) || Store.TryGetValue(Uri.EscapeDataString(key), out value))
{
return value;
}
return null;
}
}

Expand Down
10 changes: 5 additions & 5 deletions tests/Microsoft.Owin.Tests/FormsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class FormsTests
private static readonly string[] RawValues = new[] { "v1", "v2, v3", "\"v4, b\"", "v5, v6", "v7", };
private const string JoinedValues = "v1,v2, v3,\"v4, b\",v5, v6,v7";

private const string OriginalFormsString = "q1=v1&q2=v2,b&q3=v3&q3=v4&q4&q5=v5&q5=v5";
private const string OriginalFormsString = "q1=v1&q2=v2,b&q3=v3&q3=v4&q4&q5=v5&q5=v+5";

[Fact]
public void ParseForm()
Expand All @@ -30,7 +30,7 @@ public void ParseForm()
Assert.Equal("v2,b", form.Get("Q2"));
Assert.Equal("v3,v4", form.Get("q3"));
Assert.Null(form.Get("q4"));
Assert.Equal("v5,v5", form.Get("Q5"));
Assert.Equal("v5,v+5", form.Get("Q5"));
Assert.True(stream.CanRead);
}

Expand Down Expand Up @@ -89,7 +89,7 @@ public void ReadFromStream()
Assert.Equal("v2,b", form.Get("Q2"));
Assert.Equal("v3,v4", form.Get("q3"));
Assert.Null(form.Get("q4"));
Assert.Equal("v5,v5", form.Get("Q5"));
Assert.Equal("v5,v+5", form.Get("Q5"));
}

[Fact]
Expand All @@ -107,14 +107,14 @@ public void ReadFromStreamTwice()
Assert.Equal("v2,b", form.Get("Q2"));
Assert.Equal("v3,v4", form.Get("q3"));
Assert.Null(form.Get("q4"));
Assert.Equal("v5,v5", form.Get("Q5"));
Assert.Equal("v5,v+5", form.Get("Q5"));

form = request.ReadFormAsync().Result;
Assert.Equal("v1", form.Get("q1"));
Assert.Equal("v2,b", form.Get("Q2"));
Assert.Equal("v3,v4", form.Get("q3"));
Assert.Null(form.Get("q4"));
Assert.Equal("v5,v5", form.Get("Q5"));
Assert.Equal("v5,v+5", form.Get("Q5"));
}
}
}
1 change: 1 addition & 0 deletions tests/Microsoft.Owin.Tests/Microsoft.Owin.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
<Compile Include="Builder\AppBuilderTestExtensions.cs" />
<Compile Include="Builder\AppBuilderTests.cs" />
<Compile Include="CookieChunkingTests.cs" />
<Compile Include="RequestCookieTests.cs" />
<Compile Include="FormsTests.cs" />
<Compile Include="HeaderTests.cs" />
<Compile Include="HostStringTests.cs" />
Expand Down
31 changes: 31 additions & 0 deletions tests/Microsoft.Owin.Tests/RequestCookieTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// 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.

using System;
using System.Linq;
using Xunit;
using Xunit.Extensions;

namespace Microsoft.Owin.Tests
{
public class RequestCookieTests
{
[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)
{
var context = new OwinRequest();
context.Headers["Cookie"] = input;
var cookies = context.Cookies;

Assert.Equal(1, cookies.Count());
Assert.Equal(Uri.EscapeDataString(expectedKey), cookies.Single().Key);
Assert.Equal(expectedValue, cookies[expectedKey]);
}
}
}

0 comments on commit 535ab4c

Please sign in to comment.