Skip to content

Commit 6eed9e8

Browse files
committed
Add PersistentState
1 parent 9047c89 commit 6eed9e8

File tree

5 files changed

+44
-3
lines changed

5 files changed

+44
-3
lines changed

src/Servers/Connections.Abstractions/src/ConnectionContext.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
5+
using System.Collections.Generic;
56
using System.IO.Pipelines;
67
using Microsoft.AspNetCore.Connections.Features;
78

@@ -12,6 +13,30 @@ namespace Microsoft.AspNetCore.Connections
1213
/// </summary>
1314
public abstract class ConnectionContext : BaseConnectionContext, IAsyncDisposable
1415
{
16+
internal IDictionary<object, object?>? _persistentState;
17+
18+
/// <summary>
19+
/// Gets or sets a key/value collection that can be used to persist state between connections.
20+
/// Whether a transport pools and reuses <see cref="ConnectionContext"/> instances and allows state to
21+
/// be persisted depends on the transport implementation.
22+
/// <para>
23+
/// Because values added to persistent state can live in memory until a <see cref="ConnectionContext"/>
24+
/// is no longer pooled, use caution with this collection to avoid excessive memory use.
25+
/// </para>
26+
/// </summary>
27+
public virtual IDictionary<object, object?> PersistentState
28+
{
29+
get
30+
{
31+
// Lazily allocate connection metadata
32+
return _persistentState ?? (_persistentState = new ConnectionItems());
33+
}
34+
set
35+
{
36+
_persistentState = value;
37+
}
38+
}
39+
1540
/// <summary>
1641
/// Gets or sets the <see cref="IDuplexPipe"/> that can be used to read or write data on this connection.
1742
/// </summary>

src/Servers/Connections.Abstractions/src/PublicAPI.Unshipped.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,5 @@ Microsoft.AspNetCore.Connections.MultiplexedConnectionContext.MultiplexedConnect
2525
Microsoft.AspNetCore.Connections.MultiplexedConnectionDelegate
2626
abstract Microsoft.AspNetCore.Connections.MultiplexedConnectionContext.AcceptAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask<Microsoft.AspNetCore.Connections.ConnectionContext?>
2727
abstract Microsoft.AspNetCore.Connections.MultiplexedConnectionContext.ConnectAsync(Microsoft.AspNetCore.Http.Features.IFeatureCollection? features = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask<Microsoft.AspNetCore.Connections.ConnectionContext!>
28+
virtual Microsoft.AspNetCore.Connections.ConnectionContext.PersistentState.get -> System.Collections.Generic.IDictionary<object!, object?>!
29+
virtual Microsoft.AspNetCore.Connections.ConnectionContext.PersistentState.set -> void

src/Servers/Kestrel/Core/src/Internal/Http3/Http3Connection.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http3
2323
{
2424
internal class Http3Connection : IHttp3StreamLifetimeHandler, IRequestProcessor
2525
{
26+
private static readonly object StreamPersistentStateKey = new object();
27+
2628
// Internal for unit testing
2729
internal readonly Dictionary<long, IHttp3Stream> _streams = new Dictionary<long, IHttp3Stream>();
2830
internal IHttp3StreamLifetimeHandler _streamLifetimeHandler;
@@ -270,16 +272,18 @@ public async Task ProcessRequestsAsync<TContext>(IHttpApplication<TContext> appl
270272
// Request stream
271273
UpdateHighestStreamId(streamIdFeature.StreamId);
272274

275+
Http3Stream<TContext> stream;
276+
273277
// Check whether there is an existing HTTP/3 stream on the transport stream.
274278
// A stream will only be cached if the transport stream itself is reused.
275-
var stream = streamContext.Features.Get<ICachedHttp3StreamFeature<TContext>>()?.CachedStream;
276-
if (stream == null)
279+
if (!streamContext.PersistentState.TryGetValue(StreamPersistentStateKey, out var s))
277280
{
278281
stream = new Http3Stream<TContext>(application, CreateHttpStreamContext(streamContext));
279-
streamContext.Features.Set<ICachedHttp3StreamFeature<TContext>>(new DefaultCachedHttp3StreamFeature<TContext>(stream));
282+
streamContext.PersistentState.Add(StreamPersistentStateKey, stream);
280283
}
281284
else
282285
{
286+
stream = (Http3Stream<TContext>)s!;
283287
stream.InitializeWithExistingContext(streamContext.Transport);
284288
}
285289

src/Servers/Kestrel/Transport.Quic/src/Internal/QuicConnectionContext.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,11 @@ public override void Abort(ConnectionAbortedException abortReason)
9494
{
9595
context = new QuicStreamContext(this, _context);
9696
}
97+
else
98+
{
99+
context.ResetFeatureCollection();
100+
context.ResetItems();
101+
}
97102

98103
context.Initialize(stream);
99104
context.Start();

src/Servers/Kestrel/shared/TransportConnection.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ public override string ConnectionId
5454
}
5555
}
5656

57+
internal void ResetItems()
58+
{
59+
_items?.Clear();
60+
}
61+
5762
public override CancellationToken ConnectionClosed { get; set; }
5863

5964
// DO NOT remove this override to ConnectionContext.Abort. Doing so would cause

0 commit comments

Comments
 (0)