public async Task PolicyDirectlyOnEndpoint_GetsUsed() { var globalOnRejectedInvoked = false; var options = CreateOptionsAccessor(); // Policy will disallow var policy = new TestRateLimiterPolicy("myKey", 404, false); var defaultRateLimiterPolicy = new DefaultRateLimiterPolicy(RateLimiterOptions.ConvertPartitioner <string>(null, policy.GetPartition), policy.OnRejected); options.Value.OnRejected = (context, token) => { globalOnRejectedInvoked = true; context.HttpContext.Response.StatusCode = 429; return(ValueTask.CompletedTask); }; var middleware = new RateLimitingMiddleware(c => { return(Task.CompletedTask); }, new NullLoggerFactory().CreateLogger <RateLimitingMiddleware>(), options, Mock.Of <IServiceProvider>()); var context = new DefaultHttpContext(); context.SetEndpoint(new Endpoint(c => Task.CompletedTask, new EndpointMetadataCollection(new EnableRateLimitingAttribute(defaultRateLimiterPolicy)), "Test endpoint")); await middleware.Invoke(context).DefaultTimeout(); Assert.False(globalOnRejectedInvoked); Assert.Equal(StatusCodes.Status404NotFound, context.Response.StatusCode); }
public void AddPolicy_Generic_ThrowsOnDuplicateName() { var options = new RateLimiterOptions(); options.AddPolicy <string>("myKey", context => RateLimitPartition.GetNoLimiter <string>("myKey")); Assert.Throws <ArgumentException>(() => options.AddPolicy <string, TestRateLimiterPolicy>("myKey")); }
/// <summary> /// Enables rate limiting for the application. /// </summary> /// <param name="app"></param> /// <param name="options"></param> /// <returns></returns> public static IApplicationBuilder UseRateLimiter(this IApplicationBuilder app, RateLimiterOptions options) { ArgumentNullException.ThrowIfNull(app); ArgumentNullException.ThrowIfNull(options); return(app.UseMiddleware <RateLimitingMiddleware>(Options.Create(options))); }
public void UseRateLimiter_RespectsOptions() { // These are the options that should get used var options = new RateLimiterOptions(); options.RejectionStatusCode = 429; options.GlobalLimiter = new TestPartitionedRateLimiter <HttpContext>(new TestRateLimiter(false)); // These should not get used var services = new ServiceCollection(); services.Configure <RateLimiterOptions>(options => { options.GlobalLimiter = new TestPartitionedRateLimiter <HttpContext>(new TestRateLimiter(false)); options.RejectionStatusCode = 404; }); services.AddLogging(); var serviceProvider = services.BuildServiceProvider(); var appBuilder = new ApplicationBuilder(serviceProvider); // Act appBuilder.UseRateLimiter(options); var app = appBuilder.Build(); var context = new DefaultHttpContext(); app.Invoke(context); Assert.Equal(429, context.Response.StatusCode); }
/// <summary> /// Adds a new <see cref="ConcurrencyLimiter"/> with the given <see cref="ConcurrencyLimiterOptions"/> to the <see cref="RateLimiterOptions"/>. /// </summary> /// <param name="options">The <see cref="RateLimiterOptions"/> to add a limiter to.</param> /// <param name="policyName">The name that will be associated with the limiter.</param> /// <param name="configureOptions">A callback to configure the <see cref="ConcurrencyLimiterOptions"/> to be used for the limiter.</param> /// <returns>This <see cref="RateLimiterOptions"/>.</returns> public static RateLimiterOptions AddConcurrencyLimiter(this RateLimiterOptions options, string policyName, Action <ConcurrencyLimiterOptions> configureOptions) { ArgumentNullException.ThrowIfNull(configureOptions); var key = new PolicyNameKey() { PolicyName = policyName }; var concurrencyLimiterOptions = new ConcurrencyLimiterOptions(); configureOptions.Invoke(concurrencyLimiterOptions); return(options.AddPolicy(policyName, context => { return RateLimitPartition.GetConcurrencyLimiter(key, _ => concurrencyLimiterOptions); })); }
/// <summary> /// Adds a new <see cref="SlidingWindowRateLimiter"/> with the given <see cref="SlidingWindowRateLimiterOptions"/> to the <see cref="RateLimiterOptions"/>. /// </summary> /// <param name="options">The <see cref="RateLimiterOptions"/> to add a limiter to.</param> /// <param name="policyName">The name that will be associated with the limiter.</param> /// <param name="configureOptions">A callback to configure the <see cref="SlidingWindowRateLimiterOptions"/> to be used for the limiter.</param> /// <returns>This <see cref="RateLimiterOptions"/>.</returns> public static RateLimiterOptions AddSlidingWindowLimiter(this RateLimiterOptions options, string policyName, Action <SlidingWindowRateLimiterOptions> configureOptions) { ArgumentNullException.ThrowIfNull(configureOptions); var key = new PolicyNameKey() { PolicyName = policyName }; var slidingWindowRateLimiterOptions = new SlidingWindowRateLimiterOptions(); configureOptions.Invoke(slidingWindowRateLimiterOptions); // Saves an allocation in GetSlidingWindowLimiter, which would have created a new set of options if this was true. slidingWindowRateLimiterOptions.AutoReplenishment = false; return(options.AddPolicy(policyName, context => { return RateLimitPartition.GetSlidingWindowLimiter(key, _ => slidingWindowRateLimiterOptions); })); }
public void ThrowsOnNullOnRejected() { var options = new RateLimiterOptions(); Assert.Throws <ArgumentNullException>(() => options.OnRejected = null); }
public void ThrowsOnNullLimiter() { var options = new RateLimiterOptions(); Assert.Throws <ArgumentNullException>(() => options.Limiter = null); }
/// <summary> /// Adds the specified rate limiting policy to the endpoint(s). /// </summary> /// <param name="builder">The endpoint convention builder.</param> /// <param name="policy">The rate limiting policy to add to the endpoint.</param> /// <returns>The original convention builder parameter.</returns> public static TBuilder RequireRateLimiting <TBuilder, TPartitionKey>(this TBuilder builder, IRateLimiterPolicy <TPartitionKey> policy) where TBuilder : IEndpointConventionBuilder { ArgumentNullException.ThrowIfNull(builder); ArgumentNullException.ThrowIfNull(policy); builder.Add(endpointBuilder => { endpointBuilder.Metadata.Add(new EnableRateLimitingAttribute(new DefaultRateLimiterPolicy(RateLimiterOptions.ConvertPartitioner <TPartitionKey>(null, policy.GetPartition), policy.OnRejected))); }); return(builder); }
public void AddPolicy_ThrowsOnNullPolicy() { var options = new RateLimiterOptions(); Assert.Throws <ArgumentNullException>(() => options.AddPolicy <string>("myKey", policy: null)); }
public void AddPolicy_ThrowsOnNullPolicyName() { var options = new RateLimiterOptions(); Assert.Throws <ArgumentNullException>(() => options.AddPolicy <string>(null, context => RateLimitPartition.GetNoLimiter <string>("myKey"))); }