diff --git a/README.md b/README.md
index a1793f62..56665fc8 100644
--- a/README.md
+++ b/README.md
@@ -1,91 +1,91 @@
-[
](http://threemammals.com/ocelot)
-
-[](https://ci.appveyor.com/project/TomPallister/ocelot-fcfpb) Windows (AppVeyor)
-[](https://travis-ci.org/ThreeMammals/Ocelot) Linux & OSX (Travis)
-
-[](https://ci.appveyor.com/project/TomPallister/ocelot-fcfpb/history?branch=develop)
-
-[](https://coveralls.io/github/ThreeMammals/Ocelot?branch=develop)
-
-# Ocelot
-
-Ocelot is a .NET Api Gateway. This project is aimed at people using .NET running
-a micro services / service orientated architecture
-that need a unified point of entry into their system. However it will work with anything that speaks HTTP and run on any platform that asp.net core supports.
-
-In particular I want easy integration with
-IdentityServer reference and bearer tokens.
-
-We have been unable to find this in my current workplace
-without having to write our own Javascript middlewares
-to handle the IdentityServer reference tokens. We would
-rather use the IdentityServer code that already exists
-to do this.
-
-Ocelot is a bunch of middlewares in a specific order.
-
-Ocelot manipulates the HttpRequest object into a state specified by its configuration until
-it reaches a request builder middleware where it creates a HttpRequestMessage object which is
-used to make a request to a downstream service. The middleware that makes the request is
-the last thing in the Ocelot pipeline. It does not call the next middleware.
-The response from the downstream service is retrieved as the requests goes back up the Ocelot pipeline.
-There is a piece of middleware that maps the HttpResponseMessage onto the HttpResponse object and that
-is returned to the client. That is basically it with a bunch of other features!
-
-## Features
-
-A quick list of Ocelot's capabilities for more information see the [documentation](http://ocelot.readthedocs.io/en/latest/).
-
-* Routing
-* Request Aggregation
-* Service Discovery with Consul & Eureka
-* Service Fabric
-* WebSockets
-* Authentication
-* Authorisation
-* Rate Limiting
-* Caching
-* Retry policies / QoS
-* Load Balancing
-* Logging / Tracing / Correlation
-* Headers / Query String / Claims Transformation
-* Custom Middleware / Delegating Handlers
-* Configuration / Administration REST API
-* Platform / Cloud agnostic
-
-## How to install
-
-Ocelot is designed to work with ASP.NET Core only and it targets `netstandard2.0`. This means it can be used anywhere `.NET Standard 2.0` is supported, including `.NET Core 2.0` and `.NET Framework 4.6.1` and up. [This](https://docs.microsoft.com/en-us/dotnet/standard/net-standard) documentation may prove helpful when working out if Ocelot would be suitable for you.
-
-Install Ocelot and it's dependencies using NuGet.
-
-`Install-Package Ocelot`
-
-All versions can be found [here](https://www.nuget.org/packages/Ocelot/)
-
-## Documentation
-
-Please click [here](http://ocelot.readthedocs.io/en/latest/) for the Ocleot documentation. This includes lots of information and will be helpful if you want to understand the features Ocelot currently offers.
-
-## Coming up
-
-You can see what we are working on [here](https://github.com/ThreeMammals/Ocelot/issues).
-
-## Contributing
-
-We love to receive contributions from the community so please keep them coming :)
-
-Pull requests, issues and commentary welcome!
-
-Please complete the relavent template for issues and PRs. Sometimes it's worth getting in touch with us to discuss changes
-before doing any work incase this is something we are already doing or it might not make sense. We can also give
-advice on the easiest way to do things :)
-
-Finally we mark all existing issues as help wanted, small, medium and large effort. If you want to contriute for the first time I suggest looking at a help wanted & small effort issue :)
-
-## Things that are currently annoying me
-
-[ Get more details at **codescene.io**.](https://codescene.io/projects/697/jobs/latest-successful/results)
-
-
-
+[
](http://threemammals.com/ocelot)
+
+[](https://ci.appveyor.com/project/TomPallister/ocelot-fcfpb) Windows (AppVeyor)
+[](https://travis-ci.org/ThreeMammals/Ocelot) Linux & OSX (Travis)
+
+[](https://ci.appveyor.com/project/TomPallister/ocelot-fcfpb/history?branch=develop)
+
+[](https://coveralls.io/github/ThreeMammals/Ocelot?branch=develop)
+
+# Ocelot
+
+Ocelot is a .NET Api Gateway. This project is aimed at people using .NET running
+a micro services / service orientated architecture
+that need a unified point of entry into their system. However it will work with anything that speaks HTTP and run on any platform that asp.net core supports.
+
+In particular I want easy integration with
+IdentityServer reference and bearer tokens.
+
+We have been unable to find this in my current workplace
+without having to write our own Javascript middlewares
+to handle the IdentityServer reference tokens. We would
+rather use the IdentityServer code that already exists
+to do this.
+
+Ocelot is a bunch of middlewares in a specific order.
+
+Ocelot manipulates the HttpRequest object into a state specified by its configuration until
+it reaches a request builder middleware where it creates a HttpRequestMessage object which is
+used to make a request to a downstream service. The middleware that makes the request is
+the last thing in the Ocelot pipeline. It does not call the next middleware.
+The response from the downstream service is retrieved as the requests goes back up the Ocelot pipeline.
+There is a piece of middleware that maps the HttpResponseMessage onto the HttpResponse object and that
+is returned to the client. That is basically it with a bunch of other features!
+
+## Features
+
+A quick list of Ocelot's capabilities for more information see the [documentation](http://ocelot.readthedocs.io/en/latest/).
+
+* Routing
+* Request Aggregation
+* Service Discovery with Consul & Eureka
+* Service Fabric
+* WebSockets
+* Authentication
+* Authorisation
+* Rate Limiting
+* Caching
+* Retry policies / QoS
+* Load Balancing
+* Logging / Tracing / Correlation
+* Headers / Query String / Claims Transformation
+* Custom Middleware / Delegating Handlers
+* Configuration / Administration REST API
+* Platform / Cloud Agnostic
+
+## How to install
+
+Ocelot is designed to work with ASP.NET Core only and it targets `netstandard2.0`. This means it can be used anywhere `.NET Standard 2.0` is supported, including `.NET Core 2.0` and `.NET Framework 4.6.1` and up. [This](https://docs.microsoft.com/en-us/dotnet/standard/net-standard) documentation may prove helpful when working out if Ocelot would be suitable for you.
+
+Install Ocelot and it's dependencies using NuGet.
+
+`Install-Package Ocelot`
+
+All versions can be found [here](https://www.nuget.org/packages/Ocelot/)
+
+## Documentation
+
+Please click [here](http://ocelot.readthedocs.io/en/latest/) for the Ocleot documentation. This includes lots of information and will be helpful if you want to understand the features Ocelot currently offers.
+
+## Coming up
+
+You can see what we are working on [here](https://github.com/ThreeMammals/Ocelot/issues).
+
+## Contributing
+
+We love to receive contributions from the community so please keep them coming :)
+
+Pull requests, issues and commentary welcome!
+
+Please complete the relavent template for issues and PRs. Sometimes it's worth getting in touch with us to discuss changes
+before doing any work incase this is something we are already doing or it might not make sense. We can also give
+advice on the easiest way to do things :)
+
+Finally we mark all existing issues as help wanted, small, medium and large effort. If you want to contriute for the first time I suggest looking at a help wanted & small effort issue :)
+
+## Things that are currently annoying me
+
+[ Get more details at **codescene.io**.](https://codescene.io/projects/697/jobs/latest-successful/results)
+
+
+
diff --git a/docs/features/routing.rst b/docs/features/routing.rst
index 664021a6..06928371 100644
--- a/docs/features/routing.rst
+++ b/docs/features/routing.rst
@@ -177,4 +177,11 @@ and
}
In the example above if you make a request into Ocelot on /goods/delete Ocelot will match /goods/delete ReRoute. Previously it would have
-matched /goods/{catchAll} (because this is the first ReRoute in the list!).
\ No newline at end of file
+matched /goods/{catchAll} (because this is the first ReRoute in the list!).
+
+Dynamic Routing
+^^^^^^^^^^^^^^^
+
+This feature was requested in `issue 340 `_. The idea is to enable dynamic routing
+when using a service discovery provider so you don't have to provide the ReRoute config. See the docs :ref:`service-discovery` if
+this sounds interesting to you.
diff --git a/docs/features/servicediscovery.rst b/docs/features/servicediscovery.rst
index 6fe25c12..b212a2e6 100644
--- a/docs/features/servicediscovery.rst
+++ b/docs/features/servicediscovery.rst
@@ -1,3 +1,5 @@
+.. service-discovery:
+
Service Discovery
=================
@@ -88,3 +90,65 @@ 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.
+Dynamic Routing
+^^^^^^^^^^^^^^^
+
+This feature was requested in `issue 340 `_. The idea is to enable dynamic routing when using
+a service discovery provider (see that section of the docs for more info). In this mode Ocelot will use the first segmentof the upstream path to lookup the
+downstream service with the service discovery provider.
+
+An example of this would be calling ocelot with a url like https://api.mywebsite.com/product/products. Ocelot will take the first segment of
+the path which is product and use it as a key to look up the service in consul. If consul returns a service Ocelot will request it on whatever host and
+port comes back from consul plus the remaining path segments in this case products thus making the downstream call http://hostfromconsul:portfromconsul/products.
+Ocelot will apprend any query string to the downstream url as normal.
+
+In order to enable dynamic routing you need to have 0 ReRoutes in your config. At the moment you cannot mix dynamic and configuration ReRoutes. In addition to this you
+need to specify the Service Discovery provider details as outlined above and the downstream http/https scheme as DownstreamScheme.
+
+In addition to that you can set RateLimitOptions, QoSOptions, LoadBalancerOptions and HttpHandlerOptions, DownstreamScheme (You might want to call Ocelot on https but
+talk to private services over http) that will be applied to all of the dynamic ReRoutes.
+
+The config might look something like
+
+.. code-block:: json
+
+ {
+ "ReRoutes": [],
+ "Aggregates": [],
+ "GlobalConfiguration": {
+ "RequestIdKey": null,
+ "ServiceDiscoveryProvider": {
+ "Host": "localhost",
+ "Port": 8510,
+ "Type": null,
+ "Token": null,
+ "ConfigurationKey": null
+ },
+ "RateLimitOptions": {
+ "ClientIdHeader": "ClientId",
+ "QuotaExceededMessage": null,
+ "RateLimitCounterPrefix": "ocelot",
+ "DisableRateLimitHeaders": false,
+ "HttpStatusCode": 429
+ },
+ "QoSOptions": {
+ "ExceptionsAllowedBeforeBreaking": 0,
+ "DurationOfBreak": 0,
+ "TimeoutValue": 0
+ },
+ "BaseUrl": null,
+ "LoadBalancerOptions": {
+ "Type": "LeastConnection",
+ "Key": null,
+ "Expiry": 0
+ },
+ "DownstreamScheme": "http",
+ "HttpHandlerOptions": {
+ "AllowAutoRedirect": false,
+ "UseCookieContainer": false,
+ "UseTracing": false
+ }
+ }
+ }
+
+Please take a look through all of the docs to understand these options.
\ No newline at end of file
diff --git a/src/Ocelot/Configuration/Builder/DownstreamReRouteBuilder.cs b/src/Ocelot/Configuration/Builder/DownstreamReRouteBuilder.cs
index 225feb6f..b782ab0f 100644
--- a/src/Ocelot/Configuration/Builder/DownstreamReRouteBuilder.cs
+++ b/src/Ocelot/Configuration/Builder/DownstreamReRouteBuilder.cs
@@ -9,7 +9,7 @@ namespace Ocelot.Configuration.Builder
public class DownstreamReRouteBuilder
{
private AuthenticationOptions _authenticationOptions;
- private string _reRouteKey;
+ private string _loadBalancerKey;
private string _downstreamPathTemplate;
private string _upstreamTemplate;
private UpstreamPathTemplate _upstreamTemplatePattern;
@@ -25,7 +25,6 @@ namespace Ocelot.Configuration.Builder
private CacheOptions _fileCacheOptions;
private string _downstreamScheme;
private LoadBalancerOptions _loadBalancerOptions;
- private bool _useQos;
private QoSOptions _qosOptions;
private HttpHandlerOptions _httpHandlerOptions;
private bool _enableRateLimiting;
@@ -41,7 +40,6 @@ namespace Ocelot.Configuration.Builder
private List _addHeadersToDownstream;
private List _addHeadersToUpstream;
private bool _dangerousAcceptAnyServerCertificateValidator;
- private string _qosKey;
public DownstreamReRouteBuilder()
{
@@ -153,27 +151,15 @@ namespace Ocelot.Configuration.Builder
return this;
}
- public DownstreamReRouteBuilder WithIsQos(bool input)
- {
- _useQos = input;
- return this;
- }
-
public DownstreamReRouteBuilder WithQosOptions(QoSOptions input)
{
_qosOptions = input;
return this;
}
- public DownstreamReRouteBuilder WithReRouteKey(string reRouteKey)
+ public DownstreamReRouteBuilder WithLoadBalancerKey(string loadBalancerKey)
{
- _reRouteKey = reRouteKey;
- return this;
- }
-
- public DownstreamReRouteBuilder WithQosKey(string qosKey)
- {
- _qosKey = qosKey;
+ _loadBalancerKey = loadBalancerKey;
return this;
}
@@ -267,7 +253,6 @@ namespace Ocelot.Configuration.Builder
_httpHandlerOptions,
_useServiceDiscovery,
_enableRateLimiting,
- _useQos,
_qosOptions,
_downstreamScheme,
_requestIdHeaderKey,
@@ -283,12 +268,11 @@ namespace Ocelot.Configuration.Builder
_isAuthorised,
_authenticationOptions,
new PathTemplate(_downstreamPathTemplate),
- _reRouteKey,
+ _loadBalancerKey,
_delegatingHandlers,
_addHeadersToDownstream,
_addHeadersToUpstream,
- _dangerousAcceptAnyServerCertificateValidator,
- _qosKey);
+ _dangerousAcceptAnyServerCertificateValidator);
}
}
}
diff --git a/src/Ocelot/Configuration/Builder/QoSOptionsBuilder.cs b/src/Ocelot/Configuration/Builder/QoSOptionsBuilder.cs
index 93d18257..69660d83 100644
--- a/src/Ocelot/Configuration/Builder/QoSOptionsBuilder.cs
+++ b/src/Ocelot/Configuration/Builder/QoSOptionsBuilder.cs
@@ -6,7 +6,9 @@
private int _durationOfBreak;
- private int _timeoutValue;
+ private int _timeoutValue;
+
+ private string _key;
public QoSOptionsBuilder WithExceptionsAllowedBeforeBreaking(int exceptionsAllowedBeforeBreaking)
{
@@ -26,9 +28,15 @@
return this;
}
+ public QoSOptionsBuilder WithKey(string input)
+ {
+ _key = input;
+ return this;
+ }
+
public QoSOptions Build()
{
- return new QoSOptions(_exceptionsAllowedBeforeBreaking, _durationOfBreak, _timeoutValue);
+ return new QoSOptions(_exceptionsAllowedBeforeBreaking, _durationOfBreak, _timeoutValue, _key);
}
}
}
diff --git a/src/Ocelot/Configuration/Builder/ReRouteOptionsBuilder.cs b/src/Ocelot/Configuration/Builder/ReRouteOptionsBuilder.cs
index e5729823..525f653e 100644
--- a/src/Ocelot/Configuration/Builder/ReRouteOptionsBuilder.cs
+++ b/src/Ocelot/Configuration/Builder/ReRouteOptionsBuilder.cs
@@ -5,7 +5,6 @@ namespace Ocelot.Configuration.Builder
private bool _isAuthenticated;
private bool _isAuthorised;
private bool _isCached;
- private bool _isQoS;
private bool _enableRateLimiting;
public ReRouteOptionsBuilder WithIsCached(bool isCached)
@@ -26,12 +25,6 @@ namespace Ocelot.Configuration.Builder
return this;
}
- public ReRouteOptionsBuilder WithIsQos(bool isQoS)
- {
- _isQoS = isQoS;
- return this;
- }
-
public ReRouteOptionsBuilder WithRateLimiting(bool enableRateLimiting)
{
_enableRateLimiting = enableRateLimiting;
@@ -40,7 +33,7 @@ namespace Ocelot.Configuration.Builder
public ReRouteOptions Build()
{
- return new ReRouteOptions(_isAuthenticated, _isAuthorised, _isCached, _isQoS, _enableRateLimiting);
+ return new ReRouteOptions(_isAuthenticated, _isAuthorised, _isCached, _enableRateLimiting);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Ocelot/Configuration/Creator/FileInternalConfigurationCreator.cs b/src/Ocelot/Configuration/Creator/FileInternalConfigurationCreator.cs
index 06789116..97045bc8 100644
--- a/src/Ocelot/Configuration/Creator/FileInternalConfigurationCreator.cs
+++ b/src/Ocelot/Configuration/Creator/FileInternalConfigurationCreator.cs
@@ -104,8 +104,22 @@ namespace Ocelot.Configuration.Creator
}
var serviceProviderConfiguration = _serviceProviderConfigCreator.Create(fileConfiguration.GlobalConfiguration);
-
- var config = new InternalConfiguration(reRoutes, _adminPath.Path, serviceProviderConfiguration, fileConfiguration.GlobalConfiguration.RequestIdKey);
+
+ var lbOptions = CreateLoadBalancerOptions(fileConfiguration.GlobalConfiguration.LoadBalancerOptions);
+
+ var qosOptions = _qosOptionsCreator.Create(fileConfiguration.GlobalConfiguration.QoSOptions);
+
+ var httpHandlerOptions = _httpHandlerOptionsCreator.Create(fileConfiguration.GlobalConfiguration.HttpHandlerOptions);
+
+ var config = new InternalConfiguration(reRoutes,
+ _adminPath.Path,
+ serviceProviderConfiguration,
+ fileConfiguration.GlobalConfiguration.RequestIdKey,
+ lbOptions,
+ fileConfiguration.GlobalConfiguration.DownstreamScheme,
+ qosOptions,
+ httpHandlerOptions
+ );
return new OkResponse(config);
}
@@ -160,8 +174,6 @@ namespace Ocelot.Configuration.Creator
var reRouteKey = CreateReRouteKey(fileReRoute);
- var qosKey = CreateQosKey(fileReRoute);
-
var upstreamTemplatePattern = _upstreamTemplatePatternCreator.Create(fileReRoute);
var authOptionsForRoute = _authOptionsCreator.Create(fileReRoute);
@@ -172,19 +184,19 @@ namespace Ocelot.Configuration.Creator
var claimsToQueries = _claimsToThingCreator.Create(fileReRoute.AddQueriesToRequest);
- var qosOptions = _qosOptionsCreator.Create(fileReRoute);
+ var qosOptions = _qosOptionsCreator.Create(fileReRoute.QoSOptions, fileReRoute.UpstreamPathTemplate, fileReRoute.UpstreamHttpMethod.ToArray());
var rateLimitOption = _rateLimitOptionsCreator.Create(fileReRoute, globalConfiguration, fileReRouteOptions.EnableRateLimiting);
var region = _regionCreator.Create(fileReRoute);
- var httpHandlerOptions = _httpHandlerOptionsCreator.Create(fileReRoute);
+ var httpHandlerOptions = _httpHandlerOptionsCreator.Create(fileReRoute.HttpHandlerOptions);
var hAndRs = _headerFAndRCreator.Create(fileReRoute);
var downstreamAddresses = _downstreamAddressesCreator.Create(fileReRoute);
- var lbOptions = CreateLoadBalancerOptions(fileReRoute);
+ var lbOptions = CreateLoadBalancerOptions(fileReRoute.LoadBalancerOptions);
var reRoute = new DownstreamReRouteBuilder()
.WithKey(fileReRoute.Key)
@@ -205,9 +217,7 @@ namespace Ocelot.Configuration.Creator
.WithDownstreamScheme(fileReRoute.DownstreamScheme)
.WithLoadBalancerOptions(lbOptions)
.WithDownstreamAddresses(downstreamAddresses)
- .WithReRouteKey(reRouteKey)
- .WithQosKey(qosKey)
- .WithIsQos(fileReRouteOptions.IsQos)
+ .WithLoadBalancerKey(reRouteKey)
.WithQosOptions(qosOptions)
.WithEnableRateLimiting(fileReRouteOptions.EnableRateLimiting)
.WithRateLimitOptions(rateLimitOption)
@@ -226,9 +236,13 @@ namespace Ocelot.Configuration.Creator
return reRoute;
}
- private LoadBalancerOptions CreateLoadBalancerOptions(FileReRoute fileReRoute)
+ private LoadBalancerOptions CreateLoadBalancerOptions(FileLoadBalancerOptions options)
{
- return new LoadBalancerOptions(fileReRoute.LoadBalancerOptions.Type, fileReRoute.LoadBalancerOptions.Key, fileReRoute.LoadBalancerOptions.Expiry);
+ return new LoadBalancerOptionsBuilder()
+ .WithType(options.Type)
+ .WithKey(options.Key)
+ .WithExpiryInMs(options.Expiry)
+ .Build();
}
private string CreateReRouteKey(FileReRoute fileReRoute)
@@ -238,14 +252,7 @@ namespace Ocelot.Configuration.Creator
return $"{nameof(CookieStickySessions)}:{fileReRoute.LoadBalancerOptions.Key}";
}
- return CreateQosKey(fileReRoute);
- }
-
- private string CreateQosKey(FileReRoute fileReRoute)
- {
- //note - not sure if this is the correct key, but this is probably the only unique key i can think of given my poor brain
- var loadBalancerKey = $"{fileReRoute.UpstreamPathTemplate}|{string.Join(",", fileReRoute.UpstreamHttpMethod)}";
- return loadBalancerKey;
+ return $"{fileReRoute.UpstreamPathTemplate}|{string.Join(",", fileReRoute.UpstreamHttpMethod)}";
}
}
}
diff --git a/src/Ocelot/Configuration/Creator/HttpHandlerOptionsCreator.cs b/src/Ocelot/Configuration/Creator/HttpHandlerOptionsCreator.cs
index 332c25b7..7ce77b34 100644
--- a/src/Ocelot/Configuration/Creator/HttpHandlerOptionsCreator.cs
+++ b/src/Ocelot/Configuration/Creator/HttpHandlerOptionsCreator.cs
@@ -6,19 +6,19 @@ namespace Ocelot.Configuration.Creator
{
public class HttpHandlerOptionsCreator : IHttpHandlerOptionsCreator
{
- private IServiceTracer _tracer;
+ private readonly IServiceTracer _tracer;
public HttpHandlerOptionsCreator(IServiceTracer tracer)
{
_tracer = tracer;
}
- public HttpHandlerOptions Create(FileReRoute fileReRoute)
+ public HttpHandlerOptions Create(FileHttpHandlerOptions options)
{
- var useTracing = _tracer.GetType() != typeof(FakeServiceTracer) ? fileReRoute.HttpHandlerOptions.UseTracing : false;
+ var useTracing = _tracer.GetType() != typeof(FakeServiceTracer) && options.UseTracing;
- return new HttpHandlerOptions(fileReRoute.HttpHandlerOptions.AllowAutoRedirect,
- fileReRoute.HttpHandlerOptions.UseCookieContainer, useTracing);
+ return new HttpHandlerOptions(options.AllowAutoRedirect,
+ options.UseCookieContainer, useTracing);
}
}
}
diff --git a/src/Ocelot/Configuration/Creator/IHttpHandlerOptionsCreator.cs b/src/Ocelot/Configuration/Creator/IHttpHandlerOptionsCreator.cs
index 34e5ffd1..80137651 100644
--- a/src/Ocelot/Configuration/Creator/IHttpHandlerOptionsCreator.cs
+++ b/src/Ocelot/Configuration/Creator/IHttpHandlerOptionsCreator.cs
@@ -7,6 +7,6 @@ namespace Ocelot.Configuration.Creator
///
public interface IHttpHandlerOptionsCreator
{
- HttpHandlerOptions Create(FileReRoute fileReRoute);
+ HttpHandlerOptions Create(FileHttpHandlerOptions fileReRoute);
}
}
diff --git a/src/Ocelot/Configuration/Creator/IQoSOptionsCreator.cs b/src/Ocelot/Configuration/Creator/IQoSOptionsCreator.cs
index a8c84dc3..3ad42d9f 100644
--- a/src/Ocelot/Configuration/Creator/IQoSOptionsCreator.cs
+++ b/src/Ocelot/Configuration/Creator/IQoSOptionsCreator.cs
@@ -4,6 +4,8 @@ namespace Ocelot.Configuration.Creator
{
public interface IQoSOptionsCreator
{
- QoSOptions Create(FileReRoute fileReRoute);
+ QoSOptions Create(FileQoSOptions options);
+ QoSOptions Create(FileQoSOptions options, string pathTemplate, string[] httpMethods);
+ QoSOptions Create(QoSOptions options, string pathTemplate, string[] httpMethods);
}
-}
\ No newline at end of file
+}
diff --git a/src/Ocelot/Configuration/Creator/IReRouteOptionsCreator.cs b/src/Ocelot/Configuration/Creator/IReRouteOptionsCreator.cs
index f19845a8..1f7983d6 100644
--- a/src/Ocelot/Configuration/Creator/IReRouteOptionsCreator.cs
+++ b/src/Ocelot/Configuration/Creator/IReRouteOptionsCreator.cs
@@ -6,4 +6,4 @@ namespace Ocelot.Configuration.Creator
{
ReRouteOptions Create(FileReRoute fileReRoute);
}
-}
\ No newline at end of file
+}
diff --git a/src/Ocelot/Configuration/Creator/QoSOptionsCreator.cs b/src/Ocelot/Configuration/Creator/QoSOptionsCreator.cs
index 3cf6b1cd..30adaed2 100644
--- a/src/Ocelot/Configuration/Creator/QoSOptionsCreator.cs
+++ b/src/Ocelot/Configuration/Creator/QoSOptionsCreator.cs
@@ -1,17 +1,47 @@
-using Ocelot.Configuration.Builder;
-using Ocelot.Configuration.File;
-
namespace Ocelot.Configuration.Creator
{
+ using Ocelot.Configuration.Builder;
+ using Ocelot.Configuration.File;
+ using System.Linq;
+
public class QoSOptionsCreator : IQoSOptionsCreator
{
- public QoSOptions Create(FileReRoute fileReRoute)
+ public QoSOptions Create(FileQoSOptions options)
{
return new QoSOptionsBuilder()
- .WithExceptionsAllowedBeforeBreaking(fileReRoute.QoSOptions.ExceptionsAllowedBeforeBreaking)
- .WithDurationOfBreak(fileReRoute.QoSOptions.DurationOfBreak)
- .WithTimeoutValue(fileReRoute.QoSOptions.TimeoutValue)
+ .WithExceptionsAllowedBeforeBreaking(options.ExceptionsAllowedBeforeBreaking)
+ .WithDurationOfBreak(options.DurationOfBreak)
+ .WithTimeoutValue(options.TimeoutValue)
.Build();
}
+
+ public QoSOptions Create(FileQoSOptions options, string pathTemplate, string[] httpMethods)
+ {
+ var key = CreateKey(pathTemplate, httpMethods);
+
+ return Map(key, options.TimeoutValue, options.DurationOfBreak, options.ExceptionsAllowedBeforeBreaking);
+ }
+
+ public QoSOptions Create(QoSOptions options, string pathTemplate, string[] httpMethods)
+ {
+ var key = CreateKey(pathTemplate, httpMethods);
+
+ return Map(key, options.TimeoutValue, options.DurationOfBreak, options.ExceptionsAllowedBeforeBreaking);
+ }
+
+ private QoSOptions Map(string key, int timeoutValue, int durationOfBreak, int exceptionsAllowedBeforeBreaking)
+ {
+ return new QoSOptionsBuilder()
+ .WithExceptionsAllowedBeforeBreaking(exceptionsAllowedBeforeBreaking)
+ .WithDurationOfBreak(durationOfBreak)
+ .WithTimeoutValue(timeoutValue)
+ .WithKey(key)
+ .Build();
+ }
+
+ private string CreateKey(string pathTemplate, string[] httpMethods)
+ {
+ return $"{pathTemplate.FirstOrDefault()}|{string.Join(",", httpMethods)}";
+ }
}
-}
\ No newline at end of file
+}
diff --git a/src/Ocelot/Configuration/Creator/ReRouteOptionsCreator.cs b/src/Ocelot/Configuration/Creator/ReRouteOptionsCreator.cs
index 8defc420..c777a50a 100644
--- a/src/Ocelot/Configuration/Creator/ReRouteOptionsCreator.cs
+++ b/src/Ocelot/Configuration/Creator/ReRouteOptionsCreator.cs
@@ -10,14 +10,12 @@ namespace Ocelot.Configuration.Creator
var isAuthenticated = IsAuthenticated(fileReRoute);
var isAuthorised = IsAuthorised(fileReRoute);
var isCached = IsCached(fileReRoute);
- var isQos = IsQoS(fileReRoute);
var enableRateLimiting = IsEnableRateLimiting(fileReRoute);
var options = new ReRouteOptionsBuilder()
.WithIsAuthenticated(isAuthenticated)
.WithIsAuthorised(isAuthorised)
.WithIsCached(isCached)
- .WithIsQos(isQos)
.WithRateLimiting(enableRateLimiting)
.Build();
@@ -29,11 +27,6 @@ namespace Ocelot.Configuration.Creator
return (fileReRoute.RateLimitOptions != null && fileReRoute.RateLimitOptions.EnableRateLimiting) ? true : false;
}
- private bool IsQoS(FileReRoute fileReRoute)
- {
- return fileReRoute.QoSOptions?.ExceptionsAllowedBeforeBreaking > 0 && fileReRoute.QoSOptions?.TimeoutValue > 0;
- }
-
private bool IsAuthenticated(FileReRoute fileReRoute)
{
return !string.IsNullOrEmpty(fileReRoute.AuthenticationOptions?.AuthenticationProviderKey);
@@ -48,5 +41,5 @@ namespace Ocelot.Configuration.Creator
{
return fileReRoute.FileCacheOptions.TtlSeconds > 0;
}
- }
-}
\ No newline at end of file
+ }
+}
diff --git a/src/Ocelot/Configuration/Creator/ServiceProviderConfigurationCreator.cs b/src/Ocelot/Configuration/Creator/ServiceProviderConfigurationCreator.cs
index 7fbb49e4..4943aac6 100644
--- a/src/Ocelot/Configuration/Creator/ServiceProviderConfigurationCreator.cs
+++ b/src/Ocelot/Configuration/Creator/ServiceProviderConfigurationCreator.cs
@@ -7,12 +7,12 @@ namespace Ocelot.Configuration.Creator
{
public ServiceProviderConfiguration Create(FileGlobalConfiguration globalConfiguration)
{
- //todo log or return error here dont just default to something that wont work..
- var serviceProviderPort = globalConfiguration?.ServiceDiscoveryProvider?.Port ?? 0;
+ var port = globalConfiguration?.ServiceDiscoveryProvider?.Port ?? 0;
+ var host = globalConfiguration?.ServiceDiscoveryProvider?.Host ?? "consul";
return new ServiceProviderConfigurationBuilder()
- .WithHost(globalConfiguration?.ServiceDiscoveryProvider?.Host)
- .WithPort(serviceProviderPort)
+ .WithHost(host)
+ .WithPort(port)
.WithType(globalConfiguration?.ServiceDiscoveryProvider?.Type)
.WithToken(globalConfiguration?.ServiceDiscoveryProvider?.Token)
.WithConfigurationKey(globalConfiguration?.ServiceDiscoveryProvider?.ConfigurationKey)
diff --git a/src/Ocelot/Configuration/DownstreamReRoute.cs b/src/Ocelot/Configuration/DownstreamReRoute.cs
index b4118db2..f6cc876d 100644
--- a/src/Ocelot/Configuration/DownstreamReRoute.cs
+++ b/src/Ocelot/Configuration/DownstreamReRoute.cs
@@ -16,8 +16,7 @@ namespace Ocelot.Configuration
HttpHandlerOptions httpHandlerOptions,
bool useServiceDiscovery,
bool enableEndpointEndpointRateLimiting,
- bool isQos,
- QoSOptions qosOptionsOptions,
+ QoSOptions qosOptions,
string downstreamScheme,
string requestIdKey,
bool isCached,
@@ -36,8 +35,7 @@ namespace Ocelot.Configuration
List delegatingHandlers,
List addHeadersToDownstream,
List addHeadersToUpstream,
- bool dangerousAcceptAnyServerCertificateValidator,
- string qosKey)
+ bool dangerousAcceptAnyServerCertificateValidator)
{
DangerousAcceptAnyServerCertificateValidator = dangerousAcceptAnyServerCertificateValidator;
AddHeadersToDownstream = addHeadersToDownstream;
@@ -51,8 +49,7 @@ namespace Ocelot.Configuration
HttpHandlerOptions = httpHandlerOptions;
UseServiceDiscovery = useServiceDiscovery;
EnableEndpointEndpointRateLimiting = enableEndpointEndpointRateLimiting;
- IsQos = isQos;
- QosOptionsOptions = qosOptionsOptions;
+ QosOptions = qosOptions;
DownstreamScheme = downstreamScheme;
RequestIdKey = requestIdKey;
IsCached = isCached;
@@ -69,10 +66,8 @@ namespace Ocelot.Configuration
DownstreamPathTemplate = downstreamPathTemplate;
LoadBalancerKey = loadBalancerKey;
AddHeadersToUpstream = addHeadersToUpstream;
- QosKey = qosKey;
}
- public string QosKey { get; }
public string Key { get; }
public PathTemplate UpstreamPathTemplate { get; }
public List UpstreamHeadersFindAndReplace { get; }
@@ -82,8 +77,7 @@ namespace Ocelot.Configuration
public HttpHandlerOptions HttpHandlerOptions { get; }
public bool UseServiceDiscovery { get; }
public bool EnableEndpointEndpointRateLimiting { get; }
- public bool IsQos { get; }
- public QoSOptions QosOptionsOptions { get; }
+ public QoSOptions QosOptions { get; }
public string DownstreamScheme { get; }
public string RequestIdKey { get; }
public bool IsCached { get; }
diff --git a/src/Ocelot/Configuration/File/FileGlobalConfiguration.cs b/src/Ocelot/Configuration/File/FileGlobalConfiguration.cs
index 8dea9ed6..27f1f2ae 100644
--- a/src/Ocelot/Configuration/File/FileGlobalConfiguration.cs
+++ b/src/Ocelot/Configuration/File/FileGlobalConfiguration.cs
@@ -6,6 +6,9 @@
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider();
RateLimitOptions = new FileRateLimitOptions();
+ LoadBalancerOptions = new FileLoadBalancerOptions();
+ QoSOptions = new FileQoSOptions();
+ HttpHandlerOptions = new FileHttpHandlerOptions();
}
public string RequestIdKey { get; set; }
@@ -13,7 +16,15 @@
public FileServiceDiscoveryProvider ServiceDiscoveryProvider { get;set; }
public FileRateLimitOptions RateLimitOptions { get; set; }
-
+
+ public FileQoSOptions QoSOptions { get; set; }
+
public string BaseUrl { get ;set; }
+
+ public FileLoadBalancerOptions LoadBalancerOptions { get; set; }
+
+ public string DownstreamScheme { get; set; }
+
+ public FileHttpHandlerOptions HttpHandlerOptions { get; set; }
}
}
diff --git a/src/Ocelot/Configuration/HttpHandlerOptionsBuilder.cs b/src/Ocelot/Configuration/HttpHandlerOptionsBuilder.cs
new file mode 100644
index 00000000..1cfd69c6
--- /dev/null
+++ b/src/Ocelot/Configuration/HttpHandlerOptionsBuilder.cs
@@ -0,0 +1,32 @@
+namespace Ocelot.Configuration
+{
+ public class HttpHandlerOptionsBuilder
+ {
+ private bool _allowAutoRedirect;
+ private bool _useCookieContainer;
+ private bool _useTracing;
+
+ public HttpHandlerOptionsBuilder WithAllowAutoRedirect(bool input)
+ {
+ _allowAutoRedirect = input;
+ return this;
+ }
+
+ public HttpHandlerOptionsBuilder WithUseCookieContainer(bool input)
+ {
+ _useCookieContainer = input;
+ return this;
+ }
+
+ public HttpHandlerOptionsBuilder WithUseTracing(bool input)
+ {
+ _useTracing = input;
+ return this;
+ }
+
+ public HttpHandlerOptions Build()
+ {
+ return new HttpHandlerOptions(_allowAutoRedirect, _useCookieContainer, _useTracing);
+ }
+ }
+}
diff --git a/src/Ocelot/Configuration/IInternalConfiguration.cs b/src/Ocelot/Configuration/IInternalConfiguration.cs
index c1781c48..253f7ffc 100644
--- a/src/Ocelot/Configuration/IInternalConfiguration.cs
+++ b/src/Ocelot/Configuration/IInternalConfiguration.cs
@@ -5,8 +5,19 @@ namespace Ocelot.Configuration
public interface IInternalConfiguration
{
List ReRoutes { get; }
+
string AdministrationPath {get;}
+
ServiceProviderConfiguration ServiceProviderConfiguration {get;}
+
string RequestId {get;}
+
+ LoadBalancerOptions LoadBalancerOptions { get; }
+
+ string DownstreamScheme { get; }
+
+ QoSOptions QoSOptions { get; }
+
+ HttpHandlerOptions HttpHandlerOptions { get; }
}
}
diff --git a/src/Ocelot/Configuration/InternalConfiguration.cs b/src/Ocelot/Configuration/InternalConfiguration.cs
index 429bb9c0..cd939a86 100644
--- a/src/Ocelot/Configuration/InternalConfiguration.cs
+++ b/src/Ocelot/Configuration/InternalConfiguration.cs
@@ -4,17 +4,33 @@ namespace Ocelot.Configuration
{
public class InternalConfiguration : IInternalConfiguration
{
- public InternalConfiguration(List reRoutes, string administrationPath, ServiceProviderConfiguration serviceProviderConfiguration, string requestId)
+ public InternalConfiguration(
+ List reRoutes,
+ string administrationPath,
+ ServiceProviderConfiguration serviceProviderConfiguration,
+ string requestId,
+ LoadBalancerOptions loadBalancerOptions,
+ string downstreamScheme,
+ QoSOptions qoSOptions,
+ HttpHandlerOptions httpHandlerOptions)
{
ReRoutes = reRoutes;
AdministrationPath = administrationPath;
ServiceProviderConfiguration = serviceProviderConfiguration;
RequestId = requestId;
+ LoadBalancerOptions = loadBalancerOptions;
+ DownstreamScheme = downstreamScheme;
+ QoSOptions = qoSOptions;
+ HttpHandlerOptions = httpHandlerOptions;
}
public List ReRoutes { get; }
public string AdministrationPath {get;}
public ServiceProviderConfiguration ServiceProviderConfiguration {get;}
public string RequestId {get;}
+ public LoadBalancerOptions LoadBalancerOptions { get; }
+ public string DownstreamScheme { get; }
+ public QoSOptions QoSOptions { get; }
+ public HttpHandlerOptions HttpHandlerOptions { get; }
}
}
diff --git a/src/Ocelot/Configuration/LoadBalancerOptions.cs b/src/Ocelot/Configuration/LoadBalancerOptions.cs
index fd5b8b35..08dc3b87 100644
--- a/src/Ocelot/Configuration/LoadBalancerOptions.cs
+++ b/src/Ocelot/Configuration/LoadBalancerOptions.cs
@@ -1,10 +1,12 @@
+using Ocelot.LoadBalancer.LoadBalancers;
+
namespace Ocelot.Configuration
{
public class LoadBalancerOptions
{
public LoadBalancerOptions(string type, string key, int expiryInMs)
{
- Type = type;
+ Type = type ?? nameof(NoLoadBalancer);
Key = key;
ExpiryInMs = expiryInMs;
}
diff --git a/src/Ocelot/Configuration/LoadBalancerOptionsBuilder.cs b/src/Ocelot/Configuration/LoadBalancerOptionsBuilder.cs
new file mode 100644
index 00000000..c1790aa4
--- /dev/null
+++ b/src/Ocelot/Configuration/LoadBalancerOptionsBuilder.cs
@@ -0,0 +1,32 @@
+namespace Ocelot.Configuration
+{
+ public class LoadBalancerOptionsBuilder
+ {
+ private string _type;
+ private string _key;
+ private int _expiryInMs;
+
+ public LoadBalancerOptionsBuilder WithType(string type)
+ {
+ _type = type;
+ return this;
+ }
+
+ public LoadBalancerOptionsBuilder WithKey(string key)
+ {
+ _key = key;
+ return this;
+ }
+
+ public LoadBalancerOptionsBuilder WithExpiryInMs(int expiryInMs)
+ {
+ _expiryInMs = expiryInMs;
+ return this;
+ }
+
+ public LoadBalancerOptions Build()
+ {
+ return new LoadBalancerOptions(_type, _key, _expiryInMs);
+ }
+ }
+}
diff --git a/src/Ocelot/Configuration/QoSOptions.cs b/src/Ocelot/Configuration/QoSOptions.cs
index 8c5d6d27..3b7733a3 100644
--- a/src/Ocelot/Configuration/QoSOptions.cs
+++ b/src/Ocelot/Configuration/QoSOptions.cs
@@ -8,12 +8,14 @@ namespace Ocelot.Configuration
int exceptionsAllowedBeforeBreaking,
int durationofBreak,
int timeoutValue,
+ string key,
TimeoutStrategy timeoutStrategy = TimeoutStrategy.Pessimistic)
{
ExceptionsAllowedBeforeBreaking = exceptionsAllowedBeforeBreaking;
DurationOfBreak = durationofBreak;
TimeoutValue = timeoutValue;
TimeoutStrategy = timeoutStrategy;
+ Key = key;
}
public int ExceptionsAllowedBeforeBreaking { get; }
@@ -23,5 +25,8 @@ namespace Ocelot.Configuration
public int TimeoutValue { get; }
public TimeoutStrategy TimeoutStrategy { get; }
+
+ public bool UseQos => ExceptionsAllowedBeforeBreaking > 0 && TimeoutValue > 0;
+ public string Key { get; }
}
}
diff --git a/src/Ocelot/Configuration/ReRouteOptions.cs b/src/Ocelot/Configuration/ReRouteOptions.cs
index e3a7a7b1..13875ac8 100644
--- a/src/Ocelot/Configuration/ReRouteOptions.cs
+++ b/src/Ocelot/Configuration/ReRouteOptions.cs
@@ -2,19 +2,17 @@ namespace Ocelot.Configuration
{
public class ReRouteOptions
{
- public ReRouteOptions(bool isAuthenticated, bool isAuthorised, bool isCached, bool isQos, bool isEnableRateLimiting)
+ public ReRouteOptions(bool isAuthenticated, bool isAuthorised, bool isCached, bool isEnableRateLimiting)
{
IsAuthenticated = isAuthenticated;
IsAuthorised = isAuthorised;
IsCached = isCached;
- IsQos = isQos;
EnableRateLimiting = isEnableRateLimiting;
}
public bool IsAuthenticated { get; private set; }
public bool IsAuthorised { get; private set; }
public bool IsCached { get; private set; }
- public bool IsQos { get; private set; }
public bool EnableRateLimiting { get; private set; }
}
}
diff --git a/src/Ocelot/Configuration/Repository/ConsulFileConfigurationRepository.cs b/src/Ocelot/Configuration/Repository/ConsulFileConfigurationRepository.cs
index e1b6c086..d8a352a7 100644
--- a/src/Ocelot/Configuration/Repository/ConsulFileConfigurationRepository.cs
+++ b/src/Ocelot/Configuration/Repository/ConsulFileConfigurationRepository.cs
@@ -30,20 +30,18 @@ namespace Ocelot.Configuration.Repository
var internalConfig = repo.Get();
_configurationKey = "InternalConfiguration";
- var consulHost = "localhost";
- var consulPort = 8500;
+
string token = null;
if (!internalConfig.IsError)
{
- consulHost = string.IsNullOrEmpty(internalConfig.Data.ServiceProviderConfiguration?.Host) ? consulHost : internalConfig.Data.ServiceProviderConfiguration?.Host;
- consulPort = internalConfig.Data.ServiceProviderConfiguration?.Port ?? consulPort;
- token = internalConfig.Data.ServiceProviderConfiguration?.Token;
- _configurationKey = !string.IsNullOrEmpty(internalConfig.Data.ServiceProviderConfiguration?.ConfigurationKey) ?
- internalConfig.Data.ServiceProviderConfiguration?.ConfigurationKey : _configurationKey;
+ token = internalConfig.Data.ServiceProviderConfiguration.Token;
+ _configurationKey = !string.IsNullOrEmpty(internalConfig.Data.ServiceProviderConfiguration.ConfigurationKey) ?
+ internalConfig.Data.ServiceProviderConfiguration.ConfigurationKey : _configurationKey;
}
- var config = new ConsulRegistryConfiguration(consulHost, consulPort, _configurationKey, token);
+ var config = new ConsulRegistryConfiguration(internalConfig.Data.ServiceProviderConfiguration.Host,
+ internalConfig.Data.ServiceProviderConfiguration.Port, _configurationKey, token);
_consul = factory.Get(config);
}
diff --git a/src/Ocelot/DependencyInjection/OcelotBuilder.cs b/src/Ocelot/DependencyInjection/OcelotBuilder.cs
index 672e8540..3ff2defc 100644
--- a/src/Ocelot/DependencyInjection/OcelotBuilder.cs
+++ b/src/Ocelot/DependencyInjection/OcelotBuilder.cs
@@ -103,7 +103,9 @@ namespace Ocelot.DependencyInjection
_services.TryAddSingleton();
_services.TryAddSingleton();
_services.TryAddSingleton();
- _services.TryAddSingleton();
+ _services.AddSingleton();
+ _services.AddSingleton();
+ _services.TryAddSingleton();
_services.TryAddSingleton();
_services.TryAddSingleton();
_services.TryAddSingleton();
diff --git a/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteCreator.cs b/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteCreator.cs
new file mode 100644
index 00000000..71940d18
--- /dev/null
+++ b/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteCreator.cs
@@ -0,0 +1,120 @@
+namespace Ocelot.DownstreamRouteFinder.Finder
+{
+ using System.Collections.Concurrent;
+ using System.Collections.Generic;
+ using Configuration;
+ using Configuration.Builder;
+ using Configuration.Creator;
+ using Configuration.File;
+ using LoadBalancer.LoadBalancers;
+ using Responses;
+ using UrlMatcher;
+
+ public class DownstreamRouteCreator : IDownstreamRouteProvider
+ {
+ private readonly IQoSOptionsCreator _qoSOptionsCreator;
+ private readonly ConcurrentDictionary> _cache;
+
+ public DownstreamRouteCreator(IQoSOptionsCreator qoSOptionsCreator)
+ {
+ _qoSOptionsCreator = qoSOptionsCreator;
+ _cache = new ConcurrentDictionary>();
+ }
+
+ public Response Get(string upstreamUrlPath, string upstreamHttpMethod, IInternalConfiguration configuration, string upstreamHost)
+ {
+ var serviceName = GetServiceName(upstreamUrlPath);
+
+ var downstreamPath = GetDownstreamPath(upstreamUrlPath);
+
+ if(HasQueryString(downstreamPath))
+ {
+ downstreamPath = RemoveQueryString(downstreamPath);
+ }
+
+ var downstreamPathForKeys = $"/{serviceName}{downstreamPath}";
+
+ var loadBalancerKey = CreateLoadBalancerKey(downstreamPathForKeys, upstreamHttpMethod, configuration.LoadBalancerOptions);
+
+ if(_cache.TryGetValue(loadBalancerKey, out var downstreamRoute))
+ {
+ return downstreamRoute;
+ }
+
+ var qosOptions = _qoSOptionsCreator.Create(configuration.QoSOptions, downstreamPathForKeys, new []{ upstreamHttpMethod });
+
+ var downstreamReRoute = new DownstreamReRouteBuilder()
+ .WithServiceName(serviceName)
+ .WithLoadBalancerKey(loadBalancerKey)
+ .WithDownstreamPathTemplate(downstreamPath)
+ .WithUseServiceDiscovery(true)
+ .WithHttpHandlerOptions(configuration.HttpHandlerOptions)
+ .WithQosOptions(qosOptions)
+ .WithDownstreamScheme(configuration.DownstreamScheme)
+ .WithLoadBalancerOptions(configuration.LoadBalancerOptions)
+ .Build();
+
+ var reRoute = new ReRouteBuilder()
+ .WithDownstreamReRoute(downstreamReRoute)
+ .WithUpstreamHttpMethod(new List(){ upstreamHttpMethod })
+ .Build();
+
+ downstreamRoute = new OkResponse(new DownstreamRoute(new List(), reRoute));
+
+ _cache.AddOrUpdate(loadBalancerKey, downstreamRoute, (x, y) => downstreamRoute);
+
+ return downstreamRoute;
+ }
+
+ private static string RemoveQueryString(string downstreamPath)
+ {
+ return downstreamPath
+ .Substring(0, downstreamPath.IndexOf('?'));
+ }
+
+ private static bool HasQueryString(string downstreamPath)
+ {
+ return downstreamPath.Contains("?");
+ }
+
+ private static string GetDownstreamPath(string upstreamUrlPath)
+ {
+ if(upstreamUrlPath.IndexOf('/', 1) == -1)
+ {
+ return "/";
+ }
+
+ return upstreamUrlPath
+ .Substring(upstreamUrlPath.IndexOf('/', 1));
+ }
+
+ private static string GetServiceName(string upstreamUrlPath)
+ {
+ if(upstreamUrlPath.IndexOf('/', 1) == -1)
+ {
+ return upstreamUrlPath
+ .Substring(1);
+ }
+
+ return upstreamUrlPath
+ .Substring(1, upstreamUrlPath.IndexOf('/', 1))
+ .TrimEnd('/');
+ }
+
+ private string CreateLoadBalancerKey(string downstreamTemplatePath, string httpMethod, LoadBalancerOptions loadBalancerOptions)
+ {
+ if (!string.IsNullOrEmpty(loadBalancerOptions.Type) && !string.IsNullOrEmpty(loadBalancerOptions.Key) && loadBalancerOptions.Type == nameof(CookieStickySessions))
+ {
+ return $"{nameof(CookieStickySessions)}:{loadBalancerOptions.Key}";
+ }
+
+ return CreateQoSKey(downstreamTemplatePath, httpMethod);
+ }
+
+ private string CreateQoSKey(string downstreamTemplatePath, string httpMethod)
+ {
+ var loadBalancerKey = $"{downstreamTemplatePath}|{httpMethod}";
+ return loadBalancerKey;
+ }
+ }
+}
diff --git a/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs b/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs
index df70b0b3..d7713aee 100644
--- a/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs
+++ b/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs
@@ -1,62 +1,62 @@
-using System.Collections.Generic;
-using System.Linq;
-using Ocelot.Configuration;
-using Ocelot.DownstreamRouteFinder.UrlMatcher;
-using Ocelot.Errors;
-using Ocelot.Responses;
-
-namespace Ocelot.DownstreamRouteFinder.Finder
-{
- public class DownstreamRouteFinder : IDownstreamRouteFinder
- {
- private readonly IUrlPathToUrlTemplateMatcher _urlMatcher;
- private readonly IPlaceholderNameAndValueFinder _placeholderNameAndValueFinder;
-
- public DownstreamRouteFinder(IUrlPathToUrlTemplateMatcher urlMatcher, IPlaceholderNameAndValueFinder urlPathPlaceholderNameAndValueFinder)
- {
- _urlMatcher = urlMatcher;
- _placeholderNameAndValueFinder = urlPathPlaceholderNameAndValueFinder;
- }
-
- public Response FindDownstreamRoute(string path, string httpMethod, IInternalConfiguration configuration, string upstreamHost)
- {
- var downstreamRoutes = new List();
-
- var applicableReRoutes = configuration.ReRoutes
- .Where(r => RouteIsApplicableToThisRequest(r, httpMethod, upstreamHost))
- .OrderByDescending(x => x.UpstreamTemplatePattern.Priority);
-
- foreach (var reRoute in applicableReRoutes)
- {
- var urlMatch = _urlMatcher.Match(path, reRoute.UpstreamTemplatePattern.Template);
-
- if (urlMatch.Data.Match)
- {
- downstreamRoutes.Add(GetPlaceholderNamesAndValues(path, reRoute));
- }
- }
-
- if (downstreamRoutes.Any())
- {
- var notNullOption = downstreamRoutes.FirstOrDefault(x => !string.IsNullOrEmpty(x.ReRoute.UpstreamHost));
- var nullOption = downstreamRoutes.FirstOrDefault(x => string.IsNullOrEmpty(x.ReRoute.UpstreamHost));
-
- return notNullOption != null ? new OkResponse(notNullOption) : new OkResponse(nullOption);
- }
-
- return new ErrorResponse(new UnableToFindDownstreamRouteError(path, httpMethod));
- }
-
- private bool RouteIsApplicableToThisRequest(ReRoute reRoute, string httpMethod, string upstreamHost)
- {
- return reRoute.UpstreamHttpMethod.Count == 0 || reRoute.UpstreamHttpMethod.Select(x => x.Method.ToLower()).Contains(httpMethod.ToLower()) && !(!string.IsNullOrEmpty(reRoute.UpstreamHost) && reRoute.UpstreamHost != upstreamHost);
- }
-
- private DownstreamRoute GetPlaceholderNamesAndValues(string path, ReRoute reRoute)
- {
- var templatePlaceholderNameAndValues = _placeholderNameAndValueFinder.Find(path, reRoute.UpstreamPathTemplate.Value);
-
- return new DownstreamRoute(templatePlaceholderNameAndValues.Data, reRoute);
- }
- }
-}
+using System.Collections.Generic;
+using System.Linq;
+using Ocelot.Configuration;
+using Ocelot.DownstreamRouteFinder.UrlMatcher;
+using Ocelot.Errors;
+using Ocelot.Responses;
+
+namespace Ocelot.DownstreamRouteFinder.Finder
+{
+ public class DownstreamRouteFinder : IDownstreamRouteProvider
+ {
+ private readonly IUrlPathToUrlTemplateMatcher _urlMatcher;
+ private readonly IPlaceholderNameAndValueFinder _placeholderNameAndValueFinder;
+
+ public DownstreamRouteFinder(IUrlPathToUrlTemplateMatcher urlMatcher, IPlaceholderNameAndValueFinder urlPathPlaceholderNameAndValueFinder)
+ {
+ _urlMatcher = urlMatcher;
+ _placeholderNameAndValueFinder = urlPathPlaceholderNameAndValueFinder;
+ }
+
+ public Response Get(string path, string httpMethod, IInternalConfiguration configuration, string upstreamHost)
+ {
+ var downstreamRoutes = new List();
+
+ var applicableReRoutes = configuration.ReRoutes
+ .Where(r => RouteIsApplicableToThisRequest(r, httpMethod, upstreamHost))
+ .OrderByDescending(x => x.UpstreamTemplatePattern.Priority);
+
+ foreach (var reRoute in applicableReRoutes)
+ {
+ var urlMatch = _urlMatcher.Match(path, reRoute.UpstreamTemplatePattern.Template);
+
+ if (urlMatch.Data.Match)
+ {
+ downstreamRoutes.Add(GetPlaceholderNamesAndValues(path, reRoute));
+ }
+ }
+
+ if (downstreamRoutes.Any())
+ {
+ var notNullOption = downstreamRoutes.FirstOrDefault(x => !string.IsNullOrEmpty(x.ReRoute.UpstreamHost));
+ var nullOption = downstreamRoutes.FirstOrDefault(x => string.IsNullOrEmpty(x.ReRoute.UpstreamHost));
+
+ return notNullOption != null ? new OkResponse(notNullOption) : new OkResponse(nullOption);
+ }
+
+ return new ErrorResponse(new UnableToFindDownstreamRouteError(path, httpMethod));
+ }
+
+ private bool RouteIsApplicableToThisRequest(ReRoute reRoute, string httpMethod, string upstreamHost)
+ {
+ return reRoute.UpstreamHttpMethod.Count == 0 || reRoute.UpstreamHttpMethod.Select(x => x.Method.ToLower()).Contains(httpMethod.ToLower()) && !(!string.IsNullOrEmpty(reRoute.UpstreamHost) && reRoute.UpstreamHost != upstreamHost);
+ }
+
+ private DownstreamRoute GetPlaceholderNamesAndValues(string path, ReRoute reRoute)
+ {
+ var templatePlaceholderNameAndValues = _placeholderNameAndValueFinder.Find(path, reRoute.UpstreamPathTemplate.Value);
+
+ return new DownstreamRoute(templatePlaceholderNameAndValues.Data, reRoute);
+ }
+ }
+}
diff --git a/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteProviderFactory.cs b/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteProviderFactory.cs
new file mode 100644
index 00000000..b615b613
--- /dev/null
+++ b/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteProviderFactory.cs
@@ -0,0 +1,38 @@
+namespace Ocelot.DownstreamRouteFinder.Finder
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using Configuration;
+ using Microsoft.Extensions.DependencyInjection;
+
+ public class DownstreamRouteProviderFactory : IDownstreamRouteProviderFactory
+ {
+ private readonly Dictionary _providers;
+
+ public DownstreamRouteProviderFactory(IServiceProvider provider)
+ {
+ _providers = provider.GetServices().ToDictionary(x => x.GetType().Name);
+ }
+
+ public IDownstreamRouteProvider Get(IInternalConfiguration config)
+ {
+ if(!config.ReRoutes.Any() && IsServiceDiscovery(config.ServiceProviderConfiguration))
+ {
+ return _providers[nameof(DownstreamRouteCreator)];
+ }
+
+ return _providers[nameof(DownstreamRouteFinder)];
+ }
+
+ private bool IsServiceDiscovery(ServiceProviderConfiguration config)
+ {
+ if(!string.IsNullOrEmpty(config?.Host) || config?.Port > 0)
+ {
+ return true;
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/src/Ocelot/DownstreamRouteFinder/Finder/IDownstreamRouteFinder.cs b/src/Ocelot/DownstreamRouteFinder/Finder/IDownstreamRouteFinder.cs
deleted file mode 100644
index 1d8fae15..00000000
--- a/src/Ocelot/DownstreamRouteFinder/Finder/IDownstreamRouteFinder.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System.Threading.Tasks;
-using Ocelot.Configuration;
-using Ocelot.Responses;
-
-namespace Ocelot.DownstreamRouteFinder.Finder
-{
- public interface IDownstreamRouteFinder
- {
- Response FindDownstreamRoute(string upstreamUrlPath, string upstreamHttpMethod, IInternalConfiguration configuration, string upstreamHost);
- }
-}
diff --git a/src/Ocelot/DownstreamRouteFinder/Finder/IDownstreamRouteProvider.cs b/src/Ocelot/DownstreamRouteFinder/Finder/IDownstreamRouteProvider.cs
new file mode 100644
index 00000000..df14065d
--- /dev/null
+++ b/src/Ocelot/DownstreamRouteFinder/Finder/IDownstreamRouteProvider.cs
@@ -0,0 +1,11 @@
+using System.Threading.Tasks;
+using Ocelot.Configuration;
+using Ocelot.Responses;
+
+namespace Ocelot.DownstreamRouteFinder.Finder
+{
+ public interface IDownstreamRouteProvider
+ {
+ Response Get(string upstreamUrlPath, string upstreamHttpMethod, IInternalConfiguration configuration, string upstreamHost);
+ }
+}
diff --git a/src/Ocelot/DownstreamRouteFinder/Finder/IDownstreamRouteProviderFactory.cs b/src/Ocelot/DownstreamRouteFinder/Finder/IDownstreamRouteProviderFactory.cs
new file mode 100644
index 00000000..35fdd297
--- /dev/null
+++ b/src/Ocelot/DownstreamRouteFinder/Finder/IDownstreamRouteProviderFactory.cs
@@ -0,0 +1,9 @@
+namespace Ocelot.DownstreamRouteFinder.Finder
+{
+ using Configuration;
+
+ public interface IDownstreamRouteProviderFactory
+ {
+ IDownstreamRouteProvider Get(IInternalConfiguration config);
+ }
+}
diff --git a/src/Ocelot/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddleware.cs b/src/Ocelot/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddleware.cs
index 970636d3..5c40228d 100644
--- a/src/Ocelot/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddleware.cs
+++ b/src/Ocelot/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddleware.cs
@@ -1,69 +1,60 @@
-using System.Threading.Tasks;
-using System.Linq;
-using Ocelot.Configuration.Repository;
-using Ocelot.DownstreamRouteFinder.Finder;
-using Ocelot.Infrastructure.Extensions;
-using Ocelot.Logging;
-using Ocelot.Middleware;
-using Ocelot.Middleware.Multiplexer;
-
-namespace Ocelot.DownstreamRouteFinder.Middleware
-{
- public class DownstreamRouteFinderMiddleware : OcelotMiddleware
- {
- private readonly OcelotRequestDelegate _next;
- private readonly IDownstreamRouteFinder _downstreamRouteFinder;
- private readonly IInternalConfigurationRepository _repo;
- private readonly IMultiplexer _multiplexer;
-
- public DownstreamRouteFinderMiddleware(OcelotRequestDelegate next,
- IOcelotLoggerFactory loggerFactory,
- IDownstreamRouteFinder downstreamRouteFinder,
- IInternalConfigurationRepository repo,
- IMultiplexer multiplexer)
- :base(loggerFactory.CreateLogger())
- {
- _repo = repo;
- _multiplexer = multiplexer;
- _next = next;
- _downstreamRouteFinder = downstreamRouteFinder;
- }
-
- public async Task Invoke(DownstreamContext context)
- {
- var upstreamUrlPath = context.HttpContext.Request.Path.ToString();
-
- var upstreamHost = context.HttpContext.Request.Headers["Host"];
-
- var configuration = _repo.Get();
-
- if (configuration.IsError)
- {
- Logger.LogWarning($"{MiddlewareName} setting pipeline errors. IOcelotConfigurationProvider returned {configuration.Errors.ToErrorString()}");
- SetPipelineError(context, configuration.Errors);
- return;
- }
-
- context.ServiceProviderConfiguration = configuration.Data.ServiceProviderConfiguration;
-
- Logger.LogDebug($"Upstream url path is {upstreamUrlPath}");
-
- var downstreamRoute = _downstreamRouteFinder.FindDownstreamRoute(upstreamUrlPath, context.HttpContext.Request.Method, configuration.Data, upstreamHost);
-
- if (downstreamRoute.IsError)
- {
- Logger.LogWarning($"{MiddlewareName} setting pipeline errors. IDownstreamRouteFinder returned {downstreamRoute.Errors.ToErrorString()}");
-
- SetPipelineError(context, downstreamRoute.Errors);
- return;
- }
-
- var downstreamPathTemplates = string.Join(", ", downstreamRoute.Data.ReRoute.DownstreamReRoute.Select(r => r.DownstreamPathTemplate.Value));
- Logger.LogDebug($"downstream templates are {downstreamPathTemplates}");
-
- context.TemplatePlaceholderNameAndValues = downstreamRoute.Data.TemplatePlaceholderNameAndValues;
-
- await _multiplexer.Multiplex(context, downstreamRoute.Data.ReRoute, _next);
- }
- }
-}
+using System.Threading.Tasks;
+using System.Linq;
+using Ocelot.Configuration.Repository;
+using Ocelot.DownstreamRouteFinder.Finder;
+using Ocelot.Infrastructure.Extensions;
+using Ocelot.Logging;
+using Ocelot.Middleware;
+using Ocelot.Middleware.Multiplexer;
+
+namespace Ocelot.DownstreamRouteFinder.Middleware
+{
+ public class DownstreamRouteFinderMiddleware : OcelotMiddleware
+ {
+ private readonly OcelotRequestDelegate _next;
+ private readonly IDownstreamRouteProviderFactory _factory;
+ private readonly IInternalConfigurationRepository _repo;
+ private readonly IMultiplexer _multiplexer;
+
+ public DownstreamRouteFinderMiddleware(OcelotRequestDelegate next,
+ IOcelotLoggerFactory loggerFactory,
+ IDownstreamRouteProviderFactory downstreamRouteFinder,
+ IInternalConfigurationRepository repo,
+ IMultiplexer multiplexer)
+ :base(loggerFactory.CreateLogger())
+ {
+ _repo = repo;
+ _multiplexer = multiplexer;
+ _next = next;
+ _factory = downstreamRouteFinder;
+ }
+
+ public async Task Invoke(DownstreamContext context)
+ {
+ var upstreamUrlPath = context.HttpContext.Request.Path.ToString();
+
+ var upstreamHost = context.HttpContext.Request.Headers["Host"];
+
+ Logger.LogDebug($"Upstream url path is {upstreamUrlPath}");
+
+ var provider = _factory.Get(context.Configuration);
+
+ var downstreamRoute = provider.Get(upstreamUrlPath, context.HttpContext.Request.Method, context.Configuration, upstreamHost);
+
+ if (downstreamRoute.IsError)
+ {
+ Logger.LogWarning($"{MiddlewareName} setting pipeline errors. IDownstreamRouteFinder returned {downstreamRoute.Errors.ToErrorString()}");
+
+ SetPipelineError(context, downstreamRoute.Errors);
+ return;
+ }
+
+ var downstreamPathTemplates = string.Join(", ", downstreamRoute.Data.ReRoute.DownstreamReRoute.Select(r => r.DownstreamPathTemplate.Value));
+ Logger.LogDebug($"downstream templates are {downstreamPathTemplates}");
+
+ context.TemplatePlaceholderNameAndValues = downstreamRoute.Data.TemplatePlaceholderNameAndValues;
+
+ await _multiplexer.Multiplex(context, downstreamRoute.Data.ReRoute, _next);
+ }
+ }
+}
diff --git a/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs b/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs
index bc054783..defe20a9 100644
--- a/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs
+++ b/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs
@@ -73,7 +73,7 @@ namespace Ocelot.DownstreamUrlCreator.Middleware
private static bool ServiceFabricRequest(DownstreamContext context)
{
- return context.ServiceProviderConfiguration.Type == "ServiceFabric" && context.DownstreamReRoute.UseServiceDiscovery;
+ return context.Configuration.ServiceProviderConfiguration.Type == "ServiceFabric" && context.DownstreamReRoute.UseServiceDiscovery;
}
private static bool RequestForStatefullService(string query)
diff --git a/src/Ocelot/Errors/Middleware/ExceptionHandlerMiddleware.cs b/src/Ocelot/Errors/Middleware/ExceptionHandlerMiddleware.cs
index 41b0b83d..b7e51ef9 100644
--- a/src/Ocelot/Errors/Middleware/ExceptionHandlerMiddleware.cs
+++ b/src/Ocelot/Errors/Middleware/ExceptionHandlerMiddleware.cs
@@ -9,6 +9,8 @@ using Ocelot.Middleware;
namespace Ocelot.Errors.Middleware
{
+ using Configuration;
+
///
/// Catches all unhandled exceptions thrown by middleware, logs and returns a 500
///
@@ -32,8 +34,20 @@ namespace Ocelot.Errors.Middleware
public async Task Invoke(DownstreamContext context)
{
try
- {
- TrySetGlobalRequestId(context);
+ {
+ //try and get the global request id and set it for logs...
+ //should this basically be immutable per request...i guess it should!
+ //first thing is get config
+ var configuration = _configRepo.Get();
+
+ if (configuration.IsError)
+ {
+ throw new Exception($"{MiddlewareName} setting pipeline errors. IOcelotConfigurationProvider returned {configuration.Errors.ToErrorString()}");
+ }
+
+ TrySetGlobalRequestId(context, configuration.Data);
+
+ context.Configuration = configuration.Data;
Logger.LogDebug("ocelot pipeline started");
@@ -53,19 +67,9 @@ namespace Ocelot.Errors.Middleware
Logger.LogDebug("ocelot pipeline finished");
}
- private void TrySetGlobalRequestId(DownstreamContext context)
+ private void TrySetGlobalRequestId(DownstreamContext context, IInternalConfiguration configuration)
{
- //try and get the global request id and set it for logs...
- //should this basically be immutable per request...i guess it should!
- //first thing is get config
- var configuration = _configRepo.Get();
-
- if(configuration.IsError)
- {
- throw new Exception($"{MiddlewareName} setting pipeline errors. IOcelotConfigurationProvider returned {configuration.Errors.ToErrorString()}");
- }
-
- var key = configuration.Data.RequestId;
+ var key = configuration.RequestId;
if (!string.IsNullOrEmpty(key) && context.HttpContext.Request.Headers.TryGetValue(key, out var upstreamRequestIds))
{
diff --git a/src/Ocelot/LoadBalancer/LoadBalancers/LoadBalancerFactory.cs b/src/Ocelot/LoadBalancer/LoadBalancers/LoadBalancerFactory.cs
index 58f6ff4e..c9a9cbe8 100644
--- a/src/Ocelot/LoadBalancer/LoadBalancers/LoadBalancerFactory.cs
+++ b/src/Ocelot/LoadBalancer/LoadBalancers/LoadBalancerFactory.cs
@@ -29,7 +29,7 @@ namespace Ocelot.LoadBalancer.LoadBalancers
var bus = new InMemoryBus();
return new CookieStickySessions(loadBalancer, reRoute.LoadBalancerOptions.Key, reRoute.LoadBalancerOptions.ExpiryInMs, bus);
default:
- return new NoLoadBalancer(await serviceProvider.Get());
+ return new NoLoadBalancer(async () => await serviceProvider.Get());
}
}
}
diff --git a/src/Ocelot/LoadBalancer/LoadBalancers/NoLoadBalancer.cs b/src/Ocelot/LoadBalancer/LoadBalancers/NoLoadBalancer.cs
index 89f45545..3f69aded 100644
--- a/src/Ocelot/LoadBalancer/LoadBalancers/NoLoadBalancer.cs
+++ b/src/Ocelot/LoadBalancer/LoadBalancers/NoLoadBalancer.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Ocelot.Middleware;
@@ -9,22 +10,23 @@ namespace Ocelot.LoadBalancer.LoadBalancers
{
public class NoLoadBalancer : ILoadBalancer
{
- private readonly List _services;
+ private readonly Func>> _services;
- public NoLoadBalancer(List services)
+ public NoLoadBalancer(Func>> services)
{
_services = services;
}
public async Task> Lease(DownstreamContext downstreamContext)
{
- //todo no point spinning a task up here, also first or default could be null..
- if (_services == null || _services.Count == 0)
+ var services = await _services();
+ //todo first or default could be null..
+ if (services == null || services.Count == 0)
{
return new ErrorResponse(new ServicesAreEmptyError("There were no services in NoLoadBalancer"));
}
- var service = await Task.FromResult(_services.FirstOrDefault());
+ var service = await Task.FromResult(services.FirstOrDefault());
return new OkResponse(service.HostAndPort);
}
diff --git a/src/Ocelot/LoadBalancer/LoadBalancers/RoundRobin.cs b/src/Ocelot/LoadBalancer/LoadBalancers/RoundRobin.cs
index 15fcf6eb..c9a63b24 100644
--- a/src/Ocelot/LoadBalancer/LoadBalancers/RoundRobin.cs
+++ b/src/Ocelot/LoadBalancer/LoadBalancers/RoundRobin.cs
@@ -20,13 +20,13 @@ namespace Ocelot.LoadBalancer.LoadBalancers
public async Task> Lease(DownstreamContext downstreamContext)
{
- var services = await _services.Invoke();
+ var services = await _services();
if (_last >= services.Count)
{
_last = 0;
}
- var next = await Task.FromResult(services[_last]);
+ var next = services[_last];
_last++;
return new OkResponse(next.HostAndPort);
}
diff --git a/src/Ocelot/LoadBalancer/Middleware/LoadBalancingMiddleware.cs b/src/Ocelot/LoadBalancer/Middleware/LoadBalancingMiddleware.cs
index fc971a16..9568b9cf 100644
--- a/src/Ocelot/LoadBalancer/Middleware/LoadBalancingMiddleware.cs
+++ b/src/Ocelot/LoadBalancer/Middleware/LoadBalancingMiddleware.cs
@@ -22,7 +22,7 @@ namespace Ocelot.LoadBalancer.Middleware
public async Task Invoke(DownstreamContext context)
{
- var loadBalancer = await _loadBalancerHouse.Get(context.DownstreamReRoute, context.ServiceProviderConfiguration);
+ var loadBalancer = await _loadBalancerHouse.Get(context.DownstreamReRoute, context.Configuration.ServiceProviderConfiguration);
if(loadBalancer.IsError)
{
Logger.LogDebug("there was an error retriving the loadbalancer, setting pipeline error");
diff --git a/src/Ocelot/Middleware/DownstreamContext.cs b/src/Ocelot/Middleware/DownstreamContext.cs
index 1913eea9..eb21b4bb 100644
--- a/src/Ocelot/Middleware/DownstreamContext.cs
+++ b/src/Ocelot/Middleware/DownstreamContext.cs
@@ -1,11 +1,8 @@
-using System;
using System.Collections.Generic;
-using System.Net.Http;
using Microsoft.AspNetCore.Http;
using Ocelot.Configuration;
using Ocelot.DownstreamRouteFinder.UrlMatcher;
using Ocelot.Errors;
-using Ocelot.Middleware.Multiplexer;
using Ocelot.Request.Middleware;
namespace Ocelot.Middleware
@@ -20,8 +17,6 @@ namespace Ocelot.Middleware
public List TemplatePlaceholderNameAndValues { get; set; }
- public ServiceProviderConfiguration ServiceProviderConfiguration {get; set;}
-
public HttpContext HttpContext { get; }
public DownstreamReRoute DownstreamReRoute { get; set; }
@@ -32,6 +27,8 @@ namespace Ocelot.Middleware
public List Errors { get; }
+ public IInternalConfiguration Configuration { get; set; }
+
public bool IsError => Errors.Count > 0;
}
}
diff --git a/src/Ocelot/Middleware/Multiplexer/Multiplexer.cs b/src/Ocelot/Middleware/Multiplexer/Multiplexer.cs
index ffe530e8..351f8471 100644
--- a/src/Ocelot/Middleware/Multiplexer/Multiplexer.cs
+++ b/src/Ocelot/Middleware/Multiplexer/Multiplexer.cs
@@ -23,7 +23,7 @@ namespace Ocelot.Middleware.Multiplexer
var downstreamContext = new DownstreamContext(context.HttpContext)
{
TemplatePlaceholderNameAndValues = context.TemplatePlaceholderNameAndValues,
- ServiceProviderConfiguration = context.ServiceProviderConfiguration,
+ Configuration = context.Configuration,
DownstreamReRoute = reRoute.DownstreamReRoute[i],
};
diff --git a/src/Ocelot/Requester/DelegatingHandlerHandlerFactory.cs b/src/Ocelot/Requester/DelegatingHandlerHandlerFactory.cs
index 02969855..340afb47 100644
--- a/src/Ocelot/Requester/DelegatingHandlerHandlerFactory.cs
+++ b/src/Ocelot/Requester/DelegatingHandlerHandlerFactory.cs
@@ -68,7 +68,7 @@ namespace Ocelot.Requester
handlers.Add(() => (DelegatingHandler)_factory.Get());
}
- if (request.IsQos)
+ if (request.QosOptions.UseQos)
{
var qosProvider = _qosProviderHouse.Get(request);
diff --git a/src/Ocelot/Requester/HttpClientBuilder.cs b/src/Ocelot/Requester/HttpClientBuilder.cs
index 18160e02..cb1fd6db 100644
--- a/src/Ocelot/Requester/HttpClientBuilder.cs
+++ b/src/Ocelot/Requester/HttpClientBuilder.cs
@@ -58,9 +58,9 @@ namespace Ocelot.Requester
.LogWarning($"You have ignored all SSL warnings by using DangerousAcceptAnyServerCertificateValidator for this DownstreamReRoute, UpstreamPathTemplate: {context.DownstreamReRoute.UpstreamPathTemplate}, DownstreamPathTemplate: {context.DownstreamReRoute.DownstreamPathTemplate}");
}
- var timeout = context.DownstreamReRoute.QosOptionsOptions.TimeoutValue == 0
+ var timeout = context.DownstreamReRoute.QosOptions.TimeoutValue == 0
? _defaultTimeout
- : TimeSpan.FromMilliseconds(context.DownstreamReRoute.QosOptionsOptions.TimeoutValue);
+ : TimeSpan.FromMilliseconds(context.DownstreamReRoute.QosOptions.TimeoutValue);
_httpClient = new HttpClient(CreateHttpMessageHandler(httpclientHandler, context.DownstreamReRoute))
{
diff --git a/src/Ocelot/Requester/QoS/PollyQoSProvider.cs b/src/Ocelot/Requester/QoS/PollyQoSProvider.cs
index 029650e5..afbf9c3a 100644
--- a/src/Ocelot/Requester/QoS/PollyQoSProvider.cs
+++ b/src/Ocelot/Requester/QoS/PollyQoSProvider.cs
@@ -19,15 +19,15 @@ namespace Ocelot.Requester.QoS
{
_logger = loggerFactory.CreateLogger();
- _timeoutPolicy = Policy.TimeoutAsync(TimeSpan.FromMilliseconds(reRoute.QosOptionsOptions.TimeoutValue), reRoute.QosOptionsOptions.TimeoutStrategy);
+ _timeoutPolicy = Policy.TimeoutAsync(TimeSpan.FromMilliseconds(reRoute.QosOptions.TimeoutValue), reRoute.QosOptions.TimeoutStrategy);
_circuitBreakerPolicy = Policy
.Handle()
.Or()
.Or()
.CircuitBreakerAsync(
- exceptionsAllowedBeforeBreaking: reRoute.QosOptionsOptions.ExceptionsAllowedBeforeBreaking,
- durationOfBreak: TimeSpan.FromMilliseconds(reRoute.QosOptionsOptions.DurationOfBreak),
+ exceptionsAllowedBeforeBreaking: reRoute.QosOptions.ExceptionsAllowedBeforeBreaking,
+ durationOfBreak: TimeSpan.FromMilliseconds(reRoute.QosOptions.DurationOfBreak),
onBreak: (ex, breakDelay) =>
{
_logger.LogError(
diff --git a/src/Ocelot/Requester/QoS/QoSProviderFactory.cs b/src/Ocelot/Requester/QoS/QoSProviderFactory.cs
index f985c9b5..45fa78b3 100644
--- a/src/Ocelot/Requester/QoS/QoSProviderFactory.cs
+++ b/src/Ocelot/Requester/QoS/QoSProviderFactory.cs
@@ -14,7 +14,7 @@ namespace Ocelot.Requester.QoS
public IQoSProvider Get(DownstreamReRoute reRoute)
{
- if (reRoute.IsQos)
+ if (reRoute.QosOptions.UseQos)
{
return new PollyQoSProvider(reRoute, _loggerFactory);
}
diff --git a/src/Ocelot/Requester/QoS/QosProviderHouse.cs b/src/Ocelot/Requester/QoS/QosProviderHouse.cs
index 73629e7f..f0e44b39 100644
--- a/src/Ocelot/Requester/QoS/QosProviderHouse.cs
+++ b/src/Ocelot/Requester/QoS/QosProviderHouse.cs
@@ -21,26 +21,26 @@ namespace Ocelot.Requester.QoS
{
try
{
- if (_qoSProviders.TryGetValue(reRoute.QosKey, out var qosProvider))
+ if (_qoSProviders.TryGetValue(reRoute.QosOptions.Key, out var qosProvider))
{
- if (reRoute.IsQos && qosProvider.CircuitBreaker == null)
+ if (reRoute.QosOptions.UseQos && qosProvider.CircuitBreaker == null)
{
qosProvider = _qoSProviderFactory.Get(reRoute);
- Add(reRoute.QosKey, qosProvider);
+ Add(reRoute.QosOptions.Key, qosProvider);
}
- return new OkResponse(_qoSProviders[reRoute.QosKey]);
+ return new OkResponse(_qoSProviders[reRoute.QosOptions.Key]);
}
qosProvider = _qoSProviderFactory.Get(reRoute);
- Add(reRoute.QosKey, qosProvider);
+ Add(reRoute.QosOptions.Key, qosProvider);
return new OkResponse(qosProvider);
}
catch (Exception ex)
{
return new ErrorResponse(new List()
{
- new UnableToFindQoSProviderError($"unabe to find qos provider for {reRoute.QosKey}, exception was {ex}")
+ new UnableToFindQoSProviderError($"unabe to find qos provider for {reRoute.QosOptions.Key}, exception was {ex}")
});
}
}
diff --git a/src/Ocelot/ServiceDiscovery/Configuration/ConsulRegistryConfiguration.cs b/src/Ocelot/ServiceDiscovery/Configuration/ConsulRegistryConfiguration.cs
index 13ae68d2..b99f43cc 100644
--- a/src/Ocelot/ServiceDiscovery/Configuration/ConsulRegistryConfiguration.cs
+++ b/src/Ocelot/ServiceDiscovery/Configuration/ConsulRegistryConfiguration.cs
@@ -4,8 +4,8 @@ namespace Ocelot.ServiceDiscovery.Configuration
{
public ConsulRegistryConfiguration(string host, int port, string keyOfServiceInConsul, string token)
{
- Host = host;
- Port = port;
+ Host = string.IsNullOrEmpty(host) ? "localhost" : host;
+ Port = port > 0 ? port : 8500;
KeyOfServiceInConsul = keyOfServiceInConsul;
Token = token;
}
diff --git a/src/Ocelot/ServiceDiscovery/Providers/ConsulServiceDiscoveryProvider.cs b/src/Ocelot/ServiceDiscovery/Providers/ConsulServiceDiscoveryProvider.cs
index 4c1afcc7..88bcc5d5 100644
--- a/src/Ocelot/ServiceDiscovery/Providers/ConsulServiceDiscoveryProvider.cs
+++ b/src/Ocelot/ServiceDiscovery/Providers/ConsulServiceDiscoveryProvider.cs
@@ -22,12 +22,7 @@ namespace Ocelot.ServiceDiscovery.Providers
{;
_logger = factory.CreateLogger();
- var consulHost = string.IsNullOrEmpty(config?.Host) ? "localhost" : config.Host;
-
- var consulPort = config?.Port ?? 8500;
-
- _config = new ConsulRegistryConfiguration(consulHost, consulPort, config?.KeyOfServiceInConsul, config?.Token);
-
+ _config = config;
_consul = clientFactory.Get(_config);
}
diff --git a/test/Ocelot.AcceptanceTests/ServiceDiscoveryTests.cs b/test/Ocelot.AcceptanceTests/ServiceDiscoveryTests.cs
index 870ab7e8..0d5f7d0c 100644
--- a/test/Ocelot.AcceptanceTests/ServiceDiscoveryTests.cs
+++ b/test/Ocelot.AcceptanceTests/ServiceDiscoveryTests.cs
@@ -208,6 +208,121 @@ namespace Ocelot.AcceptanceTests
.BDDfy();
}
+ [Fact]
+ public void should_handle_request_to_consul_for_downstream_service_and_make_request_no_re_routes()
+ {
+ const int consulPort = 8513;
+ const string serviceName = "web";
+ const int downstreamServicePort = 8087;
+ var downstreamServiceOneUrl = $"http://localhost:{downstreamServicePort}";
+ var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}";
+ var serviceEntryOne = new ServiceEntry()
+ {
+ Service = new AgentService()
+ {
+ Service = serviceName,
+ Address = "localhost",
+ Port = downstreamServicePort,
+ ID = "web_90_0_2_224_8080",
+ Tags = new[] {"version-v1"}
+ },
+ };
+
+ var configuration = new FileConfiguration
+ {
+ GlobalConfiguration = new FileGlobalConfiguration
+ {
+ ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
+ {
+ Host = "localhost",
+ Port = consulPort
+ },
+ DownstreamScheme = "http",
+ HttpHandlerOptions = new FileHttpHandlerOptions
+ {
+ AllowAutoRedirect = true,
+ UseCookieContainer = true,
+ UseTracing = false
+ },
+ QoSOptions = new FileQoSOptions
+ {
+ TimeoutValue = 100,
+ DurationOfBreak = 1000,
+ ExceptionsAllowedBeforeBreaking = 1
+ }
+ }
+ };
+
+ this.Given(x => x.GivenThereIsAServiceRunningOn(downstreamServiceOneUrl, "/something", 200, "Hello from Laura"))
+ .And(x => x.GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl, serviceName))
+ .And(x => x.GivenTheServicesAreRegisteredWithConsul(serviceEntryOne))
+ .And(x => _steps.GivenThereIsAConfiguration(configuration))
+ .And(x => _steps.GivenOcelotIsRunning())
+ .When(x => _steps.WhenIGetUrlOnTheApiGateway("/web/something"))
+ .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
+ .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
+ .BDDfy();
+ }
+
+ [Fact]
+ public void should_use_consul_service_discovery_and_load_balance_request_no_re_routes()
+ {
+ var consulPort = 8510;
+ var serviceName = "product";
+ var serviceOnePort = 50888;
+ var serviceTwoPort = 50889;
+ var downstreamServiceOneUrl = $"http://localhost:{serviceOnePort}";
+ var downstreamServiceTwoUrl = $"http://localhost:{serviceTwoPort}";
+ var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}";
+ var serviceEntryOne = new ServiceEntry()
+ {
+ Service = new AgentService()
+ {
+ Service = serviceName,
+ Address = "localhost",
+ Port = serviceOnePort,
+ ID = Guid.NewGuid().ToString(),
+ Tags = new string[0]
+ },
+ };
+ var serviceEntryTwo = new ServiceEntry()
+ {
+ Service = new AgentService()
+ {
+ Service = serviceName,
+ Address = "localhost",
+ Port = serviceTwoPort,
+ ID = Guid.NewGuid().ToString(),
+ Tags = new string[0]
+ },
+ };
+
+ var configuration = new FileConfiguration
+ {
+ GlobalConfiguration = new FileGlobalConfiguration()
+ {
+ ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
+ {
+ Host = "localhost",
+ Port = consulPort
+ },
+ LoadBalancerOptions = new FileLoadBalancerOptions { Type = "LeastConnection" },
+ DownstreamScheme = "http"
+ }
+ };
+
+ this.Given(x => x.GivenProductServiceOneIsRunning(downstreamServiceOneUrl, 200))
+ .And(x => x.GivenProductServiceTwoIsRunning(downstreamServiceTwoUrl, 200))
+ .And(x => x.GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl, serviceName))
+ .And(x => x.GivenTheServicesAreRegisteredWithConsul(serviceEntryOne, serviceEntryTwo))
+ .And(x => _steps.GivenThereIsAConfiguration(configuration))
+ .And(x => _steps.GivenOcelotIsRunning())
+ .When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimes($"/{serviceName}/", 50))
+ .Then(x => x.ThenTheTwoServicesShouldHaveBeenCalledTimes(50))
+ .And(x => x.ThenBothServicesCalledRealisticAmountOfTimes(24, 26))
+ .BDDfy();
+ }
+
[Fact]
public void should_use_token_to_make_request_to_consul()
{
diff --git a/test/Ocelot.UnitTests/Configuration/ConsulFileConfigurationRepositoryTests.cs b/test/Ocelot.UnitTests/Configuration/ConsulFileConfigurationRepositoryTests.cs
index 6642bb8d..d26a69fc 100644
--- a/test/Ocelot.UnitTests/Configuration/ConsulFileConfigurationRepositoryTests.cs
+++ b/test/Ocelot.UnitTests/Configuration/ConsulFileConfigurationRepositoryTests.cs
@@ -55,7 +55,7 @@ namespace Ocelot.UnitTests.Configuration
_internalRepo
.Setup(x => x.Get())
- .Returns(new OkResponse(new InternalConfiguration(new List(), "", new ServiceProviderConfigurationBuilder().Build(), "")));
+ .Returns(new OkResponse(new InternalConfiguration(new List(), "", new ServiceProviderConfigurationBuilder().Build(), "", It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())));
_repo = new ConsulFileConfigurationRepository(_cache.Object, _internalRepo.Object, _factory.Object, _loggerFactory.Object);
}
@@ -140,7 +140,10 @@ namespace Ocelot.UnitTests.Configuration
{
_internalRepo
.Setup(x => x.Get())
- .Returns(new OkResponse(new InternalConfiguration(new List(), "", new ServiceProviderConfigurationBuilder().WithConfigurationKey(key).Build(), "")));
+ .Returns(new OkResponse(new InternalConfiguration(new List(), "",
+ new ServiceProviderConfigurationBuilder().WithConfigurationKey(key).Build(), "",
+ new LoadBalancerOptionsBuilder().Build(), "", new QoSOptionsBuilder().Build(),
+ new HttpHandlerOptionsBuilder().Build())));
_repo = new ConsulFileConfigurationRepository(_cache.Object, _internalRepo.Object, _factory.Object, _loggerFactory.Object);
}
diff --git a/test/Ocelot.UnitTests/Configuration/FileConfigurationSetterTests.cs b/test/Ocelot.UnitTests/Configuration/FileConfigurationSetterTests.cs
index ff33872c..57f8c4d7 100644
--- a/test/Ocelot.UnitTests/Configuration/FileConfigurationSetterTests.cs
+++ b/test/Ocelot.UnitTests/Configuration/FileConfigurationSetterTests.cs
@@ -38,7 +38,7 @@ namespace Ocelot.UnitTests.Configuration
{
var fileConfig = new FileConfiguration();
var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
- var config = new InternalConfiguration(new List(), string.Empty, serviceProviderConfig, "asdf");
+ var config = new InternalConfiguration(new List(), string.Empty, serviceProviderConfig, "asdf", new LoadBalancerOptionsBuilder().Build(), "", new QoSOptionsBuilder().Build(), new HttpHandlerOptionsBuilder().Build());
this.Given(x => GivenTheFollowingConfiguration(fileConfig))
.And(x => GivenTheRepoReturns(new OkResponse()))
diff --git a/test/Ocelot.UnitTests/Configuration/FileInternalConfigurationCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/FileInternalConfigurationCreatorTests.cs
index a097f921..c5bba51c 100644
--- a/test/Ocelot.UnitTests/Configuration/FileInternalConfigurationCreatorTests.cs
+++ b/test/Ocelot.UnitTests/Configuration/FileInternalConfigurationCreatorTests.cs
@@ -86,7 +86,7 @@
.WithDownstreamPathTemplate("/products/{productId}")
.WithUpstreamPathTemplate("/api/products/{productId}")
.WithUpstreamHttpMethod(new List { "Get" })
- .WithReRouteKey("CookieStickySessions:sessionid")
+ .WithLoadBalancerKey("CookieStickySessions:sessionid")
.Build();
this.Given(x => x.GivenTheConfigIs(new FileConfiguration
@@ -199,7 +199,7 @@
.WithDownstreamScheme("http")
.WithUpstreamHttpMethod(new List() {"Get"})
.WithDownstreamAddresses(new List() {new DownstreamHostAndPort("localhost", 51878)})
- .WithReRouteKey("/laura|Get")
+ .WithLoadBalancerKey("/laura|Get")
.Build();
var lauraReRoute = new ReRouteBuilder()
@@ -218,7 +218,7 @@
.WithDownstreamScheme("http")
.WithUpstreamHttpMethod(new List() { "Get" })
.WithDownstreamAddresses(new List() { new DownstreamHostAndPort("localhost", 51878) })
- .WithReRouteKey("/tom|Get")
+ .WithLoadBalancerKey("/tom|Get")
.Build();
var tomReRoute = new ReRouteBuilder()
@@ -361,7 +361,6 @@
.Build();
var serviceOptions = new ReRouteOptionsBuilder()
- .WithIsQos(true)
.Build();
this.Given(x => x.GivenTheConfigIs(new FileConfiguration
@@ -410,7 +409,7 @@
.WithDownstreamPathTemplate("/products/{productId}")
.WithUpstreamPathTemplate("/api/products/{productId}")
.WithUpstreamHttpMethod(new List {"Get"})
- .WithReRouteKey("/api/products/{productId}|Get")
+ .WithLoadBalancerKey("/api/products/{productId}|Get")
.Build();
this.Given(x => x.GivenTheConfigIs(new FileConfiguration
@@ -462,7 +461,7 @@
.WithUpstreamPathTemplate("/api/products/{productId}")
.WithUpstreamHttpMethod(new List {"Get"})
.WithDelegatingHandlers(handlers)
- .WithReRouteKey("/api/products/{productId}|Get")
+ .WithLoadBalancerKey("/api/products/{productId}|Get")
.Build();
this.Given(x => x.GivenTheConfigIs(new FileConfiguration
@@ -507,7 +506,7 @@
.WithUpstreamHttpMethod(new List {"Get"})
.WithUseServiceDiscovery(true)
.WithServiceName("ProductService")
- .WithReRouteKey("/api/products/{productId}|Get")
+ .WithLoadBalancerKey("/api/products/{productId}|Get")
.Build();
this.Given(x => x.GivenTheConfigIs(new FileConfiguration
@@ -558,7 +557,7 @@
.WithUpstreamPathTemplate("/api/products/{productId}")
.WithUpstreamHttpMethod(new List {"Get"})
.WithUseServiceDiscovery(false)
- .WithReRouteKey("/api/products/{productId}|Get")
+ .WithLoadBalancerKey("/api/products/{productId}|Get")
.Build();
this.Given(x => x.GivenTheConfigIs(new FileConfiguration
@@ -601,7 +600,7 @@
.WithUpstreamPathTemplate("/api/products/{productId}")
.WithUpstreamHttpMethod(new List {"Get"})
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("(?i)/api/products/.*/$", 1))
- .WithReRouteKey("/api/products/{productId}|Get")
+ .WithLoadBalancerKey("/api/products/{productId}|Get")
.Build();
this.Given(x => x.GivenTheConfigIs(new FileConfiguration
@@ -646,7 +645,7 @@
.WithUpstreamPathTemplate("/api/products/{productId}")
.WithUpstreamHttpMethod(new List {"Get"})
.WithRequestIdKey("blahhhh")
- .WithReRouteKey("/api/products/{productId}|Get")
+ .WithLoadBalancerKey("/api/products/{productId}|Get")
.Build();
this.Given(x => x.GivenTheConfigIs(new FileConfiguration
@@ -741,7 +740,7 @@
{
new ClaimToThing("CustomerId", "CustomerId", "", 0),
})
- .WithReRouteKey("/api/products/{productId}|Get")
+ .WithLoadBalancerKey("/api/products/{productId}|Get")
.Build();
var expected = new List
@@ -784,7 +783,7 @@
.WithUpstreamPathTemplate("/api/products/{productId}")
.WithUpstreamHttpMethod(new List {"Get"})
.WithAuthenticationOptions(authenticationOptions)
- .WithReRouteKey("/api/products/{productId}|Get")
+ .WithLoadBalancerKey("/api/products/{productId}|Get")
.Build();
var expected = new List
@@ -942,16 +941,15 @@
private void GivenTheQosOptionsCreatorReturns(QoSOptions qosOptions)
{
_qosOptionsCreator
- .Setup(x => x.Create(_fileConfiguration.ReRoutes[0]))
+ .Setup(x => x.Create(_fileConfiguration.ReRoutes[0].QoSOptions, It.IsAny(), It.IsAny()))
.Returns(qosOptions);
}
private void ThenTheQosOptionsAre(QoSOptions qosOptions)
{
- _config.Data.ReRoutes[0].DownstreamReRoute[0].QosOptionsOptions.DurationOfBreak.ShouldBe(qosOptions.DurationOfBreak);
-
- _config.Data.ReRoutes[0].DownstreamReRoute[0].QosOptionsOptions.ExceptionsAllowedBeforeBreaking.ShouldBe(qosOptions.ExceptionsAllowedBeforeBreaking);
- _config.Data.ReRoutes[0].DownstreamReRoute[0].QosOptionsOptions.TimeoutValue.ShouldBe(qosOptions.TimeoutValue);
+ _config.Data.ReRoutes[0].DownstreamReRoute[0].QosOptions.DurationOfBreak.ShouldBe(qosOptions.DurationOfBreak);
+ _config.Data.ReRoutes[0].DownstreamReRoute[0].QosOptions.ExceptionsAllowedBeforeBreaking.ShouldBe(qosOptions.ExceptionsAllowedBeforeBreaking);
+ _config.Data.ReRoutes[0].DownstreamReRoute[0].QosOptions.TimeoutValue.ShouldBe(qosOptions.TimeoutValue);
}
private void ThenTheServiceProviderCreatorIsCalledCorrectly()
@@ -992,13 +990,13 @@
private void GivenTheFollowingHttpHandlerOptionsAreReturned(HttpHandlerOptions httpHandlerOptions)
{
- _httpHandlerOptionsCreator.Setup(x => x.Create(It.IsAny()))
+ _httpHandlerOptionsCreator.Setup(x => x.Create(It.IsAny()))
.Returns(httpHandlerOptions);
}
private void ThenTheHttpHandlerOptionsCreatorIsCalledCorrectly()
{
- _httpHandlerOptionsCreator.Verify(x => x.Create(_fileConfiguration.ReRoutes[0]), Times.Once());
+ _httpHandlerOptionsCreator.Verify(x => x.Create(_fileConfiguration.ReRoutes[0].HttpHandlerOptions), Times.Once());
}
private void GivenTheDownstreamAddresses()
diff --git a/test/Ocelot.UnitTests/Configuration/HttpHandlerOptionsCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/HttpHandlerOptionsCreatorTests.cs
index 7316dcb3..c86c55d0 100644
--- a/test/Ocelot.UnitTests/Configuration/HttpHandlerOptionsCreatorTests.cs
+++ b/test/Ocelot.UnitTests/Configuration/HttpHandlerOptionsCreatorTests.cs
@@ -103,7 +103,7 @@ namespace Ocelot.UnitTests.Configuration
private void WhenICreateHttpHandlerOptions()
{
- _httpHandlerOptions = _httpHandlerOptionsCreator.Create(_fileReRoute);
+ _httpHandlerOptions = _httpHandlerOptionsCreator.Create(_fileReRoute.HttpHandlerOptions);
}
private void ThenTheFollowingOptionsReturned(HttpHandlerOptions expected)
diff --git a/test/Ocelot.UnitTests/Configuration/InMemoryConfigurationRepositoryTests.cs b/test/Ocelot.UnitTests/Configuration/InMemoryConfigurationRepositoryTests.cs
index 50bf1f85..dfa6362f 100644
--- a/test/Ocelot.UnitTests/Configuration/InMemoryConfigurationRepositoryTests.cs
+++ b/test/Ocelot.UnitTests/Configuration/InMemoryConfigurationRepositoryTests.cs
@@ -105,6 +105,10 @@ namespace Ocelot.UnitTests.Configuration
public ServiceProviderConfiguration ServiceProviderConfiguration => throw new NotImplementedException();
public string RequestId {get;}
+ public LoadBalancerOptions LoadBalancerOptions { get; }
+ public string DownstreamScheme { get; }
+ public QoSOptions QoSOptions { get; }
+ public HttpHandlerOptions HttpHandlerOptions { get; }
}
}
}
diff --git a/test/Ocelot.UnitTests/Configuration/QoSOptionsCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/QoSOptionsCreatorTests.cs
index 0ce64a38..0a68c238 100644
--- a/test/Ocelot.UnitTests/Configuration/QoSOptionsCreatorTests.cs
+++ b/test/Ocelot.UnitTests/Configuration/QoSOptionsCreatorTests.cs
@@ -50,7 +50,7 @@ namespace Ocelot.UnitTests.Configuration
private void WhenICreate()
{
- _result = _creator.Create(_fileReRoute);
+ _result = _creator.Create(_fileReRoute.QoSOptions);
}
private void ThenTheFollowingIsReturned(QoSOptions expected)
@@ -60,4 +60,4 @@ namespace Ocelot.UnitTests.Configuration
_result.TimeoutValue.ShouldBe(expected.TimeoutValue);
}
}
-}
\ No newline at end of file
+}
diff --git a/test/Ocelot.UnitTests/Configuration/ReRouteOptionsCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/ReRouteOptionsCreatorTests.cs
index 6961c968..d23aabc0 100644
--- a/test/Ocelot.UnitTests/Configuration/ReRouteOptionsCreatorTests.cs
+++ b/test/Ocelot.UnitTests/Configuration/ReRouteOptionsCreatorTests.cs
@@ -29,11 +29,6 @@ namespace Ocelot.UnitTests.Configuration
{
EnableRateLimiting = true
},
- QoSOptions = new FileQoSOptions
- {
- ExceptionsAllowedBeforeBreaking = 1,
- TimeoutValue = 1
- },
AuthenticationOptions = new FileAuthenticationOptions()
{
AuthenticationProviderKey = "Test"
@@ -52,7 +47,6 @@ namespace Ocelot.UnitTests.Configuration
.WithIsAuthenticated(true)
.WithIsAuthorised(true)
.WithIsCached(true)
- .WithIsQos(true)
.WithRateLimiting(true)
.Build();
@@ -76,9 +70,8 @@ namespace Ocelot.UnitTests.Configuration
{
_result.IsAuthenticated.ShouldBe(expected.IsAuthenticated);
_result.IsAuthorised.ShouldBe(expected.IsAuthorised);
- _result.IsQos.ShouldBe(expected.IsQos);
_result.IsCached.ShouldBe(expected.IsCached);
_result.EnableRateLimiting.ShouldBe(expected.EnableRateLimiting);
}
}
-}
\ No newline at end of file
+}
diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteCreatorTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteCreatorTests.cs
new file mode 100644
index 00000000..b4f82703
--- /dev/null
+++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteCreatorTests.cs
@@ -0,0 +1,268 @@
+using Ocelot.DownstreamRouteFinder.Finder;
+using Xunit;
+using Shouldly;
+using Ocelot.Configuration;
+using System.Net.Http;
+
+namespace Ocelot.UnitTests.DownstreamRouteFinder
+{
+ using System;
+ using Moq;
+ using Ocelot.Configuration.Builder;
+ using Ocelot.Configuration.Creator;
+ using Ocelot.DownstreamRouteFinder;
+ using Ocelot.LoadBalancer.LoadBalancers;
+ using Responses;
+ using TestStack.BDDfy;
+
+ public class DownstreamRouteCreatorTests
+ {
+ private readonly DownstreamRouteCreator _creator;
+ private readonly QoSOptions _qoSOptions;
+ private readonly HttpHandlerOptions _handlerOptions;
+ private readonly LoadBalancerOptions _loadBalancerOptions;
+ private Response _result;
+ private string _upstreamHost;
+ private string _upstreamUrlPath;
+ private string _upstreamHttpMethod;
+ private IInternalConfiguration _configuration;
+ private Mock _qosOptionsCreator;
+ private Response _resultTwo;
+
+ public DownstreamRouteCreatorTests()
+ {
+ _qosOptionsCreator = new Mock();
+ _qoSOptions = new QoSOptionsBuilder().Build();
+ _handlerOptions = new HttpHandlerOptionsBuilder().Build();
+ _loadBalancerOptions = new LoadBalancerOptionsBuilder().WithType(nameof(NoLoadBalancer)).Build();
+ _qosOptionsCreator
+ .Setup(x => x.Create(It.IsAny(), It.IsAny(), It.IsAny()))
+ .Returns(_qoSOptions);
+ _creator = new DownstreamRouteCreator(_qosOptionsCreator.Object);
+ }
+
+ [Fact]
+ public void should_create_downstream_route()
+ {
+ var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions);
+
+ this.Given(_ => GivenTheConfiguration(configuration))
+ .When(_ => WhenICreate())
+ .Then(_ => ThenTheDownstreamRouteIsCreated())
+ .BDDfy();
+ }
+
+ [Fact]
+ public void should_cache_downstream_route()
+ {
+ var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions);
+
+ this.Given(_ => GivenTheConfiguration(configuration, "/geoffisthebest/"))
+ .When(_ => WhenICreate())
+ .And(_ => GivenTheConfiguration(configuration, "/geoffisthebest/"))
+ .When(_ => WhenICreateAgain())
+ .Then(_ => ThenTheDownstreamRoutesAreTheSameReference())
+ .BDDfy();
+ }
+
+ [Fact]
+ public void should_not_cache_downstream_route()
+ {
+ var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions);
+
+ this.Given(_ => GivenTheConfiguration(configuration, "/geoffistheworst/"))
+ .When(_ => WhenICreate())
+ .And(_ => GivenTheConfiguration(configuration, "/geoffisthebest/"))
+ .When(_ => WhenICreateAgain())
+ .Then(_ => ThenTheDownstreamRoutesAreTheNotSameReference())
+ .BDDfy();
+ }
+
+ [Fact]
+ public void should_create_downstream_route_with_no_path()
+ {
+ var upstreamUrlPath = "/auth/";
+ var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions);
+
+ this.Given(_ => GivenTheConfiguration(configuration, upstreamUrlPath))
+ .When(_ => WhenICreate())
+ .Then(_ => ThenTheDownstreamPathIsForwardSlash())
+ .BDDfy();
+ }
+
+ [Fact]
+ public void should_create_downstream_route_with_only_first_segment_no_traling_slash()
+ {
+ var upstreamUrlPath = "/auth";
+ var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions);
+
+ this.Given(_ => GivenTheConfiguration(configuration, upstreamUrlPath))
+ .When(_ => WhenICreate())
+ .Then(_ => ThenTheDownstreamPathIsForwardSlash())
+ .BDDfy();
+ }
+
+ [Fact]
+ public void should_create_downstream_route_with_segments_no_traling_slash()
+ {
+ var upstreamUrlPath = "/auth/test";
+ var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions);
+
+ this.Given(_ => GivenTheConfiguration(configuration, upstreamUrlPath))
+ .When(_ => WhenICreate())
+ .Then(_ => ThenThePathDoesNotHaveTrailingSlash())
+ .BDDfy();
+ }
+
+ [Fact]
+ public void should_create_downstream_route_and_remove_query_string()
+ {
+ var upstreamUrlPath = "/auth/test?test=1&best=2";
+ var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions);
+
+ this.Given(_ => GivenTheConfiguration(configuration, upstreamUrlPath))
+ .When(_ => WhenICreate())
+ .Then(_ => ThenTheQueryStringIsRemoved())
+ .BDDfy();
+ }
+
+ [Fact]
+ public void should_create_downstream_route_for_sticky_sessions()
+ {
+ var loadBalancerOptions = new LoadBalancerOptionsBuilder().WithType(nameof(CookieStickySessions)).WithKey("boom").WithExpiryInMs(1).Build();
+ var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", loadBalancerOptions, "http", _qoSOptions, _handlerOptions);
+
+ this.Given(_ => GivenTheConfiguration(configuration))
+ .When(_ => WhenICreate())
+ .Then(_ => ThenTheStickySessionLoadBalancerIsUsed(loadBalancerOptions))
+ .BDDfy();
+ }
+
+ [Fact]
+ public void should_create_downstream_route_with_qos()
+ {
+ var qoSOptions = new QoSOptionsBuilder()
+ .WithExceptionsAllowedBeforeBreaking(1)
+ .WithTimeoutValue(1)
+ .Build();
+
+ var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", qoSOptions, _handlerOptions);
+
+ this.Given(_ => GivenTheConfiguration(configuration))
+ .And(_ => GivenTheQosCreatorReturns(qoSOptions))
+ .When(_ => WhenICreate())
+ .Then(_ => ThenTheQosOptionsAreSet(qoSOptions))
+ .BDDfy();
+ }
+
+ [Fact]
+ public void should_create_downstream_route_with_handler_options()
+ {
+ var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions);
+
+ this.Given(_ => GivenTheConfiguration(configuration))
+ .When(_ => WhenICreate())
+ .Then(_ => ThenTheHandlerOptionsAreSet())
+ .BDDfy();
+ }
+
+ private void GivenTheQosCreatorReturns(QoSOptions options)
+ {
+ _qosOptionsCreator
+ .Setup(x => x.Create(It.IsAny(), It.IsAny(), It.IsAny()))
+ .Returns(options);
+ }
+
+ private void ThenTheDownstreamRouteIsCreated()
+ {
+ _result.Data.ReRoute.DownstreamReRoute[0].DownstreamPathTemplate.Value.ShouldBe("/test");
+ _result.Data.ReRoute.UpstreamHttpMethod[0].ShouldBe(HttpMethod.Get);
+ _result.Data.ReRoute.DownstreamReRoute[0].ServiceName.ShouldBe("auth");
+ _result.Data.ReRoute.DownstreamReRoute[0].LoadBalancerKey.ShouldBe("/auth/test|GET");
+ _result.Data.ReRoute.DownstreamReRoute[0].UseServiceDiscovery.ShouldBeTrue();
+ _result.Data.ReRoute.DownstreamReRoute[0].HttpHandlerOptions.ShouldNotBeNull();
+ _result.Data.ReRoute.DownstreamReRoute[0].QosOptions.ShouldNotBeNull();
+ _result.Data.ReRoute.DownstreamReRoute[0].DownstreamScheme.ShouldBe("http");
+ _result.Data.ReRoute.DownstreamReRoute[0].LoadBalancerOptions.Type.ShouldBe(nameof(NoLoadBalancer));
+ _result.Data.ReRoute.DownstreamReRoute[0].HttpHandlerOptions.ShouldBe(_handlerOptions);
+ _result.Data.ReRoute.DownstreamReRoute[0].QosOptions.ShouldBe(_qoSOptions);
+ }
+
+ private void ThenTheDownstreamPathIsForwardSlash()
+ {
+ _result.Data.ReRoute.DownstreamReRoute[0].DownstreamPathTemplate.Value.ShouldBe("/");
+ _result.Data.ReRoute.DownstreamReRoute[0].ServiceName.ShouldBe("auth");
+ _result.Data.ReRoute.DownstreamReRoute[0].LoadBalancerKey.ShouldBe("/auth/|GET");
+ }
+
+ private void ThenThePathDoesNotHaveTrailingSlash()
+ {
+ _result.Data.ReRoute.DownstreamReRoute[0].DownstreamPathTemplate.Value.ShouldBe("/test");
+ _result.Data.ReRoute.DownstreamReRoute[0].ServiceName.ShouldBe("auth");
+ _result.Data.ReRoute.DownstreamReRoute[0].LoadBalancerKey.ShouldBe("/auth/test|GET");
+ }
+
+ private void ThenTheQueryStringIsRemoved()
+ {
+ _result.Data.ReRoute.DownstreamReRoute[0].DownstreamPathTemplate.Value.ShouldBe("/test");
+ _result.Data.ReRoute.DownstreamReRoute[0].ServiceName.ShouldBe("auth");
+ _result.Data.ReRoute.DownstreamReRoute[0].LoadBalancerKey.ShouldBe("/auth/test|GET");
+ }
+
+ private void ThenTheStickySessionLoadBalancerIsUsed(LoadBalancerOptions expected)
+ {
+ _result.Data.ReRoute.DownstreamReRoute[0].LoadBalancerKey.ShouldBe($"{nameof(CookieStickySessions)}:boom");
+ _result.Data.ReRoute.DownstreamReRoute[0].LoadBalancerOptions.Type.ShouldBe(nameof(CookieStickySessions));
+ _result.Data.ReRoute.DownstreamReRoute[0].LoadBalancerOptions.ShouldBe(expected);
+ }
+
+ private void ThenTheQosOptionsAreSet(QoSOptions expected)
+ {
+ _result.Data.ReRoute.DownstreamReRoute[0].QosOptions.ShouldBe(expected);
+ _result.Data.ReRoute.DownstreamReRoute[0].QosOptions.UseQos.ShouldBeTrue();
+ _qosOptionsCreator
+ .Verify(x => x.Create(expected, _upstreamUrlPath, It.IsAny()), Times.Once);
+ }
+
+ private void GivenTheConfiguration(IInternalConfiguration config)
+ {
+ _upstreamHost = "doesnt matter";
+ _upstreamUrlPath = "/auth/test";
+ _upstreamHttpMethod = "GET";
+ _configuration = config;
+ }
+
+ private void GivenTheConfiguration(IInternalConfiguration config, string upstreamUrlPath)
+ {
+ _upstreamHost = "doesnt matter";
+ _upstreamUrlPath = upstreamUrlPath;
+ _upstreamHttpMethod = "GET";
+ _configuration = config;
+ }
+
+ private void ThenTheHandlerOptionsAreSet()
+ {
+ _result.Data.ReRoute.DownstreamReRoute[0].HttpHandlerOptions.ShouldBe(_handlerOptions);
+ }
+
+ private void WhenICreate()
+ {
+ _result = _creator.Get(_upstreamUrlPath, _upstreamHttpMethod, _configuration, _upstreamHost);
+ }
+
+ private void WhenICreateAgain()
+ {
+ _resultTwo = _creator.Get(_upstreamUrlPath, _upstreamHttpMethod, _configuration, _upstreamHost);
+ }
+
+ private void ThenTheDownstreamRoutesAreTheSameReference()
+ {
+ _result.ShouldBe(_resultTwo);
+ }
+
+ private void ThenTheDownstreamRoutesAreTheNotSameReference()
+ {
+ _result.ShouldNotBe(_resultTwo);
+ }
+ }
+}
diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs
index 95bcaf47..19b50e24 100644
--- a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs
+++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs
@@ -1,98 +1,99 @@
-namespace Ocelot.UnitTests.DownstreamRouteFinder
-{
- using System.Collections.Generic;
- using System.Threading.Tasks;
- using Microsoft.AspNetCore.Http;
- using Moq;
- using Ocelot.Configuration;
- using Ocelot.Configuration.Builder;
- using Ocelot.DownstreamRouteFinder;
- using Ocelot.DownstreamRouteFinder.Finder;
- using Ocelot.DownstreamRouteFinder.Middleware;
- using Ocelot.DownstreamRouteFinder.UrlMatcher;
- using Ocelot.Logging;
- using Ocelot.Responses;
- using Shouldly;
- using TestStack.BDDfy;
- using Xunit;
- using Ocelot.Configuration.Repository;
- using Ocelot.Middleware;
- using Ocelot.Middleware.Multiplexer;
-
- public class DownstreamRouteFinderMiddlewareTests
- {
- private readonly Mock _finder;
- private readonly Mock _repo;
- private Response _downstreamRoute;
- private IInternalConfiguration _config;
- private Mock _loggerFactory;
- private Mock _logger;
- private readonly DownstreamRouteFinderMiddleware _middleware;
- private readonly DownstreamContext _downstreamContext;
- private OcelotRequestDelegate _next;
- private readonly Mock _multiplexer;
-
- public DownstreamRouteFinderMiddlewareTests()
- {
- _repo = new Mock();
- _finder = new Mock();
- _downstreamContext = new DownstreamContext(new DefaultHttpContext());
- _loggerFactory = new Mock();
- _logger = new Mock();
- _loggerFactory.Setup(x => x.CreateLogger()).Returns(_logger.Object);
- _next = context => Task.CompletedTask;
- _multiplexer = new Mock();
- _middleware = new DownstreamRouteFinderMiddleware(_next, _loggerFactory.Object, _finder.Object, _repo.Object, _multiplexer.Object);
- }
-
- [Fact]
- public void should_call_scoped_data_repository_correctly()
- {
- var config = new InternalConfiguration(null, null, new ServiceProviderConfigurationBuilder().Build(), "");
-
- var downstreamReRoute = new DownstreamReRouteBuilder()
- .WithDownstreamPathTemplate("any old string")
- .WithUpstreamHttpMethod(new List {"Get"})
- .Build();
-
- this.Given(x => x.GivenTheDownStreamRouteFinderReturns(
- new DownstreamRoute(
- new List(),
- new ReRouteBuilder()
- .WithDownstreamReRoute(downstreamReRoute)
- .WithUpstreamHttpMethod(new List { "Get" })
- .Build())))
- .And(x => GivenTheFollowingConfig(config))
- .When(x => x.WhenICallTheMiddleware())
- .Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly())
- .BDDfy();
- }
-
- private void WhenICallTheMiddleware()
- {
- _middleware.Invoke(_downstreamContext).GetAwaiter().GetType();
- }
-
- private void GivenTheFollowingConfig(IInternalConfiguration config)
- {
- _config = config;
- _repo
- .Setup(x => x.Get())
- .Returns(new OkResponse(_config));
- }
-
- private void GivenTheDownStreamRouteFinderReturns(DownstreamRoute downstreamRoute)
- {
- _downstreamRoute = new OkResponse(downstreamRoute);
- _finder
- .Setup(x => x.FindDownstreamRoute(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()))
- .Returns(_downstreamRoute);
- }
-
- private void ThenTheScopedDataRepositoryIsCalledCorrectly()
- {
- _downstreamContext.TemplatePlaceholderNameAndValues.ShouldBe(_downstreamRoute.Data.TemplatePlaceholderNameAndValues);
- _downstreamContext.ServiceProviderConfiguration.ShouldBe(_config.ServiceProviderConfiguration);
- }
- }
-}
+namespace Ocelot.UnitTests.DownstreamRouteFinder
+{
+ using System.Collections.Generic;
+ using System.Threading.Tasks;
+ using Microsoft.AspNetCore.Http;
+ using Moq;
+ using Ocelot.Configuration;
+ using Ocelot.Configuration.Builder;
+ using Ocelot.DownstreamRouteFinder;
+ using Ocelot.DownstreamRouteFinder.Finder;
+ using Ocelot.DownstreamRouteFinder.Middleware;
+ using Ocelot.DownstreamRouteFinder.UrlMatcher;
+ using Ocelot.Logging;
+ using Ocelot.Responses;
+ using Shouldly;
+ using TestStack.BDDfy;
+ using Xunit;
+ using Ocelot.Configuration.Repository;
+ using Ocelot.Middleware;
+ using Ocelot.Middleware.Multiplexer;
+
+ public class DownstreamRouteFinderMiddlewareTests
+ {
+ private readonly Mock _finder;
+ private readonly Mock _factory;
+ private readonly Mock _repo;
+ private Response _downstreamRoute;
+ private IInternalConfiguration _config;
+ private Mock _loggerFactory;
+ private Mock _logger;
+ private readonly DownstreamRouteFinderMiddleware _middleware;
+ private readonly DownstreamContext _downstreamContext;
+ private OcelotRequestDelegate _next;
+ private readonly Mock _multiplexer;
+
+ public DownstreamRouteFinderMiddlewareTests()
+ {
+ _repo = new Mock();
+ _finder = new Mock();
+ _factory = new Mock();
+ _factory.Setup(x => x.Get(It.IsAny())).Returns(_finder.Object);
+ _downstreamContext = new DownstreamContext(new DefaultHttpContext());
+ _loggerFactory = new Mock();
+ _logger = new Mock();
+ _loggerFactory.Setup(x => x.CreateLogger()).Returns(_logger.Object);
+ _next = context => Task.CompletedTask;
+ _multiplexer = new Mock();
+ _middleware = new DownstreamRouteFinderMiddleware(_next, _loggerFactory.Object, _factory.Object, _repo.Object, _multiplexer.Object);
+ }
+
+ [Fact]
+ public void should_call_scoped_data_repository_correctly()
+ {
+ var config = new InternalConfiguration(null, null, new ServiceProviderConfigurationBuilder().Build(), "", new LoadBalancerOptionsBuilder().Build(), "", new QoSOptionsBuilder().Build(), new HttpHandlerOptionsBuilder().Build());
+
+ var downstreamReRoute = new DownstreamReRouteBuilder()
+ .WithDownstreamPathTemplate("any old string")
+ .WithUpstreamHttpMethod(new List {"Get"})
+ .Build();
+
+ this.Given(x => x.GivenTheDownStreamRouteFinderReturns(
+ new DownstreamRoute(
+ new List(),
+ new ReRouteBuilder()
+ .WithDownstreamReRoute(downstreamReRoute)
+ .WithUpstreamHttpMethod(new List { "Get" })
+ .Build())))
+ .And(x => GivenTheFollowingConfig(config))
+ .When(x => x.WhenICallTheMiddleware())
+ .Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly())
+ .BDDfy();
+ }
+
+ private void WhenICallTheMiddleware()
+ {
+ _middleware.Invoke(_downstreamContext).GetAwaiter().GetType();
+ }
+
+ private void GivenTheFollowingConfig(IInternalConfiguration config)
+ {
+ _config = config;
+ _downstreamContext.Configuration = config;
+ }
+
+ private void GivenTheDownStreamRouteFinderReturns(DownstreamRoute downstreamRoute)
+ {
+ _downstreamRoute = new OkResponse(downstreamRoute);
+ _finder
+ .Setup(x => x.Get(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()))
+ .Returns(_downstreamRoute);
+ }
+
+ private void ThenTheScopedDataRepositoryIsCalledCorrectly()
+ {
+ _downstreamContext.TemplatePlaceholderNameAndValues.ShouldBe(_downstreamRoute.Data.TemplatePlaceholderNameAndValues);
+ _downstreamContext.Configuration.ServiceProviderConfiguration.ShouldBe(_config.ServiceProviderConfiguration);
+ }
+ }
+}
diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs
index 7406b1c5..6b66abe3 100644
--- a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs
+++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs
@@ -1,739 +1,739 @@
-using System.Collections.Generic;
-using Moq;
-using Ocelot.Configuration;
-using Ocelot.Configuration.Builder;
-using Ocelot.DownstreamRouteFinder;
-using Ocelot.DownstreamRouteFinder.Finder;
-using Ocelot.DownstreamRouteFinder.UrlMatcher;
-using Ocelot.Responses;
-using Ocelot.Values;
-using Shouldly;
-using TestStack.BDDfy;
-using Xunit;
-
-namespace Ocelot.UnitTests.DownstreamRouteFinder
-{
- public class DownstreamRouteFinderTests
- {
- private readonly IDownstreamRouteFinder _downstreamRouteFinder;
- private readonly Mock _mockMatcher;
- private readonly Mock _finder;
- private string _upstreamUrlPath;
- private Response _result;
- private List _reRoutesConfig;
- private InternalConfiguration _config;
- private Response _match;
- private string _upstreamHttpMethod;
- private string _upstreamHost;
-
- public DownstreamRouteFinderTests()
- {
- _mockMatcher = new Mock();
- _finder = new Mock();
- _downstreamRouteFinder = new Ocelot.DownstreamRouteFinder.Finder.DownstreamRouteFinder(_mockMatcher.Object, _finder.Object);
- }
-
- [Fact]
- public void should_return_highest_priority_when_first()
- {
- var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
-
- this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath"))
- .And(x => x.GivenTheTemplateVariableAndNameFinderReturns(
- new OkResponse>(new List())))
- .And(x => x.GivenTheConfigurationIs(new List
- {
- new ReRouteBuilder()
- .WithDownstreamReRoute(new DownstreamReRouteBuilder()
- .WithDownstreamPathTemplate("someDownstreamPath")
- .WithUpstreamPathTemplate("someUpstreamPath")
- .WithUpstreamHttpMethod(new List { "Post" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1))
- .Build())
- .WithUpstreamPathTemplate("someUpstreamPath")
- .WithUpstreamHttpMethod(new List { "Post" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1))
- .Build(),
- new ReRouteBuilder()
- .WithDownstreamReRoute(new DownstreamReRouteBuilder()
- .WithDownstreamPathTemplate("someDownstreamPath")
- .WithUpstreamPathTemplate("someUpstreamPath")
- .WithUpstreamHttpMethod(new List { "Post" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 0))
- .Build())
- .WithUpstreamPathTemplate("someUpstreamPath")
- .WithUpstreamHttpMethod(new List { "Post" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 0))
- .Build()
- }, string.Empty, serviceProviderConfig))
- .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true))))
- .And(x => x.GivenTheUpstreamHttpMethodIs("Post"))
- .When(x => x.WhenICallTheFinder())
- .Then(x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List(),
- new ReRouteBuilder()
- .WithDownstreamReRoute(new DownstreamReRouteBuilder()
- .WithDownstreamPathTemplate("someDownstreamPath")
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1))
- .WithUpstreamHttpMethod(new List { "Post" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1))
- .Build())
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1))
- .WithUpstreamHttpMethod(new List { "Post" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1))
- .Build()
- )))
- .BDDfy();
- }
-
- [Fact]
- public void should_return_highest_priority_when_lowest()
- {
- var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
-
- this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath"))
- .And(x => x.GivenTheTemplateVariableAndNameFinderReturns(
- new OkResponse>(new List())))
- .And(x => x.GivenTheConfigurationIs(new List
- {
- new ReRouteBuilder()
- .WithDownstreamReRoute(new DownstreamReRouteBuilder()
- .WithDownstreamPathTemplate("someDownstreamPath")
- .WithUpstreamPathTemplate("someUpstreamPath")
- .WithUpstreamHttpMethod(new List { "Post" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 0))
- .Build())
- .WithUpstreamPathTemplate("someUpstreamPath")
- .WithUpstreamHttpMethod(new List { "Post" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 0))
- .Build(),
- new ReRouteBuilder()
- .WithDownstreamReRoute(new DownstreamReRouteBuilder()
- .WithDownstreamPathTemplate("someDownstreamPath")
- .WithUpstreamPathTemplate("someUpstreamPath")
- .WithUpstreamHttpMethod(new List { "Post" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1))
- .Build())
- .WithUpstreamPathTemplate("someUpstreamPath")
- .WithUpstreamHttpMethod(new List { "Post" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1))
- .Build()
- }, string.Empty, serviceProviderConfig))
- .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true))))
- .And(x => x.GivenTheUpstreamHttpMethodIs("Post"))
- .When(x => x.WhenICallTheFinder())
- .Then(x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List(),
- new ReRouteBuilder()
- .WithDownstreamReRoute(new DownstreamReRouteBuilder()
- .WithDownstreamPathTemplate("someDownstreamPath")
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1))
- .WithUpstreamHttpMethod(new List { "Post" })
- .Build())
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1))
- .WithUpstreamHttpMethod(new List { "Post" })
- .Build()
- )))
- .BDDfy();
- }
-
- [Fact]
- public void should_return_route()
- {
- var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
-
- this.Given(x => x.GivenThereIsAnUpstreamUrlPath("matchInUrlMatcher/"))
- .And(x =>x.GivenTheTemplateVariableAndNameFinderReturns(
- new OkResponse>(
- new List())))
- .And(x => x.GivenTheConfigurationIs(new List
- {
- new ReRouteBuilder()
- .WithDownstreamReRoute(new DownstreamReRouteBuilder()
- .WithDownstreamPathTemplate("someDownstreamPath")
- .WithUpstreamPathTemplate("someUpstreamPath")
- .WithUpstreamHttpMethod(new List { "Get" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1))
- .Build())
- .WithUpstreamPathTemplate("someUpstreamPath")
- .WithUpstreamHttpMethod(new List { "Get" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1))
- .Build()
- }, string.Empty, serviceProviderConfig
- ))
- .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true))))
- .And(x => x.GivenTheUpstreamHttpMethodIs("Get"))
- .When(x => x.WhenICallTheFinder())
- .Then(
- x => x.ThenTheFollowingIsReturned(new DownstreamRoute(
- new List(),
- new ReRouteBuilder()
- .WithDownstreamReRoute(new DownstreamReRouteBuilder()
- .WithDownstreamPathTemplate("someDownstreamPath")
- .WithUpstreamHttpMethod(new List { "Get" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1))
- .Build())
- .WithUpstreamHttpMethod(new List { "Get" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1))
- .Build()
- )))
- .And(x => x.ThenTheUrlMatcherIsCalledCorrectly())
- .BDDfy();
- }
-
- [Fact]
- public void should_not_append_slash_to_upstream_url_path()
- {
- var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
-
- this.Given(x => x.GivenThereIsAnUpstreamUrlPath("matchInUrlMatcher"))
- .And(x =>x.GivenTheTemplateVariableAndNameFinderReturns(
- new OkResponse>(
- new List())))
- .And(x => x.GivenTheConfigurationIs(new List
- {
- new ReRouteBuilder()
- .WithDownstreamReRoute(new DownstreamReRouteBuilder()
- .WithDownstreamPathTemplate("someDownstreamPath")
- .WithUpstreamPathTemplate("someUpstreamPath")
- .WithUpstreamHttpMethod(new List { "Get" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1))
- .Build())
- .WithUpstreamPathTemplate("someUpstreamPath")
- .WithUpstreamHttpMethod(new List { "Get" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1))
- .Build()
- }, string.Empty, serviceProviderConfig
- ))
- .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true))))
- .And(x => x.GivenTheUpstreamHttpMethodIs("Get"))
- .When(x => x.WhenICallTheFinder())
- .Then(
- x => x.ThenTheFollowingIsReturned(new DownstreamRoute(
- new List(),
- new ReRouteBuilder()
- .WithDownstreamReRoute(new DownstreamReRouteBuilder()
- .WithDownstreamPathTemplate("someDownstreamPath")
- .WithUpstreamHttpMethod(new List { "Get" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1))
- .Build())
- .WithUpstreamHttpMethod(new List { "Get" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1))
- .Build()
- )))
- .And(x => x.ThenTheUrlMatcherIsCalledCorrectly("matchInUrlMatcher"))
- .BDDfy();
- }
-
- [Fact]
- public void should_return_route_if_upstream_path_and_upstream_template_are_the_same()
- {
- var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
-
- this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath"))
- .And(
- x =>
- x.GivenTheTemplateVariableAndNameFinderReturns(
- new OkResponse>(new List())))
- .And(x => x.GivenTheConfigurationIs(new List
- {
- new ReRouteBuilder()
- .WithDownstreamReRoute(new DownstreamReRouteBuilder()
- .WithDownstreamPathTemplate("someDownstreamPath")
- .WithUpstreamPathTemplate("someUpstreamPath")
- .WithUpstreamHttpMethod(new List { "Get" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1))
- .Build())
- .WithUpstreamPathTemplate("someUpstreamPath")
- .WithUpstreamHttpMethod(new List { "Get" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1))
- .Build()
- }, string.Empty, serviceProviderConfig
- ))
- .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true))))
- .And(x => x.GivenTheUpstreamHttpMethodIs("Get"))
- .When(x => x.WhenICallTheFinder())
- .Then(
- x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List(),
- new ReRouteBuilder()
- .WithDownstreamReRoute(new DownstreamReRouteBuilder()
- .WithDownstreamPathTemplate("someDownstreamPath")
- .WithUpstreamHttpMethod(new List { "Get" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1))
- .Build())
- .WithUpstreamHttpMethod(new List { "Get" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1))
- .Build()
- )))
- .BDDfy();
- }
-
- [Fact]
- public void should_return_correct_route_for_http_verb()
- {
- var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
-
- this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath"))
- .And(
- x =>
- x.GivenTheTemplateVariableAndNameFinderReturns(
- new OkResponse>(new List())))
- .And(x => x.GivenTheConfigurationIs(new List
- {
- new ReRouteBuilder()
- .WithDownstreamReRoute(new DownstreamReRouteBuilder()
- .WithDownstreamPathTemplate("someDownstreamPath")
- .WithUpstreamPathTemplate("someUpstreamPath")
- .WithUpstreamHttpMethod(new List { "Get" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1))
- .Build())
- .WithUpstreamPathTemplate("someUpstreamPath")
- .WithUpstreamHttpMethod(new List { "Get" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1))
- .Build(),
- new ReRouteBuilder()
- .WithDownstreamReRoute(new DownstreamReRouteBuilder()
- .WithDownstreamPathTemplate("someDownstreamPathForAPost")
- .WithUpstreamPathTemplate("someUpstreamPath")
- .WithUpstreamHttpMethod(new List { "Post" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1))
- .Build())
- .WithUpstreamPathTemplate("someUpstreamPath")
- .WithUpstreamHttpMethod(new List { "Post" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1))
- .Build()
- }, string.Empty, serviceProviderConfig
- ))
- .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true))))
- .And(x => x.GivenTheUpstreamHttpMethodIs("Post"))
- .When(x => x.WhenICallTheFinder())
- .Then(
- x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List(),
- new ReRouteBuilder()
- .WithDownstreamReRoute(new DownstreamReRouteBuilder()
- .WithDownstreamPathTemplate("someDownstreamPathForAPost")
- .WithUpstreamHttpMethod(new List { "Post" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1))
- .Build())
- .WithUpstreamHttpMethod(new List { "Post" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1))
- .Build()
- )))
- .BDDfy();
- }
-
- [Fact]
- public void should_not_return_route()
- {
- var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
-
- this.Given(x => x.GivenThereIsAnUpstreamUrlPath("dontMatchPath/"))
- .And(x => x.GivenTheConfigurationIs(new List
- {
- new ReRouteBuilder()
- .WithDownstreamReRoute(new DownstreamReRouteBuilder()
- .WithDownstreamPathTemplate("somPath")
- .WithUpstreamPathTemplate("somePath")
- .WithUpstreamHttpMethod(new List { "Get" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("somePath", 1))
- .Build())
- .WithUpstreamPathTemplate("somePath")
- .WithUpstreamHttpMethod(new List { "Get" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("somePath", 1))
- .Build(),
- }, string.Empty, serviceProviderConfig
- ))
- .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(false))))
- .And(x => x.GivenTheUpstreamHttpMethodIs("Get"))
- .When(x => x.WhenICallTheFinder())
- .Then(
- x => x.ThenAnErrorResponseIsReturned())
- .And(x => x.ThenTheUrlMatcherIsCalledCorrectly())
- .BDDfy();
- }
-
- [Fact]
- public void should_return_correct_route_for_http_verb_setting_multiple_upstream_http_method()
- {
- var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
-
- this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath"))
- .And(
- x =>
- x.GivenTheTemplateVariableAndNameFinderReturns(
- new OkResponse>(new List())))
- .And(x => x.GivenTheConfigurationIs(new List
- {
- new ReRouteBuilder()
- .WithDownstreamReRoute(new DownstreamReRouteBuilder()
- .WithDownstreamPathTemplate("someDownstreamPath")
- .WithUpstreamPathTemplate("someUpstreamPath")
- .WithUpstreamHttpMethod(new List { "Get", "Post" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1))
- .Build())
- .WithUpstreamPathTemplate("someUpstreamPath")
- .WithUpstreamHttpMethod(new List { "Get", "Post" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1))
- .Build()
- }, string.Empty, serviceProviderConfig
- ))
- .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true))))
- .And(x => x.GivenTheUpstreamHttpMethodIs("Post"))
- .When(x => x.WhenICallTheFinder())
- .Then(
- x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List(),
- new ReRouteBuilder()
- .WithDownstreamReRoute(new DownstreamReRouteBuilder()
- .WithDownstreamPathTemplate("someDownstreamPath")
- .WithUpstreamHttpMethod(new List { "Post" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1))
- .Build())
- .WithUpstreamHttpMethod(new List { "Post" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1))
- .Build()
- )))
- .BDDfy();
- }
-
- [Fact]
- public void should_return_correct_route_for_http_verb_setting_all_upstream_http_method()
- {
- var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
-
- this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath"))
- .And(
- x =>
- x.GivenTheTemplateVariableAndNameFinderReturns(
- new OkResponse>(new List())))
- .And(x => x.GivenTheConfigurationIs(new List
- {
- new ReRouteBuilder()
- .WithDownstreamReRoute(new DownstreamReRouteBuilder()
- .WithDownstreamPathTemplate("someDownstreamPath")
- .WithUpstreamPathTemplate("someUpstreamPath")
- .WithUpstreamHttpMethod(new List())
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1))
- .Build())
- .WithUpstreamPathTemplate("someUpstreamPath")
- .WithUpstreamHttpMethod(new List())
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1))
- .Build()
- }, string.Empty, serviceProviderConfig
- ))
- .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true))))
- .And(x => x.GivenTheUpstreamHttpMethodIs("Post"))
- .When(x => x.WhenICallTheFinder())
- .Then(
- x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List(),
- new ReRouteBuilder()
- .WithDownstreamReRoute(new DownstreamReRouteBuilder()
- .WithDownstreamPathTemplate("someDownstreamPath")
- .WithUpstreamHttpMethod(new List { "Post" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1))
- .Build())
- .WithUpstreamHttpMethod(new List { "Post" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1))
- .Build()
- )))
- .BDDfy();
- }
-
- [Fact]
- public void should_not_return_route_for_http_verb_not_setting_in_upstream_http_method()
- {
- var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
-
- this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath"))
- .And(
- x =>
- x.GivenTheTemplateVariableAndNameFinderReturns(
- new OkResponse>(new List())))
- .And(x => x.GivenTheConfigurationIs(new List
- {
- new ReRouteBuilder()
- .WithDownstreamReRoute(new DownstreamReRouteBuilder()
- .WithDownstreamPathTemplate("someDownstreamPath")
- .WithUpstreamPathTemplate("someUpstreamPath")
- .WithUpstreamHttpMethod(new List { "Get", "Patch", "Delete" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1))
- .Build())
- .WithUpstreamPathTemplate("someUpstreamPath")
- .WithUpstreamHttpMethod(new List { "Get", "Patch", "Delete" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1))
- .Build()
- }, string.Empty, serviceProviderConfig
- ))
- .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true))))
- .And(x => x.GivenTheUpstreamHttpMethodIs("Post"))
- .When(x => x.WhenICallTheFinder())
- .Then(x => x.ThenAnErrorResponseIsReturned())
- .And(x => x.ThenTheUrlMatcherIsNotCalled())
- .BDDfy();
- }
-
- [Fact]
- public void should_return_route_when_host_matches()
- {
- var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
-
- this.Given(x => x.GivenThereIsAnUpstreamUrlPath("matchInUrlMatcher/"))
- .And(x => GivenTheUpstreamHostIs("MATCH"))
- .And(x => x.GivenTheTemplateVariableAndNameFinderReturns(
- new OkResponse>(
- new List())))
- .And(x => x.GivenTheConfigurationIs(new List
- {
- new ReRouteBuilder()
- .WithDownstreamReRoute(new DownstreamReRouteBuilder()
- .WithDownstreamPathTemplate("someDownstreamPath")
- .WithUpstreamPathTemplate("someUpstreamPath")
- .WithUpstreamHttpMethod(new List { "Get" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1))
- .WithUpstreamHost("MATCH")
- .Build())
- .WithUpstreamPathTemplate("someUpstreamPath")
- .WithUpstreamHttpMethod(new List { "Get" })
- .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1))
- .WithUpstreamHost("MATCH")
- .Build()
- }, string.Empty, serviceProviderConfig
- ))
- .And(x => x.GivenTheUrlMatcherReturns(new OkResponse