mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-11-04 19:30:49 +08:00 
			
		
		
		
	
							
								
								
									
										182
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										182
									
								
								README.md
									
									
									
									
									
								
							@@ -1,91 +1,91 @@
 | 
				
			|||||||
[<img src="http://threemammals.com/images/ocelot_logo.png">](http://threemammals.com/ocelot)
 | 
					[<img src="http://threemammals.com/images/ocelot_logo.png">](http://threemammals.com/ocelot)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[](https://ci.appveyor.com/project/TomPallister/ocelot-fcfpb) Windows (AppVeyor)
 | 
					[](https://ci.appveyor.com/project/TomPallister/ocelot-fcfpb) Windows (AppVeyor)
 | 
				
			||||||
[](https://travis-ci.org/ThreeMammals/Ocelot) Linux & OSX (Travis)
 | 
					[](https://travis-ci.org/ThreeMammals/Ocelot) Linux & OSX (Travis)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[](https://ci.appveyor.com/project/TomPallister/ocelot-fcfpb/history?branch=develop)
 | 
					[](https://ci.appveyor.com/project/TomPallister/ocelot-fcfpb/history?branch=develop)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[](https://coveralls.io/github/ThreeMammals/Ocelot?branch=develop)
 | 
					[](https://coveralls.io/github/ThreeMammals/Ocelot?branch=develop)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Ocelot
 | 
					# Ocelot
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Ocelot is a .NET Api Gateway. This project is aimed at people using .NET running 
 | 
					Ocelot is a .NET Api Gateway. This project is aimed at people using .NET running 
 | 
				
			||||||
a micro services / service orientated architecture 
 | 
					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.
 | 
					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 
 | 
					In particular I want easy integration with 
 | 
				
			||||||
IdentityServer reference and bearer tokens. 
 | 
					IdentityServer reference and bearer tokens. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
We have been unable to find this in my current workplace
 | 
					We have been unable to find this in my current workplace
 | 
				
			||||||
without having to write our own Javascript middlewares 
 | 
					without having to write our own Javascript middlewares 
 | 
				
			||||||
to handle the IdentityServer reference tokens. We would
 | 
					to handle the IdentityServer reference tokens. We would
 | 
				
			||||||
rather use the IdentityServer code that already exists
 | 
					rather use the IdentityServer code that already exists
 | 
				
			||||||
to do this.
 | 
					to do this.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Ocelot is a bunch of middlewares in a specific order.
 | 
					Ocelot is a bunch of middlewares in a specific order.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Ocelot manipulates the HttpRequest object into a state specified by its configuration until 
 | 
					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 
 | 
					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 
 | 
					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 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. 
 | 
					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 
 | 
					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!
 | 
					is returned to the client. That is basically it with a bunch of other features!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Features
 | 
					## Features
 | 
				
			||||||
 | 
					
 | 
				
			||||||
A quick list of Ocelot's capabilities for more information see the [documentation](http://ocelot.readthedocs.io/en/latest/).
 | 
					A quick list of Ocelot's capabilities for more information see the [documentation](http://ocelot.readthedocs.io/en/latest/).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* Routing
 | 
					* Routing
 | 
				
			||||||
* Request Aggregation
 | 
					* Request Aggregation
 | 
				
			||||||
* Service Discovery with Consul & Eureka
 | 
					* Service Discovery with Consul & Eureka
 | 
				
			||||||
* Service Fabric
 | 
					* Service Fabric
 | 
				
			||||||
* WebSockets
 | 
					* WebSockets
 | 
				
			||||||
* Authentication
 | 
					* Authentication
 | 
				
			||||||
* Authorisation
 | 
					* Authorisation
 | 
				
			||||||
* Rate Limiting
 | 
					* Rate Limiting
 | 
				
			||||||
* Caching
 | 
					* Caching
 | 
				
			||||||
* Retry policies / QoS
 | 
					* Retry policies / QoS
 | 
				
			||||||
* Load Balancing
 | 
					* Load Balancing
 | 
				
			||||||
* Logging / Tracing / Correlation
 | 
					* Logging / Tracing / Correlation
 | 
				
			||||||
* Headers / Query String / Claims Transformation
 | 
					* Headers / Query String / Claims Transformation
 | 
				
			||||||
* Custom Middleware / Delegating Handlers
 | 
					* Custom Middleware / Delegating Handlers
 | 
				
			||||||
* Configuration / Administration REST API
 | 
					* Configuration / Administration REST API
 | 
				
			||||||
* Platform / Cloud agnostic
 | 
					* Platform / Cloud Agnostic
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## How to install
 | 
					## 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.
 | 
					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 Ocelot and it's dependencies using NuGet. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
`Install-Package Ocelot`
 | 
					`Install-Package Ocelot`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
All versions can be found [here](https://www.nuget.org/packages/Ocelot/)
 | 
					All versions can be found [here](https://www.nuget.org/packages/Ocelot/)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Documentation
 | 
					## 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.
 | 
					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
 | 
					## Coming up
 | 
				
			||||||
 | 
					
 | 
				
			||||||
You can see what we are working on [here](https://github.com/ThreeMammals/Ocelot/issues).
 | 
					You can see what we are working on [here](https://github.com/ThreeMammals/Ocelot/issues).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Contributing
 | 
					## Contributing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
We love to receive contributions from the community so please keep them coming :) 
 | 
					We love to receive contributions from the community so please keep them coming :) 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Pull requests, issues and commentary welcome!
 | 
					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 
 | 
					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
 | 
					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 :)
 | 
					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 :)
 | 
					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
 | 
					## Things that are currently annoying me
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[ Get more details at **codescene.io**.](https://codescene.io/projects/697/jobs/latest-successful/results)
 | 
					[ Get more details at **codescene.io**.](https://codescene.io/projects/697/jobs/latest-successful/results)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
					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!).
 | 
					matched /goods/{catchAll} (because this is the first ReRoute in the list!).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Dynamic Routing
 | 
				
			||||||
 | 
					^^^^^^^^^^^^^^^
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This feature was requested in `issue 340 <https://github.com/TomPallister/Ocelot/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.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,3 +1,5 @@
 | 
				
			|||||||
 | 
					.. service-discovery:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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
 | 
					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.
 | 
					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 <https://github.com/TomPallister/Ocelot/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.
 | 
				
			||||||
@@ -9,7 +9,7 @@ namespace Ocelot.Configuration.Builder
 | 
				
			|||||||
    public class DownstreamReRouteBuilder
 | 
					    public class DownstreamReRouteBuilder
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private AuthenticationOptions _authenticationOptions;
 | 
					        private AuthenticationOptions _authenticationOptions;
 | 
				
			||||||
        private string _reRouteKey;
 | 
					        private string _loadBalancerKey;
 | 
				
			||||||
        private string _downstreamPathTemplate;
 | 
					        private string _downstreamPathTemplate;
 | 
				
			||||||
        private string _upstreamTemplate;
 | 
					        private string _upstreamTemplate;
 | 
				
			||||||
        private UpstreamPathTemplate _upstreamTemplatePattern;
 | 
					        private UpstreamPathTemplate _upstreamTemplatePattern;
 | 
				
			||||||
@@ -25,7 +25,6 @@ namespace Ocelot.Configuration.Builder
 | 
				
			|||||||
        private CacheOptions _fileCacheOptions;
 | 
					        private CacheOptions _fileCacheOptions;
 | 
				
			||||||
        private string _downstreamScheme;
 | 
					        private string _downstreamScheme;
 | 
				
			||||||
        private LoadBalancerOptions _loadBalancerOptions;
 | 
					        private LoadBalancerOptions _loadBalancerOptions;
 | 
				
			||||||
        private bool _useQos;
 | 
					 | 
				
			||||||
        private QoSOptions _qosOptions;
 | 
					        private QoSOptions _qosOptions;
 | 
				
			||||||
        private HttpHandlerOptions _httpHandlerOptions;
 | 
					        private HttpHandlerOptions _httpHandlerOptions;
 | 
				
			||||||
        private bool _enableRateLimiting;
 | 
					        private bool _enableRateLimiting;
 | 
				
			||||||
@@ -41,7 +40,6 @@ namespace Ocelot.Configuration.Builder
 | 
				
			|||||||
        private List<AddHeader> _addHeadersToDownstream;
 | 
					        private List<AddHeader> _addHeadersToDownstream;
 | 
				
			||||||
        private List<AddHeader> _addHeadersToUpstream;
 | 
					        private List<AddHeader> _addHeadersToUpstream;
 | 
				
			||||||
        private bool _dangerousAcceptAnyServerCertificateValidator;
 | 
					        private bool _dangerousAcceptAnyServerCertificateValidator;
 | 
				
			||||||
        private string _qosKey;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public DownstreamReRouteBuilder()
 | 
					        public DownstreamReRouteBuilder()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -153,27 +151,15 @@ namespace Ocelot.Configuration.Builder
 | 
				
			|||||||
            return this;
 | 
					            return this;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public DownstreamReRouteBuilder WithIsQos(bool input)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            _useQos = input;
 | 
					 | 
				
			||||||
            return this;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public DownstreamReRouteBuilder WithQosOptions(QoSOptions input)
 | 
					        public DownstreamReRouteBuilder WithQosOptions(QoSOptions input)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _qosOptions = input;
 | 
					            _qosOptions = input;
 | 
				
			||||||
            return this;
 | 
					            return this;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
       
 | 
					       
 | 
				
			||||||
        public DownstreamReRouteBuilder WithReRouteKey(string reRouteKey)
 | 
					        public DownstreamReRouteBuilder WithLoadBalancerKey(string loadBalancerKey)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _reRouteKey = reRouteKey;
 | 
					            _loadBalancerKey = loadBalancerKey;
 | 
				
			||||||
            return this;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public DownstreamReRouteBuilder WithQosKey(string qosKey)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            _qosKey = qosKey;
 | 
					 | 
				
			||||||
            return this;
 | 
					            return this;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -267,7 +253,6 @@ namespace Ocelot.Configuration.Builder
 | 
				
			|||||||
                _httpHandlerOptions, 
 | 
					                _httpHandlerOptions, 
 | 
				
			||||||
                _useServiceDiscovery, 
 | 
					                _useServiceDiscovery, 
 | 
				
			||||||
                _enableRateLimiting, 
 | 
					                _enableRateLimiting, 
 | 
				
			||||||
                _useQos, 
 | 
					 | 
				
			||||||
                _qosOptions,
 | 
					                _qosOptions,
 | 
				
			||||||
                _downstreamScheme, 
 | 
					                _downstreamScheme, 
 | 
				
			||||||
                _requestIdHeaderKey, 
 | 
					                _requestIdHeaderKey, 
 | 
				
			||||||
@@ -283,12 +268,11 @@ namespace Ocelot.Configuration.Builder
 | 
				
			|||||||
                _isAuthorised, 
 | 
					                _isAuthorised, 
 | 
				
			||||||
                _authenticationOptions, 
 | 
					                _authenticationOptions, 
 | 
				
			||||||
                new PathTemplate(_downstreamPathTemplate),
 | 
					                new PathTemplate(_downstreamPathTemplate),
 | 
				
			||||||
                _reRouteKey,
 | 
					                _loadBalancerKey,
 | 
				
			||||||
                _delegatingHandlers,
 | 
					                _delegatingHandlers,
 | 
				
			||||||
                _addHeadersToDownstream,
 | 
					                _addHeadersToDownstream,
 | 
				
			||||||
                _addHeadersToUpstream,
 | 
					                _addHeadersToUpstream,
 | 
				
			||||||
                _dangerousAcceptAnyServerCertificateValidator,
 | 
					                _dangerousAcceptAnyServerCertificateValidator);
 | 
				
			||||||
                _qosKey);
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,9 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private int _durationOfBreak;
 | 
					        private int _durationOfBreak;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private int _timeoutValue;
 | 
					        private int _timeoutValue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private string _key;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public QoSOptionsBuilder WithExceptionsAllowedBeforeBreaking(int exceptionsAllowedBeforeBreaking)
 | 
					        public QoSOptionsBuilder WithExceptionsAllowedBeforeBreaking(int exceptionsAllowedBeforeBreaking)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -26,9 +28,15 @@
 | 
				
			|||||||
            return this;
 | 
					            return this;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public QoSOptionsBuilder WithKey(string input)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _key = input;
 | 
				
			||||||
 | 
					            return this;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public QoSOptions Build()
 | 
					        public QoSOptions Build()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return new QoSOptions(_exceptionsAllowedBeforeBreaking, _durationOfBreak, _timeoutValue);
 | 
					            return new QoSOptions(_exceptionsAllowedBeforeBreaking, _durationOfBreak, _timeoutValue, _key);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,6 @@ namespace Ocelot.Configuration.Builder
 | 
				
			|||||||
        private bool _isAuthenticated;
 | 
					        private bool _isAuthenticated;
 | 
				
			||||||
        private bool _isAuthorised;
 | 
					        private bool _isAuthorised;
 | 
				
			||||||
        private bool _isCached;
 | 
					        private bool _isCached;
 | 
				
			||||||
        private bool _isQoS;
 | 
					 | 
				
			||||||
        private bool _enableRateLimiting;
 | 
					        private bool _enableRateLimiting;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public ReRouteOptionsBuilder WithIsCached(bool isCached)
 | 
					        public ReRouteOptionsBuilder WithIsCached(bool isCached)
 | 
				
			||||||
@@ -26,12 +25,6 @@ namespace Ocelot.Configuration.Builder
 | 
				
			|||||||
            return this;
 | 
					            return this;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public ReRouteOptionsBuilder WithIsQos(bool isQoS)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            _isQoS = isQoS;
 | 
					 | 
				
			||||||
            return this;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public ReRouteOptionsBuilder WithRateLimiting(bool enableRateLimiting)
 | 
					        public ReRouteOptionsBuilder WithRateLimiting(bool enableRateLimiting)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _enableRateLimiting = enableRateLimiting;
 | 
					            _enableRateLimiting = enableRateLimiting;
 | 
				
			||||||
@@ -40,7 +33,7 @@ namespace Ocelot.Configuration.Builder
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        public ReRouteOptions Build()
 | 
					        public ReRouteOptions Build()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return new ReRouteOptions(_isAuthenticated, _isAuthorised, _isCached, _isQoS, _enableRateLimiting);
 | 
					            return new ReRouteOptions(_isAuthenticated, _isAuthorised, _isCached, _enableRateLimiting);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -104,8 +104,22 @@ namespace Ocelot.Configuration.Creator
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var serviceProviderConfiguration = _serviceProviderConfigCreator.Create(fileConfiguration.GlobalConfiguration);
 | 
					            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<IInternalConfiguration>(config);
 | 
					            return new OkResponse<IInternalConfiguration>(config);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -160,8 +174,6 @@ namespace Ocelot.Configuration.Creator
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            var reRouteKey = CreateReRouteKey(fileReRoute);
 | 
					            var reRouteKey = CreateReRouteKey(fileReRoute);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var qosKey = CreateQosKey(fileReRoute);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            var upstreamTemplatePattern = _upstreamTemplatePatternCreator.Create(fileReRoute);
 | 
					            var upstreamTemplatePattern = _upstreamTemplatePatternCreator.Create(fileReRoute);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var authOptionsForRoute = _authOptionsCreator.Create(fileReRoute);
 | 
					            var authOptionsForRoute = _authOptionsCreator.Create(fileReRoute);
 | 
				
			||||||
@@ -172,19 +184,19 @@ namespace Ocelot.Configuration.Creator
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            var claimsToQueries = _claimsToThingCreator.Create(fileReRoute.AddQueriesToRequest);
 | 
					            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 rateLimitOption = _rateLimitOptionsCreator.Create(fileReRoute, globalConfiguration, fileReRouteOptions.EnableRateLimiting);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var region = _regionCreator.Create(fileReRoute);
 | 
					            var region = _regionCreator.Create(fileReRoute);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var httpHandlerOptions = _httpHandlerOptionsCreator.Create(fileReRoute);
 | 
					            var httpHandlerOptions = _httpHandlerOptionsCreator.Create(fileReRoute.HttpHandlerOptions);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var hAndRs = _headerFAndRCreator.Create(fileReRoute);
 | 
					            var hAndRs = _headerFAndRCreator.Create(fileReRoute);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var downstreamAddresses = _downstreamAddressesCreator.Create(fileReRoute);
 | 
					            var downstreamAddresses = _downstreamAddressesCreator.Create(fileReRoute);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var lbOptions = CreateLoadBalancerOptions(fileReRoute);
 | 
					            var lbOptions = CreateLoadBalancerOptions(fileReRoute.LoadBalancerOptions);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
					            var reRoute = new DownstreamReRouteBuilder()
 | 
				
			||||||
                .WithKey(fileReRoute.Key)
 | 
					                .WithKey(fileReRoute.Key)
 | 
				
			||||||
@@ -205,9 +217,7 @@ namespace Ocelot.Configuration.Creator
 | 
				
			|||||||
                .WithDownstreamScheme(fileReRoute.DownstreamScheme)
 | 
					                .WithDownstreamScheme(fileReRoute.DownstreamScheme)
 | 
				
			||||||
                .WithLoadBalancerOptions(lbOptions)
 | 
					                .WithLoadBalancerOptions(lbOptions)
 | 
				
			||||||
                .WithDownstreamAddresses(downstreamAddresses)
 | 
					                .WithDownstreamAddresses(downstreamAddresses)
 | 
				
			||||||
                .WithReRouteKey(reRouteKey)
 | 
					                .WithLoadBalancerKey(reRouteKey)
 | 
				
			||||||
                .WithQosKey(qosKey)
 | 
					 | 
				
			||||||
                .WithIsQos(fileReRouteOptions.IsQos)
 | 
					 | 
				
			||||||
                .WithQosOptions(qosOptions)
 | 
					                .WithQosOptions(qosOptions)
 | 
				
			||||||
                .WithEnableRateLimiting(fileReRouteOptions.EnableRateLimiting)
 | 
					                .WithEnableRateLimiting(fileReRouteOptions.EnableRateLimiting)
 | 
				
			||||||
                .WithRateLimitOptions(rateLimitOption)
 | 
					                .WithRateLimitOptions(rateLimitOption)
 | 
				
			||||||
@@ -226,9 +236,13 @@ namespace Ocelot.Configuration.Creator
 | 
				
			|||||||
            return reRoute;
 | 
					            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)
 | 
					        private string CreateReRouteKey(FileReRoute fileReRoute)
 | 
				
			||||||
@@ -238,14 +252,7 @@ namespace Ocelot.Configuration.Creator
 | 
				
			|||||||
                return $"{nameof(CookieStickySessions)}:{fileReRoute.LoadBalancerOptions.Key}";
 | 
					                return $"{nameof(CookieStickySessions)}:{fileReRoute.LoadBalancerOptions.Key}";
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return CreateQosKey(fileReRoute);
 | 
					            return $"{fileReRoute.UpstreamPathTemplate}|{string.Join(",", fileReRoute.UpstreamHttpMethod)}";
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        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;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,19 +6,19 @@ namespace Ocelot.Configuration.Creator
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    public class HttpHandlerOptionsCreator : IHttpHandlerOptionsCreator
 | 
					    public class HttpHandlerOptionsCreator : IHttpHandlerOptionsCreator
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private IServiceTracer _tracer;
 | 
					        private readonly IServiceTracer _tracer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public HttpHandlerOptionsCreator(IServiceTracer tracer)
 | 
					        public HttpHandlerOptionsCreator(IServiceTracer tracer)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _tracer = 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,
 | 
					            return new HttpHandlerOptions(options.AllowAutoRedirect,
 | 
				
			||||||
                fileReRoute.HttpHandlerOptions.UseCookieContainer, useTracing);
 | 
					                options.UseCookieContainer, useTracing);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,6 @@ namespace Ocelot.Configuration.Creator
 | 
				
			|||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    public interface IHttpHandlerOptionsCreator
 | 
					    public interface IHttpHandlerOptionsCreator
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        HttpHandlerOptions Create(FileReRoute fileReRoute);
 | 
					        HttpHandlerOptions Create(FileHttpHandlerOptions fileReRoute);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,8 @@ namespace Ocelot.Configuration.Creator
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    public interface IQoSOptionsCreator
 | 
					    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);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,4 +6,4 @@ namespace Ocelot.Configuration.Creator
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        ReRouteOptions Create(FileReRoute fileReRoute);
 | 
					        ReRouteOptions Create(FileReRoute fileReRoute);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,17 +1,47 @@
 | 
				
			|||||||
using Ocelot.Configuration.Builder;
 | 
					 | 
				
			||||||
using Ocelot.Configuration.File;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Ocelot.Configuration.Creator
 | 
					namespace Ocelot.Configuration.Creator
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    using Ocelot.Configuration.Builder;
 | 
				
			||||||
 | 
					    using Ocelot.Configuration.File;
 | 
				
			||||||
 | 
					    using System.Linq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public class QoSOptionsCreator : IQoSOptionsCreator
 | 
					    public class QoSOptionsCreator : IQoSOptionsCreator
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        public QoSOptions Create(FileReRoute fileReRoute)
 | 
					        public QoSOptions Create(FileQoSOptions options)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return new QoSOptionsBuilder()
 | 
					            return new QoSOptionsBuilder()
 | 
				
			||||||
                .WithExceptionsAllowedBeforeBreaking(fileReRoute.QoSOptions.ExceptionsAllowedBeforeBreaking)
 | 
					                .WithExceptionsAllowedBeforeBreaking(options.ExceptionsAllowedBeforeBreaking)
 | 
				
			||||||
                .WithDurationOfBreak(fileReRoute.QoSOptions.DurationOfBreak)
 | 
					                .WithDurationOfBreak(options.DurationOfBreak)
 | 
				
			||||||
                .WithTimeoutValue(fileReRoute.QoSOptions.TimeoutValue)
 | 
					                .WithTimeoutValue(options.TimeoutValue)
 | 
				
			||||||
                .Build();
 | 
					                .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)}";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,14 +10,12 @@ namespace Ocelot.Configuration.Creator
 | 
				
			|||||||
            var isAuthenticated = IsAuthenticated(fileReRoute);
 | 
					            var isAuthenticated = IsAuthenticated(fileReRoute);
 | 
				
			||||||
            var isAuthorised = IsAuthorised(fileReRoute);
 | 
					            var isAuthorised = IsAuthorised(fileReRoute);
 | 
				
			||||||
            var isCached = IsCached(fileReRoute);
 | 
					            var isCached = IsCached(fileReRoute);
 | 
				
			||||||
            var isQos = IsQoS(fileReRoute);
 | 
					 | 
				
			||||||
            var enableRateLimiting = IsEnableRateLimiting(fileReRoute);
 | 
					            var enableRateLimiting = IsEnableRateLimiting(fileReRoute);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var options = new ReRouteOptionsBuilder()
 | 
					            var options = new ReRouteOptionsBuilder()
 | 
				
			||||||
                .WithIsAuthenticated(isAuthenticated)
 | 
					                .WithIsAuthenticated(isAuthenticated)
 | 
				
			||||||
                .WithIsAuthorised(isAuthorised)
 | 
					                .WithIsAuthorised(isAuthorised)
 | 
				
			||||||
                .WithIsCached(isCached)
 | 
					                .WithIsCached(isCached)
 | 
				
			||||||
                .WithIsQos(isQos)
 | 
					 | 
				
			||||||
                .WithRateLimiting(enableRateLimiting)
 | 
					                .WithRateLimiting(enableRateLimiting)
 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
@@ -29,11 +27,6 @@ namespace Ocelot.Configuration.Creator
 | 
				
			|||||||
            return (fileReRoute.RateLimitOptions != null && fileReRoute.RateLimitOptions.EnableRateLimiting) ? true : false;
 | 
					            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)
 | 
					        private bool IsAuthenticated(FileReRoute fileReRoute)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return !string.IsNullOrEmpty(fileReRoute.AuthenticationOptions?.AuthenticationProviderKey);
 | 
					            return !string.IsNullOrEmpty(fileReRoute.AuthenticationOptions?.AuthenticationProviderKey);
 | 
				
			||||||
@@ -48,5 +41,5 @@ namespace Ocelot.Configuration.Creator
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            return fileReRoute.FileCacheOptions.TtlSeconds > 0;
 | 
					            return fileReRoute.FileCacheOptions.TtlSeconds > 0;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,12 +7,12 @@ namespace Ocelot.Configuration.Creator
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        public ServiceProviderConfiguration Create(FileGlobalConfiguration globalConfiguration)
 | 
					        public ServiceProviderConfiguration Create(FileGlobalConfiguration globalConfiguration)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            //todo log or return error here dont just default to something that wont work..
 | 
					            var port = globalConfiguration?.ServiceDiscoveryProvider?.Port ?? 0;
 | 
				
			||||||
            var serviceProviderPort = globalConfiguration?.ServiceDiscoveryProvider?.Port ?? 0;
 | 
					            var host = globalConfiguration?.ServiceDiscoveryProvider?.Host ?? "consul";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return new ServiceProviderConfigurationBuilder()
 | 
					            return new ServiceProviderConfigurationBuilder()
 | 
				
			||||||
                .WithHost(globalConfiguration?.ServiceDiscoveryProvider?.Host)
 | 
					                .WithHost(host)
 | 
				
			||||||
                .WithPort(serviceProviderPort)
 | 
					                .WithPort(port)
 | 
				
			||||||
                .WithType(globalConfiguration?.ServiceDiscoveryProvider?.Type)
 | 
					                .WithType(globalConfiguration?.ServiceDiscoveryProvider?.Type)
 | 
				
			||||||
                .WithToken(globalConfiguration?.ServiceDiscoveryProvider?.Token)
 | 
					                .WithToken(globalConfiguration?.ServiceDiscoveryProvider?.Token)
 | 
				
			||||||
                .WithConfigurationKey(globalConfiguration?.ServiceDiscoveryProvider?.ConfigurationKey)
 | 
					                .WithConfigurationKey(globalConfiguration?.ServiceDiscoveryProvider?.ConfigurationKey)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,8 +16,7 @@ namespace Ocelot.Configuration
 | 
				
			|||||||
            HttpHandlerOptions httpHandlerOptions,
 | 
					            HttpHandlerOptions httpHandlerOptions,
 | 
				
			||||||
            bool useServiceDiscovery,
 | 
					            bool useServiceDiscovery,
 | 
				
			||||||
            bool enableEndpointEndpointRateLimiting,
 | 
					            bool enableEndpointEndpointRateLimiting,
 | 
				
			||||||
            bool isQos,
 | 
					            QoSOptions qosOptions,
 | 
				
			||||||
            QoSOptions qosOptionsOptions,
 | 
					 | 
				
			||||||
            string downstreamScheme,
 | 
					            string downstreamScheme,
 | 
				
			||||||
            string requestIdKey,
 | 
					            string requestIdKey,
 | 
				
			||||||
            bool isCached,
 | 
					            bool isCached,
 | 
				
			||||||
@@ -36,8 +35,7 @@ namespace Ocelot.Configuration
 | 
				
			|||||||
            List<string> delegatingHandlers,
 | 
					            List<string> delegatingHandlers,
 | 
				
			||||||
            List<AddHeader> addHeadersToDownstream,
 | 
					            List<AddHeader> addHeadersToDownstream,
 | 
				
			||||||
            List<AddHeader> addHeadersToUpstream,
 | 
					            List<AddHeader> addHeadersToUpstream,
 | 
				
			||||||
            bool dangerousAcceptAnyServerCertificateValidator,
 | 
					            bool dangerousAcceptAnyServerCertificateValidator)
 | 
				
			||||||
            string qosKey)
 | 
					 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            DangerousAcceptAnyServerCertificateValidator = dangerousAcceptAnyServerCertificateValidator;
 | 
					            DangerousAcceptAnyServerCertificateValidator = dangerousAcceptAnyServerCertificateValidator;
 | 
				
			||||||
            AddHeadersToDownstream = addHeadersToDownstream;
 | 
					            AddHeadersToDownstream = addHeadersToDownstream;
 | 
				
			||||||
@@ -51,8 +49,7 @@ namespace Ocelot.Configuration
 | 
				
			|||||||
            HttpHandlerOptions = httpHandlerOptions;
 | 
					            HttpHandlerOptions = httpHandlerOptions;
 | 
				
			||||||
            UseServiceDiscovery = useServiceDiscovery;
 | 
					            UseServiceDiscovery = useServiceDiscovery;
 | 
				
			||||||
            EnableEndpointEndpointRateLimiting = enableEndpointEndpointRateLimiting;
 | 
					            EnableEndpointEndpointRateLimiting = enableEndpointEndpointRateLimiting;
 | 
				
			||||||
            IsQos = isQos;
 | 
					            QosOptions = qosOptions;
 | 
				
			||||||
            QosOptionsOptions = qosOptionsOptions;
 | 
					 | 
				
			||||||
            DownstreamScheme = downstreamScheme;
 | 
					            DownstreamScheme = downstreamScheme;
 | 
				
			||||||
            RequestIdKey = requestIdKey;
 | 
					            RequestIdKey = requestIdKey;
 | 
				
			||||||
            IsCached = isCached;
 | 
					            IsCached = isCached;
 | 
				
			||||||
@@ -69,10 +66,8 @@ namespace Ocelot.Configuration
 | 
				
			|||||||
            DownstreamPathTemplate = downstreamPathTemplate;
 | 
					            DownstreamPathTemplate = downstreamPathTemplate;
 | 
				
			||||||
            LoadBalancerKey = loadBalancerKey;
 | 
					            LoadBalancerKey = loadBalancerKey;
 | 
				
			||||||
            AddHeadersToUpstream = addHeadersToUpstream;
 | 
					            AddHeadersToUpstream = addHeadersToUpstream;
 | 
				
			||||||
            QosKey = qosKey;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public string QosKey { get; }
 | 
					 | 
				
			||||||
        public string Key { get; }
 | 
					        public string Key { get; }
 | 
				
			||||||
        public PathTemplate UpstreamPathTemplate { get; }
 | 
					        public PathTemplate UpstreamPathTemplate { get; }
 | 
				
			||||||
        public List<HeaderFindAndReplace> UpstreamHeadersFindAndReplace { get; }
 | 
					        public List<HeaderFindAndReplace> UpstreamHeadersFindAndReplace { get; }
 | 
				
			||||||
@@ -82,8 +77,7 @@ namespace Ocelot.Configuration
 | 
				
			|||||||
        public HttpHandlerOptions HttpHandlerOptions { get; }
 | 
					        public HttpHandlerOptions HttpHandlerOptions { get; }
 | 
				
			||||||
        public bool UseServiceDiscovery { get; }
 | 
					        public bool UseServiceDiscovery { get; }
 | 
				
			||||||
        public bool EnableEndpointEndpointRateLimiting { get; }
 | 
					        public bool EnableEndpointEndpointRateLimiting { get; }
 | 
				
			||||||
        public bool IsQos { get; }
 | 
					        public QoSOptions QosOptions { get; }
 | 
				
			||||||
        public QoSOptions QosOptionsOptions { get; }
 | 
					 | 
				
			||||||
        public string DownstreamScheme { get; }
 | 
					        public string DownstreamScheme { get; }
 | 
				
			||||||
        public string RequestIdKey { get; }
 | 
					        public string RequestIdKey { get; }
 | 
				
			||||||
        public bool IsCached { get; }
 | 
					        public bool IsCached { get; }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,9 @@
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            ServiceDiscoveryProvider = new FileServiceDiscoveryProvider();
 | 
					            ServiceDiscoveryProvider = new FileServiceDiscoveryProvider();
 | 
				
			||||||
            RateLimitOptions = new FileRateLimitOptions();
 | 
					            RateLimitOptions = new FileRateLimitOptions();
 | 
				
			||||||
 | 
					            LoadBalancerOptions = new FileLoadBalancerOptions();
 | 
				
			||||||
 | 
					            QoSOptions = new FileQoSOptions();
 | 
				
			||||||
 | 
					            HttpHandlerOptions = new FileHttpHandlerOptions();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public string RequestIdKey { get; set; }
 | 
					        public string RequestIdKey { get; set; }
 | 
				
			||||||
@@ -13,7 +16,15 @@
 | 
				
			|||||||
        public FileServiceDiscoveryProvider ServiceDiscoveryProvider { get;set; }
 | 
					        public FileServiceDiscoveryProvider ServiceDiscoveryProvider { get;set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public FileRateLimitOptions RateLimitOptions { get; set; }
 | 
					        public FileRateLimitOptions RateLimitOptions { get; set; }
 | 
				
			||||||
        
 | 
					
 | 
				
			||||||
 | 
					        public FileQoSOptions QoSOptions { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public string BaseUrl { get ;set; }
 | 
					        public string BaseUrl { get ;set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public FileLoadBalancerOptions LoadBalancerOptions { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public string DownstreamScheme { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public FileHttpHandlerOptions HttpHandlerOptions { get; set; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										32
									
								
								src/Ocelot/Configuration/HttpHandlerOptionsBuilder.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/Ocelot/Configuration/HttpHandlerOptionsBuilder.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -5,8 +5,19 @@ namespace Ocelot.Configuration
 | 
				
			|||||||
    public interface IInternalConfiguration
 | 
					    public interface IInternalConfiguration
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        List<ReRoute> ReRoutes { get; }
 | 
					        List<ReRoute> ReRoutes { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        string AdministrationPath {get;}
 | 
					        string AdministrationPath {get;}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ServiceProviderConfiguration ServiceProviderConfiguration {get;}
 | 
					        ServiceProviderConfiguration ServiceProviderConfiguration {get;}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        string RequestId {get;}
 | 
					        string RequestId {get;}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        LoadBalancerOptions LoadBalancerOptions { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        string DownstreamScheme { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        QoSOptions QoSOptions { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        HttpHandlerOptions HttpHandlerOptions { get; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,17 +4,33 @@ namespace Ocelot.Configuration
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    public class InternalConfiguration : IInternalConfiguration
 | 
					    public class InternalConfiguration : IInternalConfiguration
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        public InternalConfiguration(List<ReRoute> reRoutes, string administrationPath, ServiceProviderConfiguration serviceProviderConfiguration, string requestId)
 | 
					        public InternalConfiguration(
 | 
				
			||||||
 | 
					            List<ReRoute> reRoutes, 
 | 
				
			||||||
 | 
					            string administrationPath, 
 | 
				
			||||||
 | 
					            ServiceProviderConfiguration serviceProviderConfiguration, 
 | 
				
			||||||
 | 
					            string requestId, 
 | 
				
			||||||
 | 
					            LoadBalancerOptions loadBalancerOptions, 
 | 
				
			||||||
 | 
					            string downstreamScheme, 
 | 
				
			||||||
 | 
					            QoSOptions qoSOptions, 
 | 
				
			||||||
 | 
					            HttpHandlerOptions httpHandlerOptions)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            ReRoutes = reRoutes;
 | 
					            ReRoutes = reRoutes;
 | 
				
			||||||
            AdministrationPath = administrationPath;
 | 
					            AdministrationPath = administrationPath;
 | 
				
			||||||
            ServiceProviderConfiguration = serviceProviderConfiguration;
 | 
					            ServiceProviderConfiguration = serviceProviderConfiguration;
 | 
				
			||||||
            RequestId = requestId;
 | 
					            RequestId = requestId;
 | 
				
			||||||
 | 
					            LoadBalancerOptions = loadBalancerOptions;
 | 
				
			||||||
 | 
					            DownstreamScheme = downstreamScheme;
 | 
				
			||||||
 | 
					            QoSOptions = qoSOptions;
 | 
				
			||||||
 | 
					            HttpHandlerOptions = httpHandlerOptions;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public List<ReRoute> ReRoutes { get; }
 | 
					        public List<ReRoute> ReRoutes { get; }
 | 
				
			||||||
        public string AdministrationPath {get;}
 | 
					        public string AdministrationPath {get;}
 | 
				
			||||||
        public ServiceProviderConfiguration ServiceProviderConfiguration {get;}
 | 
					        public ServiceProviderConfiguration ServiceProviderConfiguration {get;}
 | 
				
			||||||
        public string RequestId {get;}
 | 
					        public string RequestId {get;}
 | 
				
			||||||
 | 
					        public LoadBalancerOptions LoadBalancerOptions { get; }
 | 
				
			||||||
 | 
					        public string DownstreamScheme { get; }
 | 
				
			||||||
 | 
					        public QoSOptions QoSOptions { get; }
 | 
				
			||||||
 | 
					        public HttpHandlerOptions HttpHandlerOptions { get; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,12 @@
 | 
				
			|||||||
 | 
					using Ocelot.LoadBalancer.LoadBalancers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Ocelot.Configuration
 | 
					namespace Ocelot.Configuration
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public class LoadBalancerOptions
 | 
					    public class LoadBalancerOptions
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        public LoadBalancerOptions(string type, string key, int expiryInMs)
 | 
					        public LoadBalancerOptions(string type, string key, int expiryInMs)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Type = type;
 | 
					            Type = type ?? nameof(NoLoadBalancer);
 | 
				
			||||||
            Key = key;
 | 
					            Key = key;
 | 
				
			||||||
            ExpiryInMs = expiryInMs;
 | 
					            ExpiryInMs = expiryInMs;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										32
									
								
								src/Ocelot/Configuration/LoadBalancerOptionsBuilder.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/Ocelot/Configuration/LoadBalancerOptionsBuilder.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -8,12 +8,14 @@ namespace Ocelot.Configuration
 | 
				
			|||||||
            int exceptionsAllowedBeforeBreaking, 
 | 
					            int exceptionsAllowedBeforeBreaking, 
 | 
				
			||||||
            int durationofBreak, 
 | 
					            int durationofBreak, 
 | 
				
			||||||
            int timeoutValue, 
 | 
					            int timeoutValue, 
 | 
				
			||||||
 | 
					            string key,
 | 
				
			||||||
            TimeoutStrategy timeoutStrategy = TimeoutStrategy.Pessimistic)
 | 
					            TimeoutStrategy timeoutStrategy = TimeoutStrategy.Pessimistic)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            ExceptionsAllowedBeforeBreaking = exceptionsAllowedBeforeBreaking;
 | 
					            ExceptionsAllowedBeforeBreaking = exceptionsAllowedBeforeBreaking;
 | 
				
			||||||
            DurationOfBreak = durationofBreak;
 | 
					            DurationOfBreak = durationofBreak;
 | 
				
			||||||
            TimeoutValue = timeoutValue;
 | 
					            TimeoutValue = timeoutValue;
 | 
				
			||||||
            TimeoutStrategy = timeoutStrategy;
 | 
					            TimeoutStrategy = timeoutStrategy;
 | 
				
			||||||
 | 
					            Key = key;
 | 
				
			||||||
        }         
 | 
					        }         
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public int ExceptionsAllowedBeforeBreaking { get; }
 | 
					        public int ExceptionsAllowedBeforeBreaking { get; }
 | 
				
			||||||
@@ -23,5 +25,8 @@ namespace Ocelot.Configuration
 | 
				
			|||||||
        public int TimeoutValue { get; }
 | 
					        public int TimeoutValue { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public TimeoutStrategy TimeoutStrategy { get; }
 | 
					        public TimeoutStrategy TimeoutStrategy { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public bool UseQos => ExceptionsAllowedBeforeBreaking > 0 && TimeoutValue > 0;
 | 
				
			||||||
 | 
					        public string Key { get; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,19 +2,17 @@ namespace Ocelot.Configuration
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    public class ReRouteOptions
 | 
					    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;
 | 
					            IsAuthenticated = isAuthenticated;
 | 
				
			||||||
            IsAuthorised = isAuthorised;
 | 
					            IsAuthorised = isAuthorised;
 | 
				
			||||||
            IsCached = isCached;
 | 
					            IsCached = isCached;
 | 
				
			||||||
            IsQos = isQos;
 | 
					 | 
				
			||||||
            EnableRateLimiting = isEnableRateLimiting;
 | 
					            EnableRateLimiting = isEnableRateLimiting;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public bool IsAuthenticated { get; private set; }
 | 
					        public bool IsAuthenticated { get; private set; }
 | 
				
			||||||
        public bool IsAuthorised { get; private set; }
 | 
					        public bool IsAuthorised { get; private set; }
 | 
				
			||||||
        public bool IsCached { get; private set; }
 | 
					        public bool IsCached { get; private set; }
 | 
				
			||||||
        public bool IsQos { get; private set; }
 | 
					 | 
				
			||||||
        public bool EnableRateLimiting { get; private set; }
 | 
					        public bool EnableRateLimiting { get; private set; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,20 +30,18 @@ namespace Ocelot.Configuration.Repository
 | 
				
			|||||||
            var internalConfig = repo.Get();
 | 
					            var internalConfig = repo.Get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            _configurationKey = "InternalConfiguration";
 | 
					            _configurationKey = "InternalConfiguration";
 | 
				
			||||||
            var consulHost = "localhost";
 | 
					          
 | 
				
			||||||
            var consulPort = 8500;
 | 
					 | 
				
			||||||
            string token = null;
 | 
					            string token = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (!internalConfig.IsError)
 | 
					            if (!internalConfig.IsError)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                consulHost = string.IsNullOrEmpty(internalConfig.Data.ServiceProviderConfiguration?.Host) ? consulHost : internalConfig.Data.ServiceProviderConfiguration?.Host;
 | 
					                token = internalConfig.Data.ServiceProviderConfiguration.Token;
 | 
				
			||||||
                consulPort = internalConfig.Data.ServiceProviderConfiguration?.Port ?? consulPort;
 | 
					                _configurationKey = !string.IsNullOrEmpty(internalConfig.Data.ServiceProviderConfiguration.ConfigurationKey) ?
 | 
				
			||||||
                token = internalConfig.Data.ServiceProviderConfiguration?.Token;
 | 
					                    internalConfig.Data.ServiceProviderConfiguration.ConfigurationKey : _configurationKey;
 | 
				
			||||||
                _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);
 | 
					            _consul = factory.Get(config);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -103,7 +103,9 @@ namespace Ocelot.DependencyInjection
 | 
				
			|||||||
            _services.TryAddSingleton<IUrlPathToUrlTemplateMatcher, RegExUrlMatcher>();
 | 
					            _services.TryAddSingleton<IUrlPathToUrlTemplateMatcher, RegExUrlMatcher>();
 | 
				
			||||||
            _services.TryAddSingleton<IPlaceholderNameAndValueFinder, UrlPathPlaceholderNameAndValueFinder>();
 | 
					            _services.TryAddSingleton<IPlaceholderNameAndValueFinder, UrlPathPlaceholderNameAndValueFinder>();
 | 
				
			||||||
            _services.TryAddSingleton<IDownstreamPathPlaceholderReplacer, DownstreamTemplatePathPlaceholderReplacer>();
 | 
					            _services.TryAddSingleton<IDownstreamPathPlaceholderReplacer, DownstreamTemplatePathPlaceholderReplacer>();
 | 
				
			||||||
            _services.TryAddSingleton<IDownstreamRouteFinder, DownstreamRouteFinder>();
 | 
					            _services.AddSingleton<IDownstreamRouteProvider, DownstreamRouteFinder>();
 | 
				
			||||||
 | 
					            _services.AddSingleton<IDownstreamRouteProvider, Ocelot.DownstreamRouteFinder.Finder.DownstreamRouteCreator>();
 | 
				
			||||||
 | 
					            _services.TryAddSingleton<IDownstreamRouteProviderFactory, Ocelot.DownstreamRouteFinder.Finder.DownstreamRouteProviderFactory>();
 | 
				
			||||||
            _services.TryAddSingleton<IHttpRequester, HttpClientHttpRequester>();
 | 
					            _services.TryAddSingleton<IHttpRequester, HttpClientHttpRequester>();
 | 
				
			||||||
            _services.TryAddSingleton<IHttpResponder, HttpContextResponder>();
 | 
					            _services.TryAddSingleton<IHttpResponder, HttpContextResponder>();
 | 
				
			||||||
            _services.TryAddSingleton<IErrorsToHttpStatusCodeMapper, ErrorsToHttpStatusCodeMapper>();
 | 
					            _services.TryAddSingleton<IErrorsToHttpStatusCodeMapper, ErrorsToHttpStatusCodeMapper>();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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<string, OkResponse<DownstreamRoute>> _cache;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public DownstreamRouteCreator(IQoSOptionsCreator qoSOptionsCreator)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _qoSOptionsCreator = qoSOptionsCreator;
 | 
				
			||||||
 | 
					            _cache = new ConcurrentDictionary<string, OkResponse<DownstreamRoute>>();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public Response<DownstreamRoute> 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<string>(){ upstreamHttpMethod })
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            downstreamRoute = new OkResponse<DownstreamRoute>(new DownstreamRoute(new List<PlaceholderNameAndValue>(), 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;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,62 +1,62 @@
 | 
				
			|||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Linq;
 | 
					using System.Linq;
 | 
				
			||||||
using Ocelot.Configuration;
 | 
					using Ocelot.Configuration;
 | 
				
			||||||
using Ocelot.DownstreamRouteFinder.UrlMatcher;
 | 
					using Ocelot.DownstreamRouteFinder.UrlMatcher;
 | 
				
			||||||
using Ocelot.Errors;
 | 
					using Ocelot.Errors;
 | 
				
			||||||
using Ocelot.Responses;
 | 
					using Ocelot.Responses;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Ocelot.DownstreamRouteFinder.Finder
 | 
					namespace Ocelot.DownstreamRouteFinder.Finder
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public class DownstreamRouteFinder : IDownstreamRouteFinder
 | 
					    public class DownstreamRouteFinder : IDownstreamRouteProvider
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private readonly IUrlPathToUrlTemplateMatcher _urlMatcher;
 | 
					        private readonly IUrlPathToUrlTemplateMatcher _urlMatcher;
 | 
				
			||||||
        private readonly IPlaceholderNameAndValueFinder _placeholderNameAndValueFinder;
 | 
					        private readonly IPlaceholderNameAndValueFinder _placeholderNameAndValueFinder;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public DownstreamRouteFinder(IUrlPathToUrlTemplateMatcher urlMatcher, IPlaceholderNameAndValueFinder urlPathPlaceholderNameAndValueFinder)
 | 
					        public DownstreamRouteFinder(IUrlPathToUrlTemplateMatcher urlMatcher, IPlaceholderNameAndValueFinder urlPathPlaceholderNameAndValueFinder)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _urlMatcher = urlMatcher;
 | 
					            _urlMatcher = urlMatcher;
 | 
				
			||||||
            _placeholderNameAndValueFinder = urlPathPlaceholderNameAndValueFinder;
 | 
					            _placeholderNameAndValueFinder = urlPathPlaceholderNameAndValueFinder;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public Response<DownstreamRoute> FindDownstreamRoute(string path, string httpMethod, IInternalConfiguration configuration, string upstreamHost)
 | 
					        public Response<DownstreamRoute> Get(string path, string httpMethod, IInternalConfiguration configuration, string upstreamHost)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var downstreamRoutes = new List<DownstreamRoute>();
 | 
					            var downstreamRoutes = new List<DownstreamRoute>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var applicableReRoutes = configuration.ReRoutes
 | 
					            var applicableReRoutes = configuration.ReRoutes
 | 
				
			||||||
                .Where(r => RouteIsApplicableToThisRequest(r, httpMethod, upstreamHost))
 | 
					                .Where(r => RouteIsApplicableToThisRequest(r, httpMethod, upstreamHost))
 | 
				
			||||||
                .OrderByDescending(x => x.UpstreamTemplatePattern.Priority);
 | 
					                .OrderByDescending(x => x.UpstreamTemplatePattern.Priority);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            foreach (var reRoute in applicableReRoutes)
 | 
					            foreach (var reRoute in applicableReRoutes)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var urlMatch = _urlMatcher.Match(path, reRoute.UpstreamTemplatePattern.Template);
 | 
					                var urlMatch = _urlMatcher.Match(path, reRoute.UpstreamTemplatePattern.Template);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (urlMatch.Data.Match)
 | 
					                if (urlMatch.Data.Match)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    downstreamRoutes.Add(GetPlaceholderNamesAndValues(path, reRoute));
 | 
					                    downstreamRoutes.Add(GetPlaceholderNamesAndValues(path, reRoute));
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (downstreamRoutes.Any())
 | 
					            if (downstreamRoutes.Any())
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var notNullOption = downstreamRoutes.FirstOrDefault(x => !string.IsNullOrEmpty(x.ReRoute.UpstreamHost));
 | 
					                var notNullOption = downstreamRoutes.FirstOrDefault(x => !string.IsNullOrEmpty(x.ReRoute.UpstreamHost));
 | 
				
			||||||
                var nullOption = downstreamRoutes.FirstOrDefault(x => string.IsNullOrEmpty(x.ReRoute.UpstreamHost));
 | 
					                var nullOption = downstreamRoutes.FirstOrDefault(x => string.IsNullOrEmpty(x.ReRoute.UpstreamHost));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                return notNullOption != null ? new OkResponse<DownstreamRoute>(notNullOption) : new OkResponse<DownstreamRoute>(nullOption);
 | 
					                return notNullOption != null ? new OkResponse<DownstreamRoute>(notNullOption) : new OkResponse<DownstreamRoute>(nullOption);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return new ErrorResponse<DownstreamRoute>(new UnableToFindDownstreamRouteError(path, httpMethod));
 | 
					            return new ErrorResponse<DownstreamRoute>(new UnableToFindDownstreamRouteError(path, httpMethod));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private bool RouteIsApplicableToThisRequest(ReRoute reRoute, string httpMethod, string upstreamHost)
 | 
					        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);
 | 
					            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)
 | 
					        private DownstreamRoute GetPlaceholderNamesAndValues(string path, ReRoute reRoute)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var templatePlaceholderNameAndValues = _placeholderNameAndValueFinder.Find(path, reRoute.UpstreamPathTemplate.Value);
 | 
					            var templatePlaceholderNameAndValues = _placeholderNameAndValueFinder.Find(path, reRoute.UpstreamPathTemplate.Value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return new DownstreamRoute(templatePlaceholderNameAndValues.Data, reRoute);
 | 
					            return new DownstreamRoute(templatePlaceholderNameAndValues.Data, reRoute);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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<string, IDownstreamRouteProvider> _providers;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        public DownstreamRouteProviderFactory(IServiceProvider provider)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _providers = provider.GetServices<IDownstreamRouteProvider>().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;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,11 +0,0 @@
 | 
				
			|||||||
using System.Threading.Tasks;
 | 
					 | 
				
			||||||
using Ocelot.Configuration;
 | 
					 | 
				
			||||||
using Ocelot.Responses;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Ocelot.DownstreamRouteFinder.Finder
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    public interface IDownstreamRouteFinder
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        Response<DownstreamRoute> FindDownstreamRoute(string upstreamUrlPath, string upstreamHttpMethod, IInternalConfiguration configuration, string upstreamHost);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					using Ocelot.Configuration;
 | 
				
			||||||
 | 
					using Ocelot.Responses;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ocelot.DownstreamRouteFinder.Finder
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public interface IDownstreamRouteProvider
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Response<DownstreamRoute> Get(string upstreamUrlPath, string upstreamHttpMethod, IInternalConfiguration configuration, string upstreamHost);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					namespace Ocelot.DownstreamRouteFinder.Finder
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    using Configuration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public interface IDownstreamRouteProviderFactory
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        IDownstreamRouteProvider Get(IInternalConfiguration config);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,69 +1,60 @@
 | 
				
			|||||||
using System.Threading.Tasks;
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
using System.Linq;
 | 
					using System.Linq;
 | 
				
			||||||
using Ocelot.Configuration.Repository;
 | 
					using Ocelot.Configuration.Repository;
 | 
				
			||||||
using Ocelot.DownstreamRouteFinder.Finder;
 | 
					using Ocelot.DownstreamRouteFinder.Finder;
 | 
				
			||||||
using Ocelot.Infrastructure.Extensions;
 | 
					using Ocelot.Infrastructure.Extensions;
 | 
				
			||||||
using Ocelot.Logging;
 | 
					using Ocelot.Logging;
 | 
				
			||||||
using Ocelot.Middleware;
 | 
					using Ocelot.Middleware;
 | 
				
			||||||
using Ocelot.Middleware.Multiplexer;
 | 
					using Ocelot.Middleware.Multiplexer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Ocelot.DownstreamRouteFinder.Middleware
 | 
					namespace Ocelot.DownstreamRouteFinder.Middleware
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public class DownstreamRouteFinderMiddleware : OcelotMiddleware
 | 
					    public class DownstreamRouteFinderMiddleware : OcelotMiddleware
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private readonly OcelotRequestDelegate _next;
 | 
					        private readonly OcelotRequestDelegate _next;
 | 
				
			||||||
        private readonly IDownstreamRouteFinder _downstreamRouteFinder;
 | 
					        private readonly IDownstreamRouteProviderFactory _factory;
 | 
				
			||||||
        private readonly IInternalConfigurationRepository _repo;
 | 
					        private readonly IInternalConfigurationRepository _repo;
 | 
				
			||||||
        private readonly IMultiplexer _multiplexer;
 | 
					        private readonly IMultiplexer _multiplexer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public DownstreamRouteFinderMiddleware(OcelotRequestDelegate next,
 | 
					        public DownstreamRouteFinderMiddleware(OcelotRequestDelegate next,
 | 
				
			||||||
            IOcelotLoggerFactory loggerFactory,
 | 
					            IOcelotLoggerFactory loggerFactory,
 | 
				
			||||||
            IDownstreamRouteFinder downstreamRouteFinder,
 | 
					            IDownstreamRouteProviderFactory downstreamRouteFinder,
 | 
				
			||||||
            IInternalConfigurationRepository repo,
 | 
					            IInternalConfigurationRepository repo,
 | 
				
			||||||
            IMultiplexer multiplexer)
 | 
					            IMultiplexer multiplexer)
 | 
				
			||||||
                :base(loggerFactory.CreateLogger<DownstreamRouteFinderMiddleware>())
 | 
					                :base(loggerFactory.CreateLogger<DownstreamRouteFinderMiddleware>())
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _repo = repo;
 | 
					            _repo = repo;
 | 
				
			||||||
            _multiplexer = multiplexer;
 | 
					            _multiplexer = multiplexer;
 | 
				
			||||||
            _next = next;
 | 
					            _next = next;
 | 
				
			||||||
            _downstreamRouteFinder = downstreamRouteFinder;
 | 
					            _factory = downstreamRouteFinder;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public async Task Invoke(DownstreamContext context)
 | 
					        public async Task Invoke(DownstreamContext context)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var upstreamUrlPath = context.HttpContext.Request.Path.ToString();
 | 
					            var upstreamUrlPath = context.HttpContext.Request.Path.ToString();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var upstreamHost = context.HttpContext.Request.Headers["Host"];
 | 
					            var upstreamHost = context.HttpContext.Request.Headers["Host"];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var configuration = _repo.Get();
 | 
					            Logger.LogDebug($"Upstream url path is {upstreamUrlPath}");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (configuration.IsError)
 | 
					            var provider = _factory.Get(context.Configuration);
 | 
				
			||||||
            {
 | 
					
 | 
				
			||||||
                Logger.LogWarning($"{MiddlewareName} setting pipeline errors. IOcelotConfigurationProvider returned {configuration.Errors.ToErrorString()}");
 | 
					            var downstreamRoute = provider.Get(upstreamUrlPath, context.HttpContext.Request.Method, context.Configuration, upstreamHost);
 | 
				
			||||||
                SetPipelineError(context, configuration.Errors);
 | 
					
 | 
				
			||||||
                return;
 | 
					            if (downstreamRoute.IsError)
 | 
				
			||||||
            }
 | 
					            {
 | 
				
			||||||
 | 
					                Logger.LogWarning($"{MiddlewareName} setting pipeline errors. IDownstreamRouteFinder returned {downstreamRoute.Errors.ToErrorString()}");
 | 
				
			||||||
            context.ServiceProviderConfiguration = configuration.Data.ServiceProviderConfiguration;
 | 
					
 | 
				
			||||||
 | 
					                SetPipelineError(context, downstreamRoute.Errors);
 | 
				
			||||||
            Logger.LogDebug($"Upstream url path is {upstreamUrlPath}");
 | 
					                return;
 | 
				
			||||||
 | 
					            }            
 | 
				
			||||||
            var downstreamRoute = _downstreamRouteFinder.FindDownstreamRoute(upstreamUrlPath, context.HttpContext.Request.Method, configuration.Data, upstreamHost);
 | 
					            
 | 
				
			||||||
 | 
					            var downstreamPathTemplates = string.Join(", ", downstreamRoute.Data.ReRoute.DownstreamReRoute.Select(r => r.DownstreamPathTemplate.Value));
 | 
				
			||||||
            if (downstreamRoute.IsError)
 | 
					            Logger.LogDebug($"downstream templates are {downstreamPathTemplates}");
 | 
				
			||||||
            {
 | 
					
 | 
				
			||||||
                Logger.LogWarning($"{MiddlewareName} setting pipeline errors. IDownstreamRouteFinder returned {downstreamRoute.Errors.ToErrorString()}");
 | 
					            context.TemplatePlaceholderNameAndValues = downstreamRoute.Data.TemplatePlaceholderNameAndValues;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                SetPipelineError(context, downstreamRoute.Errors);
 | 
					            await _multiplexer.Multiplex(context, downstreamRoute.Data.ReRoute, _next);
 | 
				
			||||||
                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);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -73,7 +73,7 @@ namespace Ocelot.DownstreamUrlCreator.Middleware
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static bool ServiceFabricRequest(DownstreamContext context)
 | 
					        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)
 | 
					        private static bool RequestForStatefullService(string query)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,8 @@ using Ocelot.Middleware;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace Ocelot.Errors.Middleware
 | 
					namespace Ocelot.Errors.Middleware
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    using Configuration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// Catches all unhandled exceptions thrown by middleware, logs and returns a 500
 | 
					    /// Catches all unhandled exceptions thrown by middleware, logs and returns a 500
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
@@ -32,8 +34,20 @@ namespace Ocelot.Errors.Middleware
 | 
				
			|||||||
        public async Task Invoke(DownstreamContext context)
 | 
					        public async Task Invoke(DownstreamContext context)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            try
 | 
					            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");
 | 
					                Logger.LogDebug("ocelot pipeline started");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -53,19 +67,9 @@ namespace Ocelot.Errors.Middleware
 | 
				
			|||||||
            Logger.LogDebug("ocelot pipeline finished");
 | 
					            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...
 | 
					            var key = configuration.RequestId;
 | 
				
			||||||
            //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;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (!string.IsNullOrEmpty(key) && context.HttpContext.Request.Headers.TryGetValue(key, out var upstreamRequestIds))
 | 
					            if (!string.IsNullOrEmpty(key) && context.HttpContext.Request.Headers.TryGetValue(key, out var upstreamRequestIds))
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,7 +29,7 @@ namespace Ocelot.LoadBalancer.LoadBalancers
 | 
				
			|||||||
                    var bus = new InMemoryBus<StickySession>();
 | 
					                    var bus = new InMemoryBus<StickySession>();
 | 
				
			||||||
                    return new CookieStickySessions(loadBalancer, reRoute.LoadBalancerOptions.Key, reRoute.LoadBalancerOptions.ExpiryInMs, bus);
 | 
					                    return new CookieStickySessions(loadBalancer, reRoute.LoadBalancerOptions.Key, reRoute.LoadBalancerOptions.ExpiryInMs, bus);
 | 
				
			||||||
                default:
 | 
					                default:
 | 
				
			||||||
                    return new NoLoadBalancer(await serviceProvider.Get());
 | 
					                    return new NoLoadBalancer(async () => await serviceProvider.Get());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
using System.Collections.Generic;
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Linq;
 | 
					using System.Linq;
 | 
				
			||||||
using System.Threading.Tasks;
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
using Ocelot.Middleware;
 | 
					using Ocelot.Middleware;
 | 
				
			||||||
@@ -9,22 +10,23 @@ namespace Ocelot.LoadBalancer.LoadBalancers
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    public class NoLoadBalancer : ILoadBalancer
 | 
					    public class NoLoadBalancer : ILoadBalancer
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private readonly List<Service> _services;
 | 
					        private readonly Func<Task<List<Service>>> _services;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public NoLoadBalancer(List<Service> services)
 | 
					        public NoLoadBalancer(Func<Task<List<Service>>> services)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _services = services;
 | 
					            _services = services;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public async Task<Response<ServiceHostAndPort>> Lease(DownstreamContext downstreamContext)
 | 
					        public async Task<Response<ServiceHostAndPort>> Lease(DownstreamContext downstreamContext)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            //todo no point spinning a task up here, also first or default could be null..
 | 
					            var services = await _services();
 | 
				
			||||||
            if (_services == null || _services.Count == 0)
 | 
					            //todo first or default could be null..
 | 
				
			||||||
 | 
					            if (services == null || services.Count == 0)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                return new ErrorResponse<ServiceHostAndPort>(new ServicesAreEmptyError("There were no services in NoLoadBalancer"));
 | 
					                return new ErrorResponse<ServiceHostAndPort>(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<ServiceHostAndPort>(service.HostAndPort);
 | 
					            return new OkResponse<ServiceHostAndPort>(service.HostAndPort);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,13 +20,13 @@ namespace Ocelot.LoadBalancer.LoadBalancers
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        public async Task<Response<ServiceHostAndPort>> Lease(DownstreamContext downstreamContext)
 | 
					        public async Task<Response<ServiceHostAndPort>> Lease(DownstreamContext downstreamContext)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var services = await _services.Invoke();
 | 
					            var services = await _services();
 | 
				
			||||||
            if (_last >= services.Count)
 | 
					            if (_last >= services.Count)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                _last = 0;
 | 
					                _last = 0;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var next = await Task.FromResult(services[_last]);
 | 
					            var next = services[_last];
 | 
				
			||||||
            _last++;
 | 
					            _last++;
 | 
				
			||||||
            return new OkResponse<ServiceHostAndPort>(next.HostAndPort);
 | 
					            return new OkResponse<ServiceHostAndPort>(next.HostAndPort);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,7 +22,7 @@ namespace Ocelot.LoadBalancer.Middleware
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        public async Task Invoke(DownstreamContext context)
 | 
					        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)
 | 
					            if(loadBalancer.IsError)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                Logger.LogDebug("there was an error retriving the loadbalancer, setting pipeline error");
 | 
					                Logger.LogDebug("there was an error retriving the loadbalancer, setting pipeline error");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,8 @@
 | 
				
			|||||||
using System;
 | 
					 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Net.Http;
 | 
					 | 
				
			||||||
using Microsoft.AspNetCore.Http;
 | 
					using Microsoft.AspNetCore.Http;
 | 
				
			||||||
using Ocelot.Configuration;
 | 
					using Ocelot.Configuration;
 | 
				
			||||||
using Ocelot.DownstreamRouteFinder.UrlMatcher;
 | 
					using Ocelot.DownstreamRouteFinder.UrlMatcher;
 | 
				
			||||||
using Ocelot.Errors;
 | 
					using Ocelot.Errors;
 | 
				
			||||||
using Ocelot.Middleware.Multiplexer;
 | 
					 | 
				
			||||||
using Ocelot.Request.Middleware;
 | 
					using Ocelot.Request.Middleware;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Ocelot.Middleware
 | 
					namespace Ocelot.Middleware
 | 
				
			||||||
@@ -20,8 +17,6 @@ namespace Ocelot.Middleware
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        public List<PlaceholderNameAndValue> TemplatePlaceholderNameAndValues { get; set; }
 | 
					        public List<PlaceholderNameAndValue> TemplatePlaceholderNameAndValues { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public ServiceProviderConfiguration ServiceProviderConfiguration {get; set;}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public HttpContext HttpContext { get; }
 | 
					        public HttpContext HttpContext { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public DownstreamReRoute DownstreamReRoute { get; set; }
 | 
					        public DownstreamReRoute DownstreamReRoute { get; set; }
 | 
				
			||||||
@@ -32,6 +27,8 @@ namespace Ocelot.Middleware
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        public List<Error> Errors { get; }
 | 
					        public List<Error> Errors { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public IInternalConfiguration Configuration { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public bool IsError => Errors.Count > 0;
 | 
					        public bool IsError => Errors.Count > 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,7 +23,7 @@ namespace Ocelot.Middleware.Multiplexer
 | 
				
			|||||||
                var downstreamContext = new DownstreamContext(context.HttpContext)
 | 
					                var downstreamContext = new DownstreamContext(context.HttpContext)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    TemplatePlaceholderNameAndValues = context.TemplatePlaceholderNameAndValues,
 | 
					                    TemplatePlaceholderNameAndValues = context.TemplatePlaceholderNameAndValues,
 | 
				
			||||||
                    ServiceProviderConfiguration = context.ServiceProviderConfiguration,
 | 
					                    Configuration = context.Configuration,
 | 
				
			||||||
                    DownstreamReRoute = reRoute.DownstreamReRoute[i],
 | 
					                    DownstreamReRoute = reRoute.DownstreamReRoute[i],
 | 
				
			||||||
                };
 | 
					                };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -68,7 +68,7 @@ namespace Ocelot.Requester
 | 
				
			|||||||
                handlers.Add(() => (DelegatingHandler)_factory.Get());
 | 
					                handlers.Add(() => (DelegatingHandler)_factory.Get());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (request.IsQos)
 | 
					            if (request.QosOptions.UseQos)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var qosProvider = _qosProviderHouse.Get(request);
 | 
					                var qosProvider = _qosProviderHouse.Get(request);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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}");
 | 
					                    .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 
 | 
					                ? _defaultTimeout 
 | 
				
			||||||
                : TimeSpan.FromMilliseconds(context.DownstreamReRoute.QosOptionsOptions.TimeoutValue);
 | 
					                : TimeSpan.FromMilliseconds(context.DownstreamReRoute.QosOptions.TimeoutValue);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            _httpClient = new HttpClient(CreateHttpMessageHandler(httpclientHandler, context.DownstreamReRoute))
 | 
					            _httpClient = new HttpClient(CreateHttpMessageHandler(httpclientHandler, context.DownstreamReRoute))
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,15 +19,15 @@ namespace Ocelot.Requester.QoS
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            _logger = loggerFactory.CreateLogger<PollyQoSProvider>();
 | 
					            _logger = loggerFactory.CreateLogger<PollyQoSProvider>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            _timeoutPolicy = Policy.TimeoutAsync(TimeSpan.FromMilliseconds(reRoute.QosOptionsOptions.TimeoutValue), reRoute.QosOptionsOptions.TimeoutStrategy);
 | 
					            _timeoutPolicy = Policy.TimeoutAsync(TimeSpan.FromMilliseconds(reRoute.QosOptions.TimeoutValue), reRoute.QosOptions.TimeoutStrategy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            _circuitBreakerPolicy = Policy
 | 
					            _circuitBreakerPolicy = Policy
 | 
				
			||||||
                .Handle<HttpRequestException>()
 | 
					                .Handle<HttpRequestException>()
 | 
				
			||||||
                .Or<TimeoutRejectedException>()
 | 
					                .Or<TimeoutRejectedException>()
 | 
				
			||||||
                .Or<TimeoutException>()
 | 
					                .Or<TimeoutException>()
 | 
				
			||||||
                .CircuitBreakerAsync(
 | 
					                .CircuitBreakerAsync(
 | 
				
			||||||
                    exceptionsAllowedBeforeBreaking: reRoute.QosOptionsOptions.ExceptionsAllowedBeforeBreaking,
 | 
					                    exceptionsAllowedBeforeBreaking: reRoute.QosOptions.ExceptionsAllowedBeforeBreaking,
 | 
				
			||||||
                    durationOfBreak: TimeSpan.FromMilliseconds(reRoute.QosOptionsOptions.DurationOfBreak),
 | 
					                    durationOfBreak: TimeSpan.FromMilliseconds(reRoute.QosOptions.DurationOfBreak),
 | 
				
			||||||
                    onBreak: (ex, breakDelay) =>
 | 
					                    onBreak: (ex, breakDelay) =>
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        _logger.LogError(
 | 
					                        _logger.LogError(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,7 +14,7 @@ namespace Ocelot.Requester.QoS
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        public IQoSProvider Get(DownstreamReRoute reRoute)
 | 
					        public IQoSProvider Get(DownstreamReRoute reRoute)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (reRoute.IsQos)
 | 
					            if (reRoute.QosOptions.UseQos)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                return new PollyQoSProvider(reRoute, _loggerFactory);
 | 
					                return new PollyQoSProvider(reRoute, _loggerFactory);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,26 +21,26 @@ namespace Ocelot.Requester.QoS
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            try
 | 
					            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);
 | 
					                        qosProvider = _qoSProviderFactory.Get(reRoute);
 | 
				
			||||||
                        Add(reRoute.QosKey, qosProvider);
 | 
					                        Add(reRoute.QosOptions.Key, qosProvider);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    return new OkResponse<IQoSProvider>(_qoSProviders[reRoute.QosKey]);
 | 
					                    return new OkResponse<IQoSProvider>(_qoSProviders[reRoute.QosOptions.Key]);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                qosProvider = _qoSProviderFactory.Get(reRoute);
 | 
					                qosProvider = _qoSProviderFactory.Get(reRoute);
 | 
				
			||||||
                Add(reRoute.QosKey, qosProvider);
 | 
					                Add(reRoute.QosOptions.Key, qosProvider);
 | 
				
			||||||
                return new OkResponse<IQoSProvider>(qosProvider);
 | 
					                return new OkResponse<IQoSProvider>(qosProvider);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            catch (Exception ex)
 | 
					            catch (Exception ex)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                return new ErrorResponse<IQoSProvider>(new List<Ocelot.Errors.Error>()
 | 
					                return new ErrorResponse<IQoSProvider>(new List<Ocelot.Errors.Error>()
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    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}")
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,8 +4,8 @@ namespace Ocelot.ServiceDiscovery.Configuration
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        public ConsulRegistryConfiguration(string host, int port, string keyOfServiceInConsul, string token)
 | 
					        public ConsulRegistryConfiguration(string host, int port, string keyOfServiceInConsul, string token)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Host = host;
 | 
					            Host = string.IsNullOrEmpty(host) ? "localhost" : host;
 | 
				
			||||||
            Port = port;
 | 
					            Port = port > 0 ? port : 8500;
 | 
				
			||||||
            KeyOfServiceInConsul = keyOfServiceInConsul;
 | 
					            KeyOfServiceInConsul = keyOfServiceInConsul;
 | 
				
			||||||
            Token = token;
 | 
					            Token = token;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,12 +22,7 @@ namespace Ocelot.ServiceDiscovery.Providers
 | 
				
			|||||||
        {;
 | 
					        {;
 | 
				
			||||||
            _logger = factory.CreateLogger<ConsulServiceDiscoveryProvider>();
 | 
					            _logger = factory.CreateLogger<ConsulServiceDiscoveryProvider>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var consulHost = string.IsNullOrEmpty(config?.Host) ? "localhost" : config.Host;
 | 
					            _config = config;
 | 
				
			||||||
 | 
					 | 
				
			||||||
            var consulPort = config?.Port ?? 8500;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            _config = new ConsulRegistryConfiguration(consulHost, consulPort, config?.KeyOfServiceInConsul, config?.Token);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            _consul = clientFactory.Get(_config);
 | 
					            _consul = clientFactory.Get(_config);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -208,6 +208,121 @@ namespace Ocelot.AcceptanceTests
 | 
				
			|||||||
            .BDDfy();
 | 
					            .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]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_use_token_to_make_request_to_consul()
 | 
					        public void should_use_token_to_make_request_to_consul()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -55,7 +55,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            _internalRepo
 | 
					            _internalRepo
 | 
				
			||||||
                .Setup(x => x.Get())
 | 
					                .Setup(x => x.Get())
 | 
				
			||||||
                .Returns(new OkResponse<IInternalConfiguration>(new InternalConfiguration(new List<ReRoute>(), "", new ServiceProviderConfigurationBuilder().Build(), "")));
 | 
					                .Returns(new OkResponse<IInternalConfiguration>(new InternalConfiguration(new List<ReRoute>(), "", new ServiceProviderConfigurationBuilder().Build(), "", It.IsAny<LoadBalancerOptions>(), It.IsAny<string>(), It.IsAny<QoSOptions>(), It.IsAny<HttpHandlerOptions>())));
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
            _repo = new ConsulFileConfigurationRepository(_cache.Object, _internalRepo.Object, _factory.Object, _loggerFactory.Object);
 | 
					            _repo = new ConsulFileConfigurationRepository(_cache.Object, _internalRepo.Object, _factory.Object, _loggerFactory.Object);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -140,7 +140,10 @@ namespace Ocelot.UnitTests.Configuration
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            _internalRepo
 | 
					            _internalRepo
 | 
				
			||||||
                .Setup(x => x.Get())
 | 
					                .Setup(x => x.Get())
 | 
				
			||||||
                .Returns(new OkResponse<IInternalConfiguration>(new InternalConfiguration(new List<ReRoute>(), "", new ServiceProviderConfigurationBuilder().WithConfigurationKey(key).Build(), "")));
 | 
					                .Returns(new OkResponse<IInternalConfiguration>(new InternalConfiguration(new List<ReRoute>(), "",
 | 
				
			||||||
 | 
					                    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);
 | 
					            _repo = new ConsulFileConfigurationRepository(_cache.Object, _internalRepo.Object, _factory.Object, _loggerFactory.Object);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,7 +38,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            var fileConfig = new FileConfiguration();
 | 
					            var fileConfig = new FileConfiguration();
 | 
				
			||||||
            var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
 | 
					            var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
 | 
				
			||||||
            var config = new InternalConfiguration(new List<ReRoute>(), string.Empty, serviceProviderConfig, "asdf");
 | 
					            var config = new InternalConfiguration(new List<ReRoute>(), string.Empty, serviceProviderConfig, "asdf", new LoadBalancerOptionsBuilder().Build(), "", new QoSOptionsBuilder().Build(), new HttpHandlerOptionsBuilder().Build());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(x => GivenTheFollowingConfiguration(fileConfig))
 | 
					            this.Given(x => GivenTheFollowingConfiguration(fileConfig))
 | 
				
			||||||
                .And(x => GivenTheRepoReturns(new OkResponse()))
 | 
					                .And(x => GivenTheRepoReturns(new OkResponse()))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -86,7 +86,7 @@
 | 
				
			|||||||
                .WithDownstreamPathTemplate("/products/{productId}")
 | 
					                .WithDownstreamPathTemplate("/products/{productId}")
 | 
				
			||||||
                .WithUpstreamPathTemplate("/api/products/{productId}")
 | 
					                .WithUpstreamPathTemplate("/api/products/{productId}")
 | 
				
			||||||
                .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
					                .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
				
			||||||
                .WithReRouteKey("CookieStickySessions:sessionid")
 | 
					                .WithLoadBalancerKey("CookieStickySessions:sessionid")
 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(x => x.GivenTheConfigIs(new FileConfiguration
 | 
					            this.Given(x => x.GivenTheConfigIs(new FileConfiguration
 | 
				
			||||||
@@ -199,7 +199,7 @@
 | 
				
			|||||||
                .WithDownstreamScheme("http")
 | 
					                .WithDownstreamScheme("http")
 | 
				
			||||||
                .WithUpstreamHttpMethod(new List<string>() {"Get"})
 | 
					                .WithUpstreamHttpMethod(new List<string>() {"Get"})
 | 
				
			||||||
                .WithDownstreamAddresses(new List<DownstreamHostAndPort>() {new DownstreamHostAndPort("localhost", 51878)})
 | 
					                .WithDownstreamAddresses(new List<DownstreamHostAndPort>() {new DownstreamHostAndPort("localhost", 51878)})
 | 
				
			||||||
                .WithReRouteKey("/laura|Get")
 | 
					                .WithLoadBalancerKey("/laura|Get")
 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var lauraReRoute = new ReRouteBuilder()
 | 
					            var lauraReRoute = new ReRouteBuilder()
 | 
				
			||||||
@@ -218,7 +218,7 @@
 | 
				
			|||||||
                .WithDownstreamScheme("http")
 | 
					                .WithDownstreamScheme("http")
 | 
				
			||||||
                .WithUpstreamHttpMethod(new List<string>() { "Get" })
 | 
					                .WithUpstreamHttpMethod(new List<string>() { "Get" })
 | 
				
			||||||
                .WithDownstreamAddresses(new List<DownstreamHostAndPort>() { new DownstreamHostAndPort("localhost", 51878) })
 | 
					                .WithDownstreamAddresses(new List<DownstreamHostAndPort>() { new DownstreamHostAndPort("localhost", 51878) })
 | 
				
			||||||
                .WithReRouteKey("/tom|Get")
 | 
					                .WithLoadBalancerKey("/tom|Get")
 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var tomReRoute = new ReRouteBuilder()
 | 
					            var tomReRoute = new ReRouteBuilder()
 | 
				
			||||||
@@ -361,7 +361,6 @@
 | 
				
			|||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var serviceOptions = new ReRouteOptionsBuilder()
 | 
					            var serviceOptions = new ReRouteOptionsBuilder()
 | 
				
			||||||
                .WithIsQos(true)
 | 
					 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
             this.Given(x => x.GivenTheConfigIs(new FileConfiguration
 | 
					             this.Given(x => x.GivenTheConfigIs(new FileConfiguration
 | 
				
			||||||
@@ -410,7 +409,7 @@
 | 
				
			|||||||
                .WithDownstreamPathTemplate("/products/{productId}")
 | 
					                .WithDownstreamPathTemplate("/products/{productId}")
 | 
				
			||||||
                .WithUpstreamPathTemplate("/api/products/{productId}")
 | 
					                .WithUpstreamPathTemplate("/api/products/{productId}")
 | 
				
			||||||
                .WithUpstreamHttpMethod(new List<string> {"Get"})
 | 
					                .WithUpstreamHttpMethod(new List<string> {"Get"})
 | 
				
			||||||
                .WithReRouteKey("/api/products/{productId}|Get")
 | 
					                .WithLoadBalancerKey("/api/products/{productId}|Get")
 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(x => x.GivenTheConfigIs(new FileConfiguration
 | 
					            this.Given(x => x.GivenTheConfigIs(new FileConfiguration
 | 
				
			||||||
@@ -462,7 +461,7 @@
 | 
				
			|||||||
                .WithUpstreamPathTemplate("/api/products/{productId}")
 | 
					                .WithUpstreamPathTemplate("/api/products/{productId}")
 | 
				
			||||||
                .WithUpstreamHttpMethod(new List<string> {"Get"})
 | 
					                .WithUpstreamHttpMethod(new List<string> {"Get"})
 | 
				
			||||||
                .WithDelegatingHandlers(handlers)
 | 
					                .WithDelegatingHandlers(handlers)
 | 
				
			||||||
                .WithReRouteKey("/api/products/{productId}|Get")
 | 
					                .WithLoadBalancerKey("/api/products/{productId}|Get")
 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(x => x.GivenTheConfigIs(new FileConfiguration
 | 
					            this.Given(x => x.GivenTheConfigIs(new FileConfiguration
 | 
				
			||||||
@@ -507,7 +506,7 @@
 | 
				
			|||||||
                .WithUpstreamHttpMethod(new List<string> {"Get"})
 | 
					                .WithUpstreamHttpMethod(new List<string> {"Get"})
 | 
				
			||||||
                .WithUseServiceDiscovery(true)
 | 
					                .WithUseServiceDiscovery(true)
 | 
				
			||||||
                .WithServiceName("ProductService")
 | 
					                .WithServiceName("ProductService")
 | 
				
			||||||
                .WithReRouteKey("/api/products/{productId}|Get")
 | 
					                .WithLoadBalancerKey("/api/products/{productId}|Get")
 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(x => x.GivenTheConfigIs(new FileConfiguration
 | 
					            this.Given(x => x.GivenTheConfigIs(new FileConfiguration
 | 
				
			||||||
@@ -558,7 +557,7 @@
 | 
				
			|||||||
                .WithUpstreamPathTemplate("/api/products/{productId}")
 | 
					                .WithUpstreamPathTemplate("/api/products/{productId}")
 | 
				
			||||||
                .WithUpstreamHttpMethod(new List<string> {"Get"})
 | 
					                .WithUpstreamHttpMethod(new List<string> {"Get"})
 | 
				
			||||||
                .WithUseServiceDiscovery(false)
 | 
					                .WithUseServiceDiscovery(false)
 | 
				
			||||||
                .WithReRouteKey("/api/products/{productId}|Get")
 | 
					                .WithLoadBalancerKey("/api/products/{productId}|Get")
 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(x => x.GivenTheConfigIs(new FileConfiguration
 | 
					            this.Given(x => x.GivenTheConfigIs(new FileConfiguration
 | 
				
			||||||
@@ -601,7 +600,7 @@
 | 
				
			|||||||
                .WithUpstreamPathTemplate("/api/products/{productId}")
 | 
					                .WithUpstreamPathTemplate("/api/products/{productId}")
 | 
				
			||||||
                .WithUpstreamHttpMethod(new List<string> {"Get"})
 | 
					                .WithUpstreamHttpMethod(new List<string> {"Get"})
 | 
				
			||||||
                .WithUpstreamTemplatePattern(new UpstreamPathTemplate("(?i)/api/products/.*/$", 1))
 | 
					                .WithUpstreamTemplatePattern(new UpstreamPathTemplate("(?i)/api/products/.*/$", 1))
 | 
				
			||||||
                .WithReRouteKey("/api/products/{productId}|Get")
 | 
					                .WithLoadBalancerKey("/api/products/{productId}|Get")
 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(x => x.GivenTheConfigIs(new FileConfiguration
 | 
					            this.Given(x => x.GivenTheConfigIs(new FileConfiguration
 | 
				
			||||||
@@ -646,7 +645,7 @@
 | 
				
			|||||||
                .WithUpstreamPathTemplate("/api/products/{productId}")
 | 
					                .WithUpstreamPathTemplate("/api/products/{productId}")
 | 
				
			||||||
                .WithUpstreamHttpMethod(new List<string> {"Get"})
 | 
					                .WithUpstreamHttpMethod(new List<string> {"Get"})
 | 
				
			||||||
                .WithRequestIdKey("blahhhh")
 | 
					                .WithRequestIdKey("blahhhh")
 | 
				
			||||||
                .WithReRouteKey("/api/products/{productId}|Get")
 | 
					                .WithLoadBalancerKey("/api/products/{productId}|Get")
 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(x => x.GivenTheConfigIs(new FileConfiguration
 | 
					            this.Given(x => x.GivenTheConfigIs(new FileConfiguration
 | 
				
			||||||
@@ -741,7 +740,7 @@
 | 
				
			|||||||
                {
 | 
					                {
 | 
				
			||||||
                    new ClaimToThing("CustomerId", "CustomerId", "", 0),
 | 
					                    new ClaimToThing("CustomerId", "CustomerId", "", 0),
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
                .WithReRouteKey("/api/products/{productId}|Get")
 | 
					                .WithLoadBalancerKey("/api/products/{productId}|Get")
 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var expected = new List<ReRoute>
 | 
					            var expected = new List<ReRoute>
 | 
				
			||||||
@@ -784,7 +783,7 @@
 | 
				
			|||||||
                .WithUpstreamPathTemplate("/api/products/{productId}")
 | 
					                .WithUpstreamPathTemplate("/api/products/{productId}")
 | 
				
			||||||
                .WithUpstreamHttpMethod(new List<string> {"Get"})
 | 
					                .WithUpstreamHttpMethod(new List<string> {"Get"})
 | 
				
			||||||
                .WithAuthenticationOptions(authenticationOptions)
 | 
					                .WithAuthenticationOptions(authenticationOptions)
 | 
				
			||||||
                .WithReRouteKey("/api/products/{productId}|Get")
 | 
					                .WithLoadBalancerKey("/api/products/{productId}|Get")
 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var expected = new List<ReRoute>
 | 
					            var expected = new List<ReRoute>
 | 
				
			||||||
@@ -942,16 +941,15 @@
 | 
				
			|||||||
        private void GivenTheQosOptionsCreatorReturns(QoSOptions qosOptions)
 | 
					        private void GivenTheQosOptionsCreatorReturns(QoSOptions qosOptions)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _qosOptionsCreator
 | 
					            _qosOptionsCreator
 | 
				
			||||||
                .Setup(x => x.Create(_fileConfiguration.ReRoutes[0]))
 | 
					                .Setup(x => x.Create(_fileConfiguration.ReRoutes[0].QoSOptions, It.IsAny<string>(), It.IsAny<string[]>()))
 | 
				
			||||||
                .Returns(qosOptions);
 | 
					                .Returns(qosOptions);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void ThenTheQosOptionsAre(QoSOptions qosOptions)
 | 
					        private void ThenTheQosOptionsAre(QoSOptions qosOptions)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _config.Data.ReRoutes[0].DownstreamReRoute[0].QosOptionsOptions.DurationOfBreak.ShouldBe(qosOptions.DurationOfBreak);
 | 
					            _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].QosOptionsOptions.ExceptionsAllowedBeforeBreaking.ShouldBe(qosOptions.ExceptionsAllowedBeforeBreaking);
 | 
					            _config.Data.ReRoutes[0].DownstreamReRoute[0].QosOptions.TimeoutValue.ShouldBe(qosOptions.TimeoutValue);
 | 
				
			||||||
            _config.Data.ReRoutes[0].DownstreamReRoute[0].QosOptionsOptions.TimeoutValue.ShouldBe(qosOptions.TimeoutValue);
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void ThenTheServiceProviderCreatorIsCalledCorrectly()
 | 
					        private void ThenTheServiceProviderCreatorIsCalledCorrectly()
 | 
				
			||||||
@@ -992,13 +990,13 @@
 | 
				
			|||||||
        
 | 
					        
 | 
				
			||||||
        private void GivenTheFollowingHttpHandlerOptionsAreReturned(HttpHandlerOptions httpHandlerOptions)
 | 
					        private void GivenTheFollowingHttpHandlerOptionsAreReturned(HttpHandlerOptions httpHandlerOptions)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _httpHandlerOptionsCreator.Setup(x => x.Create(It.IsAny<FileReRoute>()))
 | 
					            _httpHandlerOptionsCreator.Setup(x => x.Create(It.IsAny<FileHttpHandlerOptions>()))
 | 
				
			||||||
                .Returns(httpHandlerOptions);
 | 
					                .Returns(httpHandlerOptions);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void ThenTheHttpHandlerOptionsCreatorIsCalledCorrectly()
 | 
					        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()
 | 
					        private void GivenTheDownstreamAddresses()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -103,7 +103,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private void WhenICreateHttpHandlerOptions()
 | 
					        private void WhenICreateHttpHandlerOptions()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _httpHandlerOptions = _httpHandlerOptionsCreator.Create(_fileReRoute);
 | 
					            _httpHandlerOptions = _httpHandlerOptionsCreator.Create(_fileReRoute.HttpHandlerOptions);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void ThenTheFollowingOptionsReturned(HttpHandlerOptions expected)
 | 
					        private void ThenTheFollowingOptionsReturned(HttpHandlerOptions expected)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -105,6 +105,10 @@ namespace Ocelot.UnitTests.Configuration
 | 
				
			|||||||
            public ServiceProviderConfiguration ServiceProviderConfiguration => throw new NotImplementedException();
 | 
					            public ServiceProviderConfiguration ServiceProviderConfiguration => throw new NotImplementedException();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            public string RequestId {get;}
 | 
					            public string RequestId {get;}
 | 
				
			||||||
 | 
					            public LoadBalancerOptions LoadBalancerOptions { get; }
 | 
				
			||||||
 | 
					            public string DownstreamScheme { get; }
 | 
				
			||||||
 | 
					            public QoSOptions QoSOptions { get; }
 | 
				
			||||||
 | 
					            public HttpHandlerOptions HttpHandlerOptions { get; }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -50,7 +50,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private void WhenICreate()
 | 
					        private void WhenICreate()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _result = _creator.Create(_fileReRoute);
 | 
					            _result = _creator.Create(_fileReRoute.QoSOptions);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void ThenTheFollowingIsReturned(QoSOptions expected)
 | 
					        private void ThenTheFollowingIsReturned(QoSOptions expected)
 | 
				
			||||||
@@ -60,4 +60,4 @@ namespace Ocelot.UnitTests.Configuration
 | 
				
			|||||||
            _result.TimeoutValue.ShouldBe(expected.TimeoutValue);
 | 
					            _result.TimeoutValue.ShouldBe(expected.TimeoutValue);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,11 +29,6 @@ namespace Ocelot.UnitTests.Configuration
 | 
				
			|||||||
                {
 | 
					                {
 | 
				
			||||||
                    EnableRateLimiting = true
 | 
					                    EnableRateLimiting = true
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                QoSOptions = new FileQoSOptions
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    ExceptionsAllowedBeforeBreaking = 1,
 | 
					 | 
				
			||||||
                    TimeoutValue = 1
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                AuthenticationOptions = new FileAuthenticationOptions()
 | 
					                AuthenticationOptions = new FileAuthenticationOptions()
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    AuthenticationProviderKey = "Test"
 | 
					                    AuthenticationProviderKey = "Test"
 | 
				
			||||||
@@ -52,7 +47,6 @@ namespace Ocelot.UnitTests.Configuration
 | 
				
			|||||||
                .WithIsAuthenticated(true)
 | 
					                .WithIsAuthenticated(true)
 | 
				
			||||||
                .WithIsAuthorised(true)
 | 
					                .WithIsAuthorised(true)
 | 
				
			||||||
                .WithIsCached(true)
 | 
					                .WithIsCached(true)
 | 
				
			||||||
                .WithIsQos(true)
 | 
					 | 
				
			||||||
                .WithRateLimiting(true)
 | 
					                .WithRateLimiting(true)
 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -76,9 +70,8 @@ namespace Ocelot.UnitTests.Configuration
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            _result.IsAuthenticated.ShouldBe(expected.IsAuthenticated);
 | 
					            _result.IsAuthenticated.ShouldBe(expected.IsAuthenticated);
 | 
				
			||||||
            _result.IsAuthorised.ShouldBe(expected.IsAuthorised);
 | 
					            _result.IsAuthorised.ShouldBe(expected.IsAuthorised);
 | 
				
			||||||
            _result.IsQos.ShouldBe(expected.IsQos);
 | 
					 | 
				
			||||||
            _result.IsCached.ShouldBe(expected.IsCached);
 | 
					            _result.IsCached.ShouldBe(expected.IsCached);
 | 
				
			||||||
            _result.EnableRateLimiting.ShouldBe(expected.EnableRateLimiting);
 | 
					            _result.EnableRateLimiting.ShouldBe(expected.EnableRateLimiting);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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<DownstreamRoute> _result;
 | 
				
			||||||
 | 
					        private string _upstreamHost;
 | 
				
			||||||
 | 
					        private string _upstreamUrlPath;
 | 
				
			||||||
 | 
					        private string _upstreamHttpMethod;
 | 
				
			||||||
 | 
					        private IInternalConfiguration _configuration;
 | 
				
			||||||
 | 
					        private Mock<IQoSOptionsCreator> _qosOptionsCreator;
 | 
				
			||||||
 | 
					        private Response<DownstreamRoute> _resultTwo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public DownstreamRouteCreatorTests()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _qosOptionsCreator = new Mock<IQoSOptionsCreator>();
 | 
				
			||||||
 | 
					            _qoSOptions = new QoSOptionsBuilder().Build();
 | 
				
			||||||
 | 
					            _handlerOptions = new HttpHandlerOptionsBuilder().Build();
 | 
				
			||||||
 | 
					            _loadBalancerOptions = new LoadBalancerOptionsBuilder().WithType(nameof(NoLoadBalancer)).Build();
 | 
				
			||||||
 | 
					            _qosOptionsCreator
 | 
				
			||||||
 | 
					                .Setup(x => x.Create(It.IsAny<QoSOptions>(), It.IsAny<string>(), It.IsAny<string[]>()))
 | 
				
			||||||
 | 
					                .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<QoSOptions>(), It.IsAny<string>(), It.IsAny<string[]>()))
 | 
				
			||||||
 | 
					                .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<string[]>()), 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);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,98 +1,99 @@
 | 
				
			|||||||
namespace Ocelot.UnitTests.DownstreamRouteFinder
 | 
					namespace Ocelot.UnitTests.DownstreamRouteFinder
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    using System.Collections.Generic;
 | 
					    using System.Collections.Generic;
 | 
				
			||||||
    using System.Threading.Tasks;
 | 
					    using System.Threading.Tasks;
 | 
				
			||||||
    using Microsoft.AspNetCore.Http;
 | 
					    using Microsoft.AspNetCore.Http;
 | 
				
			||||||
    using Moq;
 | 
					    using Moq;
 | 
				
			||||||
    using Ocelot.Configuration;
 | 
					    using Ocelot.Configuration;
 | 
				
			||||||
    using Ocelot.Configuration.Builder;
 | 
					    using Ocelot.Configuration.Builder;
 | 
				
			||||||
    using Ocelot.DownstreamRouteFinder;
 | 
					    using Ocelot.DownstreamRouteFinder;
 | 
				
			||||||
    using Ocelot.DownstreamRouteFinder.Finder;
 | 
					    using Ocelot.DownstreamRouteFinder.Finder;
 | 
				
			||||||
    using Ocelot.DownstreamRouteFinder.Middleware;
 | 
					    using Ocelot.DownstreamRouteFinder.Middleware;
 | 
				
			||||||
    using Ocelot.DownstreamRouteFinder.UrlMatcher;
 | 
					    using Ocelot.DownstreamRouteFinder.UrlMatcher;
 | 
				
			||||||
    using Ocelot.Logging;
 | 
					    using Ocelot.Logging;
 | 
				
			||||||
    using Ocelot.Responses;
 | 
					    using Ocelot.Responses;
 | 
				
			||||||
    using Shouldly;
 | 
					    using Shouldly;
 | 
				
			||||||
    using TestStack.BDDfy;
 | 
					    using TestStack.BDDfy;
 | 
				
			||||||
    using Xunit;
 | 
					    using Xunit;
 | 
				
			||||||
    using Ocelot.Configuration.Repository;
 | 
					    using Ocelot.Configuration.Repository;
 | 
				
			||||||
    using Ocelot.Middleware;
 | 
					    using Ocelot.Middleware;
 | 
				
			||||||
    using Ocelot.Middleware.Multiplexer;
 | 
					    using Ocelot.Middleware.Multiplexer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public class DownstreamRouteFinderMiddlewareTests
 | 
					    public class DownstreamRouteFinderMiddlewareTests
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private readonly Mock<IDownstreamRouteFinder> _finder;
 | 
					        private readonly Mock<IDownstreamRouteProvider> _finder;
 | 
				
			||||||
        private readonly Mock<IInternalConfigurationRepository> _repo;
 | 
					        private readonly Mock<IDownstreamRouteProviderFactory> _factory;
 | 
				
			||||||
        private Response<DownstreamRoute> _downstreamRoute;
 | 
					        private readonly Mock<IInternalConfigurationRepository> _repo;
 | 
				
			||||||
        private IInternalConfiguration _config;
 | 
					        private Response<DownstreamRoute> _downstreamRoute;
 | 
				
			||||||
        private Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
					        private IInternalConfiguration _config;
 | 
				
			||||||
        private Mock<IOcelotLogger> _logger;
 | 
					        private Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
				
			||||||
        private readonly DownstreamRouteFinderMiddleware _middleware;
 | 
					        private Mock<IOcelotLogger> _logger;
 | 
				
			||||||
        private readonly DownstreamContext _downstreamContext;
 | 
					        private readonly DownstreamRouteFinderMiddleware _middleware;
 | 
				
			||||||
        private OcelotRequestDelegate _next;
 | 
					        private readonly DownstreamContext _downstreamContext;
 | 
				
			||||||
        private readonly Mock<IMultiplexer> _multiplexer;
 | 
					        private OcelotRequestDelegate _next;
 | 
				
			||||||
 | 
					        private readonly Mock<IMultiplexer> _multiplexer;
 | 
				
			||||||
        public DownstreamRouteFinderMiddlewareTests()
 | 
					
 | 
				
			||||||
        {
 | 
					        public DownstreamRouteFinderMiddlewareTests()
 | 
				
			||||||
            _repo = new Mock<IInternalConfigurationRepository>();
 | 
					        {
 | 
				
			||||||
            _finder = new Mock<IDownstreamRouteFinder>();
 | 
					            _repo = new Mock<IInternalConfigurationRepository>();
 | 
				
			||||||
            _downstreamContext = new DownstreamContext(new DefaultHttpContext());
 | 
					            _finder = new Mock<IDownstreamRouteProvider>();
 | 
				
			||||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
					            _factory = new Mock<IDownstreamRouteProviderFactory>();
 | 
				
			||||||
            _logger = new Mock<IOcelotLogger>();
 | 
					            _factory.Setup(x => x.Get(It.IsAny<IInternalConfiguration>())).Returns(_finder.Object);
 | 
				
			||||||
            _loggerFactory.Setup(x => x.CreateLogger<DownstreamRouteFinderMiddleware>()).Returns(_logger.Object);
 | 
					            _downstreamContext = new DownstreamContext(new DefaultHttpContext());
 | 
				
			||||||
            _next = context => Task.CompletedTask;
 | 
					            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
				
			||||||
            _multiplexer = new Mock<IMultiplexer>();
 | 
					            _logger = new Mock<IOcelotLogger>();
 | 
				
			||||||
            _middleware = new DownstreamRouteFinderMiddleware(_next, _loggerFactory.Object, _finder.Object, _repo.Object, _multiplexer.Object);
 | 
					            _loggerFactory.Setup(x => x.CreateLogger<DownstreamRouteFinderMiddleware>()).Returns(_logger.Object);
 | 
				
			||||||
        }
 | 
					            _next = context => Task.CompletedTask;
 | 
				
			||||||
 | 
					            _multiplexer = new Mock<IMultiplexer>();
 | 
				
			||||||
        [Fact]
 | 
					            _middleware = new DownstreamRouteFinderMiddleware(_next, _loggerFactory.Object, _factory.Object, _repo.Object, _multiplexer.Object);
 | 
				
			||||||
        public void should_call_scoped_data_repository_correctly()
 | 
					        }
 | 
				
			||||||
        {
 | 
					
 | 
				
			||||||
            var config = new InternalConfiguration(null, null, new ServiceProviderConfigurationBuilder().Build(), "");
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_call_scoped_data_repository_correctly()
 | 
				
			||||||
            var downstreamReRoute = new DownstreamReRouteBuilder()
 | 
					        {
 | 
				
			||||||
                .WithDownstreamPathTemplate("any old string")
 | 
					            var config = new InternalConfiguration(null, null, new ServiceProviderConfigurationBuilder().Build(), "", new LoadBalancerOptionsBuilder().Build(), "", new QoSOptionsBuilder().Build(), new HttpHandlerOptionsBuilder().Build());
 | 
				
			||||||
                .WithUpstreamHttpMethod(new List<string> {"Get"})
 | 
					
 | 
				
			||||||
                .Build();
 | 
					            var downstreamReRoute = new DownstreamReRouteBuilder()
 | 
				
			||||||
 | 
					                .WithDownstreamPathTemplate("any old string")
 | 
				
			||||||
            this.Given(x => x.GivenTheDownStreamRouteFinderReturns(
 | 
					                .WithUpstreamHttpMethod(new List<string> {"Get"})
 | 
				
			||||||
                new DownstreamRoute(
 | 
					                .Build();
 | 
				
			||||||
                    new List<PlaceholderNameAndValue>(), 
 | 
					
 | 
				
			||||||
                    new ReRouteBuilder()
 | 
					            this.Given(x => x.GivenTheDownStreamRouteFinderReturns(
 | 
				
			||||||
                        .WithDownstreamReRoute(downstreamReRoute)
 | 
					                new DownstreamRoute(
 | 
				
			||||||
                        .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
					                    new List<PlaceholderNameAndValue>(), 
 | 
				
			||||||
                        .Build())))
 | 
					                    new ReRouteBuilder()
 | 
				
			||||||
                .And(x => GivenTheFollowingConfig(config))
 | 
					                        .WithDownstreamReRoute(downstreamReRoute)
 | 
				
			||||||
                .When(x => x.WhenICallTheMiddleware())
 | 
					                        .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
				
			||||||
                .Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly())
 | 
					                        .Build())))
 | 
				
			||||||
                .BDDfy();
 | 
					                .And(x => GivenTheFollowingConfig(config))
 | 
				
			||||||
        }
 | 
					                .When(x => x.WhenICallTheMiddleware())
 | 
				
			||||||
 | 
					                .Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly())
 | 
				
			||||||
        private void WhenICallTheMiddleware()
 | 
					                .BDDfy();
 | 
				
			||||||
        {
 | 
					        }
 | 
				
			||||||
            _middleware.Invoke(_downstreamContext).GetAwaiter().GetType();
 | 
					
 | 
				
			||||||
        }
 | 
					        private void WhenICallTheMiddleware()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
        private void GivenTheFollowingConfig(IInternalConfiguration config)
 | 
					            _middleware.Invoke(_downstreamContext).GetAwaiter().GetType();
 | 
				
			||||||
        {
 | 
					        }
 | 
				
			||||||
            _config = config;
 | 
					
 | 
				
			||||||
            _repo
 | 
					        private void GivenTheFollowingConfig(IInternalConfiguration config)
 | 
				
			||||||
                .Setup(x => x.Get())
 | 
					        {
 | 
				
			||||||
                .Returns(new OkResponse<IInternalConfiguration>(_config));
 | 
					            _config = config;
 | 
				
			||||||
        }
 | 
					            _downstreamContext.Configuration = config;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        private void GivenTheDownStreamRouteFinderReturns(DownstreamRoute downstreamRoute)
 | 
					
 | 
				
			||||||
        {
 | 
					        private void GivenTheDownStreamRouteFinderReturns(DownstreamRoute downstreamRoute)
 | 
				
			||||||
            _downstreamRoute = new OkResponse<DownstreamRoute>(downstreamRoute);
 | 
					        {
 | 
				
			||||||
            _finder
 | 
					            _downstreamRoute = new OkResponse<DownstreamRoute>(downstreamRoute);
 | 
				
			||||||
                .Setup(x => x.FindDownstreamRoute(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<IInternalConfiguration>(), It.IsAny<string>()))
 | 
					            _finder
 | 
				
			||||||
                .Returns(_downstreamRoute);
 | 
					                .Setup(x => x.Get(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<IInternalConfiguration>(), It.IsAny<string>()))
 | 
				
			||||||
        }
 | 
					                .Returns(_downstreamRoute);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        private void ThenTheScopedDataRepositoryIsCalledCorrectly()
 | 
					
 | 
				
			||||||
        {
 | 
					        private void ThenTheScopedDataRepositoryIsCalledCorrectly()
 | 
				
			||||||
            _downstreamContext.TemplatePlaceholderNameAndValues.ShouldBe(_downstreamRoute.Data.TemplatePlaceholderNameAndValues);
 | 
					        {
 | 
				
			||||||
            _downstreamContext.ServiceProviderConfiguration.ShouldBe(_config.ServiceProviderConfiguration);
 | 
					            _downstreamContext.TemplatePlaceholderNameAndValues.ShouldBe(_downstreamRoute.Data.TemplatePlaceholderNameAndValues);
 | 
				
			||||||
        }
 | 
					            _downstreamContext.Configuration.ServiceProviderConfiguration.ShouldBe(_config.ServiceProviderConfiguration);
 | 
				
			||||||
    }
 | 
					        }
 | 
				
			||||||
}
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -0,0 +1,98 @@
 | 
				
			|||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using Microsoft.Extensions.DependencyInjection;
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    using Ocelot.Configuration.Creator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public class DownstreamRouteProviderFactoryTests
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private readonly DownstreamRouteProviderFactory _factory;
 | 
				
			||||||
 | 
					        private IInternalConfiguration _config;
 | 
				
			||||||
 | 
					        private IDownstreamRouteProvider _result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public DownstreamRouteProviderFactoryTests()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var services = new ServiceCollection();
 | 
				
			||||||
 | 
					            services.AddSingleton<IPlaceholderNameAndValueFinder, UrlPathPlaceholderNameAndValueFinder>();
 | 
				
			||||||
 | 
					            services.AddSingleton<IUrlPathToUrlTemplateMatcher, RegExUrlMatcher>();
 | 
				
			||||||
 | 
					            services.AddSingleton<IQoSOptionsCreator, QoSOptionsCreator>();
 | 
				
			||||||
 | 
					            services.AddSingleton<IDownstreamRouteProvider, Ocelot.DownstreamRouteFinder.Finder.DownstreamRouteFinder>();
 | 
				
			||||||
 | 
					            services.AddSingleton<IDownstreamRouteProvider, Ocelot.DownstreamRouteFinder.Finder.DownstreamRouteCreator>();
 | 
				
			||||||
 | 
					            var provider = services.BuildServiceProvider();
 | 
				
			||||||
 | 
					            _factory = new DownstreamRouteProviderFactory(provider);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_return_downstream_route_finder()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var reRoutes = new List<ReRoute>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                new ReRouteBuilder().Build()
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.Given(_ => GivenTheReRoutes(reRoutes))
 | 
				
			||||||
 | 
					                .When(_ => WhenIGet())
 | 
				
			||||||
 | 
					                .Then(_ => ThenTheResultShouldBe<Ocelot.DownstreamRouteFinder.Finder.DownstreamRouteFinder>())
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_return_downstream_route_finder_as_no_service_discovery()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var spConfig = new ServiceProviderConfigurationBuilder().Build();
 | 
				
			||||||
 | 
					            var reRoutes = new List<ReRoute>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.Given(_ => GivenTheReRoutes(reRoutes, spConfig))
 | 
				
			||||||
 | 
					                .When(_ => WhenIGet())
 | 
				
			||||||
 | 
					                .Then(_ => ThenTheResultShouldBe<Ocelot.DownstreamRouteFinder.Finder.DownstreamRouteFinder>())
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_return_downstream_route_creator()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var spConfig = new ServiceProviderConfigurationBuilder().WithHost("test").WithPort(50).Build();
 | 
				
			||||||
 | 
					            var reRoutes = new List<ReRoute>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            this.Given(_ => GivenTheReRoutes(reRoutes, spConfig))
 | 
				
			||||||
 | 
					                .When(_ => WhenIGet())
 | 
				
			||||||
 | 
					                .Then(_ => ThenTheResultShouldBe<Ocelot.DownstreamRouteFinder.Finder.DownstreamRouteCreator>())
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void ThenTheResultShouldBe<T>()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _result.ShouldBeOfType<T>();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void WhenIGet()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _result = _factory.Get(_config);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void GivenTheReRoutes(List<ReRoute> reRoutes)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _config = new InternalConfiguration(reRoutes, "", null, "", new LoadBalancerOptionsBuilder().Build(), "", new QoSOptionsBuilder().Build(), new HttpHandlerOptionsBuilder().Build());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void GivenTheReRoutes(List<ReRoute> reRoutes, ServiceProviderConfiguration config)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _config = new InternalConfiguration(reRoutes, "", config, "", new LoadBalancerOptionsBuilder().Build(), "", new QoSOptionsBuilder().Build(), new HttpHandlerOptionsBuilder().Build());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -192,8 +192,9 @@
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void GivenTheServiceProviderConfigIs(ServiceProviderConfiguration config)
 | 
					        private void GivenTheServiceProviderConfigIs(ServiceProviderConfiguration config)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _downstreamContext.ServiceProviderConfiguration = config;
 | 
					            var configuration = new InternalConfiguration(null, null, config, null, null, null, null, null);
 | 
				
			||||||
 | 
					            _downstreamContext.Configuration = configuration;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void WhenICallTheMiddleware()
 | 
					        private void WhenICallTheMiddleware()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -51,7 +51,7 @@ namespace Ocelot.UnitTests.Errors
 | 
				
			|||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void NoDownstreamException()
 | 
					        public void NoDownstreamException()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var config = new InternalConfiguration(null, null, null, null);
 | 
					            var config = new InternalConfiguration(null, null, null, null, null, null, null, null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(_ => GivenAnExceptionWillNotBeThrownDownstream())
 | 
					            this.Given(_ => GivenAnExceptionWillNotBeThrownDownstream())
 | 
				
			||||||
                .And(_ => GivenTheConfigurationIs(config))
 | 
					                .And(_ => GivenTheConfigurationIs(config))
 | 
				
			||||||
@@ -64,7 +64,7 @@ namespace Ocelot.UnitTests.Errors
 | 
				
			|||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void DownstreamException()
 | 
					        public void DownstreamException()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var config = new InternalConfiguration(null, null, null, null);
 | 
					            var config = new InternalConfiguration(null, null, null, null, null, null, null, null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(_ => GivenAnExceptionWillBeThrownDownstream())
 | 
					            this.Given(_ => GivenAnExceptionWillBeThrownDownstream())
 | 
				
			||||||
                .And(_ => GivenTheConfigurationIs(config))
 | 
					                .And(_ => GivenTheConfigurationIs(config))
 | 
				
			||||||
@@ -76,7 +76,7 @@ namespace Ocelot.UnitTests.Errors
 | 
				
			|||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void ShouldSetRequestId()
 | 
					        public void ShouldSetRequestId()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var config = new InternalConfiguration(null, null, null, "requestidkey");
 | 
					            var config = new InternalConfiguration(null, null, null, "requestidkey", null, null, null, null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(_ => GivenAnExceptionWillNotBeThrownDownstream())
 | 
					            this.Given(_ => GivenAnExceptionWillNotBeThrownDownstream())
 | 
				
			||||||
                .And(_ => GivenTheConfigurationIs(config))
 | 
					                .And(_ => GivenTheConfigurationIs(config))
 | 
				
			||||||
@@ -89,7 +89,7 @@ namespace Ocelot.UnitTests.Errors
 | 
				
			|||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void ShouldSetAspDotNetRequestId()
 | 
					        public void ShouldSetAspDotNetRequestId()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var config = new InternalConfiguration(null, null, null, null);
 | 
					            var config = new InternalConfiguration(null, null, null, null, null, null, null, null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(_ => GivenAnExceptionWillNotBeThrownDownstream())
 | 
					            this.Given(_ => GivenAnExceptionWillNotBeThrownDownstream())
 | 
				
			||||||
                .And(_ => GivenTheConfigurationIs(config))
 | 
					                .And(_ => GivenTheConfigurationIs(config))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,7 +33,7 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
				
			|||||||
        public void should_store_load_balancer_on_first_request()
 | 
					        public void should_store_load_balancer_on_first_request()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
					            var reRoute = new DownstreamReRouteBuilder()
 | 
				
			||||||
                .WithReRouteKey("test")
 | 
					                .WithLoadBalancerKey("test")
 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer()))
 | 
					            this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer()))
 | 
				
			||||||
@@ -46,7 +46,7 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
					            var reRoute = new DownstreamReRouteBuilder()
 | 
				
			||||||
                .WithLoadBalancerOptions(new LoadBalancerOptions("FakeLoadBalancer", "", 0))
 | 
					                .WithLoadBalancerOptions(new LoadBalancerOptions("FakeLoadBalancer", "", 0))
 | 
				
			||||||
                .WithReRouteKey("test")
 | 
					                .WithLoadBalancerKey("test")
 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer()))
 | 
					            this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer()))
 | 
				
			||||||
@@ -60,12 +60,12 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
					            var reRoute = new DownstreamReRouteBuilder()
 | 
				
			||||||
                .WithLoadBalancerOptions(new LoadBalancerOptions("FakeLoadBalancer", "", 0))
 | 
					                .WithLoadBalancerOptions(new LoadBalancerOptions("FakeLoadBalancer", "", 0))
 | 
				
			||||||
                .WithReRouteKey("test")
 | 
					                .WithLoadBalancerKey("test")
 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
            var reRouteTwo = new DownstreamReRouteBuilder()
 | 
					            var reRouteTwo = new DownstreamReRouteBuilder()
 | 
				
			||||||
                .WithLoadBalancerOptions(new LoadBalancerOptions("FakeRoundRobinLoadBalancer", "", 0))
 | 
					                .WithLoadBalancerOptions(new LoadBalancerOptions("FakeRoundRobinLoadBalancer", "", 0))
 | 
				
			||||||
                .WithReRouteKey("testtwo")
 | 
					                .WithLoadBalancerKey("testtwo")
 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer()))
 | 
					            this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer()))
 | 
				
			||||||
@@ -92,12 +92,12 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
					            var reRoute = new DownstreamReRouteBuilder()
 | 
				
			||||||
                .WithLoadBalancerOptions(new LoadBalancerOptions("FakeLoadBalancer", "", 0))
 | 
					                .WithLoadBalancerOptions(new LoadBalancerOptions("FakeLoadBalancer", "", 0))
 | 
				
			||||||
                .WithReRouteKey("test")
 | 
					                .WithLoadBalancerKey("test")
 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var reRouteTwo = new DownstreamReRouteBuilder()
 | 
					            var reRouteTwo = new DownstreamReRouteBuilder()
 | 
				
			||||||
                .WithLoadBalancerOptions(new LoadBalancerOptions("LeastConnection", "", 0))
 | 
					                .WithLoadBalancerOptions(new LoadBalancerOptions("LeastConnection", "", 0))
 | 
				
			||||||
                .WithReRouteKey("test")
 | 
					                .WithLoadBalancerKey("test")
 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer()))
 | 
					            this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer()))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -117,7 +117,8 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
				
			|||||||
        private void GivenTheConfigurationIs(ServiceProviderConfiguration config)
 | 
					        private void GivenTheConfigurationIs(ServiceProviderConfiguration config)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _config = config;
 | 
					            _config = config;
 | 
				
			||||||
            _downstreamContext.ServiceProviderConfiguration = config;
 | 
					            var configuration = new InternalConfiguration(null, null, config, null, null, null, null, null);
 | 
				
			||||||
 | 
					            _downstreamContext.Configuration = configuration;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void GivenTheDownStreamUrlIs(string downstreamUrl)
 | 
					        private void GivenTheDownStreamUrlIs(string downstreamUrl)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					using Ocelot.Configuration;
 | 
				
			||||||
 | 
					using Ocelot.LoadBalancer.LoadBalancers;
 | 
				
			||||||
 | 
					using Shouldly;
 | 
				
			||||||
 | 
					using Xunit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ocelot.UnitTests.LoadBalancer
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class LoadBalancerOptionsTests
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_default_to_no_load_balancer()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var options = new LoadBalancerOptionsBuilder().Build();
 | 
				
			||||||
 | 
					            options.Type.ShouldBe(nameof(NoLoadBalancer));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,4 +1,6 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
using Microsoft.AspNetCore.Http;
 | 
					using Microsoft.AspNetCore.Http;
 | 
				
			||||||
using Ocelot.LoadBalancer.LoadBalancers;
 | 
					using Ocelot.LoadBalancer.LoadBalancers;
 | 
				
			||||||
using Ocelot.Middleware;
 | 
					using Ocelot.Middleware;
 | 
				
			||||||
@@ -16,6 +18,12 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
				
			|||||||
        private NoLoadBalancer _loadBalancer;
 | 
					        private NoLoadBalancer _loadBalancer;
 | 
				
			||||||
        private Response<ServiceHostAndPort> _result;
 | 
					        private Response<ServiceHostAndPort> _result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public NoLoadBalancerTests()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _services = new List<Service>();
 | 
				
			||||||
 | 
					            _loadBalancer = new NoLoadBalancer(() => Task.FromResult(_services));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_return_host_and_port()
 | 
					        public void should_return_host_and_port()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -25,6 +33,7 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
				
			|||||||
            {
 | 
					            {
 | 
				
			||||||
                new Service("product", hostAndPort, string.Empty, string.Empty, new string[0])
 | 
					                new Service("product", hostAndPort, string.Empty, string.Empty, new string[0])
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(x => x.GivenServices(services))
 | 
					            this.Given(x => x.GivenServices(services))
 | 
				
			||||||
                .When(x => x.WhenIGetTheNextHostAndPort())
 | 
					                .When(x => x.WhenIGetTheNextHostAndPort())
 | 
				
			||||||
                .Then(x => x.ThenTheHostAndPortIs(hostAndPort))
 | 
					                .Then(x => x.ThenTheHostAndPortIs(hostAndPort))
 | 
				
			||||||
@@ -34,25 +43,43 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
				
			|||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_return_error_if_no_services()
 | 
					        public void should_return_error_if_no_services()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var services = new List<Service>();
 | 
					            this.When(x => x.WhenIGetTheNextHostAndPort())
 | 
				
			||||||
 | 
					 | 
				
			||||||
            this.Given(x => x.GivenServices(services))
 | 
					 | 
				
			||||||
                .When(x => x.WhenIGetTheNextHostAndPort())
 | 
					 | 
				
			||||||
                .Then(x => x.ThenThereIsAnError())
 | 
					                .Then(x => x.ThenThereIsAnError())
 | 
				
			||||||
                .BDDfy();
 | 
					                .BDDfy();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_return_error_if_no_services_then_when_services_available_return_host_and_port()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var hostAndPort = new ServiceHostAndPort("127.0.0.1", 80);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var services = new List<Service>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                new Service("product", hostAndPort, string.Empty, string.Empty, new string[0])
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.Given(_ => WhenIGetTheNextHostAndPort())
 | 
				
			||||||
 | 
					                .And(_ => ThenThereIsAnError())
 | 
				
			||||||
 | 
					                .And(_ => GivenServices(services))
 | 
				
			||||||
 | 
					                .When(_ => WhenIGetTheNextHostAndPort())
 | 
				
			||||||
 | 
					                .Then(_ => ThenTheHostAndPortIs(hostAndPort))
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_return_error_if_null_services()
 | 
					        public void should_return_error_if_null_services()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            List<Service> services = null;
 | 
					            this.Given(x => x.GivenServicesAreNull())
 | 
				
			||||||
 | 
					 | 
				
			||||||
            this.Given(x => x.GivenServices(services))
 | 
					 | 
				
			||||||
                .When(x => x.WhenIGetTheNextHostAndPort())
 | 
					                .When(x => x.WhenIGetTheNextHostAndPort())
 | 
				
			||||||
                .Then(x => x.ThenThereIsAnError())
 | 
					                .Then(x => x.ThenThereIsAnError())
 | 
				
			||||||
                .BDDfy();
 | 
					                .BDDfy();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void GivenServicesAreNull()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _loadBalancer = new NoLoadBalancer(() => Task.FromResult((List<Service>)null));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void ThenThereIsAnError()
 | 
					        private void ThenThereIsAnError()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _result.IsError.ShouldBeTrue();
 | 
					            _result.IsError.ShouldBeTrue();
 | 
				
			||||||
@@ -60,12 +87,11 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private void GivenServices(List<Service> services)
 | 
					        private void GivenServices(List<Service> services)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _services = services;
 | 
					            _services.AddRange(services);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void WhenIGetTheNextHostAndPort()
 | 
					        private void WhenIGetTheNextHostAndPort()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _loadBalancer = new NoLoadBalancer(_services);
 | 
					 | 
				
			||||||
            _result = _loadBalancer.Lease(new DownstreamContext(new DefaultHttpContext())).Result;
 | 
					            _result = _loadBalancer.Lease(new DownstreamContext(new DefaultHttpContext())).Result;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,14 +38,21 @@ namespace Ocelot.UnitTests.Requester
 | 
				
			|||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_follow_ordering_add_specifics()
 | 
					        public void should_follow_ordering_add_specifics()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var reRoute = new DownstreamReRouteBuilder().WithIsQos(true)
 | 
					            var qosOptions = new QoSOptionsBuilder()
 | 
				
			||||||
 | 
					                .WithTimeoutValue(1)
 | 
				
			||||||
 | 
					                .WithDurationOfBreak(1)
 | 
				
			||||||
 | 
					                .WithExceptionsAllowedBeforeBreaking(1)
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var reRoute = new DownstreamReRouteBuilder()
 | 
				
			||||||
 | 
					                .WithQosOptions(qosOptions)
 | 
				
			||||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true))
 | 
					                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true))
 | 
				
			||||||
                .WithDelegatingHandlers(new List<string>
 | 
					                .WithDelegatingHandlers(new List<string>
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    "FakeDelegatingHandler",
 | 
					                    "FakeDelegatingHandler",
 | 
				
			||||||
                    "FakeDelegatingHandlerTwo"
 | 
					                    "FakeDelegatingHandlerTwo"
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
                .WithReRouteKey("")
 | 
					                .WithLoadBalancerKey("")
 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(x => GivenTheFollowingRequest(reRoute))
 | 
					            this.Given(x => GivenTheFollowingRequest(reRoute))
 | 
				
			||||||
@@ -67,7 +74,14 @@ namespace Ocelot.UnitTests.Requester
 | 
				
			|||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_follow_ordering_order_specifics_and_globals()
 | 
					        public void should_follow_ordering_order_specifics_and_globals()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var reRoute = new DownstreamReRouteBuilder().WithIsQos(true)
 | 
					            var qosOptions = new QoSOptionsBuilder()
 | 
				
			||||||
 | 
					                .WithTimeoutValue(1)
 | 
				
			||||||
 | 
					                .WithDurationOfBreak(1)
 | 
				
			||||||
 | 
					                .WithExceptionsAllowedBeforeBreaking(1)
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var reRoute = new DownstreamReRouteBuilder()
 | 
				
			||||||
 | 
					                .WithQosOptions(qosOptions)
 | 
				
			||||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true))
 | 
					                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true))
 | 
				
			||||||
                .WithDelegatingHandlers(new List<string>
 | 
					                .WithDelegatingHandlers(new List<string>
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@@ -75,7 +89,7 @@ namespace Ocelot.UnitTests.Requester
 | 
				
			|||||||
                    "FakeDelegatingHandler",
 | 
					                    "FakeDelegatingHandler",
 | 
				
			||||||
                    "FakeDelegatingHandlerFour"
 | 
					                    "FakeDelegatingHandlerFour"
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
                .WithReRouteKey("")
 | 
					                .WithLoadBalancerKey("")
 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(x => GivenTheFollowingRequest(reRoute))
 | 
					            this.Given(x => GivenTheFollowingRequest(reRoute))
 | 
				
			||||||
@@ -97,14 +111,21 @@ namespace Ocelot.UnitTests.Requester
 | 
				
			|||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_follow_ordering_order_specifics()
 | 
					        public void should_follow_ordering_order_specifics()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var reRoute = new DownstreamReRouteBuilder().WithIsQos(true)
 | 
					            var qosOptions = new QoSOptionsBuilder()
 | 
				
			||||||
 | 
					                .WithTimeoutValue(1)
 | 
				
			||||||
 | 
					                .WithDurationOfBreak(1)
 | 
				
			||||||
 | 
					                .WithExceptionsAllowedBeforeBreaking(1)
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var reRoute = new DownstreamReRouteBuilder()
 | 
				
			||||||
 | 
					                .WithQosOptions(qosOptions)
 | 
				
			||||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true))
 | 
					                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true))
 | 
				
			||||||
                .WithDelegatingHandlers(new List<string>
 | 
					                .WithDelegatingHandlers(new List<string>
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    "FakeDelegatingHandlerTwo",
 | 
					                    "FakeDelegatingHandlerTwo",
 | 
				
			||||||
                    "FakeDelegatingHandler"
 | 
					                    "FakeDelegatingHandler"
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
                .WithReRouteKey("")
 | 
					                .WithLoadBalancerKey("")
 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(x => GivenTheFollowingRequest(reRoute))
 | 
					            this.Given(x => GivenTheFollowingRequest(reRoute))
 | 
				
			||||||
@@ -126,13 +147,20 @@ namespace Ocelot.UnitTests.Requester
 | 
				
			|||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_follow_ordering_order_and_only_add_specifics_in_config()
 | 
					        public void should_follow_ordering_order_and_only_add_specifics_in_config()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var reRoute = new DownstreamReRouteBuilder().WithIsQos(true)
 | 
					            var qosOptions = new QoSOptionsBuilder()
 | 
				
			||||||
 | 
					                .WithTimeoutValue(1)
 | 
				
			||||||
 | 
					                .WithDurationOfBreak(1)
 | 
				
			||||||
 | 
					                .WithExceptionsAllowedBeforeBreaking(1)
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var reRoute = new DownstreamReRouteBuilder()
 | 
				
			||||||
 | 
					                .WithQosOptions(qosOptions)
 | 
				
			||||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true))
 | 
					                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true))
 | 
				
			||||||
                .WithDelegatingHandlers(new List<string>
 | 
					                .WithDelegatingHandlers(new List<string>
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    "FakeDelegatingHandler",
 | 
					                    "FakeDelegatingHandler",
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
                .WithReRouteKey("")
 | 
					                .WithLoadBalancerKey("")
 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(x => GivenTheFollowingRequest(reRoute))
 | 
					            this.Given(x => GivenTheFollowingRequest(reRoute))
 | 
				
			||||||
@@ -153,9 +181,16 @@ namespace Ocelot.UnitTests.Requester
 | 
				
			|||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_follow_ordering_dont_add_specifics()
 | 
					        public void should_follow_ordering_dont_add_specifics()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var reRoute = new DownstreamReRouteBuilder().WithIsQos(true)
 | 
					            var qosOptions = new QoSOptionsBuilder()
 | 
				
			||||||
 | 
					                .WithTimeoutValue(1)
 | 
				
			||||||
 | 
					                .WithDurationOfBreak(1)
 | 
				
			||||||
 | 
					                .WithExceptionsAllowedBeforeBreaking(1)
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var reRoute = new DownstreamReRouteBuilder()
 | 
				
			||||||
 | 
					                .WithQosOptions(qosOptions)
 | 
				
			||||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true))
 | 
					                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true))
 | 
				
			||||||
                .WithReRouteKey("")
 | 
					                .WithLoadBalancerKey("")
 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(x => GivenTheFollowingRequest(reRoute))
 | 
					            this.Given(x => GivenTheFollowingRequest(reRoute))
 | 
				
			||||||
@@ -175,14 +210,18 @@ namespace Ocelot.UnitTests.Requester
 | 
				
			|||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_apply_re_route_specific()
 | 
					        public void should_apply_re_route_specific()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            var qosOptions = new QoSOptionsBuilder()
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
					            var reRoute = new DownstreamReRouteBuilder()
 | 
				
			||||||
 | 
					                .WithQosOptions(qosOptions)
 | 
				
			||||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false))
 | 
					                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false))
 | 
				
			||||||
                .WithDelegatingHandlers(new List<string>
 | 
					                .WithDelegatingHandlers(new List<string>
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    "FakeDelegatingHandler",
 | 
					                    "FakeDelegatingHandler",
 | 
				
			||||||
                    "FakeDelegatingHandlerTwo"
 | 
					                    "FakeDelegatingHandlerTwo"
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
                .WithReRouteKey("")
 | 
					                .WithLoadBalancerKey("")
 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(x => GivenTheFollowingRequest(reRoute))
 | 
					            this.Given(x => GivenTheFollowingRequest(reRoute))
 | 
				
			||||||
@@ -197,8 +236,15 @@ namespace Ocelot.UnitTests.Requester
 | 
				
			|||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_all_from_all_routes_provider_and_qos()
 | 
					        public void should_all_from_all_routes_provider_and_qos()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var reRoute = new DownstreamReRouteBuilder().WithIsQos(true)
 | 
					            var qosOptions = new QoSOptionsBuilder()
 | 
				
			||||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false)).WithReRouteKey("").Build();
 | 
					                .WithTimeoutValue(1)
 | 
				
			||||||
 | 
					                .WithDurationOfBreak(1)
 | 
				
			||||||
 | 
					                .WithExceptionsAllowedBeforeBreaking(1)
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var reRoute = new DownstreamReRouteBuilder()
 | 
				
			||||||
 | 
					                .WithQosOptions(qosOptions)
 | 
				
			||||||
 | 
					                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false)).WithLoadBalancerKey("").Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(x => GivenTheFollowingRequest(reRoute))
 | 
					            this.Given(x => GivenTheFollowingRequest(reRoute))
 | 
				
			||||||
                .And(x => GivenTheQosProviderHouseReturns(new OkResponse<IQoSProvider>(It.IsAny<PollyQoSProvider>())))
 | 
					                .And(x => GivenTheQosProviderHouseReturns(new OkResponse<IQoSProvider>(It.IsAny<PollyQoSProvider>())))
 | 
				
			||||||
@@ -213,8 +259,12 @@ namespace Ocelot.UnitTests.Requester
 | 
				
			|||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_return_provider_with_no_delegates()
 | 
					        public void should_return_provider_with_no_delegates()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var reRoute = new DownstreamReRouteBuilder().WithIsQos(false)
 | 
					            var qosOptions = new QoSOptionsBuilder()
 | 
				
			||||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false)).WithReRouteKey("").Build();
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var reRoute = new DownstreamReRouteBuilder()
 | 
				
			||||||
 | 
					                .WithQosOptions(qosOptions)
 | 
				
			||||||
 | 
					                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false)).WithLoadBalancerKey("").Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(x => GivenTheFollowingRequest(reRoute))
 | 
					            this.Given(x => GivenTheFollowingRequest(reRoute))
 | 
				
			||||||
                .And(x => GivenTheServiceProviderReturnsNothing())
 | 
					                .And(x => GivenTheServiceProviderReturnsNothing())
 | 
				
			||||||
@@ -226,8 +276,15 @@ namespace Ocelot.UnitTests.Requester
 | 
				
			|||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_return_provider_with_qos_delegate()
 | 
					        public void should_return_provider_with_qos_delegate()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var reRoute = new DownstreamReRouteBuilder().WithIsQos(true)
 | 
					            var qosOptions = new QoSOptionsBuilder()
 | 
				
			||||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false)).WithReRouteKey("").Build();
 | 
					                .WithTimeoutValue(1)
 | 
				
			||||||
 | 
					                .WithDurationOfBreak(1)
 | 
				
			||||||
 | 
					                .WithExceptionsAllowedBeforeBreaking(1)
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var reRoute = new DownstreamReRouteBuilder()
 | 
				
			||||||
 | 
					                .WithQosOptions(qosOptions)
 | 
				
			||||||
 | 
					                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false)).WithLoadBalancerKey("").Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(x => GivenTheFollowingRequest(reRoute))
 | 
					            this.Given(x => GivenTheFollowingRequest(reRoute))
 | 
				
			||||||
                .And(x => GivenTheQosProviderHouseReturns(new OkResponse<IQoSProvider>(It.IsAny<PollyQoSProvider>())))
 | 
					                .And(x => GivenTheQosProviderHouseReturns(new OkResponse<IQoSProvider>(It.IsAny<PollyQoSProvider>())))
 | 
				
			||||||
@@ -241,8 +298,15 @@ namespace Ocelot.UnitTests.Requester
 | 
				
			|||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_return_error()
 | 
					        public void should_return_error()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var reRoute = new DownstreamReRouteBuilder().WithIsQos(true)
 | 
					            var qosOptions = new QoSOptionsBuilder()
 | 
				
			||||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false)).WithReRouteKey("").Build();
 | 
					                .WithTimeoutValue(1)
 | 
				
			||||||
 | 
					                .WithDurationOfBreak(1)
 | 
				
			||||||
 | 
					                .WithExceptionsAllowedBeforeBreaking(1)
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var reRoute = new DownstreamReRouteBuilder()
 | 
				
			||||||
 | 
					                .WithQosOptions(qosOptions)
 | 
				
			||||||
 | 
					                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false)).WithLoadBalancerKey("").Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(x => GivenTheFollowingRequest(reRoute))
 | 
					            this.Given(x => GivenTheFollowingRequest(reRoute))
 | 
				
			||||||
                .And(x => GivenTheQosProviderHouseReturns(new ErrorResponse<IQoSProvider>(It.IsAny<Error>())))
 | 
					                .And(x => GivenTheQosProviderHouseReturns(new ErrorResponse<IQoSProvider>(It.IsAny<Error>())))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -46,10 +46,13 @@ namespace Ocelot.UnitTests.Requester
 | 
				
			|||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_build_http_client()
 | 
					        public void should_build_http_client()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            var qosOptions = new QoSOptionsBuilder()
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
					            var reRoute = new DownstreamReRouteBuilder()
 | 
				
			||||||
                .WithIsQos(false)
 | 
					                .WithQosOptions(qosOptions)
 | 
				
			||||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false))
 | 
					                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false))
 | 
				
			||||||
                .WithReRouteKey("")
 | 
					                .WithLoadBalancerKey("")
 | 
				
			||||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
					                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -63,10 +66,13 @@ namespace Ocelot.UnitTests.Requester
 | 
				
			|||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_log_if_ignoring_ssl_errors()
 | 
					        public void should_log_if_ignoring_ssl_errors()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            var qosOptions = new QoSOptionsBuilder()
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
					            var reRoute = new DownstreamReRouteBuilder()
 | 
				
			||||||
                .WithIsQos(false)
 | 
					                .WithQosOptions(qosOptions)
 | 
				
			||||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false))
 | 
					                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false))
 | 
				
			||||||
                .WithReRouteKey("")
 | 
					                .WithLoadBalancerKey("")
 | 
				
			||||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
					                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
				
			||||||
                .WithDangerousAcceptAnyServerCertificateValidator(true)
 | 
					                .WithDangerousAcceptAnyServerCertificateValidator(true)
 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
@@ -82,10 +88,13 @@ namespace Ocelot.UnitTests.Requester
 | 
				
			|||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_call_delegating_handlers_in_order()
 | 
					        public void should_call_delegating_handlers_in_order()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            var qosOptions = new QoSOptionsBuilder()
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
					            var reRoute = new DownstreamReRouteBuilder()
 | 
				
			||||||
                .WithIsQos(false)
 | 
					                .WithQosOptions(qosOptions)
 | 
				
			||||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false))
 | 
					                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false))
 | 
				
			||||||
                .WithReRouteKey("")
 | 
					                .WithLoadBalancerKey("")
 | 
				
			||||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
					                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -110,10 +119,13 @@ namespace Ocelot.UnitTests.Requester
 | 
				
			|||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_re_use_cookies_from_container()
 | 
					        public void should_re_use_cookies_from_container()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            var qosOptions = new QoSOptionsBuilder()
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
					            var reRoute = new DownstreamReRouteBuilder()
 | 
				
			||||||
                .WithIsQos(false)
 | 
					                .WithQosOptions(qosOptions)
 | 
				
			||||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, true, false))
 | 
					                .WithHttpHandlerOptions(new HttpHandlerOptions(false, true, false))
 | 
				
			||||||
                .WithReRouteKey("")
 | 
					                .WithLoadBalancerKey("")
 | 
				
			||||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
					                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -142,10 +154,13 @@ namespace Ocelot.UnitTests.Requester
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            HttpMethod method = new HttpMethod(verb);
 | 
					            HttpMethod method = new HttpMethod(verb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var qosOptions = new QoSOptionsBuilder()
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
					            var reRoute = new DownstreamReRouteBuilder()
 | 
				
			||||||
                .WithIsQos(false)
 | 
					                .WithQosOptions(qosOptions)
 | 
				
			||||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false))
 | 
					                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false))
 | 
				
			||||||
                .WithReRouteKey("")
 | 
					                .WithLoadBalancerKey("")
 | 
				
			||||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
					                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -47,10 +47,13 @@ namespace Ocelot.UnitTests.Requester
 | 
				
			|||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_call_request_correctly()
 | 
					        public void should_call_request_correctly()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            var qosOptions = new QoSOptionsBuilder()
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
					            var reRoute = new DownstreamReRouteBuilder()
 | 
				
			||||||
                .WithIsQos(false)
 | 
					                .WithQosOptions(qosOptions)
 | 
				
			||||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false))
 | 
					                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false))
 | 
				
			||||||
                .WithReRouteKey("")
 | 
					                .WithLoadBalancerKey("")
 | 
				
			||||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
					                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -70,10 +73,13 @@ namespace Ocelot.UnitTests.Requester
 | 
				
			|||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_call_request_unable_to_complete_request()
 | 
					        public void should_call_request_unable_to_complete_request()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            var qosOptions = new QoSOptionsBuilder()
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
					            var reRoute = new DownstreamReRouteBuilder()
 | 
				
			||||||
                .WithIsQos(false)
 | 
					                .WithQosOptions(qosOptions)
 | 
				
			||||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false))
 | 
					                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false))
 | 
				
			||||||
                .WithReRouteKey("")
 | 
					                .WithLoadBalancerKey("")
 | 
				
			||||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
					                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -92,10 +98,13 @@ namespace Ocelot.UnitTests.Requester
 | 
				
			|||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void http_client_request_times_out()
 | 
					        public void http_client_request_times_out()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            var qosOptions = new QoSOptionsBuilder()
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
					            var reRoute = new DownstreamReRouteBuilder()
 | 
				
			||||||
                .WithIsQos(false)
 | 
					                .WithQosOptions(qosOptions)
 | 
				
			||||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false))
 | 
					                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false))
 | 
				
			||||||
                .WithReRouteKey("")
 | 
					                .WithLoadBalancerKey("")
 | 
				
			||||||
                .WithQosOptions(new QoSOptionsBuilder().WithTimeoutValue(1).Build())
 | 
					                .WithQosOptions(new QoSOptionsBuilder().WithTimeoutValue(1).Build())
 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,9 +31,12 @@ namespace Ocelot.UnitTests.Requester
 | 
				
			|||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_return_no_qos_provider()
 | 
					        public void should_return_no_qos_provider()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            var qosOptions = new QoSOptionsBuilder()
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
					            var reRoute = new DownstreamReRouteBuilder()
 | 
				
			||||||
 | 
					                .WithQosOptions(qosOptions)
 | 
				
			||||||
                .WithUpstreamHttpMethod(new List<string> { "get" })
 | 
					                .WithUpstreamHttpMethod(new List<string> { "get" })
 | 
				
			||||||
                .WithIsQos(false)
 | 
					 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(x => x.GivenAReRoute(reRoute))
 | 
					            this.Given(x => x.GivenAReRoute(reRoute))
 | 
				
			||||||
@@ -53,7 +56,6 @@ namespace Ocelot.UnitTests.Requester
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
					            var reRoute = new DownstreamReRouteBuilder()
 | 
				
			||||||
               .WithUpstreamHttpMethod(new List<string> { "get" })
 | 
					               .WithUpstreamHttpMethod(new List<string> { "get" })
 | 
				
			||||||
               .WithIsQos(true)
 | 
					 | 
				
			||||||
               .WithQosOptions(qosOptions)
 | 
					               .WithQosOptions(qosOptions)
 | 
				
			||||||
               .Build();
 | 
					               .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,8 +25,14 @@ namespace Ocelot.UnitTests.Requester
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_store_qos_provider_on_first_request()
 | 
					        public void should_store_qos_provider_on_first_request()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var reRoute = new DownstreamReRouteBuilder().WithQosKey("test").Build();
 | 
					            var qosOptions = new QoSOptionsBuilder()
 | 
				
			||||||
 | 
					                .WithKey("test")
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var reRoute = new DownstreamReRouteBuilder()
 | 
				
			||||||
 | 
					                .WithQosOptions(qosOptions)
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(x => x.GivenThereIsAQoSProvider(reRoute, new FakeQoSProvider()))
 | 
					            this.Given(x => x.GivenThereIsAQoSProvider(reRoute, new FakeQoSProvider()))
 | 
				
			||||||
                .Then(x => x.ThenItIsAdded())
 | 
					                .Then(x => x.ThenItIsAdded())
 | 
				
			||||||
@@ -36,7 +42,13 @@ namespace Ocelot.UnitTests.Requester
 | 
				
			|||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_not_store_qos_provider_on_first_request()
 | 
					        public void should_not_store_qos_provider_on_first_request()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var reRoute = new DownstreamReRouteBuilder().WithQosKey("test").Build();
 | 
					            var qosOptions = new QoSOptionsBuilder()
 | 
				
			||||||
 | 
					                .WithKey("test")
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var reRoute = new DownstreamReRouteBuilder()
 | 
				
			||||||
 | 
					                .WithQosOptions(qosOptions)
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(x => x.GivenThereIsAQoSProvider(reRoute, new FakeQoSProvider()))
 | 
					            this.Given(x => x.GivenThereIsAQoSProvider(reRoute, new FakeQoSProvider()))
 | 
				
			||||||
                .When(x => x.WhenWeGetTheQoSProvider(reRoute))
 | 
					                .When(x => x.WhenWeGetTheQoSProvider(reRoute))
 | 
				
			||||||
@@ -47,8 +59,21 @@ namespace Ocelot.UnitTests.Requester
 | 
				
			|||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_store_qos_providers_by_key()
 | 
					        public void should_store_qos_providers_by_key()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var reRoute = new DownstreamReRouteBuilder().WithQosKey("test").Build();
 | 
					            var qosOptions = new QoSOptionsBuilder()
 | 
				
			||||||
            var reRouteTwo = new DownstreamReRouteBuilder().WithQosKey("testTwo").Build();
 | 
					                .WithKey("test")
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var qosOptionsTwo = new QoSOptionsBuilder()
 | 
				
			||||||
 | 
					                .WithKey("testTwo")
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var reRoute = new DownstreamReRouteBuilder()
 | 
				
			||||||
 | 
					                .WithQosOptions(qosOptions)
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var reRouteTwo = new DownstreamReRouteBuilder()
 | 
				
			||||||
 | 
					                .WithQosOptions(qosOptionsTwo)
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(x => x.GivenThereIsAQoSProvider(reRoute, new FakeQoSProvider()))
 | 
					            this.Given(x => x.GivenThereIsAQoSProvider(reRoute, new FakeQoSProvider()))
 | 
				
			||||||
                .And(x => x.GivenThereIsAQoSProvider(reRouteTwo, new FakePollyQoSProvider()))
 | 
					                .And(x => x.GivenThereIsAQoSProvider(reRouteTwo, new FakePollyQoSProvider()))
 | 
				
			||||||
@@ -62,7 +87,12 @@ namespace Ocelot.UnitTests.Requester
 | 
				
			|||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_return_error_if_no_qos_provider_with_key()
 | 
					        public void should_return_error_if_no_qos_provider_with_key()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var reRoute = new DownstreamReRouteBuilder().Build();
 | 
					            var qosOptions = new QoSOptionsBuilder()
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var reRoute = new DownstreamReRouteBuilder()
 | 
				
			||||||
 | 
					                .WithQosOptions(qosOptions)
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.When(x => x.WhenWeGetTheQoSProvider(reRoute))
 | 
					            this.When(x => x.WhenWeGetTheQoSProvider(reRoute))
 | 
				
			||||||
            .Then(x => x.ThenAnErrorIsReturned())
 | 
					            .Then(x => x.ThenAnErrorIsReturned())
 | 
				
			||||||
@@ -72,9 +102,24 @@ namespace Ocelot.UnitTests.Requester
 | 
				
			|||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_get_new_qos_provider_if_reroute_qos_provider_has_changed()
 | 
					        public void should_get_new_qos_provider_if_reroute_qos_provider_has_changed()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var reRoute = new DownstreamReRouteBuilder().WithQosKey("test").Build();
 | 
					            var useQoSOptions = new QoSOptionsBuilder()
 | 
				
			||||||
 | 
					                .WithTimeoutValue(1)
 | 
				
			||||||
 | 
					                .WithKey("test")
 | 
				
			||||||
 | 
					                .WithDurationOfBreak(1)
 | 
				
			||||||
 | 
					                .WithExceptionsAllowedBeforeBreaking(1)
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var reRouteTwo = new DownstreamReRouteBuilder().WithQosKey("test").WithIsQos(true).Build();
 | 
					            var dontUseQoSOptions = new QoSOptionsBuilder()
 | 
				
			||||||
 | 
					                .WithKey("test")
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var reRoute = new DownstreamReRouteBuilder()
 | 
				
			||||||
 | 
					                .WithQosOptions(dontUseQoSOptions)
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var reRouteTwo = new DownstreamReRouteBuilder()
 | 
				
			||||||
 | 
					                .WithQosOptions(useQoSOptions)
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.Given(x => x.GivenThereIsAQoSProvider(reRoute, new FakeQoSProvider()))
 | 
					            this.Given(x => x.GivenThereIsAQoSProvider(reRoute, new FakeQoSProvider()))
 | 
				
			||||||
                .When(x => x.WhenWeGetTheQoSProvider(reRoute))
 | 
					                .When(x => x.WhenWeGetTheQoSProvider(reRoute))
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user