make rate limiting whitelist a function so users can override with dynamic behaviour

* Make rate-limiting client whitelist dynamic
* Refactor `RateLimitOptions.ClientWhiteList`
* Fix typo in variable `enbleRateLimiting`
* Fix case in variable `clientIdheader`
author Taiwo Otubamowo <totubamowo@deloitte.co.uk>

* fix 1045

* #492 log 500 with error log level, acceptance test, unit test

* #492 minor changes

* initial commit for new feature #1077

allow to limit the number of concurrent tcp connection to a downstream service

* protect code against value not in accurate range

add unit test

* Do not crash host on Dispose

* Add test

* Pin GitVersion.CommandLine package version

* #683 validate if there are duplicated placeholders in UpstreamPathTemplate

* Use registered scheme from Eureka (#1087)

* extra test

* very brief mention MaxConnectionsPerServer in docs

* build develop like a PR

* more docs

* test

Co-authored-by: Taiwo O. <44668623+totubamowo@users.noreply.github.com>
Co-authored-by: Catcher Wong <catcher_hwq@outlook.com>
Co-authored-by: jlukawska <56401969+jlukawska@users.noreply.github.com>
Co-authored-by: buretjph <58700930+buretjph@users.noreply.github.com>
Co-authored-by: Jonathan Mezach <jonathanmezach@gmail.com>
Co-authored-by: 彭伟 <pengweiqhca@sina.com>
This commit is contained in:
Tom Pallister
2020-01-19 17:47:57 +00:00
committed by GitHub
parent 07df311094
commit ebe662abe6
15 changed files with 303 additions and 126 deletions

View File

@ -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)

View File

@ -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; }
}
}
}

View File

@ -38,6 +38,14 @@
error.ShouldBeOfType<RequestCanceledError>();
}
[Fact]
public void should_return_request_canceled_for_subtype()
{
var error = _mapper.Map(new SomeException());
error.ShouldBeOfType<RequestCanceledError>();
}
[Fact]
public void should_return_error_from_mapper()
{
@ -56,5 +64,8 @@
error.ShouldBeOfType<AnyError>();
}
private class SomeException : OperationCanceledException
{ }
}
}

View File

@ -41,9 +41,10 @@ namespace Ocelot.UnitTests.Requester
public void should_call_services_correctly()
{
this.Given(x => x.GivenTheRequestIs())
.And(x => x.GivenTheRequesterReturns(new OkResponse<HttpResponseMessage>(new HttpResponseMessage())))
.And(x => x.GivenTheRequesterReturns(new OkResponse<HttpResponseMessage>(new HttpResponseMessage(System.Net.HttpStatusCode.OK))))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheDownstreamResponseIsSet())
.Then(x => InformationIsLogged())
.BDDfy();
}
@ -57,6 +58,17 @@ namespace Ocelot.UnitTests.Requester
.BDDfy();
}
[Fact]
public void should_log_downstream_internal_server_error()
{
this.Given(x => x.GivenTheRequestIs())
.And(x => x.GivenTheRequesterReturns(
new OkResponse<HttpResponseMessage>(new HttpResponseMessage(System.Net.HttpStatusCode.InternalServerError))))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.WarningIsLogged())
.BDDfy();
}
private void ThenTheErrorIsSet()
{
_downstreamContext.IsError.ShouldBeTrue();
@ -98,5 +110,23 @@ namespace Ocelot.UnitTests.Requester
_downstreamContext.DownstreamResponse.Content.ShouldBe(_response.Data.Content);
_downstreamContext.DownstreamResponse.StatusCode.ShouldBe(_response.Data.StatusCode);
}
private void WarningIsLogged()
{
_logger.Verify(
x => x.LogWarning(
It.IsAny<string>()
),
Times.Once);
}
private void InformationIsLogged()
{
_logger.Verify(
x => x.LogInformation(
It.IsAny<string>()
),
Times.Once);
}
}
}