mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-11-04 20:10:50 +08:00 
			
		
		
		
	Merge branch 'feature/dynamic-rate-limit-client-whitelist' of https://github.com/totubamowo/Ocelot into totubamowo-feature/dynamic-rate-limit-client-whitelist
This commit is contained in:
		@@ -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<string> _clientWhitelist;
 | 
			
		||||
        private Func<List<string>> _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<string> clientWhitelist)
 | 
			
		||||
        public RateLimitOptionsBuilder WithClientWhiteList(Func<List<string>> 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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Configuration
 | 
			
		||||
{
 | 
			
		||||
@@ -7,12 +8,14 @@ namespace Ocelot.Configuration
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public class RateLimitOptions
 | 
			
		||||
    {
 | 
			
		||||
        public RateLimitOptions(bool enbleRateLimiting, string clientIdHeader, List<string> clientWhitelist, bool disableRateLimitHeaders,
 | 
			
		||||
        private readonly Func<List<string>> _getClientWhitelist;
 | 
			
		||||
 | 
			
		||||
        public RateLimitOptions(bool enableRateLimiting, string clientIdHeader, Func<List<string>> getClientWhitelist, bool disableRateLimitHeaders,
 | 
			
		||||
            string quotaExceededMessage, string rateLimitCounterPrefix, RateLimitRule rateLimitRule, int httpStatusCode)
 | 
			
		||||
        {
 | 
			
		||||
            EnableRateLimiting = enbleRateLimiting;
 | 
			
		||||
            EnableRateLimiting = enableRateLimiting;
 | 
			
		||||
            ClientIdHeader = clientIdHeader;
 | 
			
		||||
            ClientWhitelist = clientWhitelist ?? new List<string>();
 | 
			
		||||
            _getClientWhitelist = getClientWhitelist;
 | 
			
		||||
            DisableRateLimitHeaders = disableRateLimitHeaders;
 | 
			
		||||
            QuotaExceededMessage = quotaExceededMessage;
 | 
			
		||||
            RateLimitCounterPrefix = rateLimitCounterPrefix;
 | 
			
		||||
@@ -22,18 +25,21 @@ namespace Ocelot.Configuration
 | 
			
		||||
 | 
			
		||||
        public RateLimitRule RateLimitRule { get; private set; }
 | 
			
		||||
 | 
			
		||||
        public List<string> ClientWhitelist { get; private set; }
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets the list of white listed clients
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public List<string> ClientWhitelist { get => _getClientWhitelist(); }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets or sets the HTTP header that holds the client identifier, by default is X-ClientId
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public string ClientIdHeader { get; private set; }
 | 
			
		||||
 | 
			
		||||
        public string ClientIdHeader { get; private set; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets or sets the HTTP Status code returned when rate limiting occurs, by default value is set to 429 (Too Many Requests)
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public int HttpStatusCode { get; private set; }
 | 
			
		||||
 | 
			
		||||
        public int HttpStatusCode { get; private set; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// 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
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets or sets the counter prefix, used to compose the rate limit counter cache key
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public string RateLimitCounterPrefix { get; private set; }
 | 
			
		||||
 | 
			
		||||
        public string RateLimitCounterPrefix { get; private set; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Enables endpoint rate limiting based URL path and HTTP verb
 | 
			
		||||
        /// </summary>
 | 
			
		||||
@@ -56,4 +62,4 @@ namespace Ocelot.Configuration
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public bool DisableRateLimitHeaders { get; private set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
 
 | 
			
		||||
@@ -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<string>(), false, "", "", new RateLimitRule("1s", 100, 3), 429))
 | 
			
		||||
                .WithRateLimitOptions(new RateLimitOptions(true, "ClientId", () => new List<string>(), false, "", "", new RateLimitRule("1s", 100, 3), 429))
 | 
			
		||||
                .WithUpstreamHttpMethod(new List<string> { "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<string>() { "ocelotclient2" }, false, "", "", new RateLimitRule("1s", 100, 3), 429))
 | 
			
		||||
                             new Ocelot.Configuration.RateLimitOptions(true, "ClientId", () => new List<string>() { "ocelotclient2" }, false, "", "", new RateLimitRule("1s", 100, 3), 429))
 | 
			
		||||
                         .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                         .Build())
 | 
			
		||||
                     .WithUpstreamHttpMethod(new List<string> { "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; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user