Skip to content

Commit d621150

Browse files
authored
Merge pull request #43534 from dotnet-maestro-bot/merge/release/7.0-rc1-to-release/7.0
[automated] Merge branch 'release/7.0-rc1' => 'release/7.0'
2 parents 662fa48 + c2f01e4 commit d621150

File tree

14 files changed

+114
-46
lines changed

14 files changed

+114
-46
lines changed

src/Grpc/JsonTranscoding/src/Microsoft.AspNetCore.Grpc.Swagger/Microsoft.AspNetCore.Grpc.Swagger.csproj

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33
<Description>Swagger for gRPC ASP.NET Core</Description>
44
<PackageTags>gRPC RPC HTTP/2 REST Swagger OpenAPI</PackageTags>
55
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
6-
<IsPackable>false</IsPackable>
7-
<IsShipping>false</IsShipping>
6+
<VersionPrefix>$(ExperimentalVersionPrefix)</VersionPrefix>
87
</PropertyGroup>
98

109
<ItemGroup>

src/Middleware/RateLimiting/src/LeaseContext.cs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,19 @@ namespace Microsoft.AspNetCore.RateLimiting;
77

88
internal struct LeaseContext : IDisposable
99
{
10-
public bool? GlobalRejected { get; init; }
10+
public RequestRejectionReason? RequestRejectionReason { get; init; }
1111

12-
public required RateLimitLease Lease { get; init; }
12+
public RateLimitLease? Lease { get; init; }
1313

1414
public void Dispose()
1515
{
16-
Lease.Dispose();
16+
Lease?.Dispose();
1717
}
1818
}
19+
20+
internal enum RequestRejectionReason
21+
{
22+
EndpointLimiter,
23+
GlobalLimiter,
24+
RequestCanceled
25+
}

src/Middleware/RateLimiting/src/RateLimitingMiddleware.cs

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -78,20 +78,25 @@ public Task Invoke(HttpContext context)
7878
private async Task InvokeInternal(HttpContext context, EnableRateLimitingAttribute? enableRateLimitingAttribute)
7979
{
8080
using var leaseContext = await TryAcquireAsync(context);
81-
if (leaseContext.Lease.IsAcquired)
81+
if (leaseContext.Lease?.IsAcquired == true)
8282
{
8383
await _next(context);
8484
}
8585
else
8686
{
87+
// If the request was canceled, do not call OnRejected, just return.
88+
if (leaseContext.RequestRejectionReason == RequestRejectionReason.RequestCanceled)
89+
{
90+
return;
91+
}
8792
var thisRequestOnRejected = _defaultOnRejected;
8893
RateLimiterLog.RequestRejectedLimitsExceeded(_logger);
8994
// OnRejected "wins" over DefaultRejectionStatusCode - we set DefaultRejectionStatusCode first,
9095
// then call OnRejected in case it wants to do any further modification of the status code.
9196
context.Response.StatusCode = _rejectionStatusCode;
9297

9398
// If this request was rejected by the endpoint limiter, use its OnRejected if available.
94-
if (leaseContext.GlobalRejected == false)
99+
if (leaseContext.RequestRejectionReason == RequestRejectionReason.EndpointLimiter)
95100
{
96101
DefaultRateLimiterPolicy? policy;
97102
// Use custom policy OnRejected if available, else use OnRejected from the Options if available.
@@ -111,15 +116,16 @@ private async Task InvokeInternal(HttpContext context, EnableRateLimitingAttribu
111116
}
112117
if (thisRequestOnRejected is not null)
113118
{
114-
await thisRequestOnRejected(new OnRejectedContext() { HttpContext = context, Lease = leaseContext.Lease }, context.RequestAborted);
119+
// leaseContext.Lease will only be null when the request was canceled.
120+
await thisRequestOnRejected(new OnRejectedContext() { HttpContext = context, Lease = leaseContext.Lease! }, context.RequestAborted);
115121
}
116122
}
117123
}
118124

119125
private ValueTask<LeaseContext> TryAcquireAsync(HttpContext context)
120126
{
121127
var leaseContext = CombinedAcquire(context);
122-
if (leaseContext.Lease.IsAcquired)
128+
if (leaseContext.Lease?.IsAcquired == true)
123129
{
124130
return ValueTask.FromResult(leaseContext);
125131
}
@@ -139,14 +145,14 @@ private LeaseContext CombinedAcquire(HttpContext context)
139145
globalLease = _globalLimiter.AttemptAcquire(context);
140146
if (!globalLease.IsAcquired)
141147
{
142-
return new LeaseContext() { GlobalRejected = true, Lease = globalLease };
148+
return new LeaseContext() { RequestRejectionReason = RequestRejectionReason.GlobalLimiter, Lease = globalLease };
143149
}
144150
}
145151
endpointLease = _endpointLimiter.AttemptAcquire(context);
146152
if (!endpointLease.IsAcquired)
147153
{
148154
globalLease?.Dispose();
149-
return new LeaseContext() { GlobalRejected = false, Lease = endpointLease };
155+
return new LeaseContext() { RequestRejectionReason = RequestRejectionReason.EndpointLimiter, Lease = endpointLease };
150156
}
151157
}
152158
catch (Exception)
@@ -170,21 +176,30 @@ private async ValueTask<LeaseContext> CombinedWaitAsync(HttpContext context, Can
170176
globalLease = await _globalLimiter.AcquireAsync(context, cancellationToken: cancellationToken);
171177
if (!globalLease.IsAcquired)
172178
{
173-
return new LeaseContext() { GlobalRejected = true, Lease = globalLease };
179+
return new LeaseContext() { RequestRejectionReason = RequestRejectionReason.GlobalLimiter, Lease = globalLease };
174180
}
175181
}
176182
endpointLease = await _endpointLimiter.AcquireAsync(context, cancellationToken: cancellationToken);
177183
if (!endpointLease.IsAcquired)
178184
{
179185
globalLease?.Dispose();
180-
return new LeaseContext() { GlobalRejected = false, Lease = endpointLease };
186+
return new LeaseContext() { RequestRejectionReason = RequestRejectionReason.EndpointLimiter, Lease = endpointLease };
181187
}
182188
}
183-
catch (Exception)
189+
catch (Exception ex)
184190
{
185191
endpointLease?.Dispose();
186192
globalLease?.Dispose();
187-
throw;
193+
// Don't throw if the request was canceled - instead log.
194+
if (ex is OperationCanceledException && context.RequestAborted.IsCancellationRequested)
195+
{
196+
RateLimiterLog.RequestCanceled(_logger);
197+
return new LeaseContext() { RequestRejectionReason = RequestRejectionReason.RequestCanceled };
198+
}
199+
else
200+
{
201+
throw;
202+
}
188203
}
189204

190205
return globalLease is null ? new LeaseContext() { Lease = endpointLease } : new LeaseContext() { Lease = new DefaultCombinedLease(globalLease, endpointLease) };
@@ -234,5 +249,8 @@ private static partial class RateLimiterLog
234249

235250
[LoggerMessage(2, LogLevel.Debug, "This endpoint requires a rate limiting policy with name {PolicyName}, but no such policy exists.", EventName = "WarnMissingPolicy")]
236251
internal static partial void WarnMissingPolicy(ILogger logger, string policyName);
252+
253+
[LoggerMessage(3, LogLevel.Debug, "The request was canceled.", EventName = "RequestCanceled")]
254+
internal static partial void RequestCanceled(ILogger logger);
237255
}
238-
}
256+
}

src/Middleware/RateLimiting/test/RateLimitingMiddlewareTests.cs

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@
66
using Microsoft.AspNetCore.Testing;
77
using Microsoft.Extensions.Logging;
88
using Microsoft.Extensions.Logging.Abstractions;
9+
using Microsoft.Extensions.Logging.Testing;
910
using Microsoft.Extensions.Options;
1011
using Moq;
1112

1213
namespace Microsoft.AspNetCore.RateLimiting;
1314

14-
public class RateLimitingMiddlewareTests : LoggedTest
15+
public class RateLimitingMiddlewareTests
1516
{
1617
[Fact]
1718
public void Ctor_ThrowsExceptionsWhenNullArgs()
@@ -115,22 +116,35 @@ public async Task RequestRejected_WinsOverDefaultStatusCode()
115116
}
116117

117118
[Fact]
118-
public async Task RequestAborted_ThrowsTaskCanceledException()
119+
public async Task RequestAborted_DoesNotThrowTaskCanceledException()
119120
{
121+
var sink = new TestSink(
122+
TestSink.EnableWithTypeName<RateLimitingMiddleware>,
123+
TestSink.EnableWithTypeName<RateLimitingMiddleware>);
124+
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
125+
120126
var options = CreateOptionsAccessor();
121127
options.Value.GlobalLimiter = new TestPartitionedRateLimiter<HttpContext>(new TestRateLimiter(false));
122128

123129
var middleware = new RateLimitingMiddleware(c =>
124130
{
125131
return Task.CompletedTask;
126132
},
127-
new NullLoggerFactory().CreateLogger<RateLimitingMiddleware>(),
133+
loggerFactory.CreateLogger<RateLimitingMiddleware>(),
128134
options,
129135
Mock.Of<IServiceProvider>());
130136

131137
var context = new DefaultHttpContext();
132138
context.RequestAborted = new CancellationToken(true);
133-
await Assert.ThrowsAsync<TaskCanceledException>(() => middleware.Invoke(context)).DefaultTimeout();
139+
await middleware.Invoke(context);
140+
Assert.Equal(StatusCodes.Status200OK, context.Response.StatusCode);
141+
142+
var logMessages = sink.Writes.ToList();
143+
144+
Assert.Single(logMessages);
145+
var message = logMessages.First();
146+
Assert.Equal(LogLevel.Debug, message.LogLevel);
147+
Assert.Equal("The request was canceled.", message.State.ToString());
134148
}
135149

136150
[Fact]
@@ -609,4 +623,4 @@ public async Task MultipleEndpointPolicies_LastOneWins()
609623

610624
private IOptions<RateLimiterOptions> CreateOptionsAccessor() => Options.Create(new RateLimiterOptions());
611625

612-
}
626+
}

src/Security/Authorization/Core/src/DefaultAuthorizationPolicyProvider.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,6 @@ public Task<AuthorizationPolicy> GetDefaultPolicyAsync()
7676
/// <summary>
7777
/// Determines if policies from this provider can be cached, which is true only for this type.
7878
/// </summary>
79-
public virtual bool CanCachePolicy => GetType() == typeof(DefaultAuthorizationPolicyProvider);
79+
public virtual bool AllowsCachingPolicies => GetType() == typeof(DefaultAuthorizationPolicyProvider);
8080
#endif
8181
}

src/Security/Authorization/Core/src/IAuthorizationPolicyProvider.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,6 @@ public interface IAuthorizationPolicyProvider
3333
/// <summary>
3434
/// Determines if policies from this provider can be cached, defaults to false.
3535
/// </summary>
36-
bool CanCachePolicy => false;
36+
bool AllowsCachingPolicies => false;
3737
#endif
3838
}

src/Security/Authorization/Core/src/PublicAPI/net7.0/PublicAPI.Unshipped.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#nullable enable
22
Microsoft.AspNetCore.Authorization.AuthorizationBuilder
33
Microsoft.AspNetCore.Authorization.AuthorizationBuilder.AuthorizationBuilder(Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> void
4-
Microsoft.AspNetCore.Authorization.IAuthorizationPolicyProvider.CanCachePolicy.get -> bool
4+
Microsoft.AspNetCore.Authorization.IAuthorizationPolicyProvider.AllowsCachingPolicies.get -> bool
55
Microsoft.AspNetCore.Authorization.Infrastructure.PassThroughAuthorizationHandler.PassThroughAuthorizationHandler(Microsoft.Extensions.Options.IOptions<Microsoft.AspNetCore.Authorization.AuthorizationOptions!>! options) -> void
66
static Microsoft.AspNetCore.Authorization.AuthorizationPolicy.CombineAsync(Microsoft.AspNetCore.Authorization.IAuthorizationPolicyProvider! policyProvider, System.Collections.Generic.IEnumerable<Microsoft.AspNetCore.Authorization.IAuthorizeData!>! authorizeData, System.Collections.Generic.IEnumerable<Microsoft.AspNetCore.Authorization.AuthorizationPolicy!>! policies) -> System.Threading.Tasks.Task<Microsoft.AspNetCore.Authorization.AuthorizationPolicy?>!
77
virtual Microsoft.AspNetCore.Authorization.AuthorizationBuilder.AddDefaultPolicy(string! name, Microsoft.AspNetCore.Authorization.AuthorizationPolicy! policy) -> Microsoft.AspNetCore.Authorization.AuthorizationBuilder!
@@ -14,4 +14,4 @@ virtual Microsoft.AspNetCore.Authorization.AuthorizationBuilder.Services.get ->
1414
virtual Microsoft.AspNetCore.Authorization.AuthorizationBuilder.SetDefaultPolicy(Microsoft.AspNetCore.Authorization.AuthorizationPolicy! policy) -> Microsoft.AspNetCore.Authorization.AuthorizationBuilder!
1515
virtual Microsoft.AspNetCore.Authorization.AuthorizationBuilder.SetFallbackPolicy(Microsoft.AspNetCore.Authorization.AuthorizationPolicy? policy) -> Microsoft.AspNetCore.Authorization.AuthorizationBuilder!
1616
virtual Microsoft.AspNetCore.Authorization.AuthorizationBuilder.SetInvokeHandlersAfterFailure(bool invoke) -> Microsoft.AspNetCore.Authorization.AuthorizationBuilder!
17-
virtual Microsoft.AspNetCore.Authorization.DefaultAuthorizationPolicyProvider.CanCachePolicy.get -> bool
17+
virtual Microsoft.AspNetCore.Authorization.DefaultAuthorizationPolicyProvider.AllowsCachingPolicies.get -> bool

src/Security/Authorization/Policy/src/AuthorizationMiddleware.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public AuthorizationMiddleware(RequestDelegate next, IAuthorizationPolicyProvide
4848
{
4949
ArgumentNullException.ThrowIfNull(services);
5050

51-
if (_policyProvider.CanCachePolicy)
51+
if (_policyProvider.AllowsCachingPolicies)
5252
{
5353
_policyCache = services.GetService<AuthorizationPolicyCache>();
5454
_canCache = _policyCache != null;

src/Security/Authorization/test/AuthorizationMiddlewareTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ public async Task OnAuthorizationAsync_WillNotCallPolicyProviderWithCache()
233233
.Callback(() => getPolicyCount++);
234234
policyProvider.Setup(p => p.GetFallbackPolicyAsync()).ReturnsAsync(policy)
235235
.Callback(() => getFallbackPolicyCount++);
236-
policyProvider.Setup(p => p.CanCachePolicy).Returns(true);
236+
policyProvider.Setup(p => p.AllowsCachingPolicies).Returns(true);
237237
var next = new TestRequestDelegate();
238238

239239
var endpoint = CreateEndpoint(new AuthorizeAttribute("whatever"));
@@ -283,7 +283,7 @@ public override Task<AuthorizationPolicy> GetPolicyAsync(string policyName)
283283
return Task.FromResult(new AuthorizationPolicyBuilder().RequireAssertion(_ => true).Build());
284284
}
285285

286-
public override bool CanCachePolicy => _canCache;
286+
public override bool AllowsCachingPolicies => _canCache;
287287
}
288288

289289
[Theory]

src/Servers/Kestrel/Transport.Quic/test/QuicConnectionContextTests.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,8 @@ public async Task StreamPool_StreamAbortedOnClient_NotPooled()
421421
public async Task StreamPool_StreamAbortedOnClientAndServer_NotPooled()
422422
{
423423
// Arrange
424+
using var httpEventSource = new HttpEventSourceListener(LoggerFactory);
425+
424426
await using var connectionListener = await QuicTestHelpers.CreateConnectionListenerFactory(LoggerFactory);
425427

426428
var options = QuicTestHelpers.CreateClientConnectionOptions(connectionListener.EndPoint);

src/Servers/Kestrel/Transport.Sockets/src/Internal/SocketConnection.cs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ internal sealed partial class SocketConnection : TransportConnection
3333

3434
internal SocketConnection(Socket socket,
3535
MemoryPool<byte> memoryPool,
36-
PipeScheduler transportScheduler,
36+
PipeScheduler socketScheduler,
3737
ILogger logger,
3838
SocketSenderPool socketSenderPool,
3939
PipeOptions inputOptions,
@@ -55,12 +55,7 @@ internal SocketConnection(Socket socket,
5555

5656
ConnectionClosed = _connectionClosedTokenSource.Token;
5757

58-
// On *nix platforms, Sockets already dispatches to the ThreadPool.
59-
// Yes, the IOQueues are still used for the PipeSchedulers. This is intentional.
60-
// https://github.com/aspnet/KestrelHttpServer/issues/2573
61-
var awaiterScheduler = OperatingSystem.IsWindows() ? transportScheduler : PipeScheduler.Inline;
62-
63-
_receiver = new SocketReceiver(awaiterScheduler);
58+
_receiver = new SocketReceiver(socketScheduler);
6459

6560
var pair = DuplexPipe.CreateConnectionPair(inputOptions, outputOptions);
6661

src/Servers/Kestrel/Transport.Sockets/src/SocketConnectionContextFactory.cs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,13 @@ public SocketConnectionContextFactory(SocketConnectionFactoryOptions options, IL
5656
{
5757
var memoryPool = _options.MemoryPoolFactory();
5858
var transportScheduler = options.UnsafePreferInlineScheduling ? PipeScheduler.Inline : new IOQueue();
59-
// https://github.com/aspnet/KestrelHttpServer/issues/2573
60-
var awaiterScheduler = OperatingSystem.IsWindows() ? transportScheduler : PipeScheduler.Inline;
6159

6260
_settings[i] = new QueueSettings()
6361
{
6462
Scheduler = transportScheduler,
6563
InputOptions = new PipeOptions(memoryPool, applicationScheduler, transportScheduler, maxReadBufferSize, maxReadBufferSize / 2, useSynchronizationContext: false),
6664
OutputOptions = new PipeOptions(memoryPool, transportScheduler, applicationScheduler, maxWriteBufferSize, maxWriteBufferSize / 2, useSynchronizationContext: false),
67-
SocketSenderPool = new SocketSenderPool(awaiterScheduler),
65+
SocketSenderPool = new SocketSenderPool(transportScheduler),
6866
MemoryPool = memoryPool,
6967
};
7068
}
@@ -73,16 +71,14 @@ public SocketConnectionContextFactory(SocketConnectionFactoryOptions options, IL
7371
{
7472
var memoryPool = _options.MemoryPoolFactory();
7573
var transportScheduler = options.UnsafePreferInlineScheduling ? PipeScheduler.Inline : PipeScheduler.ThreadPool;
76-
// https://github.com/aspnet/KestrelHttpServer/issues/2573
77-
var awaiterScheduler = OperatingSystem.IsWindows() ? transportScheduler : PipeScheduler.Inline;
7874
_settings = new QueueSettings[]
7975
{
8076
new QueueSettings()
8177
{
8278
Scheduler = transportScheduler,
8379
InputOptions = new PipeOptions(memoryPool, applicationScheduler, transportScheduler, maxReadBufferSize, maxReadBufferSize / 2, useSynchronizationContext: false),
8480
OutputOptions = new PipeOptions(memoryPool, transportScheduler, applicationScheduler, maxWriteBufferSize, maxWriteBufferSize / 2, useSynchronizationContext: false),
85-
SocketSenderPool = new SocketSenderPool(awaiterScheduler),
81+
SocketSenderPool = new SocketSenderPool(PipeScheduler.Inline),
8682
MemoryPool = memoryPool,
8783
}
8884
};
@@ -101,7 +97,7 @@ public ConnectionContext Create(Socket socket)
10197

10298
var connection = new SocketConnection(socket,
10399
setting.MemoryPool,
104-
setting.Scheduler,
100+
PipeScheduler.Inline,
105101
_logger,
106102
setting.SocketSenderPool,
107103
setting.InputOptions,

0 commit comments

Comments
 (0)