diff --git a/src/Ocelot/Configuration/Builder/RateLimitOptionsBuilder.cs b/src/Ocelot/Configuration/Builder/RateLimitOptionsBuilder.cs index eba79769..eaaa4dab 100644 --- a/src/Ocelot/Configuration/Builder/RateLimitOptionsBuilder.cs +++ b/src/Ocelot/Configuration/Builder/RateLimitOptionsBuilder.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; namespace Ocelot.Configuration.Builder { @@ -7,6 +8,7 @@ namespace Ocelot.Configuration.Builder private bool _enableRateLimiting; private string _clientIdHeader; private List _clientWhitelist; + private Func> _getClientWhitelist; private bool _disableRateLimitHeaders; private string _quotaExceededMessage; private string _rateLimitCounterPrefix; @@ -19,15 +21,15 @@ namespace Ocelot.Configuration.Builder return this; } - public RateLimitOptionsBuilder WithClientIdHeader(string clientIdheader) + public RateLimitOptionsBuilder WithClientIdHeader(string clientIdHeader) { - _clientIdHeader = clientIdheader; + _clientIdHeader = clientIdHeader; return this; } - public RateLimitOptionsBuilder WithClientWhiteList(List clientWhitelist) + public RateLimitOptionsBuilder WithClientWhiteList(Func> getClientWhitelist) { - _clientWhitelist = clientWhitelist; + _getClientWhitelist = getClientWhitelist; return this; } @@ -63,9 +65,9 @@ namespace Ocelot.Configuration.Builder public RateLimitOptions Build() { - return new RateLimitOptions(_enableRateLimiting, _clientIdHeader, _clientWhitelist, - _disableRateLimitHeaders, _quotaExceededMessage, _rateLimitCounterPrefix, + return new RateLimitOptions(_enableRateLimiting, _clientIdHeader, _getClientWhitelist, + _disableRateLimitHeaders, _quotaExceededMessage, _rateLimitCounterPrefix, _rateLimitRule, _httpStatusCode); } } -} +} diff --git a/src/Ocelot/Configuration/Creator/RateLimitOptionsCreator.cs b/src/Ocelot/Configuration/Creator/RateLimitOptionsCreator.cs index 8f300dd2..ba167bfe 100644 --- a/src/Ocelot/Configuration/Creator/RateLimitOptionsCreator.cs +++ b/src/Ocelot/Configuration/Creator/RateLimitOptionsCreator.cs @@ -11,7 +11,7 @@ namespace Ocelot.Configuration.Creator { return new RateLimitOptionsBuilder() .WithClientIdHeader(globalConfiguration.RateLimitOptions.ClientIdHeader) - .WithClientWhiteList(fileRateLimitRule.ClientWhitelist) + .WithClientWhiteList(() => fileRateLimitRule.ClientWhitelist) .WithDisableRateLimitHeaders(globalConfiguration.RateLimitOptions.DisableRateLimitHeaders) .WithEnableRateLimiting(fileRateLimitRule.EnableRateLimiting) .WithHttpStatusCode(globalConfiguration.RateLimitOptions.HttpStatusCode) diff --git a/src/Ocelot/Configuration/RateLimitOptions.cs b/src/Ocelot/Configuration/RateLimitOptions.cs index db1da8eb..28472825 100644 --- a/src/Ocelot/Configuration/RateLimitOptions.cs +++ b/src/Ocelot/Configuration/RateLimitOptions.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; namespace Ocelot.Configuration { @@ -7,12 +8,14 @@ namespace Ocelot.Configuration /// public class RateLimitOptions { - public RateLimitOptions(bool enbleRateLimiting, string clientIdHeader, List clientWhitelist, bool disableRateLimitHeaders, + private readonly Func> _getClientWhitelist; + + public RateLimitOptions(bool enableRateLimiting, string clientIdHeader, Func> getClientWhitelist, bool disableRateLimitHeaders, string quotaExceededMessage, string rateLimitCounterPrefix, RateLimitRule rateLimitRule, int httpStatusCode) { - EnableRateLimiting = enbleRateLimiting; + EnableRateLimiting = enableRateLimiting; ClientIdHeader = clientIdHeader; - ClientWhitelist = clientWhitelist ?? new List(); + _getClientWhitelist = getClientWhitelist; DisableRateLimitHeaders = disableRateLimitHeaders; QuotaExceededMessage = quotaExceededMessage; RateLimitCounterPrefix = rateLimitCounterPrefix; @@ -22,18 +25,21 @@ namespace Ocelot.Configuration public RateLimitRule RateLimitRule { get; private set; } - public List ClientWhitelist { get; private set; } + /// + /// Gets the list of white listed clients + /// + public List ClientWhitelist { get => _getClientWhitelist(); } /// /// Gets or sets the HTTP header that holds the client identifier, by default is X-ClientId /// - public string ClientIdHeader { get; private set; } - + public string ClientIdHeader { get; private set; } + /// /// Gets or sets the HTTP Status code returned when rate limiting occurs, by default value is set to 429 (Too Many Requests) /// - public int HttpStatusCode { get; private set; } - + public int HttpStatusCode { get; private set; } + /// /// Gets or sets a value that will be used as a formatter for the QuotaExceeded response message. /// If none specified the default will be: @@ -44,8 +50,8 @@ namespace Ocelot.Configuration /// /// Gets or sets the counter prefix, used to compose the rate limit counter cache key /// - public string RateLimitCounterPrefix { get; private set; } - + public string RateLimitCounterPrefix { get; private set; } + /// /// Enables endpoint rate limiting based URL path and HTTP verb /// @@ -56,4 +62,4 @@ namespace Ocelot.Configuration /// public bool DisableRateLimitHeaders { get; private set; } } -} +} diff --git a/test/Ocelot.UnitTests/Configuration/RateLimitOptionsCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/RateLimitOptionsCreatorTests.cs index 75e9cfca..a2bc1957 100644 --- a/test/Ocelot.UnitTests/Configuration/RateLimitOptionsCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/RateLimitOptionsCreatorTests.cs @@ -50,7 +50,7 @@ namespace Ocelot.UnitTests.Configuration }; var expected = new RateLimitOptionsBuilder() .WithClientIdHeader("ClientIdHeader") - .WithClientWhiteList(fileReRoute.RateLimitOptions.ClientWhitelist) + .WithClientWhiteList(() => fileReRoute.RateLimitOptions.ClientWhitelist) .WithDisableRateLimitHeaders(true) .WithEnableRateLimiting(true) .WithHttpStatusCode(200) diff --git a/test/Ocelot.UnitTests/RateLimit/ClientRateLimitMiddlewareTests.cs b/test/Ocelot.UnitTests/RateLimit/ClientRateLimitMiddlewareTests.cs index 2b54bbfa..d0f69cec 100644 --- a/test/Ocelot.UnitTests/RateLimit/ClientRateLimitMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/RateLimit/ClientRateLimitMiddlewareTests.cs @@ -49,15 +49,15 @@ namespace Ocelot.UnitTests.RateLimit [Fact] public void should_call_middleware_and_ratelimiting() - { - var upstreamTemplate = new UpstreamPathTemplateBuilder().Build(); + { + var upstreamTemplate = new UpstreamPathTemplateBuilder().Build(); var downstreamReRoute = new DownstreamReRouteBuilder() .WithEnableRateLimiting(true) - .WithRateLimitOptions(new RateLimitOptions(true, "ClientId", new List(), false, "", "", new RateLimitRule("1s", 100, 3), 429)) + .WithRateLimitOptions(new RateLimitOptions(true, "ClientId", () => new List(), false, "", "", new RateLimitRule("1s", 100, 3), 429)) .WithUpstreamHttpMethod(new List { "Get" }) .WithUpstreamPathTemplate(upstreamTemplate) - .Build(); + .Build(); var reRoute = new ReRouteBuilder() .WithDownstreamReRoute(downstreamReRoute) @@ -82,7 +82,7 @@ namespace Ocelot.UnitTests.RateLimit .WithDownstreamReRoute(new DownstreamReRouteBuilder() .WithEnableRateLimiting(true) .WithRateLimitOptions( - new Ocelot.Configuration.RateLimitOptions(true, "ClientId", new List() { "ocelotclient2" }, false, "", "", new RateLimitRule("1s", 100, 3), 429)) + new Ocelot.Configuration.RateLimitOptions(true, "ClientId", () => new List() { "ocelotclient2" }, false, "", "", new RateLimitRule("1s", 100, 3), 429)) .WithUpstreamHttpMethod(new List { "Get" }) .Build()) .WithUpstreamHttpMethod(new List { "Get" }) @@ -102,8 +102,8 @@ namespace Ocelot.UnitTests.RateLimit private void WhenICallTheMiddlewareMultipleTime(int times) { - var clientId = "ocelotclient1"; - + var clientId = "ocelotclient1"; + for (int i = 0; i < times; i++) { var request = new HttpRequestMessage(new HttpMethod("GET"), _url); @@ -117,8 +117,8 @@ namespace Ocelot.UnitTests.RateLimit private void WhenICallTheMiddlewareWithWhiteClient() { - var clientId = "ocelotclient2"; - + var clientId = "ocelotclient2"; + for (int i = 0; i < 10; i++) { var request = new HttpRequestMessage(new HttpMethod("GET"), _url); @@ -127,10 +127,10 @@ namespace Ocelot.UnitTests.RateLimit _downstreamContext.HttpContext.Request.Headers.TryAdd("ClientId", clientId); _middleware.Invoke(_downstreamContext).GetAwaiter().GetResult(); - _responseStatusCode = (int)_downstreamContext.HttpContext.Response.StatusCode; - } - } - + _responseStatusCode = (int)_downstreamContext.HttpContext.Response.StatusCode; + } + } + private void ThenresponseStatusCodeIs429() { _responseStatusCode.ShouldBe(429); @@ -145,7 +145,7 @@ namespace Ocelot.UnitTests.RateLimit internal class FakeStream : Stream { public override void Flush() - { + { //do nothing //throw new System.NotImplementedException(); } @@ -176,4 +176,4 @@ namespace Ocelot.UnitTests.RateLimit public override long Length { get; } public override long Position { get; set; } } -} +}