From da98f22495ca1199e4183c33da02086da300617f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Sun, 24 May 2020 01:03:41 +0200 Subject: [PATCH 01/10] Added Extension property to SetCookieHeaderValue and parsing for it --- src/Http/Headers/src/SetCookieHeaderValue.cs | 53 +++++++++++++++++--- 1 file changed, 45 insertions(+), 8 deletions(-) diff --git a/src/Http/Headers/src/SetCookieHeaderValue.cs b/src/Http/Headers/src/SetCookieHeaderValue.cs index cdf12381aa44..6500d2ad904c 100644 --- a/src/Http/Headers/src/SetCookieHeaderValue.cs +++ b/src/Http/Headers/src/SetCookieHeaderValue.cs @@ -98,6 +98,8 @@ public StringSegment Value public bool HttpOnly { get; set; } + public List Extensions { get; set; } + // name="value"; expires=Sun, 06 Nov 1994 08:49:37 GMT; max-age=86400; domain=domain1; path=path1; secure; samesite={strict|lax|none}; httponly public override string ToString() { @@ -154,6 +156,14 @@ public override string ToString() length += SeparatorToken.Length + HttpOnlyToken.Length; } + if(Extensions != null) + { + foreach (var extension in Extensions) + { + length += SeparatorToken.Length + extension.Length; + } + } + return string.Create(length, (this, maxAge, sameSite), (span, tuple) => { var (headerValue, maxAgeValue, sameSite) = tuple; @@ -203,6 +213,14 @@ public override string ToString() { AppendSegment(ref span, HttpOnlyToken, null); } + + if(Extensions != null) + { + foreach (var extension in Extensions) + { + AppendSegment(ref span, extension, null); + } + } }); } @@ -280,6 +298,14 @@ public void AppendToStringBuilder(StringBuilder builder) { AppendSegment(builder, HttpOnlyToken, null); } + + if (Extensions != null) + { + foreach (var extension in Extensions) + { + AppendSegment(builder, extension, null); + } + } } private static void AppendSegment(StringBuilder builder, StringSegment name, StringSegment value) @@ -498,13 +524,13 @@ private static int GetSetCookieLength(StringSegment input, int startIndex, out S // extension-av = else { - // TODO: skiping it for now to avoid parsing failure? Store it in a list? - // = (no spaces) - if (!ReadEqualsSign(input, ref offset)) - { - return 0; - } + var tokenStart = offset - itemLength; ReadToSemicolonOrEnd(input, ref offset); + + if (result.Extensions == null) + result.Extensions = new List(); + + result.Extensions.Add(input.Subsegment(tokenStart, offset - tokenStart)); } } @@ -554,12 +580,13 @@ public override bool Equals(object obj) && StringSegment.Equals(Path, other.Path, StringComparison.OrdinalIgnoreCase) && Secure == other.Secure && SameSite == other.SameSite - && HttpOnly == other.HttpOnly; + && HttpOnly == other.HttpOnly + && HeaderUtilities.AreEqualCollections(Extensions, other.Extensions); } public override int GetHashCode() { - return StringSegmentComparer.OrdinalIgnoreCase.GetHashCode(_name) + var hash = StringSegmentComparer.OrdinalIgnoreCase.GetHashCode(_name) ^ StringSegmentComparer.OrdinalIgnoreCase.GetHashCode(_value) ^ (Expires.HasValue ? Expires.GetHashCode() : 0) ^ (MaxAge.HasValue ? MaxAge.GetHashCode() : 0) @@ -568,6 +595,16 @@ public override int GetHashCode() ^ Secure.GetHashCode() ^ SameSite.GetHashCode() ^ HttpOnly.GetHashCode(); + + if (Extensions != null) + { + foreach (var extension in Extensions) + { + hash ^= extension.GetHashCode(); + } + } + + return hash; } } } From 9d0d6d7bd01ae612bf266464303fd3e14839f377 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Sun, 24 May 2020 11:03:34 +0200 Subject: [PATCH 02/10] Update reference assemblies --- src/Http/Headers/ref/Microsoft.Net.Http.Headers.netcoreapp.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Http/Headers/ref/Microsoft.Net.Http.Headers.netcoreapp.cs b/src/Http/Headers/ref/Microsoft.Net.Http.Headers.netcoreapp.cs index 74bfe68f38e0..8f0a8cd79ef2 100644 --- a/src/Http/Headers/ref/Microsoft.Net.Http.Headers.netcoreapp.cs +++ b/src/Http/Headers/ref/Microsoft.Net.Http.Headers.netcoreapp.cs @@ -329,6 +329,7 @@ public SetCookieHeaderValue(Microsoft.Extensions.Primitives.StringSegment name) public SetCookieHeaderValue(Microsoft.Extensions.Primitives.StringSegment name, Microsoft.Extensions.Primitives.StringSegment value) { } public Microsoft.Extensions.Primitives.StringSegment Domain { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } public System.DateTimeOffset? Expires { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } + public System.Collections.Generic.List Extensions { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } public bool HttpOnly { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } public System.TimeSpan? MaxAge { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } public Microsoft.Extensions.Primitives.StringSegment Name { get { throw null; } set { } } From 3b50e0f38ccbccd4afd0eae6572dabe3d689e5ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Sun, 24 May 2020 12:48:19 +0200 Subject: [PATCH 03/10] Change Equals() to respect order of Extensions --- src/Http/Headers/src/SetCookieHeaderValue.cs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/Http/Headers/src/SetCookieHeaderValue.cs b/src/Http/Headers/src/SetCookieHeaderValue.cs index 6500d2ad904c..d801a5317e67 100644 --- a/src/Http/Headers/src/SetCookieHeaderValue.cs +++ b/src/Http/Headers/src/SetCookieHeaderValue.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.Contracts; +using System.Linq; using System.Text; using Microsoft.Extensions.Primitives; @@ -572,7 +573,7 @@ public override bool Equals(object obj) return false; } - return StringSegment.Equals(_name, other._name, StringComparison.OrdinalIgnoreCase) + var equal = StringSegment.Equals(_name, other._name, StringComparison.OrdinalIgnoreCase) && StringSegment.Equals(_value, other._value, StringComparison.OrdinalIgnoreCase) && Expires.Equals(other.Expires) && MaxAge.Equals(other.MaxAge) @@ -580,8 +581,20 @@ public override bool Equals(object obj) && StringSegment.Equals(Path, other.Path, StringComparison.OrdinalIgnoreCase) && Secure == other.Secure && SameSite == other.SameSite - && HttpOnly == other.HttpOnly - && HeaderUtilities.AreEqualCollections(Extensions, other.Extensions); + && HttpOnly == other.HttpOnly; + + if (!equal) + return false; + + if (Extensions == null) + { + return (other.Extensions == null) || (other.Extensions.Count == 0); + } + + if (other.Extensions == null) + return Extensions.Count == 0; + + return Extensions.SequenceEqual(other.Extensions, StringSegmentComparer.OrdinalIgnoreCase); } public override int GetHashCode() From 79b85772b7ffdd28becd16502cc8fd002bd576e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Sun, 24 May 2020 12:49:39 +0200 Subject: [PATCH 04/10] Added test data for parsing of extension-av --- .../Headers/test/SetCookieHeaderValueTest.cs | 54 +++++++++++++++---- 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/src/Http/Headers/test/SetCookieHeaderValueTest.cs b/src/Http/Headers/test/SetCookieHeaderValueTest.cs index 4f33c54599b6..37528ecfcdd8 100644 --- a/src/Http/Headers/test/SetCookieHeaderValueTest.cs +++ b/src/Http/Headers/test/SetCookieHeaderValueTest.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using Microsoft.Extensions.Primitives; using Xunit; namespace Microsoft.Net.Http.Headers @@ -24,9 +25,14 @@ public static TheoryData SetCookieHeaderDataSet HttpOnly = true, MaxAge = TimeSpan.FromDays(1), Path = "path1", - Secure = true + Secure = true, + Extensions = new List() + { + "extension1", + "extension2=value" + } }; - dataset.Add(header1, "name1=n1=v1&n2=v2&n3=v3; expires=Sun, 06 Nov 1994 08:49:37 GMT; max-age=86400; domain=domain1; path=path1; secure; samesite=strict; httponly"); + dataset.Add(header1, "name1=n1=v1&n2=v2&n3=v3; expires=Sun, 06 Nov 1994 08:49:37 GMT; max-age=86400; domain=domain1; path=path1; secure; samesite=strict; httponly; extension1; extension2=value"); var header2 = new SetCookieHeaderValue("name2", ""); dataset.Add(header2, "name2="); @@ -59,6 +65,15 @@ public static TheoryData SetCookieHeaderDataSet }; dataset.Add(header7, "name7=value7; samesite=none"); + var header8 = new SetCookieHeaderValue("name8", "value8") + { + Extensions = new List() + { + "extension1", + "extension2=value" + } + }; + dataset.Add(header8, "name8=value8; extension1; extension2=value"); return dataset; } @@ -124,9 +139,14 @@ public static TheoryData, string[]> ListOfSetCookieH HttpOnly = true, MaxAge = TimeSpan.FromDays(1), Path = "path1", - Secure = true + Secure = true, + Extensions = new List() + { + "extension1", + "extension2=value" + } }; - var string1 = "name1=n1=v1&n2=v2&n3=v3; expires=Sun, 06 Nov 1994 08:49:37 GMT; max-age=86400; domain=domain1; path=path1; secure; samesite=strict; httponly"; + var string1 = "name1=n1=v1&n2=v2&n3=v3; expires=Sun, 06 Nov 1994 08:49:37 GMT; max-age=86400; domain=domain1; path=path1; secure; samesite=strict; httponly; extension1; extension2=value"; var header2 = new SetCookieHeaderValue("name2", "value2"); var string2 = "name2=value2"; @@ -170,6 +190,17 @@ public static TheoryData, string[]> ListOfSetCookieH var string8a = "name8=value8; samesite"; var string8b = "name8=value8; samesite=invalid"; + var header9 = new SetCookieHeaderValue("name9", "value9") + { + Extensions = new List + { + "extension1", + "extension2=value" + } + }; + var string9 = "name9=value9; extension1; extension2=value"; + + dataset.Add(new[] { header1 }.ToList(), new[] { string1 }); dataset.Add(new[] { header1, header1 }.ToList(), new[] { string1, string1 }); dataset.Add(new[] { header1, header1 }.ToList(), new[] { string1, null, "", " ", ",", " , ", string1 }); @@ -185,6 +216,7 @@ public static TheoryData, string[]> ListOfSetCookieH dataset.Add(new[] { header7 }.ToList(), new[] { string7 }); dataset.Add(new[] { header8 }.ToList(), new[] { string8a }); dataset.Add(new[] { header8 }.ToList(), new[] { string8b }); + dataset.Add(new[] { header9 }.ToList(), new[] { string9 }); return dataset; } @@ -378,15 +410,19 @@ public void SetCookieHeaderValue_TryParseList_AcceptsValidValues(IList Date: Sun, 24 May 2020 12:54:13 +0200 Subject: [PATCH 05/10] Fix of parsing multiple cookies in one string Because extension-av doesn't have any fixed format we have to look after commas when parsing to determine end of Set-Cookie string --- src/Http/Headers/src/SetCookieHeaderValue.cs | 22 ++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/Http/Headers/src/SetCookieHeaderValue.cs b/src/Http/Headers/src/SetCookieHeaderValue.cs index d801a5317e67..caac61c007e3 100644 --- a/src/Http/Headers/src/SetCookieHeaderValue.cs +++ b/src/Http/Headers/src/SetCookieHeaderValue.cs @@ -157,7 +157,7 @@ public override string ToString() length += SeparatorToken.Length + HttpOnlyToken.Length; } - if(Extensions != null) + if (Extensions != null) { foreach (var extension in Extensions) { @@ -215,7 +215,7 @@ public override string ToString() AppendSegment(ref span, HttpOnlyToken, null); } - if(Extensions != null) + if (Extensions != null) { foreach (var extension in Extensions) { @@ -526,7 +526,7 @@ private static int GetSetCookieLength(StringSegment input, int startIndex, out S else { var tokenStart = offset - itemLength; - ReadToSemicolonOrEnd(input, ref offset); + ReadToSemicolonOrEnd(input, ref offset, includeComma: true); if (result.Extensions == null) result.Extensions = new List(); @@ -550,14 +550,28 @@ private static bool ReadEqualsSign(StringSegment input, ref int offset) return true; } - private static StringSegment ReadToSemicolonOrEnd(StringSegment input, ref int offset) + private static StringSegment ReadToSemicolonOrEnd(StringSegment input, ref int offset, bool includeComma = false) { var end = input.IndexOf(';', offset); + if (end < 0) + { + // Also valid end of cookie + if (includeComma) + end = input.IndexOf(',', offset); + } + else if (includeComma) + { + var commaPosition = input.IndexOf(',', offset); + if (commaPosition >= 0 && commaPosition < end) + end = commaPosition; + } + if (end < 0) { // Remainder of the string end = input.Length; } + var itemLength = end - offset; var result = input.Subsegment(offset, itemLength); offset += itemLength; From 0c95698a2db4084c38eeddaadb303811f57dde7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Mon, 25 May 2020 00:38:22 +0200 Subject: [PATCH 06/10] Extension-av order doesn't matter --- src/Http/Headers/src/SetCookieHeaderValue.cs | 18 +++--------------- .../Headers/test/SetCookieHeaderValueTest.cs | 4 ++-- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/src/Http/Headers/src/SetCookieHeaderValue.cs b/src/Http/Headers/src/SetCookieHeaderValue.cs index caac61c007e3..07287f9c1a51 100644 --- a/src/Http/Headers/src/SetCookieHeaderValue.cs +++ b/src/Http/Headers/src/SetCookieHeaderValue.cs @@ -587,7 +587,7 @@ public override bool Equals(object obj) return false; } - var equal = StringSegment.Equals(_name, other._name, StringComparison.OrdinalIgnoreCase) + return StringSegment.Equals(_name, other._name, StringComparison.OrdinalIgnoreCase) && StringSegment.Equals(_value, other._value, StringComparison.OrdinalIgnoreCase) && Expires.Equals(other.Expires) && MaxAge.Equals(other.MaxAge) @@ -595,20 +595,8 @@ public override bool Equals(object obj) && StringSegment.Equals(Path, other.Path, StringComparison.OrdinalIgnoreCase) && Secure == other.Secure && SameSite == other.SameSite - && HttpOnly == other.HttpOnly; - - if (!equal) - return false; - - if (Extensions == null) - { - return (other.Extensions == null) || (other.Extensions.Count == 0); - } - - if (other.Extensions == null) - return Extensions.Count == 0; - - return Extensions.SequenceEqual(other.Extensions, StringSegmentComparer.OrdinalIgnoreCase); + && HttpOnly == other.HttpOnly + && HeaderUtilities.AreEqualCollections(Extensions, other.Extensions, StringSegmentComparer.OrdinalIgnoreCase); } public override int GetHashCode() diff --git a/src/Http/Headers/test/SetCookieHeaderValueTest.cs b/src/Http/Headers/test/SetCookieHeaderValueTest.cs index 37528ecfcdd8..3b685a66f5cb 100644 --- a/src/Http/Headers/test/SetCookieHeaderValueTest.cs +++ b/src/Http/Headers/test/SetCookieHeaderValueTest.cs @@ -410,7 +410,7 @@ public void SetCookieHeaderValue_TryParseList_AcceptsValidValues(IList Date: Sat, 6 Jun 2020 22:27:24 +0200 Subject: [PATCH 07/10] Updated SetCookieHeaderValue to reflect comments in PR --- src/Http/Headers/src/SetCookieHeaderValue.cs | 42 +++++++------------- 1 file changed, 15 insertions(+), 27 deletions(-) diff --git a/src/Http/Headers/src/SetCookieHeaderValue.cs b/src/Http/Headers/src/SetCookieHeaderValue.cs index 07287f9c1a51..f86252c74a08 100644 --- a/src/Http/Headers/src/SetCookieHeaderValue.cs +++ b/src/Http/Headers/src/SetCookieHeaderValue.cs @@ -99,7 +99,7 @@ public StringSegment Value public bool HttpOnly { get; set; } - public List Extensions { get; set; } + public IList Extensions { get; } = new List(); // name="value"; expires=Sun, 06 Nov 1994 08:49:37 GMT; max-age=86400; domain=domain1; path=path1; secure; samesite={strict|lax|none}; httponly public override string ToString() @@ -157,12 +157,9 @@ public override string ToString() length += SeparatorToken.Length + HttpOnlyToken.Length; } - if (Extensions != null) + foreach (var extension in Extensions) { - foreach (var extension in Extensions) - { - length += SeparatorToken.Length + extension.Length; - } + length += SeparatorToken.Length + extension.Length; } return string.Create(length, (this, maxAge, sameSite), (span, tuple) => @@ -215,12 +212,9 @@ public override string ToString() AppendSegment(ref span, HttpOnlyToken, null); } - if (Extensions != null) + foreach (var extension in Extensions) { - foreach (var extension in Extensions) - { - AppendSegment(ref span, extension, null); - } + AppendSegment(ref span, extension, null); } }); } @@ -300,12 +294,9 @@ public void AppendToStringBuilder(StringBuilder builder) AppendSegment(builder, HttpOnlyToken, null); } - if (Extensions != null) + foreach (var extension in Extensions) { - foreach (var extension in Extensions) - { - AppendSegment(builder, extension, null); - } + AppendSegment(builder, extension, null); } } @@ -425,7 +416,7 @@ private static int GetSetCookieLength(StringSegment input, int startIndex, out S { return 0; } - var dateString = ReadToSemicolonOrEnd(input, ref offset); + var dateString = ReadToSemicolonOrEnd(input, ref offset, false); DateTimeOffset expirationDate; if (!HttpRuleParser.TryStringToDate(dateString, out expirationDate)) { @@ -527,10 +518,6 @@ private static int GetSetCookieLength(StringSegment input, int startIndex, out S { var tokenStart = offset - itemLength; ReadToSemicolonOrEnd(input, ref offset, includeComma: true); - - if (result.Extensions == null) - result.Extensions = new List(); - result.Extensions.Add(input.Subsegment(tokenStart, offset - tokenStart)); } } @@ -550,20 +537,24 @@ private static bool ReadEqualsSign(StringSegment input, ref int offset) return true; } - private static StringSegment ReadToSemicolonOrEnd(StringSegment input, ref int offset, bool includeComma = false) + private static StringSegment ReadToSemicolonOrEnd(StringSegment input, ref int offset, bool includeComma = true) { var end = input.IndexOf(';', offset); if (end < 0) { // Also valid end of cookie if (includeComma) + { end = input.IndexOf(',', offset); + } } else if (includeComma) { var commaPosition = input.IndexOf(',', offset); if (commaPosition >= 0 && commaPosition < end) + { end = commaPosition; + } } if (end < 0) @@ -611,12 +602,9 @@ public override int GetHashCode() ^ SameSite.GetHashCode() ^ HttpOnly.GetHashCode(); - if (Extensions != null) + foreach (var extension in Extensions) { - foreach (var extension in Extensions) - { - hash ^= extension.GetHashCode(); - } + hash ^= extension.GetHashCode(); } return hash; From 5b530216fe420f621b0cb9f115b9ef685650ba82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Sat, 6 Jun 2020 22:28:18 +0200 Subject: [PATCH 08/10] Update ref --- src/Http/Headers/ref/Microsoft.Net.Http.Headers.netcoreapp.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Http/Headers/ref/Microsoft.Net.Http.Headers.netcoreapp.cs b/src/Http/Headers/ref/Microsoft.Net.Http.Headers.netcoreapp.cs index 8f0a8cd79ef2..6c319d5e77c0 100644 --- a/src/Http/Headers/ref/Microsoft.Net.Http.Headers.netcoreapp.cs +++ b/src/Http/Headers/ref/Microsoft.Net.Http.Headers.netcoreapp.cs @@ -329,7 +329,7 @@ public SetCookieHeaderValue(Microsoft.Extensions.Primitives.StringSegment name) public SetCookieHeaderValue(Microsoft.Extensions.Primitives.StringSegment name, Microsoft.Extensions.Primitives.StringSegment value) { } public Microsoft.Extensions.Primitives.StringSegment Domain { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } public System.DateTimeOffset? Expires { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } - public System.Collections.Generic.List Extensions { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } + public System.Collections.Generic.IList Extensions { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } public bool HttpOnly { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } public System.TimeSpan? MaxAge { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } public Microsoft.Extensions.Primitives.StringSegment Name { get { throw null; } set { } } From 47441de0cf44b5b65a6f5fb329579e16ad2b815b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Sat, 6 Jun 2020 22:29:31 +0200 Subject: [PATCH 09/10] Extend tests. Mainly check all possible combinations of SetCookieHeaders --- .../Headers/test/SetCookieHeaderValueTest.cs | 58 ++++++++++--------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/src/Http/Headers/test/SetCookieHeaderValueTest.cs b/src/Http/Headers/test/SetCookieHeaderValueTest.cs index 3b685a66f5cb..4e5a2b42d15a 100644 --- a/src/Http/Headers/test/SetCookieHeaderValueTest.cs +++ b/src/Http/Headers/test/SetCookieHeaderValueTest.cs @@ -4,8 +4,10 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net; using System.Text; using Microsoft.Extensions.Primitives; +using Moq; using Xunit; namespace Microsoft.Net.Http.Headers @@ -26,12 +28,9 @@ public static TheoryData SetCookieHeaderDataSet MaxAge = TimeSpan.FromDays(1), Path = "path1", Secure = true, - Extensions = new List() - { - "extension1", - "extension2=value" - } }; + header1.Extensions.Add("extension1"); + header1.Extensions.Add("extension2=value"); dataset.Add(header1, "name1=n1=v1&n2=v2&n3=v3; expires=Sun, 06 Nov 1994 08:49:37 GMT; max-age=86400; domain=domain1; path=path1; secure; samesite=strict; httponly; extension1; extension2=value"); var header2 = new SetCookieHeaderValue("name2", ""); @@ -65,14 +64,9 @@ public static TheoryData SetCookieHeaderDataSet }; dataset.Add(header7, "name7=value7; samesite=none"); - var header8 = new SetCookieHeaderValue("name8", "value8") - { - Extensions = new List() - { - "extension1", - "extension2=value" - } - }; + var header8 = new SetCookieHeaderValue("name8", "value8"); + header8.Extensions.Add("extension1"); + header8.Extensions.Add("extension2=value"); dataset.Add(header8, "name8=value8; extension1; extension2=value"); return dataset; @@ -139,13 +133,11 @@ public static TheoryData, string[]> ListOfSetCookieH HttpOnly = true, MaxAge = TimeSpan.FromDays(1), Path = "path1", - Secure = true, - Extensions = new List() - { - "extension1", - "extension2=value" - } + Secure = true }; + header1.Extensions.Add("extension1"); + header1.Extensions.Add("extension2=value"); + var string1 = "name1=n1=v1&n2=v2&n3=v3; expires=Sun, 06 Nov 1994 08:49:37 GMT; max-age=86400; domain=domain1; path=path1; secure; samesite=strict; httponly; extension1; extension2=value"; var header2 = new SetCookieHeaderValue("name2", "value2"); @@ -190,14 +182,9 @@ public static TheoryData, string[]> ListOfSetCookieH var string8a = "name8=value8; samesite"; var string8b = "name8=value8; samesite=invalid"; - var header9 = new SetCookieHeaderValue("name9", "value9") - { - Extensions = new List - { - "extension1", - "extension2=value" - } - }; + var header9 = new SetCookieHeaderValue("name9", "value9"); + header9.Extensions.Add("extension1"); + header9.Extensions.Add("extension2=value"); var string9 = "name9=value9; extension1; extension2=value"; @@ -218,6 +205,21 @@ public static TheoryData, string[]> ListOfSetCookieH dataset.Add(new[] { header8 }.ToList(), new[] { string8b }); dataset.Add(new[] { header9 }.ToList(), new[] { string9 }); + foreach (var item1 in SetCookieHeaderDataSet) + { + var pair_cookie1 = (SetCookieHeaderValue)item1[0]; + var pair_string1 = item1[1].ToString(); + + foreach (var item2 in SetCookieHeaderDataSet) + { + var pair_cookie2 = (SetCookieHeaderValue)item2[0]; + var pair_string2 = item2[1].ToString(); + + dataset.Add(new[] { pair_cookie1, pair_cookie2 }.ToList(), new[] { string.Join(", ", pair_string1, pair_string2) }); + + } + } + return dataset; } } @@ -466,7 +468,7 @@ public void SetCookieHeaderValue_TryParseList_ExcludesInvalidValues(IList cookies, + IList cookies, #pragma warning restore xUnit1026 // Theory methods should use all of their parameters string[] input) { From f1f12a731fcbb275a2c5f17bf5da6f7a3c3e4144 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Sat, 6 Jun 2020 22:31:58 +0200 Subject: [PATCH 10/10] Comment of special case --- src/Http/Headers/src/SetCookieHeaderValue.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Http/Headers/src/SetCookieHeaderValue.cs b/src/Http/Headers/src/SetCookieHeaderValue.cs index f86252c74a08..ce71f21d78dc 100644 --- a/src/Http/Headers/src/SetCookieHeaderValue.cs +++ b/src/Http/Headers/src/SetCookieHeaderValue.cs @@ -416,7 +416,8 @@ private static int GetSetCookieLength(StringSegment input, int startIndex, out S { return 0; } - var dateString = ReadToSemicolonOrEnd(input, ref offset, false); + // We don't want to include comma, becouse date may contain it (eg. Sun, 06 Nov...) + var dateString = ReadToSemicolonOrEnd(input, ref offset, includeComma: false); DateTimeOffset expirationDate; if (!HttpRuleParser.TryStringToDate(dateString, out expirationDate)) {