Skip to content

Commit 3c228e5

Browse files
uabarahonaTratcher
andauthored
Optimizing ChunkingCookieManager (#31625)
* Adding initial refactor to improve perfromance on ChunkingCookieManager * Moving new API to correct file * Adding some interface implementation for tests * Addressing feedback given by asp.net team * Remove spaces * Changing to use readonlyspan * Adding DIM as discussion point * CollectionMarshal * Removing unnecesary implementations and fixing public api * Fixing public api for different targets * Addressing feedback from asp.net team * Update src/Http/Http.Features/src/IResponseCookies.cs Co-authored-by: Chris Ross <[email protected]>
1 parent 3489b86 commit 3c228e5

File tree

15 files changed

+811
-49
lines changed

15 files changed

+811
-49
lines changed

src/Http/Http.Features/src/IResponseCookies.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4+
#if NET6_0_OR_GREATER
5+
using System;
6+
using System.Collections.Generic;
7+
#endif
8+
49
namespace Microsoft.AspNetCore.Http
510
{
611
/// <summary>
@@ -23,6 +28,21 @@ public interface IResponseCookies
2328
/// <param name="options"><see cref="CookieOptions"/> included in the new cookie setting.</param>
2429
void Append(string key, string value, CookieOptions options);
2530

31+
#if NET6_0_OR_GREATER
32+
/// <summary>
33+
/// Add elements of specified collection as cookies.
34+
/// </summary>
35+
/// <param name="keyValuePairs">Key value pair collections whose elements will be added as cookies.</param>
36+
/// <param name="options"><see cref="CookieOptions"/> included in new cookie settings.</param>
37+
void Append(ReadOnlySpan<KeyValuePair<string, string>> keyValuePairs, CookieOptions options)
38+
{
39+
foreach (var keyValuePair in keyValuePairs)
40+
{
41+
Append(keyValuePair.Key, keyValuePair.Value, options);
42+
}
43+
}
44+
#endif
45+
2646
/// <summary>
2747
/// Sets an expired cookie.
2848
/// </summary>

src/Http/Http.Features/src/Microsoft.AspNetCore.Http.Features.csproj

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
44
<Description>ASP.NET Core HTTP feature interface definitions.</Description>
@@ -10,10 +10,14 @@
1010
<Nullable>enable</Nullable>
1111
</PropertyGroup>
1212

13-
1413
<ItemGroup>
1514
<Reference Include="Microsoft.Extensions.Primitives" />
1615
<Reference Include="System.IO.Pipelines" />
1716
</ItemGroup>
1817

18+
<ItemGroup>
19+
<AdditionalFiles Include="PublicAPI/$(TargetFramework)/PublicAPI.Shipped.txt" />
20+
<AdditionalFiles Include="PublicAPI/$(TargetFramework)/PublicAPI.Unshipped.txt" />
21+
</ItemGroup>
22+
1923
</Project>

src/Http/Http.Features/src/PublicAPI.Unshipped.txt renamed to src/Http/Http.Features/src/PublicAPI/net461/PublicAPI.Unshipped.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@ Microsoft.AspNetCore.Http.Features.IFeatureCollection.Get<TFeature>() -> TFeatur
1414
Microsoft.AspNetCore.Http.Features.IFeatureCollection.Set<TFeature>(TFeature? instance) -> void
1515
Microsoft.AspNetCore.Http.Features.IServerVariablesFeature.this[string! variableName].get -> string?
1616
Microsoft.AspNetCore.Http.ISession.TryGetValue(string! key, out byte[]? value) -> bool
17-
Microsoft.AspNetCore.Http.Features.FeatureCollection.FeatureCollection(int initialCapacity) -> void
17+
Microsoft.AspNetCore.Http.Features.FeatureCollection.FeatureCollection(int initialCapacity) -> void

src/Http/Http.Features/src/PublicAPI/net6.0/PublicAPI.Shipped.txt

Lines changed: 247 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#nullable enable
2+
*REMOVED*Microsoft.AspNetCore.Http.Features.FeatureCollection.Set<TFeature>(TFeature instance) -> void
3+
*REMOVED*Microsoft.AspNetCore.Http.Features.IFeatureCollection.Get<TFeature>() -> TFeature
4+
*REMOVED*Microsoft.AspNetCore.Http.Features.IFeatureCollection.Set<TFeature>(TFeature instance) -> void
5+
*REMOVED*Microsoft.AspNetCore.Http.Features.IHttpBufferingFeature
6+
*REMOVED*Microsoft.AspNetCore.Http.Features.IHttpBufferingFeature.DisableRequestBuffering() -> void
7+
*REMOVED*Microsoft.AspNetCore.Http.Features.IHttpBufferingFeature.DisableResponseBuffering() -> void
8+
*REMOVED*Microsoft.AspNetCore.Http.Features.IHttpSendFileFeature
9+
*REMOVED*Microsoft.AspNetCore.Http.Features.IHttpSendFileFeature.SendFileAsync(string! path, long offset, long? count, System.Threading.CancellationToken cancellation) -> System.Threading.Tasks.Task!
10+
*REMOVED*Microsoft.AspNetCore.Http.Features.IServerVariablesFeature.this[string! variableName].get -> string!
11+
*REMOVED*Microsoft.AspNetCore.Http.ISession.TryGetValue(string! key, out byte[]! value) -> bool
12+
Microsoft.AspNetCore.Http.Features.FeatureCollection.Set<TFeature>(TFeature? instance) -> void
13+
Microsoft.AspNetCore.Http.Features.IFeatureCollection.Get<TFeature>() -> TFeature?
14+
Microsoft.AspNetCore.Http.Features.IFeatureCollection.Set<TFeature>(TFeature? instance) -> void
15+
Microsoft.AspNetCore.Http.Features.IServerVariablesFeature.this[string! variableName].get -> string?
16+
Microsoft.AspNetCore.Http.ISession.TryGetValue(string! key, out byte[]? value) -> bool
17+
Microsoft.AspNetCore.Http.Features.FeatureCollection.FeatureCollection(int initialCapacity) -> void
18+
Microsoft.AspNetCore.Http.IResponseCookies.Append(System.ReadOnlySpan<System.Collections.Generic.KeyValuePair<string!, string!>> keyValuePairs, Microsoft.AspNetCore.Http.CookieOptions! options) -> void

src/Http/Http.Features/src/PublicAPI/netstandard2.0/PublicAPI.Shipped.txt

Lines changed: 247 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#nullable enable
2+
*REMOVED*Microsoft.AspNetCore.Http.Features.FeatureCollection.Set<TFeature>(TFeature instance) -> void
3+
*REMOVED*Microsoft.AspNetCore.Http.Features.IFeatureCollection.Get<TFeature>() -> TFeature
4+
*REMOVED*Microsoft.AspNetCore.Http.Features.IFeatureCollection.Set<TFeature>(TFeature instance) -> void
5+
*REMOVED*Microsoft.AspNetCore.Http.Features.IHttpBufferingFeature
6+
*REMOVED*Microsoft.AspNetCore.Http.Features.IHttpBufferingFeature.DisableRequestBuffering() -> void
7+
*REMOVED*Microsoft.AspNetCore.Http.Features.IHttpBufferingFeature.DisableResponseBuffering() -> void
8+
*REMOVED*Microsoft.AspNetCore.Http.Features.IHttpSendFileFeature
9+
*REMOVED*Microsoft.AspNetCore.Http.Features.IHttpSendFileFeature.SendFileAsync(string! path, long offset, long? count, System.Threading.CancellationToken cancellation) -> System.Threading.Tasks.Task!
10+
*REMOVED*Microsoft.AspNetCore.Http.Features.IServerVariablesFeature.this[string! variableName].get -> string!
11+
*REMOVED*Microsoft.AspNetCore.Http.ISession.TryGetValue(string! key, out byte[]! value) -> bool
12+
Microsoft.AspNetCore.Http.Features.FeatureCollection.Set<TFeature>(TFeature? instance) -> void
13+
Microsoft.AspNetCore.Http.Features.IFeatureCollection.Get<TFeature>() -> TFeature?
14+
Microsoft.AspNetCore.Http.Features.IFeatureCollection.Set<TFeature>(TFeature? instance) -> void
15+
Microsoft.AspNetCore.Http.Features.IServerVariablesFeature.this[string! variableName].get -> string?
16+
Microsoft.AspNetCore.Http.ISession.TryGetValue(string! key, out byte[]? value) -> bool
17+
Microsoft.AspNetCore.Http.Features.FeatureCollection.FeatureCollection(int initialCapacity) -> void

src/Http/Http/src/Internal/ResponseCookies.cs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,57 @@ public void Append(string key, string value, CookieOptions options)
8888
Headers[HeaderNames.SetCookie] = StringValues.Concat(Headers[HeaderNames.SetCookie], cookieValue);
8989
}
9090

91+
/// <inheritdoc />
92+
public void Append(ReadOnlySpan<KeyValuePair<string, string>> keyValuePairs, CookieOptions options)
93+
{
94+
if (options == null)
95+
{
96+
throw new ArgumentNullException(nameof(options));
97+
}
98+
99+
// SameSite=None cookies must be marked as Secure.
100+
if (!options.Secure && options.SameSite == SameSiteMode.None)
101+
{
102+
if (_logger == null)
103+
{
104+
var services = _features.Get<IServiceProvidersFeature>()?.RequestServices;
105+
_logger = services?.GetService<ILogger<ResponseCookies>>();
106+
}
107+
108+
if (_logger != null)
109+
{
110+
foreach (var keyValuePair in keyValuePairs)
111+
{
112+
Log.SameSiteCookieNotSecure(_logger, keyValuePair.Key);
113+
}
114+
}
115+
}
116+
117+
var setCookieHeaderValue = new SetCookieHeaderValue(string.Empty)
118+
{
119+
Domain = options.Domain,
120+
Path = options.Path,
121+
Expires = options.Expires,
122+
MaxAge = options.MaxAge,
123+
Secure = options.Secure,
124+
SameSite = (Net.Http.Headers.SameSiteMode)options.SameSite,
125+
HttpOnly = options.HttpOnly
126+
};
127+
128+
var cookierHeaderValue = setCookieHeaderValue.ToString()[1..];
129+
var cookies = new string[keyValuePairs.Length];
130+
var position = 0;
131+
132+
foreach (var keyValuePair in keyValuePairs)
133+
{
134+
var key = _enableCookieNameEncoding ? Uri.EscapeDataString(keyValuePair.Key) : keyValuePair.Key;
135+
cookies[position] = string.Concat(key, "=", Uri.EscapeDataString(keyValuePair.Value), cookierHeaderValue);
136+
position++;
137+
}
138+
139+
Headers.Append(HeaderNames.SetCookie, cookies);
140+
}
141+
91142
/// <inheritdoc />
92143
public void Delete(string key)
93144
{

src/Mvc/Mvc.ViewFeatures/test/CookieTempDataProviderTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -501,4 +501,4 @@ public override byte[] Serialize(IDictionary<string, object> values)
501501
}
502502
}
503503
}
504-
}
504+
}

0 commit comments

Comments
 (0)