Skip to content

[release/7.0-preview6] Update dependencies from dotnet/runtime dotnet/efcore & Make RateLimitingMiddleware endpoint-aware #42358

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
479a502
Update dependencies from https://github.com/dotnet/efcore build 20220…
dotnet-maestro[bot] Jun 23, 2022
70922e5
Update dependencies from https://github.com/dotnet/runtime build 2022…
dotnet-maestro[bot] Jun 23, 2022
0db6f12
Update dependencies from https://github.com/dotnet/runtime build 2022…
dotnet-maestro[bot] Jun 24, 2022
297be90
Update dependencies from https://github.com/dotnet/efcore build 20220…
dotnet-maestro[bot] Jun 24, 2022
93d5e93
Add IEndpointConventionBuilder extensions for RateLimitingMiddleware
wtgodbe May 20, 2022
e8fddb0
Some changes
wtgodbe Jun 2, 2022
ef99c4f
More
wtgodbe Jun 7, 2022
5558d37
Rename
wtgodbe Jun 9, 2022
697dddf
More
wtgodbe Jun 21, 2022
ad5a408
More fixes
wtgodbe Jun 21, 2022
dc8ea7e
More stuff
wtgodbe Jun 22, 2022
ea5cd30
Example of activating
wtgodbe Jun 22, 2022
8a9f2f1
Changes
wtgodbe Jun 23, 2022
845e2ad
More stuff
wtgodbe Jun 23, 2022
7b7fb45
Name change
wtgodbe Jun 23, 2022
4948f20
Fix some stuff
wtgodbe Jun 24, 2022
61e57d9
Fixup
wtgodbe Jun 24, 2022
9fe0328
Add some tests
wtgodbe Jun 24, 2022
597701b
More tests
wtgodbe Jun 24, 2022
899d4f2
Renames
wtgodbe Jun 24, 2022
384cde4
Minor
wtgodbe Jun 25, 2022
fd514a4
Some feedback
wtgodbe Jun 27, 2022
bb25332
No more reflection
wtgodbe Jun 27, 2022
b35e6b9
Try to satisfy linuc
wtgodbe Jun 27, 2022
d6706fa
Suppress linker warning
wtgodbe Jun 28, 2022
bf7a8de
Fix linkability bug
wtgodbe Jun 28, 2022
dfd347e
Merge remote-tracking branch 'origin/backport/pr-42417-to-release/7.0…
Jun 28, 2022
af7e7ed
Add ToArray() to MemoryOutputCacheStoreTests
javiercn Jun 23, 2022
14d078e
Fix MemoryOutputCacheStoreTests properly
javiercn Jun 23, 2022
d33b86e
More utf8 fixes
javiercn Jun 23, 2022
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
276 changes: 138 additions & 138 deletions eng/Version.Details.xml

Large diffs are not rendered by default.

144 changes: 75 additions & 69 deletions eng/Versions.props

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions src/Middleware/OutputCaching/test/MemoryOutputCacheStoreTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public class MemoryOutputCacheStoreTests
public async Task StoreAndGetValue_Succeeds()
{
var store = new MemoryOutputCacheStore(new MemoryCache(new MemoryCacheOptions()));
var value = "abc"u8;
var value = "abc"u8.ToArray();
var key = "abc";

await store.SetAsync(key, value, null, TimeSpan.FromMinutes(1), default);
Expand All @@ -31,7 +31,7 @@ public async Task StoreAndGetValue_TimesOut()
{
var testClock = new TestMemoryOptionsClock { UtcNow = DateTimeOffset.UtcNow };
var store = new MemoryOutputCacheStore(new MemoryCache(new MemoryCacheOptions { Clock = testClock }));
var value = "abc"u8;
var value = "abc"u8.ToArray();
var key = "abc";

await store.SetAsync(key, value, null, TimeSpan.FromMilliseconds(5), default);
Expand All @@ -46,7 +46,7 @@ public async Task StoreAndGetValue_TimesOut()
public async Task StoreNullKey_ThrowsException()
{
var store = new MemoryOutputCacheStore(new MemoryCache(new MemoryCacheOptions()));
var value = "abc"u8;
var value = "abc"u8.ToArray();
string key = null;

_ = await Assert.ThrowsAsync<ArgumentNullException>("key", () => store.SetAsync(key, value, null, TimeSpan.FromMilliseconds(5), default).AsTask());
Expand All @@ -67,7 +67,7 @@ public async Task EvictByTag_SingleTag_SingleEntry()
{
var testClock = new TestMemoryOptionsClock { UtcNow = DateTimeOffset.UtcNow };
var store = new MemoryOutputCacheStore(new MemoryCache(new MemoryCacheOptions { Clock = testClock }));
var value = "abc"u8;
var value = "abc"u8.ToArray();
var key = "abc";
var tags = new string[] { "tag1" };

Expand All @@ -83,7 +83,7 @@ public async Task EvictByTag_SingleTag_MultipleEntries()
{
var testClock = new TestMemoryOptionsClock { UtcNow = DateTimeOffset.UtcNow };
var store = new MemoryOutputCacheStore(new MemoryCache(new MemoryCacheOptions { Clock = testClock }));
var value = "abc"u8;
var value = "abc"u8.ToArray();
var key1 = "abc";
var key2 = "def";
var tags = new string[] { "tag1" };
Expand All @@ -103,7 +103,7 @@ public async Task EvictByTag_MultipleTags_SingleEntry()
{
var testClock = new TestMemoryOptionsClock { UtcNow = DateTimeOffset.UtcNow };
var store = new MemoryOutputCacheStore(new MemoryCache(new MemoryCacheOptions { Clock = testClock }));
var value = "abc"u8;
var value = "abc"u8.ToArray();
var key = "abc";
var tags = new string[] { "tag1", "tag2" };

Expand All @@ -119,7 +119,7 @@ public async Task EvictByTag_MultipleTags_MultipleEntries()
{
var testClock = new TestMemoryOptionsClock { UtcNow = DateTimeOffset.UtcNow };
var store = new MemoryOutputCacheStore(new MemoryCache(new MemoryCacheOptions { Clock = testClock }));
var value = "abc"u8;
var value = "abc"u8.ToArray();
var key1 = "abc";
var key2 = "def";
var tags1 = new string[] { "tag1", "tag2" };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public async Task StoreAndGet_StoresAllValues()
var key = "abc";
var entry = new OutputCacheEntry()
{
Body = new CachedResponseBody(new List<byte[]>() { "lorem"u8, "ipsum"u8 }, 10),
Body = new CachedResponseBody(new List<byte[]>() { "lorem"u8.ToArray(), "ipsum"u8.ToArray() }, 10),
Created = DateTimeOffset.UtcNow,
Headers = new HeaderDictionary { [HeaderNames.Accept] = "text/plain", [HeaderNames.AcceptCharset] = "utf8" },
StatusCode = StatusCodes.Status201Created,
Expand Down
98 changes: 98 additions & 0 deletions src/Middleware/RateLimiting/src/DefaultCombinedLease.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Threading.RateLimiting;

namespace Microsoft.AspNetCore.RateLimiting;

internal sealed class DefaultCombinedLease : RateLimitLease
{
private readonly RateLimitLease? _globalLease;
private readonly RateLimitLease _endpointLease;
private HashSet<string>? _metadataNames;

public DefaultCombinedLease(RateLimitLease? globalLease, RateLimitLease endpointLease)
{
_globalLease = globalLease;
_endpointLease = endpointLease;
}

public override bool IsAcquired => true;

public override IEnumerable<string> MetadataNames
{
get
{
if (_metadataNames is null)
{
_metadataNames = new HashSet<string>();
if (_globalLease is not null)
{
foreach (string metadataName in _globalLease.MetadataNames)
{
_metadataNames.Add(metadataName);
}
}
foreach (string metadataName in _endpointLease.MetadataNames)
{
_metadataNames.Add(metadataName);
}
}
return _metadataNames;
}
}

public override bool TryGetMetadata(string metadataName, out object? metadata)
{
// Use the first metadata item of a given name, ignore duplicates, we can't reliably merge arbitrary metadata
// Creating an object[] if there are multiple of the same metadataName could work, but makes consumption of metadata messy
// and makes MetadataName.Create<T>(...) uses no longer work
if (_endpointLease.TryGetMetadata(metadataName, out metadata))
{
return true;
}
if (_globalLease is not null)
{
if (_globalLease.TryGetMetadata(metadataName, out metadata))
{
return true;
}
}

metadata = null;
return false;
}

protected override void Dispose(bool disposing)
{
List<Exception>? exceptions = null;

// Dispose endpoint lease first, then global lease (reverse order of when they were acquired)
// Avoids issues where dispose might unblock a queued acquire and then the acquire fails when acquiring the next limiter.
// When disposing in reverse order there wont be any issues of unblocking an acquire that affects acquires on limiters in the chain after it
try
{
_endpointLease.Dispose();
}
catch (Exception ex)
{
exceptions ??= new List<Exception>();
exceptions.Add(ex);
}

try
{
_globalLease?.Dispose();
}
catch (Exception ex)
{
exceptions ??= new List<Exception>();
exceptions.Add(ex);
}

if (exceptions is not null)
{
throw new AggregateException(exceptions);
}
}
}
19 changes: 19 additions & 0 deletions src/Middleware/RateLimiting/src/DefaultKeyType.T.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Microsoft.AspNetCore.RateLimiting;

internal sealed class DefaultKeyType<TKey>: DefaultKeyType
{
private readonly TKey _key;

public DefaultKeyType(TKey key)
{
_key = key;
}

public override object? GetKey()
{
return _key;
}
}
9 changes: 9 additions & 0 deletions src/Middleware/RateLimiting/src/DefaultKeyType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Microsoft.AspNetCore.RateLimiting;

internal abstract class DefaultKeyType
{
public abstract object? GetKey();
}
44 changes: 44 additions & 0 deletions src/Middleware/RateLimiting/src/DefaultKeyTypeEqualityComparer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics.CodeAnalysis;

namespace Microsoft.AspNetCore.RateLimiting;
internal class DefaultKeyTypeEqualityComparer : IEqualityComparer<DefaultKeyType>
{
public bool Equals(DefaultKeyType? x, DefaultKeyType? y)
{
if (x == null && y == null)
{
return true;
}
else if (x == null || y == null)
{
return false;
}

var xKey = x.GetKey();
var yKey = y.GetKey();
if (xKey == null && yKey == null)
{
return true;
}
else if (xKey == null || yKey == null)
{
return false;
}

return xKey.Equals(yKey);
}

public int GetHashCode([DisallowNull] DefaultKeyType obj)
{
var key = obj.GetKey();
if (key is not null)
{
return key.GetHashCode();
}
// REVIEW - is this reasonable?
return default;
}
}
25 changes: 25 additions & 0 deletions src/Middleware/RateLimiting/src/DefaultRateLimiterPolicy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Threading.RateLimiting;
using Microsoft.AspNetCore.Http;

namespace Microsoft.AspNetCore.RateLimiting;
internal sealed class DefaultRateLimiterPolicy : IRateLimiterPolicy<DefaultKeyType>
{
private readonly Func<HttpContext, RateLimitPartition<DefaultKeyType>> _partitioner;
private readonly Func<OnRejectedContext, CancellationToken, ValueTask>? _onRejected;

public DefaultRateLimiterPolicy(Func<HttpContext, RateLimitPartition<DefaultKeyType>> partitioner, Func<OnRejectedContext, CancellationToken, ValueTask>? onRejected)
{
_partitioner = partitioner;
_onRejected = onRejected;
}

public Func<OnRejectedContext, CancellationToken, ValueTask>? OnRejected => _onRejected;

public RateLimitPartition<DefaultKeyType> GetPartition(HttpContext httpContext)
{
return _partitioner(httpContext);
}
}
15 changes: 15 additions & 0 deletions src/Middleware/RateLimiting/src/IRateLimiterMetadata.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Microsoft.AspNetCore.RateLimiting;

/// <summary>
/// An interface which can be used to identify a type which provides metadata needed for enabling request rate limiting support.
/// </summary>
internal interface IRateLimiterMetadata
{
/// <summary>
/// The name of the limiter which needs to be applied.
/// </summary>
string PolicyName { get; }
}
24 changes: 24 additions & 0 deletions src/Middleware/RateLimiting/src/IRateLimiterPolicy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Threading.RateLimiting;
using Microsoft.AspNetCore.Http;

namespace Microsoft.AspNetCore.RateLimiting;

/// <summary>
/// An interface which is used to represent a RateLimiter policy.
/// </summary>
public interface IRateLimiterPolicy<TPartitionKey>
{
/// <summary>
/// Gets the <see cref="Func{OnRejectedContext, CancellationToken, ValueTask}"/> that handles requests rejected by this middleware.
/// </summary>
Func<OnRejectedContext, CancellationToken, ValueTask>? OnRejected { get; }

/// <summary>
/// Gets the <see cref="RateLimitPartition{TPartitionKey}"/> that applies to the given <see cref="HttpContext"/>.
/// </summary>
/// <param name="httpContext">The <see cref="HttpContext"/> to get the partition for.</param>
RateLimitPartition<TPartitionKey> GetPartition(HttpContext httpContext);
}
17 changes: 17 additions & 0 deletions src/Middleware/RateLimiting/src/LeaseContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Threading.RateLimiting;

namespace Microsoft.AspNetCore.RateLimiting;
internal struct LeaseContext : IDisposable
{
public bool? GlobalRejected { get; init; }

public required RateLimitLease Lease { get; init; }

public void Dispose()
{
Lease.Dispose();
}
}
36 changes: 0 additions & 36 deletions src/Middleware/RateLimiting/src/NoLimiter.cs

This file was deleted.

23 changes: 23 additions & 0 deletions src/Middleware/RateLimiting/src/OnRejectedContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Threading.RateLimiting;
using Microsoft.AspNetCore.Http;

namespace Microsoft.AspNetCore.RateLimiting;

/// <summary>
/// Holds state needed for the OnRejected callback in the RateLimitingMiddleware.
/// </summary>
public sealed class OnRejectedContext
{
/// <summary>
/// Gets or sets the <see cref="HttpContext"/> that the OnRejected callback will have access to
/// </summary>
public required HttpContext HttpContext { get; init; }

/// <summary>
/// Gets or sets the failed <see cref="RateLimitLease"/> that the OnRejected callback will have access to
/// </summary>
public required RateLimitLease Lease { get; init; }
}
Loading