From 21be46e68042ffbcdf0c76e1dc7cf86617ff4027 Mon Sep 17 00:00:00 2001 From: totubamowo Date: Wed, 30 Oct 2019 11:56:55 +0000 Subject: [PATCH 01/19] Make rate-limiting client whitelist dynamic * Refactor `RateLimitOptions.ClientWhiteList` * Fix typo in variable `enbleRateLimiting` * Fix case in variable `clientIdheader` author Taiwo Otubamowo --- .../Builder/RateLimitOptionsBuilder.cs | 18 ++++++----- .../Creator/RateLimitOptionsCreator.cs | 2 +- src/Ocelot/Configuration/RateLimitOptions.cs | 30 +++++++++++-------- .../RateLimitOptionsCreatorTests.cs | 2 +- .../ClientRateLimitMiddlewareTests.cs | 30 +++++++++---------- 5 files changed, 45 insertions(+), 37 deletions(-) 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; } } -} +} From 2c97c5859d260847d2220657e8946484784e5ea7 Mon Sep 17 00:00:00 2001 From: catcherwong Date: Tue, 5 Nov 2019 11:02:04 +0800 Subject: [PATCH 02/19] fix 1045 --- src/Ocelot/Requester/HttpExeptionToErrorMapper.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Ocelot/Requester/HttpExeptionToErrorMapper.cs b/src/Ocelot/Requester/HttpExeptionToErrorMapper.cs index 100d01f4..f2fbad2d 100644 --- a/src/Ocelot/Requester/HttpExeptionToErrorMapper.cs +++ b/src/Ocelot/Requester/HttpExeptionToErrorMapper.cs @@ -1,6 +1,6 @@ namespace Ocelot.Requester { - using Errors; + using Ocelot.Errors; using Microsoft.Extensions.DependencyInjection; using System; using System.Collections.Generic; @@ -23,7 +23,7 @@ namespace Ocelot.Requester return _mappers[type](exception); } - if (type == typeof(OperationCanceledException)) + if (type == typeof(OperationCanceledException) || type.IsSubclassOf(typeof(OperationCanceledException))) { return new RequestCanceledError(exception.Message); } From f0667471dd752ab0893e7ed024c40aeab3f5276c Mon Sep 17 00:00:00 2001 From: jlukawska Date: Thu, 7 Nov 2019 09:18:05 +0100 Subject: [PATCH 03/19] #492 log 500 with error log level, acceptance test, unit test --- .../Middleware/HttpRequesterMiddleware.cs | 7 ++- .../Ocelot.AcceptanceTests.csproj | 1 + .../ReturnsErrorTests.cs | 36 +++++++++++- test/Ocelot.AcceptanceTests/Steps.cs | 57 +++++++++++++++++++ .../Requester/HttpRequesterMiddlewareTests.cs | 21 +++++++ 5 files changed, 120 insertions(+), 2 deletions(-) diff --git a/src/Ocelot/Requester/Middleware/HttpRequesterMiddleware.cs b/src/Ocelot/Requester/Middleware/HttpRequesterMiddleware.cs index 92d3128e..22e4d8f8 100644 --- a/src/Ocelot/Requester/Middleware/HttpRequesterMiddleware.cs +++ b/src/Ocelot/Requester/Middleware/HttpRequesterMiddleware.cs @@ -20,7 +20,12 @@ namespace Ocelot.Requester.Middleware public async Task Invoke(DownstreamContext context) { - var response = await _requester.GetResponse(context); + var response = await _requester.GetResponse(context); + + if (response.Data != null && response.Data.StatusCode == System.Net.HttpStatusCode.InternalServerError) + { + Logger.LogError("500 (Internal Server Error) status code, request uri: " + response.Data.RequestMessage?.RequestUri, null); + } if (response.IsError) { diff --git a/test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.csproj b/test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.csproj index 762448e7..38f2ecca 100644 --- a/test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.csproj +++ b/test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.csproj @@ -40,6 +40,7 @@ + all diff --git a/test/Ocelot.AcceptanceTests/ReturnsErrorTests.cs b/test/Ocelot.AcceptanceTests/ReturnsErrorTests.cs index f72efff8..8f9a6455 100644 --- a/test/Ocelot.AcceptanceTests/ReturnsErrorTests.cs +++ b/test/Ocelot.AcceptanceTests/ReturnsErrorTests.cs @@ -20,7 +20,8 @@ [Fact] public void should_return_internal_server_error_if_downstream_service_returns_internal_server_error() - { + { + var configuration = new FileConfiguration { ReRoutes = new List @@ -49,6 +50,39 @@ .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.InternalServerError)) .BDDfy(); + } + + [Fact] + public void should_log_error_if_downstream_service_returns_internal_server_error() + { + var configuration = new FileConfiguration + { + ReRoutes = new List + { + new FileReRoute + { + DownstreamPathTemplate = "/", + UpstreamPathTemplate = "/", + UpstreamHttpMethod = new List { "Get" }, + DownstreamHostAndPorts = new List + { + new FileHostAndPort + { + Host = "localhost", + Port = 53876, + }, + }, + DownstreamScheme = "http", + }, + }, + }; + + this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:53876")) + .And(x => _steps.GivenThereIsAConfiguration(configuration)) + .And(x => _steps.GivenOcelotIsRunningWithLogger()) + .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) + .Then(x => _steps.ThenErrorShouldBeLogged()) + .BDDfy(); } private void GivenThereIsAServiceRunningOn(string url) diff --git a/test/Ocelot.AcceptanceTests/Steps.cs b/test/Ocelot.AcceptanceTests/Steps.cs index 6b9870bd..0fbb0105 100644 --- a/test/Ocelot.AcceptanceTests/Steps.cs +++ b/test/Ocelot.AcceptanceTests/Steps.cs @@ -10,12 +10,14 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; + using Moq; using Newtonsoft.Json; using Ocelot.Cache.CacheManager; using Ocelot.Configuration.Creator; using Ocelot.Configuration.File; using Ocelot.DependencyInjection; using Ocelot.Infrastructure; + using Ocelot.Logging; using Ocelot.Middleware; using Ocelot.Middleware.Multiplexer; using Ocelot.Provider.Consul; @@ -1120,5 +1122,60 @@ _ocelotClient = _ocelotServer.CreateClient(); } + + public void GivenOcelotIsRunningWithLogger() + { + _webHostBuilder = new WebHostBuilder(); + + _webHostBuilder + .ConfigureAppConfiguration((hostingContext, config) => + { + config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath); + var env = hostingContext.HostingEnvironment; + config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: false) + .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: false); + config.AddJsonFile("ocelot.json", false, false); + config.AddEnvironmentVariables(); + }) + .ConfigureServices(s => + { + s.AddOcelot(); + s.AddSingleton(); + }) + .Configure(app => + { + app.UseOcelot().Wait(); + }); + + _ocelotServer = new TestServer(_webHostBuilder); + + _ocelotClient = _ocelotServer.CreateClient(); + } + + public void ThenErrorShouldBeLogged() + { + MockLoggerFactory loggerFactory = (MockLoggerFactory)_ocelotServer.Host.Services.GetService(); + loggerFactory.Verify(); + } + + internal class MockLoggerFactory : IOcelotLoggerFactory + { + private Mock _logger; + + public IOcelotLogger CreateLogger() + { + if (_logger == null) + { + _logger = new Mock(); + _logger.Setup(x => x.LogError(It.IsAny(), It.IsAny())).Verifiable(); + } + return _logger.Object; + } + + public void Verify() + { + _logger.Verify(x => x.LogError(It.IsAny(), It.IsAny()), Times.Once); + } + } } } diff --git a/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs b/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs index a597df6b..8b4c53c5 100644 --- a/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs @@ -1,6 +1,7 @@ namespace Ocelot.UnitTests.Requester { using Microsoft.AspNetCore.Http; + using Microsoft.Extensions.Logging; using Moq; using Ocelot.Configuration.Builder; using Ocelot.Logging; @@ -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(new HttpResponseMessage(System.Net.HttpStatusCode.InternalServerError)))) + .When(x => x.WhenICallTheMiddleware()) + .Then(x => x.ErrorIsLogged()) + .BDDfy(); + } + private void ThenTheErrorIsSet() { _downstreamContext.IsError.ShouldBeTrue(); @@ -98,5 +110,14 @@ namespace Ocelot.UnitTests.Requester _downstreamContext.DownstreamResponse.Content.ShouldBe(_response.Data.Content); _downstreamContext.DownstreamResponse.StatusCode.ShouldBe(_response.Data.StatusCode); } + + private void ErrorIsLogged() + { + _logger.Verify( + x => x.LogError( + It.IsAny(), + It.IsAny() + )); + } } } From 90c56768879826ba9b16992bede383ac92ab4d94 Mon Sep 17 00:00:00 2001 From: jlukawska Date: Mon, 11 Nov 2019 21:47:31 +0100 Subject: [PATCH 04/19] #492 minor changes --- src/Ocelot/Requester/Middleware/HttpRequesterMiddleware.cs | 4 ++-- .../Requester/HttpRequesterMiddlewareTests.cs | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Ocelot/Requester/Middleware/HttpRequesterMiddleware.cs b/src/Ocelot/Requester/Middleware/HttpRequesterMiddleware.cs index 22e4d8f8..0919fac3 100644 --- a/src/Ocelot/Requester/Middleware/HttpRequesterMiddleware.cs +++ b/src/Ocelot/Requester/Middleware/HttpRequesterMiddleware.cs @@ -22,9 +22,9 @@ namespace Ocelot.Requester.Middleware { var response = await _requester.GetResponse(context); - if (response.Data != null && response.Data.StatusCode == System.Net.HttpStatusCode.InternalServerError) + if (response.Data?.StatusCode == System.Net.HttpStatusCode.InternalServerError) { - Logger.LogError("500 (Internal Server Error) status code, request uri: " + response.Data.RequestMessage?.RequestUri, null); + Logger.LogError($"{(int)response.Data.StatusCode} ({response.Data.ReasonPhrase}) status code, request uri: {response.Data.RequestMessage?.RequestUri}", null); } if (response.IsError) diff --git a/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs b/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs index 8b4c53c5..8d3525f8 100644 --- a/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs @@ -117,7 +117,8 @@ namespace Ocelot.UnitTests.Requester x => x.LogError( It.IsAny(), It.IsAny() - )); + ), + Times.Once); } } } From 3942c329abb303e7f6c62c1365a3c88c8a55ef96 Mon Sep 17 00:00:00 2001 From: Jean-Philippe BURET Date: Tue, 10 Dec 2019 13:50:15 +0100 Subject: [PATCH 05/19] initial commit for new feature #1077 allow to limit the number of concurrent tcp connection to a downstream service --- .../Creator/HttpHandlerOptionsCreator.cs | 2 +- .../File/FileHttpHandlerOptions.cs | 7 +++- .../Configuration/HttpHandlerOptions.cs | 38 ++++++++++++------- .../HttpHandlerOptionsBuilder.cs | 9 ++++- src/Ocelot/Requester/HttpClientBuilder.cs | 5 ++- .../HttpHandlerOptionsCreatorTests.cs | 12 +++--- ...atingHandlerHandlerProviderFactoryTests.cs | 24 ++++++------ .../Requester/HttpClientBuilderTests.cs | 18 ++++----- .../Requester/HttpClientHttpRequesterTest.cs | 6 +-- 9 files changed, 73 insertions(+), 48 deletions(-) diff --git a/src/Ocelot/Configuration/Creator/HttpHandlerOptionsCreator.cs b/src/Ocelot/Configuration/Creator/HttpHandlerOptionsCreator.cs index 08e79ad1..d14415aa 100644 --- a/src/Ocelot/Configuration/Creator/HttpHandlerOptionsCreator.cs +++ b/src/Ocelot/Configuration/Creator/HttpHandlerOptionsCreator.cs @@ -19,7 +19,7 @@ var useTracing = _tracer != null && options.UseTracing; return new HttpHandlerOptions(options.AllowAutoRedirect, - options.UseCookieContainer, useTracing, options.UseProxy); + options.UseCookieContainer, useTracing, options.UseProxy, options.MaxConnectionsPerServer); } } } diff --git a/src/Ocelot/Configuration/File/FileHttpHandlerOptions.cs b/src/Ocelot/Configuration/File/FileHttpHandlerOptions.cs index d765af58..b83be428 100644 --- a/src/Ocelot/Configuration/File/FileHttpHandlerOptions.cs +++ b/src/Ocelot/Configuration/File/FileHttpHandlerOptions.cs @@ -6,7 +6,8 @@ { AllowAutoRedirect = false; UseCookieContainer = false; - UseProxy = true; + UseProxy = true; + MaxConnectionsPerServer = int.MaxValue; } public bool AllowAutoRedirect { get; set; } @@ -15,6 +16,8 @@ public bool UseTracing { get; set; } - public bool UseProxy { get; set; } + public bool UseProxy { get; set; } + + public int MaxConnectionsPerServer { get; set; } } } diff --git a/src/Ocelot/Configuration/HttpHandlerOptions.cs b/src/Ocelot/Configuration/HttpHandlerOptions.cs index b551287f..e76cc117 100644 --- a/src/Ocelot/Configuration/HttpHandlerOptions.cs +++ b/src/Ocelot/Configuration/HttpHandlerOptions.cs @@ -6,32 +6,44 @@ /// public class HttpHandlerOptions { - public HttpHandlerOptions(bool allowAutoRedirect, bool useCookieContainer, bool useTracing, bool useProxy) - { - AllowAutoRedirect = allowAutoRedirect; - UseCookieContainer = useCookieContainer; - UseTracing = useTracing; - UseProxy = useProxy; + public HttpHandlerOptions(bool allowAutoRedirect, bool useCookieContainer, bool useTracing, bool useProxy, int maxConnectionsPerServer) + { + AllowAutoRedirect = allowAutoRedirect; + UseCookieContainer = useCookieContainer; + UseTracing = useTracing; + UseProxy = useProxy; + MaxConnectionsPerServer = maxConnectionsPerServer; } + /// /// Specify if auto redirect is enabled - /// - public bool AllowAutoRedirect { get; private set; } - + /// + /// AllowAutoRedirect + public bool AllowAutoRedirect { get; private set; } + /// /// Specify is handler has to use a cookie container - /// + /// + /// UseCookieContainer public bool UseCookieContainer { get; private set; } /// /// Specify is handler has to use a opentracing - /// + /// + /// UseTracing public bool UseTracing { get; private set; } /// /// Specify if handler has to use a proxy - /// - public bool UseProxy { get; private set; } + /// + /// UseProxy + public bool UseProxy { get; private set; } + + /// + /// Specify the maximum of concurrent connection to a network endpoint + /// + /// MaxConnectionsPerServer + public int MaxConnectionsPerServer { get; private set; } } } diff --git a/src/Ocelot/Configuration/HttpHandlerOptionsBuilder.cs b/src/Ocelot/Configuration/HttpHandlerOptionsBuilder.cs index bf8aa042..8e66094b 100644 --- a/src/Ocelot/Configuration/HttpHandlerOptionsBuilder.cs +++ b/src/Ocelot/Configuration/HttpHandlerOptionsBuilder.cs @@ -6,6 +6,7 @@ private bool _useCookieContainer; private bool _useTracing; private bool _useProxy; + private int _maxConnectionPerServer; public HttpHandlerOptionsBuilder WithAllowAutoRedirect(bool input) { @@ -30,10 +31,16 @@ _useProxy = useProxy; return this; } + public HttpHandlerOptionsBuilder WithUseMaxConnectionPerServer(int maxConnectionPerServer) + { + _maxConnectionPerServer = maxConnectionPerServer; + return this; + } + public HttpHandlerOptions Build() { - return new HttpHandlerOptions(_allowAutoRedirect, _useCookieContainer, _useTracing, _useProxy); + return new HttpHandlerOptions(_allowAutoRedirect, _useCookieContainer, _useTracing, _useProxy, _maxConnectionPerServer); } } } diff --git a/src/Ocelot/Requester/HttpClientBuilder.cs b/src/Ocelot/Requester/HttpClientBuilder.cs index 64df44b1..e7d45857 100644 --- a/src/Ocelot/Requester/HttpClientBuilder.cs +++ b/src/Ocelot/Requester/HttpClientBuilder.cs @@ -90,7 +90,9 @@ namespace Ocelot.Requester { AllowAutoRedirect = context.DownstreamReRoute.HttpHandlerOptions.AllowAutoRedirect, UseCookies = context.DownstreamReRoute.HttpHandlerOptions.UseCookieContainer, - UseProxy = context.DownstreamReRoute.HttpHandlerOptions.UseProxy + UseProxy = context.DownstreamReRoute.HttpHandlerOptions.UseProxy, + MaxConnectionsPerServer = context.DownstreamReRoute.HttpHandlerOptions.MaxConnectionsPerServer + }; } @@ -101,6 +103,7 @@ namespace Ocelot.Requester AllowAutoRedirect = context.DownstreamReRoute.HttpHandlerOptions.AllowAutoRedirect, UseCookies = context.DownstreamReRoute.HttpHandlerOptions.UseCookieContainer, UseProxy = context.DownstreamReRoute.HttpHandlerOptions.UseProxy, + MaxConnectionsPerServer = context.DownstreamReRoute.HttpHandlerOptions.MaxConnectionsPerServer, CookieContainer = new CookieContainer() }; } diff --git a/test/Ocelot.UnitTests/Configuration/HttpHandlerOptionsCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/HttpHandlerOptionsCreatorTests.cs index 4915dc5d..db81f199 100644 --- a/test/Ocelot.UnitTests/Configuration/HttpHandlerOptionsCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/HttpHandlerOptionsCreatorTests.cs @@ -41,7 +41,7 @@ namespace Ocelot.UnitTests.Configuration } }; - var expectedOptions = new HttpHandlerOptions(false, false, false, true); + var expectedOptions = new HttpHandlerOptions(false, false, false, true, int.MaxValue); this.Given(x => GivenTheFollowing(fileReRoute)) .When(x => WhenICreateHttpHandlerOptions()) @@ -60,7 +60,7 @@ namespace Ocelot.UnitTests.Configuration } }; - var expectedOptions = new HttpHandlerOptions(false, false, true, true); + var expectedOptions = new HttpHandlerOptions(false, false, true, true, int.MaxValue); this.Given(x => GivenTheFollowing(fileReRoute)) .And(x => GivenARealTracer()) @@ -73,7 +73,7 @@ namespace Ocelot.UnitTests.Configuration public void should_create_options_with_useCookie_false_and_allowAutoRedirect_true_as_default() { var fileReRoute = new FileReRoute(); - var expectedOptions = new HttpHandlerOptions(false, false, false, true); + var expectedOptions = new HttpHandlerOptions(false, false, false, true, int.MaxValue); this.Given(x => GivenTheFollowing(fileReRoute)) .When(x => WhenICreateHttpHandlerOptions()) @@ -94,7 +94,7 @@ namespace Ocelot.UnitTests.Configuration } }; - var expectedOptions = new HttpHandlerOptions(false, false, false, true); + var expectedOptions = new HttpHandlerOptions(false, false, false, true, int.MaxValue); this.Given(x => GivenTheFollowing(fileReRoute)) .When(x => WhenICreateHttpHandlerOptions()) @@ -110,7 +110,7 @@ namespace Ocelot.UnitTests.Configuration HttpHandlerOptions = new FileHttpHandlerOptions() }; - var expectedOptions = new HttpHandlerOptions(false, false, false, true); + var expectedOptions = new HttpHandlerOptions(false, false, false, true, int.MaxValue); this.Given(x => GivenTheFollowing(fileReRoute)) .When(x => WhenICreateHttpHandlerOptions()) @@ -129,7 +129,7 @@ namespace Ocelot.UnitTests.Configuration } }; - var expectedOptions = new HttpHandlerOptions(false, false, false, false); + var expectedOptions = new HttpHandlerOptions(false, false, false, false, int.MaxValue); this.Given(x => GivenTheFollowing(fileReRoute)) .When(x => WhenICreateHttpHandlerOptions()) diff --git a/test/Ocelot.UnitTests/Requester/DelegatingHandlerHandlerProviderFactoryTests.cs b/test/Ocelot.UnitTests/Requester/DelegatingHandlerHandlerProviderFactoryTests.cs index 2b2340ef..050b2da8 100644 --- a/test/Ocelot.UnitTests/Requester/DelegatingHandlerHandlerProviderFactoryTests.cs +++ b/test/Ocelot.UnitTests/Requester/DelegatingHandlerHandlerProviderFactoryTests.cs @@ -52,7 +52,7 @@ namespace Ocelot.UnitTests.Requester var reRoute = new DownstreamReRouteBuilder() .WithQosOptions(qosOptions) - .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true, true)) + .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true, true, int.MaxValue)) .WithDelegatingHandlers(new List { "FakeDelegatingHandler", @@ -88,7 +88,7 @@ namespace Ocelot.UnitTests.Requester var reRoute = new DownstreamReRouteBuilder() .WithQosOptions(qosOptions) - .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true, true)) + .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true, true, int.MaxValue)) .WithDelegatingHandlers(new List { "FakeDelegatingHandlerTwo", @@ -125,7 +125,7 @@ namespace Ocelot.UnitTests.Requester var reRoute = new DownstreamReRouteBuilder() .WithQosOptions(qosOptions) - .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true, true)) + .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true, true, int.MaxValue)) .WithDelegatingHandlers(new List { "FakeDelegatingHandlerTwo", @@ -161,7 +161,7 @@ namespace Ocelot.UnitTests.Requester var reRoute = new DownstreamReRouteBuilder() .WithQosOptions(qosOptions) - .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true, true)) + .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true, true, int.MaxValue)) .WithDelegatingHandlers(new List { "FakeDelegatingHandler", @@ -195,7 +195,7 @@ namespace Ocelot.UnitTests.Requester var reRoute = new DownstreamReRouteBuilder() .WithQosOptions(qosOptions) - .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true, true)) + .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true, true, int.MaxValue)) .WithLoadBalancerKey("") .Build(); @@ -221,7 +221,7 @@ namespace Ocelot.UnitTests.Requester var reRoute = new DownstreamReRouteBuilder() .WithQosOptions(qosOptions) - .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true)) + .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true, int.MaxValue)) .WithDelegatingHandlers(new List { "FakeDelegatingHandler", @@ -249,7 +249,7 @@ namespace Ocelot.UnitTests.Requester var reRoute = new DownstreamReRouteBuilder() .WithQosOptions(qosOptions) - .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true)).WithLoadBalancerKey("").Build(); + .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true, int.MaxValue)).WithLoadBalancerKey("").Build(); this.Given(x => GivenTheFollowingRequest(reRoute)) .And(x => GivenTheQosFactoryReturns(new FakeQoSHandler())) @@ -269,7 +269,7 @@ namespace Ocelot.UnitTests.Requester var reRoute = new DownstreamReRouteBuilder() .WithQosOptions(qosOptions) - .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true)).WithLoadBalancerKey("").Build(); + .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true, int.MaxValue)).WithLoadBalancerKey("").Build(); this.Given(x => GivenTheFollowingRequest(reRoute)) .And(x => GivenTheServiceProviderReturnsNothing()) @@ -289,7 +289,7 @@ namespace Ocelot.UnitTests.Requester var reRoute = new DownstreamReRouteBuilder() .WithQosOptions(qosOptions) - .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true)).WithLoadBalancerKey("").Build(); + .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true, int.MaxValue)).WithLoadBalancerKey("").Build(); this.Given(x => GivenTheFollowingRequest(reRoute)) .And(x => GivenTheQosFactoryReturns(new FakeQoSHandler())) @@ -309,7 +309,7 @@ namespace Ocelot.UnitTests.Requester var reRoute = new DownstreamReRouteBuilder() .WithQosOptions(qosOptions) - .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true)).WithLoadBalancerKey("").Build(); + .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true, int.MaxValue)).WithLoadBalancerKey("").Build(); this.Given(x => GivenTheFollowingRequest(reRoute)) .And(x => GivenTheQosFactoryReturns(new FakeQoSHandler())) @@ -331,7 +331,7 @@ namespace Ocelot.UnitTests.Requester var reRoute = new DownstreamReRouteBuilder() .WithQosOptions(qosOptions) - .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true, true)) + .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true, true, int.MaxValue)) .WithLoadBalancerKey("") .Build(); @@ -361,7 +361,7 @@ namespace Ocelot.UnitTests.Requester var reRoute = new DownstreamReRouteBuilder() .WithQosOptions(qosOptions) - .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true, true)) + .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true, true, int.MaxValue)) .WithLoadBalancerKey("") .Build(); diff --git a/test/Ocelot.UnitTests/Requester/HttpClientBuilderTests.cs b/test/Ocelot.UnitTests/Requester/HttpClientBuilderTests.cs index 34bf11c1..c8dbd4a2 100644 --- a/test/Ocelot.UnitTests/Requester/HttpClientBuilderTests.cs +++ b/test/Ocelot.UnitTests/Requester/HttpClientBuilderTests.cs @@ -52,7 +52,7 @@ namespace Ocelot.UnitTests.Requester var reRoute = new DownstreamReRouteBuilder() .WithQosOptions(qosOptions) - .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true)) + .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue)) .WithLoadBalancerKey("") .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("").Build()) .WithQosOptions(new QoSOptionsBuilder().Build()) @@ -73,7 +73,7 @@ namespace Ocelot.UnitTests.Requester var reRoute = new DownstreamReRouteBuilder() .WithQosOptions(qosOptions) - .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true)) + .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue)) .WithLoadBalancerKey("") .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("").Build()) .WithQosOptions(new QoSOptionsBuilder().Build()) @@ -99,7 +99,7 @@ namespace Ocelot.UnitTests.Requester var reRoute = new DownstreamReRouteBuilder() .WithQosOptions(qosOptions) - .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true)) + .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue)) .WithLoadBalancerKey("") .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("").Build()) .WithQosOptions(new QoSOptionsBuilder().Build()) @@ -126,7 +126,7 @@ namespace Ocelot.UnitTests.Requester var reRouteA = new DownstreamReRouteBuilder() .WithQosOptions(qosOptions) - .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true)) + .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue)) .WithLoadBalancerKey("") .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithContainsQueryString(true).WithOriginalValue("").Build()) .WithQosOptions(new QoSOptionsBuilder().Build()) @@ -134,7 +134,7 @@ namespace Ocelot.UnitTests.Requester var reRouteB = new DownstreamReRouteBuilder() .WithQosOptions(qosOptions) - .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true)) + .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue)) .WithLoadBalancerKey("") .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithContainsQueryString(true).WithOriginalValue("").Build()) .WithQosOptions(new QoSOptionsBuilder().Build()) @@ -161,7 +161,7 @@ namespace Ocelot.UnitTests.Requester var reRoute = new DownstreamReRouteBuilder() .WithQosOptions(qosOptions) - .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true)) + .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue)) .WithLoadBalancerKey("") .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("").Build()) .WithQosOptions(new QoSOptionsBuilder().Build()) @@ -184,7 +184,7 @@ namespace Ocelot.UnitTests.Requester var reRoute = new DownstreamReRouteBuilder() .WithQosOptions(qosOptions) - .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true)) + .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue)) .WithLoadBalancerKey("") .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("").Build()) .WithQosOptions(new QoSOptionsBuilder().Build()) @@ -216,7 +216,7 @@ namespace Ocelot.UnitTests.Requester var reRoute = new DownstreamReRouteBuilder() .WithQosOptions(qosOptions) - .WithHttpHandlerOptions(new HttpHandlerOptions(false, true, false, true)) + .WithHttpHandlerOptions(new HttpHandlerOptions(false, true, false, true, int.MaxValue)) .WithLoadBalancerKey("") .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("").Build()) .WithQosOptions(new QoSOptionsBuilder().Build()) @@ -252,7 +252,7 @@ namespace Ocelot.UnitTests.Requester var reRoute = new DownstreamReRouteBuilder() .WithQosOptions(qosOptions) - .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true)) + .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue)) .WithLoadBalancerKey("") .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("").Build()) .WithQosOptions(new QoSOptionsBuilder().Build()) diff --git a/test/Ocelot.UnitTests/Requester/HttpClientHttpRequesterTest.cs b/test/Ocelot.UnitTests/Requester/HttpClientHttpRequesterTest.cs index 53106d93..43bfa5d5 100644 --- a/test/Ocelot.UnitTests/Requester/HttpClientHttpRequesterTest.cs +++ b/test/Ocelot.UnitTests/Requester/HttpClientHttpRequesterTest.cs @@ -57,7 +57,7 @@ namespace Ocelot.UnitTests.Requester var reRoute = new DownstreamReRouteBuilder() .WithQosOptions(qosOptions) - .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true)) + .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue)) .WithLoadBalancerKey("") .WithUpstreamPathTemplate(upstreamTemplate) .WithQosOptions(new QoSOptionsBuilder().Build()) @@ -86,7 +86,7 @@ namespace Ocelot.UnitTests.Requester var reRoute = new DownstreamReRouteBuilder() .WithQosOptions(qosOptions) - .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true)) + .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue)) .WithLoadBalancerKey("") .WithUpstreamPathTemplate(upstreamTemplate) .WithQosOptions(new QoSOptionsBuilder().Build()) @@ -114,7 +114,7 @@ namespace Ocelot.UnitTests.Requester var reRoute = new DownstreamReRouteBuilder() .WithQosOptions(qosOptions) - .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true)) + .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue)) .WithLoadBalancerKey("") .WithUpstreamPathTemplate(upstreamTemplate) .WithQosOptions(new QoSOptionsBuilder().WithTimeoutValue(1).Build()) From dbb61834d92ee6b523d029791cb03386e55acedd Mon Sep 17 00:00:00 2001 From: Jean-Philippe BURET Date: Tue, 10 Dec 2019 14:23:54 +0100 Subject: [PATCH 06/19] protect code against value not in accurate range add unit test --- .../Creator/HttpHandlerOptionsCreator.cs | 5 ++- .../HttpHandlerOptionsCreatorTests.cs | 39 +++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/Ocelot/Configuration/Creator/HttpHandlerOptionsCreator.cs b/src/Ocelot/Configuration/Creator/HttpHandlerOptionsCreator.cs index d14415aa..4e38100b 100644 --- a/src/Ocelot/Configuration/Creator/HttpHandlerOptionsCreator.cs +++ b/src/Ocelot/Configuration/Creator/HttpHandlerOptionsCreator.cs @@ -18,8 +18,11 @@ { var useTracing = _tracer != null && options.UseTracing; + //be sure that maxConnectionPerServer is in correct range of values + int maxConnectionPerServer = (options.MaxConnectionsPerServer > 0) ? maxConnectionPerServer = options.MaxConnectionsPerServer : maxConnectionPerServer = int.MaxValue; + return new HttpHandlerOptions(options.AllowAutoRedirect, - options.UseCookieContainer, useTracing, options.UseProxy, options.MaxConnectionsPerServer); + options.UseCookieContainer, useTracing, options.UseProxy, maxConnectionPerServer); } } } diff --git a/test/Ocelot.UnitTests/Configuration/HttpHandlerOptionsCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/HttpHandlerOptionsCreatorTests.cs index db81f199..39db08f5 100644 --- a/test/Ocelot.UnitTests/Configuration/HttpHandlerOptionsCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/HttpHandlerOptionsCreatorTests.cs @@ -137,6 +137,44 @@ namespace Ocelot.UnitTests.Configuration .BDDfy(); } + [Fact] + public void should_create_options_with_specified_MaxConnectionsPerServer() + { + var fileReRoute = new FileReRoute + { + HttpHandlerOptions = new FileHttpHandlerOptions + { + MaxConnectionsPerServer = 10 + } + }; + + var expectedOptions = new HttpHandlerOptions(false, false, false, true, 10); + + this.Given(x => GivenTheFollowing(fileReRoute)) + .When(x => WhenICreateHttpHandlerOptions()) + .Then(x => ThenTheFollowingOptionsReturned(expectedOptions)) + .BDDfy(); + } + + [Fact] + public void should_create_options_fixing_specified_MaxConnectionsPerServer_range() + { + var fileReRoute = new FileReRoute + { + HttpHandlerOptions = new FileHttpHandlerOptions + { + MaxConnectionsPerServer = -1 + } + }; + + var expectedOptions = new HttpHandlerOptions(false, false, false, true, int.MaxValue); + + this.Given(x => GivenTheFollowing(fileReRoute)) + .When(x => WhenICreateHttpHandlerOptions()) + .Then(x => ThenTheFollowingOptionsReturned(expectedOptions)) + .BDDfy(); + } + private void GivenTheFollowing(FileReRoute fileReRoute) { _fileReRoute = fileReRoute; @@ -154,6 +192,7 @@ namespace Ocelot.UnitTests.Configuration _httpHandlerOptions.UseCookieContainer.ShouldBe(expected.UseCookieContainer); _httpHandlerOptions.UseTracing.ShouldBe(expected.UseTracing); _httpHandlerOptions.UseProxy.ShouldBe(expected.UseProxy); + _httpHandlerOptions.MaxConnectionsPerServer.ShouldBe(expected.MaxConnectionsPerServer); } private void GivenARealTracer() From fd74ea280b0c8973234383131d0350cfe6097df9 Mon Sep 17 00:00:00 2001 From: Jonathan Mezach Date: Thu, 12 Dec 2019 08:12:10 +0100 Subject: [PATCH 07/19] Do not crash host on Dispose --- src/Ocelot/Configuration/Repository/FileConfigurationPoller.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Ocelot/Configuration/Repository/FileConfigurationPoller.cs b/src/Ocelot/Configuration/Repository/FileConfigurationPoller.cs index cca50d0b..9a2b67e6 100644 --- a/src/Ocelot/Configuration/Repository/FileConfigurationPoller.cs +++ b/src/Ocelot/Configuration/Repository/FileConfigurationPoller.cs @@ -105,7 +105,8 @@ namespace Ocelot.Configuration.Repository public void Dispose() { - _timer.Dispose(); + _timer?.Dispose(); + _timer = null; } } } From ac7d0d0af3e9f16c6f76237ca7750e7fdf466915 Mon Sep 17 00:00:00 2001 From: Jonathan Mezach Date: Thu, 12 Dec 2019 08:35:22 +0100 Subject: [PATCH 08/19] Add test --- .../FileConfigurationPollerTests.cs | 32 +++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/test/Ocelot.UnitTests/Configuration/FileConfigurationPollerTests.cs b/test/Ocelot.UnitTests/Configuration/FileConfigurationPollerTests.cs index 3008fc6b..bfc0c98c 100644 --- a/test/Ocelot.UnitTests/Configuration/FileConfigurationPollerTests.cs +++ b/test/Ocelot.UnitTests/Configuration/FileConfigurationPollerTests.cs @@ -41,14 +41,14 @@ namespace Ocelot.UnitTests.Configuration _internalConfigCreator = new Mock(); _internalConfigCreator.Setup(x => x.Create(It.IsAny())).ReturnsAsync(new OkResponse(_internalConfig)); _poller = new FileConfigurationPoller(_factory.Object, _repo.Object, _config.Object, _internalConfigRepo.Object, _internalConfigCreator.Object); - _poller.StartAsync(new CancellationToken()); } [Fact] public void should_start() { - this.Given(x => ThenTheSetterIsCalled(_fileConfig, 1)) - .BDDfy(); + this.Given(x => GivenPollerHasStarted()) + .Given(x => ThenTheSetterIsCalled(_fileConfig, 1)) + .BDDfy(); } [Fact] @@ -71,7 +71,8 @@ namespace Ocelot.UnitTests.Configuration } }; - this.Given(x => WhenTheConfigIsChanged(newConfig, 0)) + this.Given(x => GivenPollerHasStarted()) + .Given(x => WhenTheConfigIsChanged(newConfig, 0)) .Then(x => ThenTheSetterIsCalledAtLeast(newConfig, 1)) .BDDfy(); } @@ -96,7 +97,8 @@ namespace Ocelot.UnitTests.Configuration } }; - this.Given(x => WhenTheConfigIsChanged(newConfig, 10)) + this.Given(x => GivenPollerHasStarted()) + .Given(x => WhenTheConfigIsChanged(newConfig, 10)) .Then(x => ThenTheSetterIsCalled(newConfig, 1)) .BDDfy(); } @@ -121,11 +123,24 @@ namespace Ocelot.UnitTests.Configuration } }; - this.Given(x => WhenProviderErrors()) + this.Given(x => GivenPollerHasStarted()) + .Given(x => WhenProviderErrors()) .Then(x => ThenTheSetterIsCalled(newConfig, 0)) .BDDfy(); } + [Fact] + public void should_dispose_cleanly_without_starting() + { + this.When(x => WhenPollerIsDisposed()) + .BDDfy(); + } + + private void GivenPollerHasStarted() + { + _poller.StartAsync(CancellationToken.None); + } + private void WhenProviderErrors() { _repo @@ -141,6 +156,11 @@ namespace Ocelot.UnitTests.Configuration .ReturnsAsync(new OkResponse(newConfig)); } + private void WhenPollerIsDisposed() + { + _poller.Dispose(); + } + private void ThenTheSetterIsCalled(FileConfiguration fileConfig, int times) { var result = WaitFor(4000).Until(() => From ef52ea3fc48705e19519c67e03a611cb6bdd3236 Mon Sep 17 00:00:00 2001 From: Jonathan Mezach Date: Thu, 12 Dec 2019 08:48:13 +0100 Subject: [PATCH 09/19] Pin GitVersion.CommandLine package version --- build.cake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.cake b/build.cake index 5eb3d77c..8726183e 100644 --- a/build.cake +++ b/build.cake @@ -1,4 +1,4 @@ -#tool "nuget:?package=GitVersion.CommandLine" +#tool "nuget:?package=GitVersion.CommandLine&version=5.0.1" #tool "nuget:?package=GitReleaseNotes" #addin nuget:?package=Cake.Json #addin nuget:?package=Newtonsoft.Json From caf5cf80fa84f57708b3eadec9cc35a63b448dd6 Mon Sep 17 00:00:00 2001 From: jlukawska Date: Mon, 16 Dec 2019 21:19:31 +0100 Subject: [PATCH 10/19] #683 validate if there are duplicated placeholders in UpstreamPathTemplate --- .../FileConfigurationFluentValidator.cs | 13 ++++++++++ .../FileConfigurationFluentValidatorTests.cs | 26 +++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/src/Ocelot/Configuration/Validator/FileConfigurationFluentValidator.cs b/src/Ocelot/Configuration/Validator/FileConfigurationFluentValidator.cs index add4fe0b..e2f7f24d 100644 --- a/src/Ocelot/Configuration/Validator/FileConfigurationFluentValidator.cs +++ b/src/Ocelot/Configuration/Validator/FileConfigurationFluentValidator.cs @@ -9,6 +9,7 @@ using System; using System.Collections.Generic; using System.Linq; + using System.Text.RegularExpressions; using System.Threading.Tasks; public class FileConfigurationFluentValidator : AbstractValidator, IConfigurationValidator @@ -35,6 +36,10 @@ .Must((config, reRoute) => HaveServiceDiscoveryProviderRegistered(reRoute, config.GlobalConfiguration.ServiceDiscoveryProvider)) .WithMessage((config, reRoute) => $"Unable to start Ocelot, errors are: Unable to start Ocelot because either a ReRoute or GlobalConfiguration are using ServiceDiscoveryOptions but no ServiceDiscoveryFinderDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Consul and services.AddConsul() or Ocelot.Provider.Eureka and services.AddEureka()?"); + RuleForEach(configuration => configuration.ReRoutes) + .Must((config, reRoute) => IsPlaceholderNotDuplicatedIn(reRoute.UpstreamPathTemplate)) + .WithMessage((config, reRoute) => $"{nameof(reRoute)} {reRoute.UpstreamPathTemplate} has duplicated placeholder"); + RuleFor(configuration => configuration.GlobalConfiguration.ServiceDiscoveryProvider) .Must(HaveServiceDiscoveryProviderRegistered) .WithMessage((config, reRoute) => $"Unable to start Ocelot, errors are: Unable to start Ocelot because either a ReRoute or GlobalConfiguration are using ServiceDiscoveryOptions but no ServiceDiscoveryFinderDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Consul and services.AddConsul() or Ocelot.Provider.Eureka and services.AddEureka()?"); @@ -109,6 +114,14 @@ return reRoutesForAggregate.Count() == fileAggregateReRoute.ReRouteKeys.Count; } + private bool IsPlaceholderNotDuplicatedIn(string upstreamPathTemplate) + { + Regex regExPlaceholder = new Regex("{[^}]+}"); + var matches = regExPlaceholder.Matches(upstreamPathTemplate); + var upstreamPathPlaceholders = matches.Select(m => m.Value); + return upstreamPathPlaceholders.Count() == upstreamPathPlaceholders.Distinct().Count(); + } + private static bool DoesNotContainReRoutesWithSpecificRequestIdKeys(FileAggregateReRoute fileAggregateReRoute, List reRoutes) { diff --git a/test/Ocelot.UnitTests/Configuration/Validation/FileConfigurationFluentValidatorTests.cs b/test/Ocelot.UnitTests/Configuration/Validation/FileConfigurationFluentValidatorTests.cs index 943001fc..7055c1ad 100644 --- a/test/Ocelot.UnitTests/Configuration/Validation/FileConfigurationFluentValidatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/Validation/FileConfigurationFluentValidatorTests.cs @@ -1341,6 +1341,32 @@ .BDDfy(); } + [Fact] + public void configuration_is_invalid_when_placeholder_is_used_twice_in_upstream_path_template() + { + this.Given(x => x.GivenAConfiguration(new FileConfiguration + { + ReRoutes = new List + { + new FileReRoute + { + DownstreamPathTemplate = "/bar/{everything}", + DownstreamScheme = "http", + DownstreamHostAndPorts = new List + { + new FileHostAndPort() { Host = "a.b.cd" }, + }, + UpstreamPathTemplate = "/foo/bar/{everything}/{everything}", + UpstreamHttpMethod = new List { "Get" }, + }, + }, + })) + .When(x => x.WhenIValidateTheConfiguration()) + .Then(x => x.ThenTheResultIsNotValid()) + .And(x => x.ThenTheErrorMessageAtPositionIs(0, "reRoute /foo/bar/{everything}/{everything} has duplicated placeholder")) + .BDDfy(); + } + private void GivenAConfiguration(FileConfiguration fileConfiguration) { _fileConfiguration = fileConfiguration; From b28ced4ec5e519081b8824d0c0d39d3e071cb0be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BD=AD=E4=BC=9F?= Date: Sun, 19 Jan 2020 18:42:11 +0800 Subject: [PATCH 11/19] Use registered scheme from Eureka (#1087) --- src/Ocelot.Provider.Eureka/Eureka.cs | 2 +- .../DownstreamUrlCreatorMiddleware.cs | 5 ++- .../Middleware/LoadBalancingMiddleware.cs | 5 +++ .../ServiceDiscoveryProviderFactory.cs | 2 +- src/Ocelot/Values/ServiceHostAndPort.cs | 7 +++- .../DownstreamUrlCreatorMiddlewareTests.cs | 30 ++++++++++++++++ .../LoadBalancerMiddlewareTests.cs | 36 +++++++++++++++++++ 7 files changed, 83 insertions(+), 4 deletions(-) diff --git a/src/Ocelot.Provider.Eureka/Eureka.cs b/src/Ocelot.Provider.Eureka/Eureka.cs index 8316beac..8a064549 100644 --- a/src/Ocelot.Provider.Eureka/Eureka.cs +++ b/src/Ocelot.Provider.Eureka/Eureka.cs @@ -26,7 +26,7 @@ if (instances != null && instances.Any()) { - services.AddRange(instances.Select(i => new Service(i.ServiceId, new ServiceHostAndPort(i.Host, i.Port), "", "", new List()))); + services.AddRange(instances.Select(i => new Service(i.ServiceId, new ServiceHostAndPort(i.Host, i.Port, i.Uri.Scheme), "", "", new List()))); } return Task.FromResult(services); diff --git a/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs b/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs index d2e53b95..7d19d523 100644 --- a/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs +++ b/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs @@ -37,7 +37,10 @@ namespace Ocelot.DownstreamUrlCreator.Middleware return; } - context.DownstreamRequest.Scheme = context.DownstreamReRoute.DownstreamScheme; + if (!string.IsNullOrEmpty(context.DownstreamReRoute.DownstreamScheme)) + { + context.DownstreamRequest.Scheme = context.DownstreamReRoute.DownstreamScheme; + } if (ServiceFabricRequest(context)) { diff --git a/src/Ocelot/LoadBalancer/Middleware/LoadBalancingMiddleware.cs b/src/Ocelot/LoadBalancer/Middleware/LoadBalancingMiddleware.cs index 22456430..646af5fe 100644 --- a/src/Ocelot/LoadBalancer/Middleware/LoadBalancingMiddleware.cs +++ b/src/Ocelot/LoadBalancer/Middleware/LoadBalancingMiddleware.cs @@ -45,6 +45,11 @@ namespace Ocelot.LoadBalancer.Middleware context.DownstreamRequest.Port = hostAndPort.Data.DownstreamPort; } + if (!string.IsNullOrEmpty(hostAndPort.Data.Scheme)) + { + context.DownstreamRequest.Scheme = hostAndPort.Data.Scheme; + } + try { await _next.Invoke(context); diff --git a/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs b/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs index 1863a206..7a580872 100644 --- a/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs +++ b/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs @@ -34,7 +34,7 @@ namespace Ocelot.ServiceDiscovery foreach (var downstreamAddress in reRoute.DownstreamAddresses) { - var service = new Service(reRoute.ServiceName, new ServiceHostAndPort(downstreamAddress.Host, downstreamAddress.Port), string.Empty, string.Empty, new string[0]); + var service = new Service(reRoute.ServiceName, new ServiceHostAndPort(downstreamAddress.Host, downstreamAddress.Port, reRoute.DownstreamScheme), string.Empty, string.Empty, new string[0]); services.Add(service); } diff --git a/src/Ocelot/Values/ServiceHostAndPort.cs b/src/Ocelot/Values/ServiceHostAndPort.cs index 4a8e3748..fff7edba 100644 --- a/src/Ocelot/Values/ServiceHostAndPort.cs +++ b/src/Ocelot/Values/ServiceHostAndPort.cs @@ -8,8 +8,13 @@ DownstreamPort = downstreamPort; } + public ServiceHostAndPort(string downstreamHost, int downstreamPort, string scheme) + : this(downstreamHost, downstreamPort) => Scheme = scheme; + public string DownstreamHost { get; } - public int DownstreamPort { get; } + public int DownstreamPort { get; } + + public string Scheme { get; } } } diff --git a/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs b/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs index ffd52b08..7ed6a02a 100644 --- a/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs @@ -350,6 +350,36 @@ .BDDfy(); } + [Fact] + public void should_not_replace_by_empty_scheme() + { + var downstreamReRoute = new DownstreamReRouteBuilder() + .WithDownstreamScheme("") + .WithServiceName("Ocelot/OcelotApp") + .WithUseServiceDiscovery(true) + .Build(); + + var downstreamRoute = new DownstreamRoute( + new List(), + new ReRouteBuilder() + .WithDownstreamReRoute(downstreamReRoute) + .Build()); + + var config = new ServiceProviderConfigurationBuilder() + .WithType("ServiceFabric") + .WithHost("localhost") + .WithPort(19081) + .Build(); + + this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute)) + .And(x => GivenTheServiceProviderConfigIs(config)) + .And(x => x.GivenTheDownstreamRequestUriIs("https://localhost:19081?PartitionKind=test&PartitionKey=1")) + .And(x => x.GivenTheUrlReplacerWillReturnSequence("/api/products/1", "Ocelot/OcelotApp")) + .When(x => x.WhenICallTheMiddleware()) + .Then(x => x.ThenTheDownstreamRequestUriIs("https://localhost:19081/Ocelot/OcelotApp/api/products/1?PartitionKind=test&PartitionKey=1")) + .BDDfy(); + } + private void GivenTheServiceProviderConfigIs(ServiceProviderConfiguration config) { var configuration = new InternalConfiguration(null, null, config, null, null, null, null, null); diff --git a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs index 8d31572a..2705b3b7 100644 --- a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs @@ -1,3 +1,5 @@ +using System; +using System.Linq.Expressions; using Ocelot.Middleware; namespace Ocelot.UnitTests.LoadBalancer @@ -108,6 +110,26 @@ namespace Ocelot.UnitTests.LoadBalancer .BDDfy(); } + [Fact] + public void should_set_scheme() + { + var downstreamRoute = new DownstreamReRouteBuilder() + .WithUpstreamHttpMethod(new List { "Get" }) + .Build(); + + var serviceProviderConfig = new ServiceProviderConfigurationBuilder() + .Build(); + + this.Given(x => x.GivenTheDownStreamUrlIs("http://my.url/abc?q=123")) + .And(x => GivenTheConfigurationIs(serviceProviderConfig)) + .And(x => x.GivenTheDownStreamRouteIs(downstreamRoute, new List())) + .And(x => x.GivenTheLoadBalancerHouseReturns()) + .And(x => x.GivenTheLoadBalancerReturnsOk()) + .When(x => x.WhenICallTheMiddleware()) + .Then(x => x.ThenAnHostAndPortIsSetOnPipeline()) + .BDDfy(); + } + private void WhenICallTheMiddleware() { _middleware = new LoadBalancingMiddleware(_next, _loggerFactory.Object, _loadBalancerHouse.Object); @@ -135,6 +157,13 @@ namespace Ocelot.UnitTests.LoadBalancer .ReturnsAsync(_getHostAndPortError); } + private void GivenTheLoadBalancerReturnsOk() + { + _loadBalancer + .Setup(x => x.Lease(It.IsAny())) + .ReturnsAsync(new OkResponse(new ServiceHostAndPort("abc", 123, "https"))); + } + private void GivenTheLoadBalancerReturns() { _hostAndPort = new ServiceHostAndPort("127.0.0.1", 80); @@ -186,6 +215,13 @@ namespace Ocelot.UnitTests.LoadBalancer _downstreamContext.Errors.ShouldBe(_getHostAndPortError.Errors); } + private void ThenAnHostAndPortIsSetOnPipeline() + { + _downstreamContext.DownstreamRequest.Host.ShouldBeEquivalentTo("abc"); + _downstreamContext.DownstreamRequest.Port.ShouldBeEquivalentTo(123); + _downstreamContext.DownstreamRequest.Scheme.ShouldBeEquivalentTo("https"); + } + private void ThenTheDownstreamUrlIsReplacedWith(string expectedUri) { _downstreamContext.DownstreamRequest.ToHttpRequestMessage().RequestUri.OriginalString.ShouldBe(expectedUri); From e4f5a71939f6c337e3be838181f3845fe6338557 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Sun, 19 Jan 2020 11:10:21 +0000 Subject: [PATCH 12/19] extra test --- .../HttpHandlerOptionsCreatorTests.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/Ocelot.UnitTests/Configuration/HttpHandlerOptionsCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/HttpHandlerOptionsCreatorTests.cs index 39db08f5..c4f6eb84 100644 --- a/test/Ocelot.UnitTests/Configuration/HttpHandlerOptionsCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/HttpHandlerOptionsCreatorTests.cs @@ -175,6 +175,25 @@ namespace Ocelot.UnitTests.Configuration .BDDfy(); } + [Fact] + public void should_create_options_fixing_specified_MaxConnectionsPerServer_range_when_zero() + { + var fileReRoute = new FileReRoute + { + HttpHandlerOptions = new FileHttpHandlerOptions + { + MaxConnectionsPerServer = 0 + } + }; + + var expectedOptions = new HttpHandlerOptions(false, false, false, true, int.MaxValue); + + this.Given(x => GivenTheFollowing(fileReRoute)) + .When(x => WhenICreateHttpHandlerOptions()) + .Then(x => ThenTheFollowingOptionsReturned(expectedOptions)) + .BDDfy(); + } + private void GivenTheFollowing(FileReRoute fileReRoute) { _fileReRoute = fileReRoute; From 49d1748105a89ed50a68bb04536b93ceca6d175d Mon Sep 17 00:00:00 2001 From: TomPallister Date: Sun, 19 Jan 2020 11:14:42 +0000 Subject: [PATCH 13/19] very brief mention MaxConnectionsPerServer in docs --- docs/features/configuration.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/features/configuration.rst b/docs/features/configuration.rst index 38ecf808..7f8500e8 100644 --- a/docs/features/configuration.rst +++ b/docs/features/configuration.rst @@ -62,7 +62,8 @@ Here is an example ReRoute configuration, You don't need to set all of these thi "HttpHandlerOptions": { "AllowAutoRedirect": true, "UseCookieContainer": true, - "UseTracing": true + "UseTracing": true, + "MaxConnectionsPerServer": 100 }, "DangerousAcceptAnyServerCertificateValidator": false } From 4a18e4681476eb1490ce52342e2a03155a8da1e5 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Sun, 19 Jan 2020 11:15:50 +0000 Subject: [PATCH 14/19] build develop like a PR --- .circleci/config.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 0f904362..e6944a97 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -27,4 +27,3 @@ workflows: branches: ignore: - master - - develop From 836923d26890846907da04643b00e2694a151067 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Sun, 19 Jan 2020 11:19:03 +0000 Subject: [PATCH 15/19] more docs --- docs/features/configuration.rst | 5 +++++ docs/features/servicediscovery.rst | 2 ++ 2 files changed, 7 insertions(+) diff --git a/docs/features/configuration.rst b/docs/features/configuration.rst index 7f8500e8..7983af39 100644 --- a/docs/features/configuration.rst +++ b/docs/features/configuration.rst @@ -223,3 +223,8 @@ If you want to ignore SSL warnings / errors set the following in your ReRoute co "DangerousAcceptAnyServerCertificateValidator": true I don't recommend doing this, I suggest creating your own certificate and then getting it trusted by your local / remote machine if you can. + +MaxConnectionsPerServer +^^^^^^^^^^^^^^^^^^^^^^^ + +This controls how many connections the internal HttpClient will open. This can be set at ReRoute or global level. \ No newline at end of file diff --git a/docs/features/servicediscovery.rst b/docs/features/servicediscovery.rst index f36f9f78..f23d2a4a 100644 --- a/docs/features/servicediscovery.rst +++ b/docs/features/servicediscovery.rst @@ -155,6 +155,8 @@ Eureka. One of the services polls Eureka every 30 seconds (default) and gets the When Ocelot asks for a given service it is retrieved from memory so performance is not a big problem. Please note that this code is provided by the Pivotal.Discovery.Client NuGet package so big thanks to them for all the hard work. +Ocelot will use the scheme (http/https) set in Eureka if these values are not provided in ocelot.json + Dynamic Routing ^^^^^^^^^^^^^^^ From 1723076874d86ea6818dbcb67ea6d219e77dc6d7 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Sun, 19 Jan 2020 17:20:36 +0000 Subject: [PATCH 16/19] test --- .../Requester/HttpExeptionToErrorMapperTests.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/Ocelot.UnitTests/Requester/HttpExeptionToErrorMapperTests.cs b/test/Ocelot.UnitTests/Requester/HttpExeptionToErrorMapperTests.cs index bad8668e..14413aad 100644 --- a/test/Ocelot.UnitTests/Requester/HttpExeptionToErrorMapperTests.cs +++ b/test/Ocelot.UnitTests/Requester/HttpExeptionToErrorMapperTests.cs @@ -38,6 +38,14 @@ error.ShouldBeOfType(); } + [Fact] + public void should_return_request_canceled_for_subtype() + { + var error = _mapper.Map(new SomeException()); + + error.ShouldBeOfType(); + } + [Fact] public void should_return_error_from_mapper() { @@ -56,5 +64,8 @@ error.ShouldBeOfType(); } + + private class SomeException : OperationCanceledException + { } } } From e45071fa1070b026137f51f6fec94f9fa077a4be Mon Sep 17 00:00:00 2001 From: EL Aisati Ahmed Date: Tue, 4 Feb 2020 17:59:39 +0100 Subject: [PATCH 17/19] Fix issue #1088 (Ocelot Administration doesn't work with .NET Core 3.x) Fixed OcelotMiddlewareConfigurationDelegate configuration --- samples/AdministrationApi/AdministrationApi.csproj | 9 +++++---- samples/AdministrationApi/Program.cs | 13 ++++--------- ...IdentityServerMiddlewareConfigurationProvider.cs | 8 +++++++- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/samples/AdministrationApi/AdministrationApi.csproj b/samples/AdministrationApi/AdministrationApi.csproj index 3fcf5dc8..7f8a351c 100644 --- a/samples/AdministrationApi/AdministrationApi.csproj +++ b/samples/AdministrationApi/AdministrationApi.csproj @@ -3,11 +3,12 @@ netcoreapp3.1 - + - - - + + + + \ No newline at end of file diff --git a/samples/AdministrationApi/Program.cs b/samples/AdministrationApi/Program.cs index a5e46fda..a69f1dc6 100644 --- a/samples/AdministrationApi/Program.cs +++ b/samples/AdministrationApi/Program.cs @@ -1,19 +1,14 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore; -using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; +using Ocelot.Administration; using Ocelot.DependencyInjection; using Ocelot.Middleware; -using Ocelot.Administration; +using System.IO; namespace AdministrationApi { - public class Program + public class Program { public static void Main(string[] args) { diff --git a/src/Ocelot.Administration/IdentityServerMiddlewareConfigurationProvider.cs b/src/Ocelot.Administration/IdentityServerMiddlewareConfigurationProvider.cs index b4b8994a..0d263463 100644 --- a/src/Ocelot.Administration/IdentityServerMiddlewareConfigurationProvider.cs +++ b/src/Ocelot.Administration/IdentityServerMiddlewareConfigurationProvider.cs @@ -27,7 +27,13 @@ } app.UseAuthentication(); - app.UseMvc(); + app.UseRouting(); + app.UseAuthorization(); + app.UseEndpoints(endpoints => + { + endpoints.MapDefaultControllerRoute(); + endpoints.MapControllers(); + }); }); } From 157737ef01b33ba784814392d080d442e273a808 Mon Sep 17 00:00:00 2001 From: EL Aisati Ahmed Date: Tue, 4 Feb 2020 18:11:38 +0100 Subject: [PATCH 18/19] Revert "Merge branch 'feature/issue#1088'" This reverts commit 914a386b0e79612a832a0ddc4c1b7fda7e8cf4a2. --- samples/AdministrationApi/AdministrationApi.csproj | 9 ++++----- samples/AdministrationApi/Program.cs | 13 +++++++++---- ...IdentityServerMiddlewareConfigurationProvider.cs | 8 +------- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/samples/AdministrationApi/AdministrationApi.csproj b/samples/AdministrationApi/AdministrationApi.csproj index 7f8a351c..3fcf5dc8 100644 --- a/samples/AdministrationApi/AdministrationApi.csproj +++ b/samples/AdministrationApi/AdministrationApi.csproj @@ -3,12 +3,11 @@ netcoreapp3.1 - + - - - - + + + \ No newline at end of file diff --git a/samples/AdministrationApi/Program.cs b/samples/AdministrationApi/Program.cs index a69f1dc6..a5e46fda 100644 --- a/samples/AdministrationApi/Program.cs +++ b/samples/AdministrationApi/Program.cs @@ -1,14 +1,19 @@ -using Microsoft.AspNetCore.Hosting; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore; +using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; -using Ocelot.Administration; using Ocelot.DependencyInjection; using Ocelot.Middleware; -using System.IO; +using Ocelot.Administration; namespace AdministrationApi { - public class Program + public class Program { public static void Main(string[] args) { diff --git a/src/Ocelot.Administration/IdentityServerMiddlewareConfigurationProvider.cs b/src/Ocelot.Administration/IdentityServerMiddlewareConfigurationProvider.cs index 0d263463..b4b8994a 100644 --- a/src/Ocelot.Administration/IdentityServerMiddlewareConfigurationProvider.cs +++ b/src/Ocelot.Administration/IdentityServerMiddlewareConfigurationProvider.cs @@ -27,13 +27,7 @@ } app.UseAuthentication(); - app.UseRouting(); - app.UseAuthorization(); - app.UseEndpoints(endpoints => - { - endpoints.MapDefaultControllerRoute(); - endpoints.MapControllers(); - }); + app.UseMvc(); }); } From f4eb93b66ca072d5f1b93a5d95eb64d54d1b5977 Mon Sep 17 00:00:00 2001 From: EL Aisati Ahmed Date: Tue, 4 Feb 2020 18:20:33 +0100 Subject: [PATCH 19/19] Fix issue #1088 (Ocelot Administration doesn't work with .NET Core 3.x) --- samples/AdministrationApi/AdministrationApi.csproj | 12 +++++++----- samples/AdministrationApi/Program.cs | 13 ++++--------- ...IdentityServerMiddlewareConfigurationProvider.cs | 8 +++++++- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/samples/AdministrationApi/AdministrationApi.csproj b/samples/AdministrationApi/AdministrationApi.csproj index 3fcf5dc8..4366ca06 100644 --- a/samples/AdministrationApi/AdministrationApi.csproj +++ b/samples/AdministrationApi/AdministrationApi.csproj @@ -1,13 +1,15 @@ - + netcoreapp3.1 - + + + + + - - - + \ No newline at end of file diff --git a/samples/AdministrationApi/Program.cs b/samples/AdministrationApi/Program.cs index a5e46fda..a69f1dc6 100644 --- a/samples/AdministrationApi/Program.cs +++ b/samples/AdministrationApi/Program.cs @@ -1,19 +1,14 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore; -using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; +using Ocelot.Administration; using Ocelot.DependencyInjection; using Ocelot.Middleware; -using Ocelot.Administration; +using System.IO; namespace AdministrationApi { - public class Program + public class Program { public static void Main(string[] args) { diff --git a/src/Ocelot.Administration/IdentityServerMiddlewareConfigurationProvider.cs b/src/Ocelot.Administration/IdentityServerMiddlewareConfigurationProvider.cs index b4b8994a..0d263463 100644 --- a/src/Ocelot.Administration/IdentityServerMiddlewareConfigurationProvider.cs +++ b/src/Ocelot.Administration/IdentityServerMiddlewareConfigurationProvider.cs @@ -27,7 +27,13 @@ } app.UseAuthentication(); - app.UseMvc(); + app.UseRouting(); + app.UseAuthorization(); + app.UseEndpoints(endpoints => + { + endpoints.MapDefaultControllerRoute(); + endpoints.MapControllers(); + }); }); }