Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
dd27d36
Update dependencies from https://dev.azure.com/dnceng/internal/_git/d…
dotnet-bot May 20, 2025
8d460db
Merge commit '0542b041117341e0c85341f75ba068cc57204964'
Jun 4, 2025
341cea8
Resolve conflicts
wtgodbe Jun 4, 2025
c563c3f
Merged PR 50632: [release/9.0] Merge from public
wtgodbe Jun 4, 2025
8e3e42f
Update dependencies from https://dev.azure.com/dnceng/internal/_git/d…
dotnet-bot Jun 5, 2025
e0694e1
Update dependencies from https://dev.azure.com/dnceng/internal/_git/d…
dotnet-bot Jun 5, 2025
e021ea6
Update dependencies from https://dev.azure.com/dnceng/internal/_git/d…
dotnet-bot Jun 5, 2025
d36c5c6
Merged PR 50151: Harden Cookie parsing
BrennanConroy Jun 6, 2025
f6dd0fa
Merge commit '543d8e329fee0d36e19562d03eef14344fddb6a7'
Jun 6, 2025
a968a8d
Merge commit '8315d8e1173fd6ca2d1574979ce45d09c0b801d1'
Jun 9, 2025
503aa88
Merge commit 'bd99997ac72930d857dfd5feb89c143ab31d22d8'
Jun 9, 2025
9b05cef
Update dependencies from https://dev.azure.com/dnceng/internal/_git/d…
dotnet-bot Jun 11, 2025
7381ec7
Update dependencies from https://dev.azure.com/dnceng/internal/_git/d…
dotnet-bot Jun 11, 2025
4d98e62
Update dependencies from https://dev.azure.com/dnceng/internal/_git/d…
dotnet-bot Jun 11, 2025
3720a89
Merge commit 'd4f69475669276aa2b67ba90a61fcaa39d7ef13a'
Jun 11, 2025
4b18c4b
Update dependencies from https://dev.azure.com/dnceng/internal/_git/d…
dotnet-bot Jun 12, 2025
ff2da1a
Merged PR 50253: [internal/release/9.0] Update dependencies from dnce…
Jun 12, 2025
0484e26
Update dependencies from https://dev.azure.com/dnceng/internal/_git/d…
dotnet-bot Jun 16, 2025
634d576
Update dependencies from https://dev.azure.com/dnceng/internal/_git/d…
dotnet-bot Jun 17, 2025
c6213af
Update dependencies from https://dev.azure.com/dnceng/internal/_git/d…
dotnet-bot Jun 17, 2025
f6b3a5d
Merged PR 50934: [internal/release/9.0] Update dependencies from dnce…
Jun 17, 2025
1100019
Merge commit 'f6b3a5da75eb405046889a5447ec9b14cc29d285' into internal…
vseanreesermsft Jul 8, 2025
52895e9
Update baseline, SDK
wtgodbe Jul 8, 2025
f432909
Merge branch 'release/9.0' into internal-merge-9.0-2025-07-08-1439
wtgodbe Jul 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions NuGet.config
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
<clear />
<!--Begin: Package sources managed by Dependency Flow automation. Do not edit the sources below.-->
<!-- Begin: Package sources from dotnet-runtime -->
<add key="darc-int-dotnet-runtime-3c298d9" value="https://pkgs.dev.azure.com/dnceng/internal/_packaging/darc-int-dotnet-runtime-3c298d9f/nuget/v3/index.json" />
<!-- End: Package sources from dotnet-runtime -->
<!-- Begin: Package sources from dotnet-efcore -->
<add key="darc-int-dotnet-efcore-67d253c" value="https://pkgs.dev.azure.com/dnceng/internal/_packaging/darc-int-dotnet-efcore-67d253c1/nuget/v3/index.json" />
<!-- End: Package sources from dotnet-efcore -->
<!--End: Package sources managed by Dependency Flow automation. Do not edit the sources above.-->
<add key="dotnet-eng" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json" />
Expand All @@ -28,8 +30,10 @@
<clear />
<!--Begin: Package sources managed by Dependency Flow automation. Do not edit the sources below.-->
<!-- Begin: Package sources from dotnet-efcore -->
<add key="darc-int-dotnet-efcore-67d253c" value="true" />
<!-- End: Package sources from dotnet-efcore -->
<!-- Begin: Package sources from dotnet-runtime -->
<add key="darc-int-dotnet-runtime-3c298d9" value="true" />
<!-- End: Package sources from dotnet-runtime -->
<!--End: Package sources managed by Dependency Flow automation. Do not edit the sources above.-->
</disabledPackageSources>
Expand Down
776 changes: 388 additions & 388 deletions eng/Baseline.Designer.props

Large diffs are not rendered by default.

212 changes: 106 additions & 106 deletions eng/Baseline.xml

Large diffs are not rendered by default.

320 changes: 160 additions & 160 deletions eng/Version.Details.xml

Large diffs are not rendered by default.

162 changes: 81 additions & 81 deletions eng/Versions.props

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions global.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"sdk": {
"version": "9.0.107"
"version": "9.0.108"
},
"tools": {
"dotnet": "9.0.107",
"dotnet": "9.0.108",
"runtimes": {
"dotnet/x86": [
"$(MicrosoftNETCoreBrowserDebugHostTransportVersion)"
Expand Down
36 changes: 24 additions & 12 deletions src/Http/Headers/test/CookieHeaderValueTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public static TheoryData<string> InvalidCookieValues
}
}

public static TheoryData<IList<CookieHeaderValue>, string?[]> ListOfCookieHeaderDataSet
public static TheoryData<IList<CookieHeaderValue>, string?[]> ListOfStrictCookieHeaderDataSet
{
get
{
Expand All @@ -94,19 +94,30 @@ public static TheoryData<string> InvalidCookieValues

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 });
dataset.Add(new[] { header2 }.ToList(), new[] { string2 });
dataset.Add(new[] { header1, header2 }.ToList(), new[] { string1, string2 });
dataset.Add(new[] { header1, header2 }.ToList(), new[] { string1 + ", " + string2 });
dataset.Add(new[] { header2, header1 }.ToList(), new[] { string2 + "; " + string1 });
dataset.Add(new[] { header1, header2, header3, header4 }.ToList(), new[] { string1, string2, string3, string4 });
dataset.Add(new[] { header1, header2, header3, header4 }.ToList(), new[] { string.Join(",", string1, string2, string3, string4) });
dataset.Add(new[] { header1, header2, header3, header4 }.ToList(), new[] { string.Join(";", string1, string2, string3, string4) });

return dataset;
}
}

public static TheoryData<IList<CookieHeaderValue>, string?[]> ListOfCookieHeaderDataSet
{
get
{
var header1 = new CookieHeaderValue("name1", "n1=v1&n2=v2&n3=v3");
var string1 = "name1=n1=v1&n2=v2&n3=v3";

var dataset = new TheoryData<IList<CookieHeaderValue>, string?[]>();
dataset.Concat(ListOfStrictCookieHeaderDataSet);
dataset.Add(new[] { header1, header1 }.ToList(), new[] { string1, null, "", " ", ";", " , ", string1 });
return dataset;
}
}

public static TheoryData<IList<CookieHeaderValue>?, string?[]> ListWithInvalidCookieHeaderDataSet
{
get
Expand All @@ -127,18 +138,19 @@ public static TheoryData<string> InvalidCookieValues
dataset.Add(new[] { header1 }.ToList(), new[] { validString1, invalidString1 });
dataset.Add(new[] { header1 }.ToList(), new[] { validString1, null, "", " ", ";", " , ", invalidString1 });
dataset.Add(new[] { header1 }.ToList(), new[] { invalidString1, null, "", " ", ";", " , ", validString1 });
dataset.Add(new[] { header1 }.ToList(), new[] { validString1 + ", " + invalidString1 });
dataset.Add(new[] { header2 }.ToList(), new[] { invalidString1 + ", " + validString2 });
dataset.Add(null, new[] { validString1 + ", " });
dataset.Add(null, new[] { invalidString1 + ", " + validString2 });
dataset.Add(new[] { header1 }.ToList(), new[] { invalidString1 + "; " + validString1 });
dataset.Add(new[] { header2 }.ToList(), new[] { validString2 + "; " + invalidString1 });
dataset.Add(new[] { header1, header2, header3 }.ToList(), new[] { invalidString1, validString1, validString2, validString3 });
dataset.Add(new[] { header1, header2, header3 }.ToList(), new[] { validString1, invalidString1, validString2, validString3 });
dataset.Add(new[] { header1, header2, header3 }.ToList(), new[] { validString1, validString2, invalidString1, validString3 });
dataset.Add(new[] { header1, header2, header3 }.ToList(), new[] { validString1, validString2, validString3, invalidString1 });
dataset.Add(new[] { header1, header2, header3 }.ToList(), new[] { string.Join(",", invalidString1, validString1, validString2, validString3) });
dataset.Add(new[] { header1, header2, header3 }.ToList(), new[] { string.Join(",", validString1, invalidString1, validString2, validString3) });
dataset.Add(new[] { header1, header2, header3 }.ToList(), new[] { string.Join(",", validString1, validString2, invalidString1, validString3) });
dataset.Add(new[] { header1, header2, header3 }.ToList(), new[] { string.Join(",", validString1, validString2, validString3, invalidString1) });
dataset.Add(null, new[] { string.Join(",", invalidString1, validString1, validString2, validString3) });
dataset.Add(null, new[] { string.Join(",", validString1, invalidString1, validString2, validString3) });
dataset.Add(null, new[] { string.Join(",", validString1, validString2, invalidString1, validString3) });
dataset.Add(null, new[] { string.Join(",", validString1, validString2, validString3, invalidString1) });
dataset.Add(null, new[] { string.Join(",", validString1, validString2, validString3) });
dataset.Add(new[] { header1, header2, header3 }.ToList(), new[] { string.Join(";", invalidString1, validString1, validString2, validString3) });
dataset.Add(new[] { header1, header2, header3 }.ToList(), new[] { string.Join(";", validString1, invalidString1, validString2, validString3) });
dataset.Add(new[] { header1, header2, header3 }.ToList(), new[] { string.Join(";", validString1, validString2, invalidString1, validString3) });
Expand Down Expand Up @@ -248,7 +260,7 @@ public void CookieHeaderValue_ParseList_AcceptsValidValues(IList<CookieHeaderVal
}

[Theory]
[MemberData(nameof(ListOfCookieHeaderDataSet))]
[MemberData(nameof(ListOfStrictCookieHeaderDataSet))]
public void CookieHeaderValue_ParseStrictList_AcceptsValidValues(IList<CookieHeaderValue> cookies, string[] input)
{
var results = CookieHeaderValue.ParseStrictList(input);
Expand All @@ -267,7 +279,7 @@ public void CookieHeaderValue_TryParseList_AcceptsValidValues(IList<CookieHeader
}

[Theory]
[MemberData(nameof(ListOfCookieHeaderDataSet))]
[MemberData(nameof(ListOfStrictCookieHeaderDataSet))]
public void CookieHeaderValue_TryParseStrictList_AcceptsValidValues(IList<CookieHeaderValue> cookies, string[] input)
{
var result = CookieHeaderValue.TryParseStrictList(input, out var results);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ public void GetListT_StringWithQualityHeaderValidValue_Success()
public void GetListT_CookieHeaderValue_Success()
{
var context = new DefaultHttpContext();
context.Request.Headers.Cookie = "cookie1=a,cookie2=b";
context.Request.Headers.Cookie = "cookie1=a;cookie2=b";

var result = context.Request.GetTypedHeaders().GetList<CookieHeaderValue>(HeaderNames.Cookie);

Expand Down
13 changes: 10 additions & 3 deletions src/Http/Http/test/RequestCookiesCollectionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,18 @@ public void ParseManyCookies()
[Theory]
[InlineData(",", null)]
[InlineData(";", null)]
[InlineData("er=dd,cc,bb", new[] { "dd" })]
[InlineData("er=dd,err=cc,errr=bb", new[] { "dd", "cc", "bb" })]
[InlineData("errorcookie=dd,:(\"sa;", new[] { "dd" })]
[InlineData("er=dd,cc,bb", null)]
[InlineData("er=dd,err=cc,errr=bb", null)]
[InlineData("errorcookie=dd,:(\"sa;", null)]
[InlineData("s;", null)]
[InlineData("er=;,err=,errr=\\,errrr=\"", null)]
[InlineData("a@a=a;", null)]
[InlineData("a@ a=a;", null)]
[InlineData("a a=a;", null)]
[InlineData(",a=a;", null)]
[InlineData(",a=a", null)]
[InlineData("a=a;,b=b", new []{ "a" })] // valid cookie followed by invalid cookie
[InlineData(",a=a;b=b", new[] { "b" })] // invalid cookie followed by valid cookie
public void ParseInvalidCookies(string cookieToParse, string[] expectedCookieValues)
{
var cookies = RequestCookieCollection.Parse(new StringValues(new[] { cookieToParse }));
Expand Down
40 changes: 37 additions & 3 deletions src/Http/Shared/CookieHeaderParserShared.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,17 @@ public static bool TryParseValue(StringSegment value, ref int index, bool suppor

if (!TryGetCookieLength(value, ref current, out parsedName, out parsedValue))
{
var separatorIndex = value.IndexOf(';', current);
if (separatorIndex > 0)
{
// Skip the invalid values and keep trying.
index = separatorIndex;
}
else
{
// No more separators, so we're done.
index = value.Length;
}
return false;
}

Expand All @@ -97,6 +108,17 @@ public static bool TryParseValue(StringSegment value, ref int index, bool suppor
// If we support multiple values and we've not reached the end of the string, then we must have a separator.
if ((separatorFound && !supportsMultipleValues) || (!separatorFound && (current < value.Length)))
{
var separatorIndex = value.IndexOf(';', current);
if (separatorIndex > 0)
{
// Skip the invalid values and keep trying.
index = separatorIndex;
}
else
{
// No more separators, so we're done.
index = value.Length;
}
return false;
}

Expand All @@ -112,7 +134,7 @@ private static int GetNextNonEmptyOrWhitespaceIndex(StringSegment input, int sta
separatorFound = false;
var current = startIndex + HttpRuleParser.GetWhitespaceLength(input, startIndex);

if ((current == input.Length) || (input[current] != ',' && input[current] != ';'))
if (current == input.Length || input[current] != ';')
{
return current;
}
Expand All @@ -125,8 +147,8 @@ private static int GetNextNonEmptyOrWhitespaceIndex(StringSegment input, int sta

if (skipEmptyValues)
{
// Most headers only split on ',', but cookies primarily split on ';'
while ((current < input.Length) && ((input[current] == ',') || (input[current] == ';')))
// Cookies are split on ';'
while (current < input.Length && input[current] == ';')
{
current++; // skip delimiter.
current = current + HttpRuleParser.GetWhitespaceLength(input, current);
Expand All @@ -136,6 +158,18 @@ private static int GetNextNonEmptyOrWhitespaceIndex(StringSegment input, int sta
return current;
}

/*
* https://www.rfc-editor.org/rfc/rfc6265#section-4.1.1
* cookie-pair = cookie-name "=" cookie-value
* cookie-name = token
* token = 1*<any CHAR except CTLs or separators>
separators = "(" | ")" | "<" | ">" | "@"
| "," | ";" | ":" | "\" | <">
| "/" | "[" | "]" | "?" | "="
| "{" | "}" | SP | HT
CTL = <any US-ASCII control character
(octets 0 - 31) and DEL (127)>
*/
// name=value; name="value"
internal static bool TryGetCookieLength(StringSegment input, ref int offset, [NotNullWhen(true)] out StringSegment? parsedName, [NotNullWhen(true)] out StringSegment? parsedValue)
{
Expand Down
Loading