mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-11-04 10:35:28 +08:00 
			
		
		
		
	Feature/expose http handlers (#224)
* temp commit * trying to work out how to expose the http handlers in a decent way.. * pissing about at lunch * changed to func so you can instanciate object or new it up each time * docs for dele handlers * upgraded to sdk 2.1.4 * some validation for consul services
This commit is contained in:
		
							
								
								
									
										43
									
								
								docs/features/delegatinghandlers.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								docs/features/delegatinghandlers.rst
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					Delegating Handers
 | 
				
			||||||
 | 
					==================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Ocelot allows the user to add delegating handlers to the HttpClient transport. This feature was requested `GitHub #208 <https://github.com/TomPallister/Ocelot/issues/208>`_ and I decided that it was going to be useful in various ways.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Usage
 | 
				
			||||||
 | 
					^^^^^^
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In order to add delegating handlers to the HttpClient transport you need to do the following.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code-block:: csharp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    services.AddOcelot()
 | 
				
			||||||
 | 
					            .AddDelegatingHandler(() => new FakeHandler())
 | 
				
			||||||
 | 
					            .AddDelegatingHandler(() => new FakeHandler());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Or for singleton like behaviour..
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code-block:: csharp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var handlerOne = new FakeHandler();
 | 
				
			||||||
 | 
					    var handlerTwo = new FakeHandler();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    services.AddOcelot()
 | 
				
			||||||
 | 
					            .AddDelegatingHandler(() => handlerOne)
 | 
				
			||||||
 | 
					            .AddDelegatingHandler(() => handlerTwo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You can have as many DelegatingHandlers as you want and they are run in a first in first out order. If you are using Ocelot's QoS functionality then that will always be run after your last delegating handler.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In order to create a class that can be used a delegating handler it must look as follows
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code-block:: csharp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public class FakeHandler : DelegatingHandler
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            //do stuff and optionally call the base handler..
 | 
				
			||||||
 | 
					            return await base.SendAsync(request, cancellationToken);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Hopefully other people will find this feature useful!
 | 
				
			||||||
@@ -33,6 +33,8 @@ Thanks for taking a look at the Ocelot documentation. Please use the left hand n
 | 
				
			|||||||
   features/requestid
 | 
					   features/requestid
 | 
				
			||||||
   features/middlewareinjection
 | 
					   features/middlewareinjection
 | 
				
			||||||
   features/loadbalancer
 | 
					   features/loadbalancer
 | 
				
			||||||
 | 
					   features/delegatinghandlers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. toctree::
 | 
					.. toctree::
 | 
				
			||||||
   :maxdepth: 2
 | 
					   :maxdepth: 2
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "projects": [ "src", "test" ],
 | 
					  "projects": [ "src", "test" ],
 | 
				
			||||||
  "sdk": {
 | 
					  "sdk": {
 | 
				
			||||||
    "version": "2.0.2"
 | 
					    "version": "2.1.4"
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					namespace Ocelot.DependencyInjection
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public interface IOcelotAdministrationBuilder
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        IOcelotAdministrationBuilder AddRafty();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
using Butterfly.Client.AspNetCore;
 | 
					using Butterfly.Client.AspNetCore;
 | 
				
			||||||
using CacheManager.Core;
 | 
					using CacheManager.Core;
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Net.Http;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Ocelot.DependencyInjection
 | 
					namespace Ocelot.DependencyInjection
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -10,5 +11,6 @@ namespace Ocelot.DependencyInjection
 | 
				
			|||||||
        IOcelotBuilder AddCacheManager(Action<ConfigurationBuilderCachePart> settings);
 | 
					        IOcelotBuilder AddCacheManager(Action<ConfigurationBuilderCachePart> settings);
 | 
				
			||||||
        IOcelotBuilder AddOpenTracing(Action<ButterflyOptions> settings);      
 | 
					        IOcelotBuilder AddOpenTracing(Action<ButterflyOptions> settings);      
 | 
				
			||||||
        IOcelotAdministrationBuilder AddAdministration(string path, string secret);
 | 
					        IOcelotAdministrationBuilder AddAdministration(string path, string secret);
 | 
				
			||||||
 | 
					        IOcelotBuilder AddDelegatingHandler(Func<DelegatingHandler> delegatingHandler);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					using Microsoft.Extensions.Configuration;
 | 
				
			||||||
 | 
					using Microsoft.Extensions.DependencyInjection;
 | 
				
			||||||
 | 
					using Ocelot.Raft;
 | 
				
			||||||
 | 
					using Rafty.Concensus;
 | 
				
			||||||
 | 
					using Rafty.FiniteStateMachine;
 | 
				
			||||||
 | 
					using Rafty.Infrastructure;
 | 
				
			||||||
 | 
					using Rafty.Log;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ocelot.DependencyInjection
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class OcelotAdministrationBuilder : IOcelotAdministrationBuilder
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private readonly IServiceCollection _services;
 | 
				
			||||||
 | 
					        private readonly IConfiguration _configurationRoot;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        public OcelotAdministrationBuilder(IServiceCollection services, IConfiguration configurationRoot)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _configurationRoot = configurationRoot;
 | 
				
			||||||
 | 
					            _services = services;    
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        public IOcelotAdministrationBuilder AddRafty()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var settings = new InMemorySettings(4000, 5000, 100, 5000);
 | 
				
			||||||
 | 
					            _services.AddSingleton<ILog, SqlLiteLog>();
 | 
				
			||||||
 | 
					            _services.AddSingleton<IFiniteStateMachine, OcelotFiniteStateMachine>();
 | 
				
			||||||
 | 
					            _services.AddSingleton<ISettings>(settings);
 | 
				
			||||||
 | 
					            _services.AddSingleton<IPeersProvider, FilePeersProvider>();
 | 
				
			||||||
 | 
					            _services.AddSingleton<INode, Node>();
 | 
				
			||||||
 | 
					            _services.Configure<FilePeers>(_configurationRoot);
 | 
				
			||||||
 | 
					            return this;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,19 +1,12 @@
 | 
				
			|||||||
using Butterfly.Client.AspNetCore;
 | 
					 | 
				
			||||||
using CacheManager.Core;
 | 
					using CacheManager.Core;
 | 
				
			||||||
using IdentityServer4.AccessTokenValidation;
 | 
					 | 
				
			||||||
using IdentityServer4.Models;
 | 
					using IdentityServer4.Models;
 | 
				
			||||||
using Microsoft.AspNetCore.Builder;
 | 
					 | 
				
			||||||
using Microsoft.AspNetCore.Hosting;
 | 
					 | 
				
			||||||
using Microsoft.AspNetCore.Http;
 | 
					using Microsoft.AspNetCore.Http;
 | 
				
			||||||
using Microsoft.Extensions.Configuration;
 | 
					using Microsoft.Extensions.Configuration;
 | 
				
			||||||
using Microsoft.Extensions.DependencyInjection;
 | 
					using Microsoft.Extensions.DependencyInjection;
 | 
				
			||||||
using Microsoft.Extensions.DependencyInjection.Extensions;
 | 
					 | 
				
			||||||
using Ocelot.Authorisation;
 | 
					using Ocelot.Authorisation;
 | 
				
			||||||
using Ocelot.Cache;
 | 
					using Ocelot.Cache;
 | 
				
			||||||
using Ocelot.Claims;
 | 
					using Ocelot.Claims;
 | 
				
			||||||
using Ocelot.Configuration;
 | 
					 | 
				
			||||||
using Ocelot.Configuration.Authentication;
 | 
					using Ocelot.Configuration.Authentication;
 | 
				
			||||||
using Ocelot.Configuration.Builder;
 | 
					 | 
				
			||||||
using Ocelot.Configuration.Creator;
 | 
					using Ocelot.Configuration.Creator;
 | 
				
			||||||
using Ocelot.Configuration.File;
 | 
					using Ocelot.Configuration.File;
 | 
				
			||||||
using Ocelot.Configuration.Parser;
 | 
					using Ocelot.Configuration.Parser;
 | 
				
			||||||
@@ -32,7 +25,6 @@ using Ocelot.LoadBalancer.LoadBalancers;
 | 
				
			|||||||
using Ocelot.Logging;
 | 
					using Ocelot.Logging;
 | 
				
			||||||
using Ocelot.Middleware;
 | 
					using Ocelot.Middleware;
 | 
				
			||||||
using Ocelot.QueryStrings;
 | 
					using Ocelot.QueryStrings;
 | 
				
			||||||
using Ocelot.Raft;
 | 
					 | 
				
			||||||
using Ocelot.RateLimit;
 | 
					using Ocelot.RateLimit;
 | 
				
			||||||
using Ocelot.Request.Builder;
 | 
					using Ocelot.Request.Builder;
 | 
				
			||||||
using Ocelot.Request.Mapper;
 | 
					using Ocelot.Request.Mapper;
 | 
				
			||||||
@@ -40,24 +32,29 @@ using Ocelot.Requester;
 | 
				
			|||||||
using Ocelot.Requester.QoS;
 | 
					using Ocelot.Requester.QoS;
 | 
				
			||||||
using Ocelot.Responder;
 | 
					using Ocelot.Responder;
 | 
				
			||||||
using Ocelot.ServiceDiscovery;
 | 
					using Ocelot.ServiceDiscovery;
 | 
				
			||||||
using Rafty.Concensus;
 | 
					 | 
				
			||||||
using Rafty.FiniteStateMachine;
 | 
					 | 
				
			||||||
using Rafty.Infrastructure;
 | 
					 | 
				
			||||||
using Rafty.Log;
 | 
					 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.IdentityModel.Tokens.Jwt;
 | 
					using System.IdentityModel.Tokens.Jwt;
 | 
				
			||||||
using System.Linq;
 | 
					 | 
				
			||||||
using System.Reflection;
 | 
					using System.Reflection;
 | 
				
			||||||
using System.Security.Cryptography.X509Certificates;
 | 
					using System.Security.Cryptography.X509Certificates;
 | 
				
			||||||
 | 
					using IdentityServer4.AccessTokenValidation;
 | 
				
			||||||
 | 
					using Microsoft.AspNetCore.Builder;
 | 
				
			||||||
 | 
					using Microsoft.AspNetCore.Hosting;
 | 
				
			||||||
 | 
					using Ocelot.Configuration;
 | 
				
			||||||
 | 
					using Ocelot.Configuration.Builder;
 | 
				
			||||||
using FileConfigurationProvider = Ocelot.Configuration.Provider.FileConfigurationProvider;
 | 
					using FileConfigurationProvider = Ocelot.Configuration.Provider.FileConfigurationProvider;
 | 
				
			||||||
 | 
					using Microsoft.Extensions.DependencyInjection.Extensions;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Net.Http;
 | 
				
			||||||
 | 
					using Butterfly.Client.AspNetCore;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Ocelot.DependencyInjection
 | 
					namespace Ocelot.DependencyInjection
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public class OcelotBuilder : IOcelotBuilder
 | 
					    public class OcelotBuilder : IOcelotBuilder
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private IServiceCollection _services;
 | 
					        private readonly IServiceCollection _services;
 | 
				
			||||||
        private IConfiguration _configurationRoot;
 | 
					        private readonly IConfiguration _configurationRoot;
 | 
				
			||||||
 | 
					        private IDelegatingHandlerHandlerProvider _provider;
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        public OcelotBuilder(IServiceCollection services, IConfiguration configurationRoot)
 | 
					        public OcelotBuilder(IServiceCollection services, IConfiguration configurationRoot)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -122,6 +119,9 @@ namespace Ocelot.DependencyInjection
 | 
				
			|||||||
            _services.TryAddSingleton<IRequestMapper, RequestMapper>();
 | 
					            _services.TryAddSingleton<IRequestMapper, RequestMapper>();
 | 
				
			||||||
            _services.TryAddSingleton<IHttpHandlerOptionsCreator, HttpHandlerOptionsCreator>();
 | 
					            _services.TryAddSingleton<IHttpHandlerOptionsCreator, HttpHandlerOptionsCreator>();
 | 
				
			||||||
            _services.TryAddSingleton<IDownstreamAddressesCreator, DownstreamAddressesCreator>();
 | 
					            _services.TryAddSingleton<IDownstreamAddressesCreator, DownstreamAddressesCreator>();
 | 
				
			||||||
 | 
					            _services.TryAddSingleton<IDelegatingHandlerHandlerProviderFactory, DelegatingHandlerHandlerProviderFactory>();
 | 
				
			||||||
 | 
					            _services.TryAddSingleton<IDelegatingHandlerHandlerHouse, DelegatingHandlerHandlerHouse>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // see this for why we register this as singleton http://stackoverflow.com/questions/37371264/invalidoperationexception-unable-to-resolve-service-for-type-microsoft-aspnetc
 | 
					            // see this for why we register this as singleton http://stackoverflow.com/questions/37371264/invalidoperationexception-unable-to-resolve-service-for-type-microsoft-aspnetc
 | 
				
			||||||
            // could maybe use a scoped data repository
 | 
					            // could maybe use a scoped data repository
 | 
				
			||||||
            _services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
 | 
					            _services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
 | 
				
			||||||
@@ -142,6 +142,11 @@ namespace Ocelot.DependencyInjection
 | 
				
			|||||||
            _services.AddMiddlewareAnalysis();
 | 
					            _services.AddMiddlewareAnalysis();
 | 
				
			||||||
            _services.AddWebEncoders();
 | 
					            _services.AddWebEncoders();
 | 
				
			||||||
            _services.AddSingleton<IAdministrationPath>(new NullAdministrationPath());
 | 
					            _services.AddSingleton<IAdministrationPath>(new NullAdministrationPath());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            //these get picked out later and added to http request
 | 
				
			||||||
 | 
					            _provider = new DelegatingHandlerHandlerProvider();
 | 
				
			||||||
 | 
					            _services.TryAddSingleton<IDelegatingHandlerHandlerProvider>(_provider);
 | 
				
			||||||
 | 
					            _services.AddTransient<ITracingHandler, NoTracingHandler>();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public IOcelotAdministrationBuilder AddAdministration(string path, string secret)
 | 
					        public IOcelotAdministrationBuilder AddAdministration(string path, string secret)
 | 
				
			||||||
@@ -161,6 +166,19 @@ namespace Ocelot.DependencyInjection
 | 
				
			|||||||
            return new OcelotAdministrationBuilder(_services, _configurationRoot);
 | 
					            return new OcelotAdministrationBuilder(_services, _configurationRoot);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public IOcelotBuilder AddDelegatingHandler(Func<DelegatingHandler> delegatingHandler)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _provider.Add(delegatingHandler);
 | 
				
			||||||
 | 
					            return this;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public IOcelotBuilder AddOpenTracing(Action<ButterflyOptions> settings)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _services.AddTransient<ITracingHandler, OcelotHttpTracingHandler>();
 | 
				
			||||||
 | 
					            _services.AddButterfly(settings);   
 | 
				
			||||||
 | 
					            return this;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public IOcelotBuilder AddStoreOcelotConfigurationInConsul()
 | 
					        public IOcelotBuilder AddStoreOcelotConfigurationInConsul()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var serviceDiscoveryPort = _configurationRoot.GetValue("GlobalConfiguration:ServiceDiscoveryProvider:Port", 0);
 | 
					            var serviceDiscoveryPort = _configurationRoot.GetValue("GlobalConfiguration:ServiceDiscoveryProvider:Port", 0);
 | 
				
			||||||
@@ -203,13 +221,6 @@ namespace Ocelot.DependencyInjection
 | 
				
			|||||||
            return this;
 | 
					            return this;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public IOcelotBuilder AddOpenTracing(Action<ButterflyOptions> settings)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            _services.AddTransient<OcelotHttpTracingHandler>();
 | 
					 | 
				
			||||||
            _services.AddButterfly(settings);   
 | 
					 | 
				
			||||||
            return this;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        private void AddIdentityServer(IIdentityServerConfiguration identityServerConfiguration, IAdministrationPath adminPath) 
 | 
					        private void AddIdentityServer(IIdentityServerConfiguration identityServerConfiguration, IAdministrationPath adminPath) 
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _services.TryAddSingleton<IIdentityServerConfiguration>(identityServerConfiguration);
 | 
					            _services.TryAddSingleton<IIdentityServerConfiguration>(identityServerConfiguration);
 | 
				
			||||||
@@ -281,33 +292,4 @@ namespace Ocelot.DependencyInjection
 | 
				
			|||||||
            };
 | 
					            };
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    public interface IOcelotAdministrationBuilder
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        IOcelotAdministrationBuilder AddRafty();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public class OcelotAdministrationBuilder : IOcelotAdministrationBuilder
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        private IServiceCollection _services;
 | 
					 | 
				
			||||||
        private IConfiguration _configurationRoot;
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        public OcelotAdministrationBuilder(IServiceCollection services, IConfiguration configurationRoot)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            _configurationRoot = configurationRoot;
 | 
					 | 
				
			||||||
            _services = services;    
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        public IOcelotAdministrationBuilder AddRafty()
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            var settings = new InMemorySettings(4000, 5000, 100, 5000);
 | 
					 | 
				
			||||||
            _services.AddSingleton<ILog, SqlLiteLog>();
 | 
					 | 
				
			||||||
            _services.AddSingleton<IFiniteStateMachine, OcelotFiniteStateMachine>();
 | 
					 | 
				
			||||||
            _services.AddSingleton<ISettings>(settings);
 | 
					 | 
				
			||||||
            _services.AddSingleton<IPeersProvider, FilePeersProvider>();
 | 
					 | 
				
			||||||
            _services.AddSingleton<INode, Node>();
 | 
					 | 
				
			||||||
            _services.Configure<FilePeers>(_configurationRoot);
 | 
					 | 
				
			||||||
            return this;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,6 @@
 | 
				
			|||||||
using System;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					 | 
				
			||||||
using System.Linq;
 | 
					using System.Linq;
 | 
				
			||||||
using System.Threading.Tasks;
 | 
					 | 
				
			||||||
using Ocelot.Configuration;
 | 
					using Ocelot.Configuration;
 | 
				
			||||||
using Ocelot.Configuration.Provider;
 | 
					 | 
				
			||||||
using Ocelot.DownstreamRouteFinder.UrlMatcher;
 | 
					using Ocelot.DownstreamRouteFinder.UrlMatcher;
 | 
				
			||||||
using Ocelot.Errors;
 | 
					using Ocelot.Errors;
 | 
				
			||||||
using Ocelot.Responses;
 | 
					using Ocelot.Responses;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -62,7 +62,7 @@ namespace Ocelot.Errors.Middleware
 | 
				
			|||||||
        private async Task TrySetGlobalRequestId(HttpContext context)
 | 
					        private async Task TrySetGlobalRequestId(HttpContext context)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
                //try and get the global request id and set it for logs...
 | 
					                //try and get the global request id and set it for logs...
 | 
				
			||||||
                //shoudl this basically be immutable per request...i guess it should!
 | 
					                //should this basically be immutable per request...i guess it should!
 | 
				
			||||||
                //first thing is get config
 | 
					                //first thing is get config
 | 
				
			||||||
                 var configuration = await _configProvider.Get(); 
 | 
					                 var configuration = await _configProvider.Get(); 
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,6 +33,7 @@
 | 
				
			|||||||
        UnmappableRequestError,
 | 
					        UnmappableRequestError,
 | 
				
			||||||
        RateLimitOptionsError,
 | 
					        RateLimitOptionsError,
 | 
				
			||||||
        PathTemplateDoesntStartWithForwardSlash,
 | 
					        PathTemplateDoesntStartWithForwardSlash,
 | 
				
			||||||
        FileValidationFailedError
 | 
					        FileValidationFailedError,
 | 
				
			||||||
 | 
					        UnableToFindDelegatingHandlerProviderError
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,6 @@
 | 
				
			|||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Threading.Tasks;
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
using Microsoft.AspNetCore.Http;
 | 
					using Microsoft.AspNetCore.Http;
 | 
				
			||||||
using Ocelot.Configuration.Provider;
 | 
					 | 
				
			||||||
using Ocelot.Infrastructure.RequestData;
 | 
					using Ocelot.Infrastructure.RequestData;
 | 
				
			||||||
using Ocelot.LoadBalancer.LoadBalancers;
 | 
					using Ocelot.LoadBalancer.LoadBalancers;
 | 
				
			||||||
using Ocelot.Logging;
 | 
					using Ocelot.Logging;
 | 
				
			||||||
@@ -46,11 +45,14 @@ namespace Ocelot.LoadBalancer.Middleware
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var uriBuilder = new UriBuilder(DownstreamRequest.RequestUri);
 | 
					            var uriBuilder = new UriBuilder(DownstreamRequest.RequestUri);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            uriBuilder.Host = hostAndPort.Data.DownstreamHost;
 | 
					            uriBuilder.Host = hostAndPort.Data.DownstreamHost;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (hostAndPort.Data.DownstreamPort > 0)
 | 
					            if (hostAndPort.Data.DownstreamPort > 0)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                uriBuilder.Port = hostAndPort.Data.DownstreamPort;
 | 
					                uriBuilder.Port = hostAndPort.Data.DownstreamPort;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            DownstreamRequest.RequestUri = uriBuilder.Uri;
 | 
					            DownstreamRequest.RequestUri = uriBuilder.Uri;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            try
 | 
					            try
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,9 +13,10 @@ namespace Ocelot.Request.Builder
 | 
				
			|||||||
            IQoSProvider qosProvider,
 | 
					            IQoSProvider qosProvider,
 | 
				
			||||||
            bool useCookieContainer,
 | 
					            bool useCookieContainer,
 | 
				
			||||||
            bool allowAutoRedirect,
 | 
					            bool allowAutoRedirect,
 | 
				
			||||||
 | 
					            string reRouteKey,
 | 
				
			||||||
            bool isTracing)
 | 
					            bool isTracing)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return new OkResponse<Request>(new Request(httpRequestMessage, isQos, qosProvider, allowAutoRedirect, useCookieContainer, isTracing));
 | 
					             return new OkResponse<Request>(new Request(httpRequestMessage, isQos, qosProvider, allowAutoRedirect, useCookieContainer, reRouteKey, isTracing));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,6 +14,7 @@
 | 
				
			|||||||
            IQoSProvider qosProvider,
 | 
					            IQoSProvider qosProvider,
 | 
				
			||||||
            bool useCookieContainer,
 | 
					            bool useCookieContainer,
 | 
				
			||||||
            bool allowAutoRedirect,
 | 
					            bool allowAutoRedirect,
 | 
				
			||||||
 | 
					            string reRouteKe,
 | 
				
			||||||
            bool isTracing);
 | 
					            bool isTracing);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -47,7 +47,9 @@ namespace Ocelot.Request.Middleware
 | 
				
			|||||||
                    qosProvider.Data,
 | 
					                    qosProvider.Data,
 | 
				
			||||||
                    DownstreamRoute.ReRoute.HttpHandlerOptions.UseCookieContainer,
 | 
					                    DownstreamRoute.ReRoute.HttpHandlerOptions.UseCookieContainer,
 | 
				
			||||||
                    DownstreamRoute.ReRoute.HttpHandlerOptions.AllowAutoRedirect,
 | 
					                    DownstreamRoute.ReRoute.HttpHandlerOptions.AllowAutoRedirect,
 | 
				
			||||||
 | 
					                    DownstreamRoute.ReRoute.ReRouteKey,
 | 
				
			||||||
                    DownstreamRoute.ReRoute.HttpHandlerOptions.UseTracing);
 | 
					                    DownstreamRoute.ReRoute.HttpHandlerOptions.UseTracing);
 | 
				
			||||||
 | 
					                    
 | 
				
			||||||
            if (buildResult.IsError)
 | 
					            if (buildResult.IsError)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                _logger.LogDebug("IRequestCreator returned an error, setting pipeline error");
 | 
					                _logger.LogDebug("IRequestCreator returned an error, setting pipeline error");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,6 +11,7 @@ namespace Ocelot.Request
 | 
				
			|||||||
            IQoSProvider qosProvider, 
 | 
					            IQoSProvider qosProvider, 
 | 
				
			||||||
            bool allowAutoRedirect,
 | 
					            bool allowAutoRedirect,
 | 
				
			||||||
            bool useCookieContainer,
 | 
					            bool useCookieContainer,
 | 
				
			||||||
 | 
					            string reRouteKey,
 | 
				
			||||||
            bool isTracing
 | 
					            bool isTracing
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -19,6 +20,7 @@ namespace Ocelot.Request
 | 
				
			|||||||
            QosProvider = qosProvider;
 | 
					            QosProvider = qosProvider;
 | 
				
			||||||
            AllowAutoRedirect = allowAutoRedirect;
 | 
					            AllowAutoRedirect = allowAutoRedirect;
 | 
				
			||||||
            UseCookieContainer = useCookieContainer;
 | 
					            UseCookieContainer = useCookieContainer;
 | 
				
			||||||
 | 
					            ReRouteKey = reRouteKey;
 | 
				
			||||||
            IsTracing = isTracing;
 | 
					            IsTracing = isTracing;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -28,5 +30,6 @@ namespace Ocelot.Request
 | 
				
			|||||||
        public IQoSProvider QosProvider { get; private set; }
 | 
					        public IQoSProvider QosProvider { get; private set; }
 | 
				
			||||||
        public bool AllowAutoRedirect { get; private set; }
 | 
					        public bool AllowAutoRedirect { get; private set; }
 | 
				
			||||||
        public bool UseCookieContainer { get; private set; }
 | 
					        public bool UseCookieContainer { get; private set; }
 | 
				
			||||||
 | 
					        public string ReRouteKey { get; private set; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										49
									
								
								src/Ocelot/Requester/DelegatingHandlerHandlerHouse.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								src/Ocelot/Requester/DelegatingHandlerHandlerHouse.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,49 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Concurrent;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using Ocelot.Errors;
 | 
				
			||||||
 | 
					using Ocelot.Responses;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ocelot.Requester
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class DelegatingHandlerHandlerHouse : IDelegatingHandlerHandlerHouse
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private readonly IDelegatingHandlerHandlerProviderFactory _factory;
 | 
				
			||||||
 | 
					        private readonly ConcurrentDictionary<string, IDelegatingHandlerHandlerProvider> _housed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public DelegatingHandlerHandlerHouse(IDelegatingHandlerHandlerProviderFactory factory)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _factory = factory;
 | 
				
			||||||
 | 
					            _housed = new ConcurrentDictionary<string, IDelegatingHandlerHandlerProvider>();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public Response<IDelegatingHandlerHandlerProvider> Get(Request.Request request)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (_housed.TryGetValue(request.ReRouteKey, out var provider))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    //todo once day we might need a check here to see if we need to create a new provider
 | 
				
			||||||
 | 
					                    provider = _housed[request.ReRouteKey];
 | 
				
			||||||
 | 
					                    return new OkResponse<IDelegatingHandlerHandlerProvider>(provider);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                provider = _factory.Get(request);
 | 
				
			||||||
 | 
					                AddHoused(request.ReRouteKey, provider);
 | 
				
			||||||
 | 
					                return new OkResponse<IDelegatingHandlerHandlerProvider>(provider);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (Exception ex)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return new ErrorResponse<IDelegatingHandlerHandlerProvider>(new List<Error>()
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    new UnableToFindDelegatingHandlerProviderError($"unabe to find delegating handler provider for {request.ReRouteKey} exception is {ex}")
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void AddHoused(string key, IDelegatingHandlerHandlerProvider provider)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _housed.AddOrUpdate(key, provider, (k, v) => provider);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										28
									
								
								src/Ocelot/Requester/DelegatingHandlerHandlerProvider.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/Ocelot/Requester/DelegatingHandlerHandlerProvider.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Net.Http;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ocelot.Requester
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class DelegatingHandlerHandlerProvider : IDelegatingHandlerHandlerProvider
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private readonly Dictionary<int, Func<DelegatingHandler>> _handlers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public DelegatingHandlerHandlerProvider()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _handlers = new Dictionary<int, Func<DelegatingHandler>>();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public void Add(Func<DelegatingHandler> handler)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var key = _handlers.Count == 0 ? 0 : _handlers.Count + 1;
 | 
				
			||||||
 | 
					            _handlers[key] = handler;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public List<Func<DelegatingHandler>> Get()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return _handlers.Count > 0 ? _handlers.OrderBy(x => x.Key).Select(x => x.Value).ToList() : new List<Func<DelegatingHandler>>();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					using System.Net.Http;
 | 
				
			||||||
 | 
					using Ocelot.Logging;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ocelot.Requester
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class DelegatingHandlerHandlerProviderFactory : IDelegatingHandlerHandlerProviderFactory
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private readonly ITracingHandler _tracingHandler;
 | 
				
			||||||
 | 
					        private readonly IOcelotLoggerFactory _loggerFactory;
 | 
				
			||||||
 | 
					        private readonly IDelegatingHandlerHandlerProvider _allRoutesProvider;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public DelegatingHandlerHandlerProviderFactory(IOcelotLoggerFactory loggerFactory, IDelegatingHandlerHandlerProvider allRoutesProvider, ITracingHandler tracingHandler)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _tracingHandler = tracingHandler;
 | 
				
			||||||
 | 
					            _loggerFactory = loggerFactory;
 | 
				
			||||||
 | 
					            _allRoutesProvider = allRoutesProvider;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public IDelegatingHandlerHandlerProvider Get(Request.Request request)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var handlersAppliedToAll = _allRoutesProvider.Get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var provider = new DelegatingHandlerHandlerProvider();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            foreach (var handler in handlersAppliedToAll)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                provider.Add(handler);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (request.IsTracing)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                provider.Add(() => (DelegatingHandler)_tracingHandler);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (request.IsQos)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                provider.Add(() => new PollyCircuitBreakingDelegatingHandler(request.QosProvider, _loggerFactory));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return provider;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,48 +1,33 @@
 | 
				
			|||||||
using Microsoft.Extensions.DependencyInjection;
 | 
					using System.Linq;
 | 
				
			||||||
using Ocelot.Logging;
 | 
					 | 
				
			||||||
using Ocelot.Requester.QoS;
 | 
					 | 
				
			||||||
using System;
 | 
					 | 
				
			||||||
using System.Collections.Generic;
 | 
					 | 
				
			||||||
using System.Linq;
 | 
					 | 
				
			||||||
using System.Net.Http;
 | 
					using System.Net.Http;
 | 
				
			||||||
using System.Threading.Tasks;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Ocelot.Requester
 | 
					namespace Ocelot.Requester
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    internal class HttpClientBuilder : IHttpClientBuilder
 | 
					    public class HttpClientBuilder : IHttpClientBuilder
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private readonly Dictionary<int, Func<DelegatingHandler>> _handlers = new Dictionary<int, Func<DelegatingHandler>>();
 | 
					        private readonly IDelegatingHandlerHandlerHouse _house;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public  IHttpClientBuilder WithQos(IQoSProvider qosProvider, IOcelotLogger logger)
 | 
					        public HttpClientBuilder(IDelegatingHandlerHandlerHouse house)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _handlers.Add(5000, () => new PollyCircuitBreakingDelegatingHandler(qosProvider, logger));
 | 
					            _house = house;
 | 
				
			||||||
 | 
					 | 
				
			||||||
            return this;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private IHttpClientBuilder WithTracing(IServiceProvider provider)
 | 
					        public IHttpClient Create(Request.Request request)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _handlers.Add(6000, () => provider.GetService<OcelotHttpTracingHandler>());
 | 
					            var httpclientHandler = new HttpClientHandler { AllowAutoRedirect = request.AllowAutoRedirect, UseCookies = request.UseCookieContainer};
 | 
				
			||||||
            return this;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
        public IHttpClient Create(bool useCookies, bool allowAutoRedirect, bool isTracing, IServiceProvider provider)
 | 
					            var client = new HttpClient(CreateHttpMessageHandler(httpclientHandler, request));                
 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            var httpclientHandler = new HttpClientHandler { AllowAutoRedirect = allowAutoRedirect, UseCookies = useCookies };
 | 
					 | 
				
			||||||
            if (isTracing)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                WithTracing(provider);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            var client = new HttpClient(CreateHttpMessageHandler(httpclientHandler));                
 | 
					 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
            return new HttpClientWrapper(client);
 | 
					            return new HttpClientWrapper(client);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private HttpMessageHandler CreateHttpMessageHandler(HttpMessageHandler httpMessageHandler)
 | 
					        private HttpMessageHandler CreateHttpMessageHandler(HttpMessageHandler httpMessageHandler, Request.Request request)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _handlers
 | 
					            var provider = _house.Get(request);
 | 
				
			||||||
                .OrderByDescending(handler => handler.Key)
 | 
					
 | 
				
			||||||
                .Select(handler => handler.Value)
 | 
					            //todo handle error
 | 
				
			||||||
 | 
					            provider.Data.Get()
 | 
				
			||||||
 | 
					                .Select(handler => handler)
 | 
				
			||||||
                .Reverse()
 | 
					                .Reverse()
 | 
				
			||||||
                .ToList()
 | 
					                .ToList()
 | 
				
			||||||
                .ForEach(handler =>
 | 
					                .ForEach(handler =>
 | 
				
			||||||
@@ -54,22 +39,4 @@ namespace Ocelot.Requester
 | 
				
			|||||||
            return httpMessageHandler;
 | 
					            return httpMessageHandler;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// <summary>
 | 
					 | 
				
			||||||
    /// This class was made to make unit testing easier when HttpClient is used.
 | 
					 | 
				
			||||||
    /// </summary>
 | 
					 | 
				
			||||||
    internal class HttpClientWrapper : IHttpClient
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        public HttpClient Client { get; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public HttpClientWrapper(HttpClient client)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            Client = client;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return Client.SendAsync(request);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -1,8 +1,6 @@
 | 
				
			|||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections.Concurrent;
 | 
					 | 
				
			||||||
using System.Net.Http;
 | 
					using System.Net.Http;
 | 
				
			||||||
using System.Threading.Tasks;
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
using Ocelot.Configuration;
 | 
					 | 
				
			||||||
using Ocelot.Logging;
 | 
					using Ocelot.Logging;
 | 
				
			||||||
using Ocelot.Responses;
 | 
					using Ocelot.Responses;
 | 
				
			||||||
using Polly.CircuitBreaker;
 | 
					using Polly.CircuitBreaker;
 | 
				
			||||||
@@ -14,22 +12,24 @@ namespace Ocelot.Requester
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        private readonly IHttpClientCache _cacheHandlers;
 | 
					        private readonly IHttpClientCache _cacheHandlers;
 | 
				
			||||||
        private readonly IOcelotLogger _logger;
 | 
					        private readonly IOcelotLogger _logger;
 | 
				
			||||||
        private readonly IServiceProvider _serviceProvider;
 | 
					        private readonly IDelegatingHandlerHandlerHouse _house;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public HttpClientHttpRequester(IOcelotLoggerFactory loggerFactory, IHttpClientCache cacheHandlers, IServiceProvider provider)
 | 
					        public HttpClientHttpRequester(IOcelotLoggerFactory loggerFactory, 
 | 
				
			||||||
 | 
					            IHttpClientCache cacheHandlers,
 | 
				
			||||||
 | 
					            IDelegatingHandlerHandlerHouse house)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _logger = loggerFactory.CreateLogger<HttpClientHttpRequester>();
 | 
					            _logger = loggerFactory.CreateLogger<HttpClientHttpRequester>();
 | 
				
			||||||
            _cacheHandlers = cacheHandlers;
 | 
					            _cacheHandlers = cacheHandlers;
 | 
				
			||||||
            _serviceProvider = provider;
 | 
					            _house = house;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public async Task<Response<HttpResponseMessage>> GetResponse(Request.Request request)
 | 
					        public async Task<Response<HttpResponseMessage>> GetResponse(Request.Request request)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var builder = new HttpClientBuilder();
 | 
					            var builder = new HttpClientBuilder(_house);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var cacheKey = GetCacheKey(request, builder);
 | 
					            var cacheKey = GetCacheKey(request);
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
            var httpClient = GetHttpClient(cacheKey, builder, request.UseCookieContainer, request.AllowAutoRedirect, request.IsTracing);
 | 
					            var httpClient = GetHttpClient(cacheKey, builder, request);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            try
 | 
					            try
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@@ -57,24 +57,24 @@ namespace Ocelot.Requester
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private IHttpClient GetHttpClient(string cacheKey, IHttpClientBuilder builder, bool useCookieContainer, bool allowAutoRedirect,bool isTracing)
 | 
					        private IHttpClient GetHttpClient(string cacheKey, IHttpClientBuilder builder, Request.Request request)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var httpClient = _cacheHandlers.Get(cacheKey);
 | 
					            var httpClient = _cacheHandlers.Get(cacheKey);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (httpClient == null)
 | 
					            if (httpClient == null)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                httpClient = builder.Create(useCookieContainer, allowAutoRedirect, isTracing, _serviceProvider);
 | 
					                httpClient = builder.Create(request);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return httpClient;
 | 
					            return httpClient;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private string GetCacheKey(Request.Request request, IHttpClientBuilder builder)
 | 
					        private string GetCacheKey(Request.Request request)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            string baseUrl = $"{request.HttpRequestMessage.RequestUri.Scheme}://{request.HttpRequestMessage.RequestUri.Authority}";
 | 
					            var baseUrl = $"{request.HttpRequestMessage.RequestUri.Scheme}://{request.HttpRequestMessage.RequestUri.Authority}";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (request.IsQos)
 | 
					            if (request.IsQos)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                builder.WithQos(request.QosProvider, _logger);
 | 
					 | 
				
			||||||
                baseUrl = $"{baseUrl}{request.QosProvider.CircuitBreaker.CircuitBreakerPolicy.PolicyKey}";
 | 
					                baseUrl = $"{baseUrl}{request.QosProvider.CircuitBreaker.CircuitBreakerPolicy.PolicyKey}";
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
           
 | 
					           
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										23
									
								
								src/Ocelot/Requester/HttpClientWrapper.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/Ocelot/Requester/HttpClientWrapper.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					using System.Net.Http;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ocelot.Requester
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// This class was made to make unit testing easier when HttpClient is used.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    internal class HttpClientWrapper : IHttpClient
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public HttpClient Client { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public HttpClientWrapper(HttpClient client)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Client = client;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return Client.SendAsync(request);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/Ocelot/Requester/IDelegatingHandlerHandlerHouse.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/Ocelot/Requester/IDelegatingHandlerHandlerHouse.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					using Ocelot.Responses;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ocelot.Requester
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public interface IDelegatingHandlerHandlerHouse
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Response<IDelegatingHandlerHandlerProvider> Get(Request.Request request);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										12
									
								
								src/Ocelot/Requester/IDelegatingHandlerHandlerProvider.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/Ocelot/Requester/IDelegatingHandlerHandlerProvider.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Net.Http;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ocelot.Requester
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public interface IDelegatingHandlerHandlerProvider
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        void Add(Func<DelegatingHandler> handler);
 | 
				
			||||||
 | 
					        List<Func<DelegatingHandler>> Get();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					namespace Ocelot.Requester
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public interface IDelegatingHandlerHandlerProviderFactory
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        IDelegatingHandlerHandlerProvider Get(Request.Request request);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,27 +1,14 @@
 | 
				
			|||||||
using System;
 | 
					using System.Net.Http;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using Ocelot.Configuration;
 | 
				
			||||||
using System.Linq;
 | 
					 | 
				
			||||||
using System.Net.Http;
 | 
					 | 
				
			||||||
using System.Threading.Tasks;
 | 
					 | 
				
			||||||
using Ocelot.Logging;
 | 
					 | 
				
			||||||
using Ocelot.Requester.QoS;
 | 
					 | 
				
			||||||
using System.Net;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Ocelot.Requester
 | 
					namespace Ocelot.Requester
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public interface IHttpClientBuilder
 | 
					    public interface IHttpClientBuilder
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					 | 
				
			||||||
        /// <summary>
 | 
					 | 
				
			||||||
        /// Sets a PollyCircuitBreakingDelegatingHandler .
 | 
					 | 
				
			||||||
        /// </summary>
 | 
					 | 
				
			||||||
        IHttpClientBuilder WithQos(IQoSProvider qosProvider, IOcelotLogger logger);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// Creates the <see cref="HttpClient"/>
 | 
					        /// Creates the <see cref="HttpClient"/>
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        /// <param name="useCookies">Defines if http client should use cookie container</param>
 | 
					        /// <param name="request"></param>
 | 
				
			||||||
        /// <param name="allowAutoRedirect">Defines if http client should allow auto redirect</param>
 | 
					        IHttpClient Create(Request.Request request);
 | 
				
			||||||
        IHttpClient Create(bool useCookies, bool allowAutoRedirect, bool isTracing, IServiceProvider provider);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,7 +8,16 @@ using Butterfly.OpenTracing;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace Ocelot.Requester
 | 
					namespace Ocelot.Requester
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public class OcelotHttpTracingHandler : DelegatingHandler
 | 
					    public interface ITracingHandler
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public class NoTracingHandler : DelegatingHandler, ITracingHandler
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public class OcelotHttpTracingHandler : DelegatingHandler, ITracingHandler
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private readonly IServiceTracer _tracer;
 | 
					        private readonly IServiceTracer _tracer;
 | 
				
			||||||
        private const string prefix_spanId = "ot-spanId";
 | 
					        private const string prefix_spanId = "ot-spanId";
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,10 +16,10 @@ namespace Ocelot.Requester
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        public PollyCircuitBreakingDelegatingHandler(
 | 
					        public PollyCircuitBreakingDelegatingHandler(
 | 
				
			||||||
            IQoSProvider qoSProvider,
 | 
					            IQoSProvider qoSProvider,
 | 
				
			||||||
            IOcelotLogger logger)
 | 
					            IOcelotLoggerFactory loggerFactory)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _qoSProvider = qoSProvider;
 | 
					            _qoSProvider = qoSProvider;
 | 
				
			||||||
            _logger = logger;
 | 
					            _logger = loggerFactory.CreateLogger<PollyCircuitBreakingDelegatingHandler>();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
 | 
					        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					using Ocelot.Errors;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ocelot.Requester
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class UnableToFindDelegatingHandlerProviderError : Error
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public UnableToFindDelegatingHandlerProviderError(string message)
 | 
				
			||||||
 | 
					            : base(message, OcelotErrorCode.UnableToFindDelegatingHandlerProviderError)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -4,6 +4,7 @@ using System.Linq;
 | 
				
			|||||||
using System.Threading.Tasks;
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
using Consul;
 | 
					using Consul;
 | 
				
			||||||
using Ocelot.Infrastructure.Extensions;
 | 
					using Ocelot.Infrastructure.Extensions;
 | 
				
			||||||
 | 
					using Ocelot.Logging;
 | 
				
			||||||
using Ocelot.Values;
 | 
					using Ocelot.Values;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Ocelot.ServiceDiscovery
 | 
					namespace Ocelot.ServiceDiscovery
 | 
				
			||||||
@@ -11,13 +12,18 @@ namespace Ocelot.ServiceDiscovery
 | 
				
			|||||||
    public class ConsulServiceDiscoveryProvider : IServiceDiscoveryProvider
 | 
					    public class ConsulServiceDiscoveryProvider : IServiceDiscoveryProvider
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private readonly ConsulRegistryConfiguration _consulConfig;
 | 
					        private readonly ConsulRegistryConfiguration _consulConfig;
 | 
				
			||||||
 | 
					        private readonly IOcelotLogger _logger;
 | 
				
			||||||
        private readonly ConsulClient _consul;
 | 
					        private readonly ConsulClient _consul;
 | 
				
			||||||
        private const string VersionPrefix = "version-";
 | 
					        private const string VersionPrefix = "version-";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public ConsulServiceDiscoveryProvider(ConsulRegistryConfiguration consulRegistryConfiguration)
 | 
					        public ConsulServiceDiscoveryProvider(ConsulRegistryConfiguration consulRegistryConfiguration, IOcelotLoggerFactory factory)
 | 
				
			||||||
        {
 | 
					        {;
 | 
				
			||||||
 | 
					            _logger = factory.CreateLogger<ConsulServiceDiscoveryProvider>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var consulHost = string.IsNullOrEmpty(consulRegistryConfiguration?.HostName) ? "localhost" : consulRegistryConfiguration.HostName;
 | 
					            var consulHost = string.IsNullOrEmpty(consulRegistryConfiguration?.HostName) ? "localhost" : consulRegistryConfiguration.HostName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var consulPort = consulRegistryConfiguration?.Port ?? 8500;
 | 
					            var consulPort = consulRegistryConfiguration?.Port ?? 8500;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            _consulConfig = new ConsulRegistryConfiguration(consulHost, consulPort, consulRegistryConfiguration?.KeyOfServiceInConsul);
 | 
					            _consulConfig = new ConsulRegistryConfiguration(consulHost, consulPort, consulRegistryConfiguration?.KeyOfServiceInConsul);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            _consul = new ConsulClient(config =>
 | 
					            _consul = new ConsulClient(config =>
 | 
				
			||||||
@@ -30,7 +36,19 @@ namespace Ocelot.ServiceDiscovery
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            var queryResult = await _consul.Health.Service(_consulConfig.KeyOfServiceInConsul, string.Empty, true);
 | 
					            var queryResult = await _consul.Health.Service(_consulConfig.KeyOfServiceInConsul, string.Empty, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var services = queryResult.Response.Select(BuildService);
 | 
					            var services = new List<Service>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            foreach (var serviceEntry in queryResult.Response)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (IsValid(serviceEntry))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    services.Add(BuildService(serviceEntry));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    _logger.LogError($"Unable to use service Address: {serviceEntry.Service.Address} and Port: {serviceEntry.Service.Port} as it is invalid. Address must contain host only e.g. localhost and port must be greater than 0");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return services.ToList();
 | 
					            return services.ToList();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -45,6 +63,16 @@ namespace Ocelot.ServiceDiscovery
 | 
				
			|||||||
                serviceEntry.Service.Tags ?? Enumerable.Empty<string>());
 | 
					                serviceEntry.Service.Tags ?? Enumerable.Empty<string>());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private bool IsValid(ServiceEntry serviceEntry)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (serviceEntry.Service.Address.Contains("http://") || serviceEntry.Service.Address.Contains("https://") || serviceEntry.Service.Port <= 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return false;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private string GetVersionFromStrings(IEnumerable<string> strings)
 | 
					        private string GetVersionFromStrings(IEnumerable<string> strings)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return strings
 | 
					            return strings
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,19 @@
 | 
				
			|||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using Ocelot.Configuration;
 | 
					using Ocelot.Configuration;
 | 
				
			||||||
 | 
					using Ocelot.Logging;
 | 
				
			||||||
using Ocelot.Values;
 | 
					using Ocelot.Values;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Ocelot.ServiceDiscovery
 | 
					namespace Ocelot.ServiceDiscovery
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public class ServiceDiscoveryProviderFactory : IServiceDiscoveryProviderFactory
 | 
					    public class ServiceDiscoveryProviderFactory : IServiceDiscoveryProviderFactory
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					        private readonly IOcelotLoggerFactory _factory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public ServiceDiscoveryProviderFactory(IOcelotLoggerFactory factory)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _factory = factory;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public  IServiceDiscoveryProvider Get(ServiceProviderConfiguration serviceConfig, ReRoute reRoute)
 | 
					        public  IServiceDiscoveryProvider Get(ServiceProviderConfiguration serviceConfig, ReRoute reRoute)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (reRoute.UseServiceDiscovery)
 | 
					            if (reRoute.UseServiceDiscovery)
 | 
				
			||||||
@@ -28,7 +36,7 @@ namespace Ocelot.ServiceDiscovery
 | 
				
			|||||||
        private IServiceDiscoveryProvider GetServiceDiscoveryProvider(string keyOfServiceInConsul, string providerHostName, int providerPort)
 | 
					        private IServiceDiscoveryProvider GetServiceDiscoveryProvider(string keyOfServiceInConsul, string providerHostName, int providerPort)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var consulRegistryConfiguration = new ConsulRegistryConfiguration(providerHostName, providerPort, keyOfServiceInConsul);
 | 
					            var consulRegistryConfiguration = new ConsulRegistryConfiguration(providerHostName, providerPort, keyOfServiceInConsul);
 | 
				
			||||||
            return new ConsulServiceDiscoveryProvider(consulRegistryConfiguration);
 | 
					            return new ConsulServiceDiscoveryProvider(consulRegistryConfiguration, _factory);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										116
									
								
								test/Ocelot.AcceptanceTests/HttpDelegatingHandlersTests.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								test/Ocelot.AcceptanceTests/HttpDelegatingHandlersTests.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,116 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.IO;
 | 
				
			||||||
 | 
					using System.Net;
 | 
				
			||||||
 | 
					using System.Net.Http;
 | 
				
			||||||
 | 
					using System.Threading;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					using Microsoft.AspNetCore.Builder;
 | 
				
			||||||
 | 
					using Microsoft.AspNetCore.Hosting;
 | 
				
			||||||
 | 
					using Microsoft.AspNetCore.Http;
 | 
				
			||||||
 | 
					using Ocelot.Configuration.File;
 | 
				
			||||||
 | 
					using Shouldly;
 | 
				
			||||||
 | 
					using TestStack.BDDfy;
 | 
				
			||||||
 | 
					using Xunit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ocelot.AcceptanceTests
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class HttpDelegatingHandlersTests
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private IWebHost _builder;
 | 
				
			||||||
 | 
					        private readonly Steps _steps;
 | 
				
			||||||
 | 
					        private string _downstreamPath;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public HttpDelegatingHandlersTests()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _steps = new Steps();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_call_handlers()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var configuration = new FileConfiguration
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                ReRoutes = new List<FileReRoute>
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    new FileReRoute
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        DownstreamPathTemplate = "/",
 | 
				
			||||||
 | 
					                        DownstreamScheme = "http",
 | 
				
			||||||
 | 
					                        DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            new FileHostAndPort
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                Host = "localhost",
 | 
				
			||||||
 | 
					                                Port = 61879,
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        UpstreamPathTemplate = "/",
 | 
				
			||||||
 | 
					                        UpstreamHttpMethod = new List<string> { "Get" },
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var handlerOne = new FakeHandler();
 | 
				
			||||||
 | 
					            var handlerTwo = new FakeHandler();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:61879", "/", 200, "Hello from Laura"))
 | 
				
			||||||
 | 
					                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
				
			||||||
 | 
					                .And(x => _steps.GivenOcelotIsRunningWithHandlers(handlerOne, handlerTwo))
 | 
				
			||||||
 | 
					                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
				
			||||||
 | 
					                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
				
			||||||
 | 
					                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
				
			||||||
 | 
					                .And(x => ThenTheHandlersAreCalledCorrectly(handlerOne, handlerTwo))
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void ThenTheHandlersAreCalledCorrectly(FakeHandler one, FakeHandler two)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            one.TimeCalled.ShouldBeLessThan(two.TimeCalled);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        class FakeHandler : DelegatingHandler
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					            public DateTime TimeCalled { get; private set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                TimeCalled = DateTime.Now;
 | 
				
			||||||
 | 
					                return await base.SendAsync(request, cancellationToken);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode, string responseBody)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _builder = new WebHostBuilder()
 | 
				
			||||||
 | 
					                .UseUrls(baseUrl)
 | 
				
			||||||
 | 
					                .UseKestrel()
 | 
				
			||||||
 | 
					                .UseContentRoot(Directory.GetCurrentDirectory())
 | 
				
			||||||
 | 
					                .UseIISIntegration()
 | 
				
			||||||
 | 
					                .Configure(app =>
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    app.UsePathBase(basePath);
 | 
				
			||||||
 | 
					                    app.Run(async context =>
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        _downstreamPath = !string.IsNullOrEmpty(context.Request.PathBase.Value) ? context.Request.PathBase.Value : context.Request.Path.Value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if (_downstreamPath != basePath)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            context.Response.StatusCode = statusCode;
 | 
				
			||||||
 | 
					                            await context.Response.WriteAsync("downstream path didnt match base path");
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        else
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            context.Response.StatusCode = statusCode;
 | 
				
			||||||
 | 
					                            await context.Response.WriteAsync(responseBody);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            _builder.Start();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -88,6 +88,38 @@ namespace Ocelot.AcceptanceTests
 | 
				
			|||||||
            _ocelotClient = _ocelotServer.CreateClient();
 | 
					            _ocelotClient = _ocelotServer.CreateClient();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// This is annoying cos it should be in the constructor but we need to set up the file before calling startup so its a step.
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        public void GivenOcelotIsRunningWithHandlers(DelegatingHandler handlerOne, DelegatingHandler handlerTwo)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _webHostBuilder = new WebHostBuilder();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            _webHostBuilder.ConfigureServices(s =>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                s.AddSingleton(_webHostBuilder);
 | 
				
			||||||
 | 
					                s.AddOcelot()
 | 
				
			||||||
 | 
					                    .AddDelegatingHandler(() => handlerOne)
 | 
				
			||||||
 | 
					                    .AddDelegatingHandler(() => handlerTwo);
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            _webHostBuilder.ConfigureAppConfiguration((hostingContext, config) =>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
 | 
				
			||||||
 | 
					                var env = hostingContext.HostingEnvironment;
 | 
				
			||||||
 | 
					                config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
 | 
				
			||||||
 | 
					                    .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
 | 
				
			||||||
 | 
					                config.AddJsonFile("configuration.json");
 | 
				
			||||||
 | 
					                config.AddEnvironmentVariables();
 | 
				
			||||||
 | 
					            }).Configure(a =>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                a.UseOcelot().Wait();
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            _ocelotServer = new TestServer(_webHostBuilder);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            _ocelotClient = _ocelotServer.CreateClient();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// This is annoying cos it should be in the constructor but we need to set up the file before calling startup so its a step.
 | 
					        /// This is annoying cos it should be in the constructor but we need to set up the file before calling startup so its a step.
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,13 +1,7 @@
 | 
				
			|||||||
using System;
 | 
					 | 
				
			||||||
using CacheManager.Core;
 | 
					 | 
				
			||||||
using Microsoft.AspNetCore.Builder;
 | 
					using Microsoft.AspNetCore.Builder;
 | 
				
			||||||
using Microsoft.AspNetCore.Hosting;
 | 
					 | 
				
			||||||
using Microsoft.Extensions.Configuration;
 | 
					 | 
				
			||||||
using Microsoft.Extensions.DependencyInjection;
 | 
					using Microsoft.Extensions.DependencyInjection;
 | 
				
			||||||
using Microsoft.Extensions.Logging;
 | 
					 | 
				
			||||||
using Ocelot.DependencyInjection;
 | 
					using Ocelot.DependencyInjection;
 | 
				
			||||||
using Ocelot.Middleware;
 | 
					using Ocelot.Middleware;
 | 
				
			||||||
using ConfigurationBuilder = Microsoft.Extensions.Configuration.ConfigurationBuilder;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Ocelot.ManualTest
 | 
					namespace Ocelot.ManualTest
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -15,11 +9,6 @@ namespace Ocelot.ManualTest
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        public void ConfigureServices(IServiceCollection services)
 | 
					        public void ConfigureServices(IServiceCollection services)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Action<ConfigurationBuilderCachePart> settings = (x) =>
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                x.WithDictionaryHandle();
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            services.AddAuthentication()
 | 
					            services.AddAuthentication()
 | 
				
			||||||
                .AddJwtBearer("TestKey", x =>
 | 
					                .AddJwtBearer("TestKey", x =>
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@@ -28,7 +17,10 @@ namespace Ocelot.ManualTest
 | 
				
			|||||||
                });
 | 
					                });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            services.AddOcelot()
 | 
					            services.AddOcelot()
 | 
				
			||||||
                    .AddCacheManager(settings)
 | 
					                    .AddCacheManager(x =>
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        x.WithDictionaryHandle();
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
                    .AddOpenTracing(option =>
 | 
					                    .AddOpenTracing(option =>
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        option.CollectorUrl = "http://localhost:9618";
 | 
					                        option.CollectorUrl = "http://localhost:9618";
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,8 @@
 | 
				
			|||||||
using CacheManager.Core;
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Net.Http;
 | 
				
			||||||
 | 
					using CacheManager.Core;
 | 
				
			||||||
using Microsoft.AspNetCore.Hosting;
 | 
					using Microsoft.AspNetCore.Hosting;
 | 
				
			||||||
using Microsoft.AspNetCore.Hosting.Internal;
 | 
					using Microsoft.AspNetCore.Hosting.Internal;
 | 
				
			||||||
using Microsoft.Extensions.Configuration;
 | 
					using Microsoft.Extensions.Configuration;
 | 
				
			||||||
@@ -9,10 +13,9 @@ using Ocelot.Configuration.File;
 | 
				
			|||||||
using Ocelot.Configuration.Setter;
 | 
					using Ocelot.Configuration.Setter;
 | 
				
			||||||
using Ocelot.DependencyInjection;
 | 
					using Ocelot.DependencyInjection;
 | 
				
			||||||
using Ocelot.Requester;
 | 
					using Ocelot.Requester;
 | 
				
			||||||
 | 
					using Ocelot.UnitTests.Requester;
 | 
				
			||||||
using Shouldly;
 | 
					using Shouldly;
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					 | 
				
			||||||
using System.Linq;
 | 
					 | 
				
			||||||
using TestStack.BDDfy;
 | 
					using TestStack.BDDfy;
 | 
				
			||||||
using Xunit;
 | 
					using Xunit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -20,11 +23,11 @@ namespace Ocelot.UnitTests.DependencyInjection
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    public class OcelotBuilderTests
 | 
					    public class OcelotBuilderTests
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private IServiceCollection _services;
 | 
					        private readonly IServiceCollection _services;
 | 
				
			||||||
        private IServiceProvider _serviceProvider;
 | 
					        private IServiceProvider _serviceProvider;
 | 
				
			||||||
        private IConfiguration _configRoot;
 | 
					        private readonly IConfiguration _configRoot;
 | 
				
			||||||
        private IOcelotBuilder _ocelotBuilder;
 | 
					        private IOcelotBuilder _ocelotBuilder;
 | 
				
			||||||
        private int _maxRetries;
 | 
					        private readonly int _maxRetries;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public OcelotBuilderTests()
 | 
					        public OcelotBuilderTests()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -38,6 +41,19 @@ namespace Ocelot.UnitTests.DependencyInjection
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        private Exception _ex;
 | 
					        private Exception _ex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_add_delegating_handlers()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var fakeOne = new FakeDelegatingHandler(0);
 | 
				
			||||||
 | 
					            var fakeTwo = new FakeDelegatingHandler(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.Given(x => WhenISetUpOcelotServices())
 | 
				
			||||||
 | 
					                .When(x => AddDelegate(fakeOne))
 | 
				
			||||||
 | 
					                .And(x => AddDelegate(fakeTwo))
 | 
				
			||||||
 | 
					                .Then(x => ThenTheProviderIsRegisteredAndReturnsHandlers())
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_set_up_services()
 | 
					        public void should_set_up_services()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -74,7 +90,7 @@ namespace Ocelot.UnitTests.DependencyInjection
 | 
				
			|||||||
                .BDDfy();
 | 
					                .BDDfy();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
         [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_set_up_rafty()
 | 
					        public void should_set_up_rafty()
 | 
				
			||||||
        {            
 | 
					        {            
 | 
				
			||||||
            this.Given(x => WhenISetUpOcelotServices())
 | 
					            this.Given(x => WhenISetUpOcelotServices())
 | 
				
			||||||
@@ -119,6 +135,17 @@ namespace Ocelot.UnitTests.DependencyInjection
 | 
				
			|||||||
            path.Path.ShouldBe("/administration");
 | 
					            path.Path.ShouldBe("/administration");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void ThenTheProviderIsRegisteredAndReturnsHandlers()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _serviceProvider = _services.BuildServiceProvider();
 | 
				
			||||||
 | 
					            var provider = _serviceProvider.GetService<IDelegatingHandlerHandlerProvider>();
 | 
				
			||||||
 | 
					            var handlers = provider.Get();
 | 
				
			||||||
 | 
					            var handler = (FakeDelegatingHandler)handlers[0].Invoke();
 | 
				
			||||||
 | 
					            handler.Order.ShouldBe(0);
 | 
				
			||||||
 | 
					            handler = (FakeDelegatingHandler)handlers[1].Invoke();
 | 
				
			||||||
 | 
					            handler.Order.ShouldBe(1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void OnlyOneVersionOfEachCacheIsRegistered()
 | 
					        private void OnlyOneVersionOfEachCacheIsRegistered()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var outputCache = _services.Single(x => x.ServiceType == typeof(IOcelotCache<CachedResponse>));
 | 
					            var outputCache = _services.Single(x => x.ServiceType == typeof(IOcelotCache<CachedResponse>));
 | 
				
			||||||
@@ -157,6 +184,11 @@ namespace Ocelot.UnitTests.DependencyInjection
 | 
				
			|||||||
            }       
 | 
					            }       
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void AddDelegate(DelegatingHandler handler)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _ocelotBuilder.AddDelegatingHandler(() => handler);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void ThenAnOcelotBuilderIsReturned()
 | 
					        private void ThenAnOcelotBuilderIsReturned()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _ocelotBuilder.ShouldBeOfType<OcelotBuilder>();
 | 
					            _ocelotBuilder.ShouldBeOfType<OcelotBuilder>();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -58,7 +58,7 @@
 | 
				
			|||||||
            this.Given(x => x.GivenTheDownStreamUrlIs("any old string"))
 | 
					            this.Given(x => x.GivenTheDownStreamUrlIs("any old string"))
 | 
				
			||||||
                .And(x => x.GivenTheQosProviderHouseReturns(new OkResponse<IQoSProvider>(new NoQoSProvider())))
 | 
					                .And(x => x.GivenTheQosProviderHouseReturns(new OkResponse<IQoSProvider>(new NoQoSProvider())))
 | 
				
			||||||
                .And(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
					                .And(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
				
			||||||
                .And(x => x.GivenTheRequestBuilderReturns(new Ocelot.Request.Request(new HttpRequestMessage(), true, new NoQoSProvider(), false, false,false)))
 | 
					                .And(x => x.GivenTheRequestBuilderReturns(new Ocelot.Request.Request(new HttpRequestMessage(), true, new NoQoSProvider(), false, false, "", false)))
 | 
				
			||||||
                .When(x => x.WhenICallTheMiddleware())
 | 
					                .When(x => x.WhenICallTheMiddleware())
 | 
				
			||||||
                .Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly())
 | 
					                .Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly())
 | 
				
			||||||
                .BDDfy();
 | 
					                .BDDfy();
 | 
				
			||||||
@@ -78,7 +78,7 @@
 | 
				
			|||||||
            this.Given(x => x.GivenTheDownStreamUrlIs("any old string"))
 | 
					            this.Given(x => x.GivenTheDownStreamUrlIs("any old string"))
 | 
				
			||||||
                .And(x => x.GivenTheQosProviderHouseReturns(new ErrorResponse<IQoSProvider>(It.IsAny<Error>())))
 | 
					                .And(x => x.GivenTheQosProviderHouseReturns(new ErrorResponse<IQoSProvider>(It.IsAny<Error>())))
 | 
				
			||||||
                .And(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
					                .And(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
				
			||||||
                .And(x => x.GivenTheRequestBuilderReturns(new Ocelot.Request.Request(new HttpRequestMessage(), true, new NoQoSProvider(), false, false, false)))
 | 
					                .And(x => x.GivenTheRequestBuilderReturns(new Ocelot.Request.Request(new HttpRequestMessage(), true, new NoQoSProvider(), false, false, "", false)))
 | 
				
			||||||
                .When(x => x.WhenICallTheMiddleware())
 | 
					                .When(x => x.WhenICallTheMiddleware())
 | 
				
			||||||
                .Then(x => x.ThenTheScopedDataRepositoryQosProviderError())
 | 
					                .Then(x => x.ThenTheScopedDataRepositoryQosProviderError())
 | 
				
			||||||
                .BDDfy();
 | 
					                .BDDfy();
 | 
				
			||||||
@@ -132,8 +132,8 @@
 | 
				
			|||||||
                                    It.IsAny<IQoSProvider>(),
 | 
					                                    It.IsAny<IQoSProvider>(),
 | 
				
			||||||
                                    It.IsAny<bool>(),
 | 
					                                    It.IsAny<bool>(),
 | 
				
			||||||
                                    It.IsAny<bool>(),
 | 
					                                    It.IsAny<bool>(),
 | 
				
			||||||
                                    It.IsAny<bool>()
 | 
					                                    It.IsAny<string>(),
 | 
				
			||||||
                                    ))
 | 
					                                    It.IsAny<bool>()))
 | 
				
			||||||
                .ReturnsAsync(_request);
 | 
					                .ReturnsAsync(_request);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
namespace Ocelot.UnitTests.Request
 | 
					namespace Ocelot.UnitTests.Request
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    using System.Net.Http;
 | 
					    using System.Net.Http;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -17,9 +17,9 @@
 | 
				
			|||||||
        private readonly HttpRequestMessage _requestMessage;
 | 
					        private readonly HttpRequestMessage _requestMessage;
 | 
				
			||||||
        private readonly bool _useCookieContainer;
 | 
					        private readonly bool _useCookieContainer;
 | 
				
			||||||
        private readonly bool _allowAutoRedirect;
 | 
					        private readonly bool _allowAutoRedirect;
 | 
				
			||||||
        private readonly bool _useTracing;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        private Response<Ocelot.Request.Request> _response;
 | 
					        private Response<Ocelot.Request.Request> _response;
 | 
				
			||||||
 | 
					        private string _reRouteKey;
 | 
				
			||||||
 | 
					        private readonly bool _useTracing;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public HttpRequestCreatorTests()
 | 
					        public HttpRequestCreatorTests()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -28,7 +28,7 @@
 | 
				
			|||||||
            _qoSProvider = new NoQoSProvider();
 | 
					            _qoSProvider = new NoQoSProvider();
 | 
				
			||||||
            _useCookieContainer = false;
 | 
					            _useCookieContainer = false;
 | 
				
			||||||
            _allowAutoRedirect = false;
 | 
					            _allowAutoRedirect = false;
 | 
				
			||||||
            _useTracing = false;
 | 
					
 | 
				
			||||||
            _requestMessage = new HttpRequestMessage();
 | 
					            _requestMessage = new HttpRequestMessage();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -48,7 +48,7 @@
 | 
				
			|||||||
        private void WhenIBuildARequest()
 | 
					        private void WhenIBuildARequest()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _response = _requestCreator.Build(_requestMessage,
 | 
					            _response = _requestCreator.Build(_requestMessage,
 | 
				
			||||||
                    _isQos, _qoSProvider, _useCookieContainer, _allowAutoRedirect, _useTracing)
 | 
					                    _isQos, _qoSProvider, _useCookieContainer, _allowAutoRedirect, _reRouteKey, _useTracing)
 | 
				
			||||||
                .GetAwaiter()
 | 
					                .GetAwaiter()
 | 
				
			||||||
                .GetResult();
 | 
					                .GetResult();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,108 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Net.Http;
 | 
				
			||||||
 | 
					using Moq;
 | 
				
			||||||
 | 
					using Ocelot.Requester;
 | 
				
			||||||
 | 
					using Ocelot.Responses;
 | 
				
			||||||
 | 
					using Shouldly;
 | 
				
			||||||
 | 
					using TestStack.BDDfy;
 | 
				
			||||||
 | 
					using Xunit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ocelot.UnitTests.Requester
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class DelegatingHandlerHandlerHouseTests
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private readonly DelegatingHandlerHandlerHouse _house;
 | 
				
			||||||
 | 
					        private Mock<IDelegatingHandlerHandlerProviderFactory> _factory;
 | 
				
			||||||
 | 
					        private readonly Mock<IDelegatingHandlerHandlerProvider> _provider;
 | 
				
			||||||
 | 
					        private Ocelot.Request.Request _request;
 | 
				
			||||||
 | 
					        private Response<IDelegatingHandlerHandlerProvider> _result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public DelegatingHandlerHandlerHouseTests()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _provider = new Mock<IDelegatingHandlerHandlerProvider>();
 | 
				
			||||||
 | 
					            _factory = new Mock<IDelegatingHandlerHandlerProviderFactory>();
 | 
				
			||||||
 | 
					            _house = new DelegatingHandlerHandlerHouse(_factory.Object);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_create_and_store_provider()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var request = new Ocelot.Request.Request(new HttpRequestMessage(), true, null, true, true, "key", false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.Given(x => GivenTheRequest(request))
 | 
				
			||||||
 | 
					                .And(x => GivenTheProviderReturns())
 | 
				
			||||||
 | 
					                .When(x => WhenIGet())
 | 
				
			||||||
 | 
					                .Then(x => ThenTheFactoryIsCalled(1))
 | 
				
			||||||
 | 
					                .And(x => ThenTheProviderIsNotNull())
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_get_provider()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var request = new Ocelot.Request.Request(new HttpRequestMessage(), true, null, true, true, "key", false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.Given(x => GivenTheRequest(request))
 | 
				
			||||||
 | 
					                .And(x => GivenTheProviderReturns())
 | 
				
			||||||
 | 
					                .And(x => WhenIGet())
 | 
				
			||||||
 | 
					                .And(x => GivenTheFactoryIsCleared())
 | 
				
			||||||
 | 
					                .When(x => WhenIGet())
 | 
				
			||||||
 | 
					                .Then(x => ThenTheFactoryIsCalled(0))
 | 
				
			||||||
 | 
					                .And(x => ThenTheProviderIsNotNull())
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_return_error()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var request = new Ocelot.Request.Request(new HttpRequestMessage(), true, null, true, true, "key", false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.Given(x => GivenTheRequest(request))
 | 
				
			||||||
 | 
					                .And(x => GivenTheProviderThrows())
 | 
				
			||||||
 | 
					                .When(x => WhenIGet())
 | 
				
			||||||
 | 
					                .And(x => ThenAnErrorIsReturned())
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void ThenAnErrorIsReturned()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _result.IsError.ShouldBeTrue();
 | 
				
			||||||
 | 
					            _result.Errors[0].ShouldBeOfType<UnableToFindDelegatingHandlerProviderError>();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void GivenTheProviderThrows()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _factory.Setup(x => x.Get(It.IsAny<Ocelot.Request.Request>())).Throws<Exception>();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void GivenTheFactoryIsCleared()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _factory = new Mock<IDelegatingHandlerHandlerProviderFactory>();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void ThenTheProviderIsNotNull()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _result.Data.ShouldBe(_provider.Object);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void WhenIGet()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _result = _house.Get(_request);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void GivenTheRequest(Ocelot.Request.Request request)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _request = request;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void GivenTheProviderReturns()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _factory.Setup(x => x.Get(It.IsAny<Ocelot.Request.Request>())).Returns(_provider.Object);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void ThenTheFactoryIsCalled(int times)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _factory.Verify(x => x.Get(_request), Times.Exactly(times));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,124 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Net.Http;
 | 
				
			||||||
 | 
					using Moq;
 | 
				
			||||||
 | 
					using Ocelot.Logging;
 | 
				
			||||||
 | 
					using Ocelot.Requester;
 | 
				
			||||||
 | 
					using Shouldly;
 | 
				
			||||||
 | 
					using TestStack.BDDfy;
 | 
				
			||||||
 | 
					using Xunit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ocelot.UnitTests.Requester
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class DelegatingHandlerHandlerProviderFactoryTests
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private readonly DelegatingHandlerHandlerProviderFactory _factory;
 | 
				
			||||||
 | 
					        private Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
				
			||||||
 | 
					        private Ocelot.Request.Request _request;
 | 
				
			||||||
 | 
					        private IDelegatingHandlerHandlerProvider _provider;
 | 
				
			||||||
 | 
					        private readonly Mock<IDelegatingHandlerHandlerProvider> _allRoutesProvider;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public DelegatingHandlerHandlerProviderFactoryTests()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _allRoutesProvider = new Mock<IDelegatingHandlerHandlerProvider>();
 | 
				
			||||||
 | 
					            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
				
			||||||
 | 
					            _factory = new DelegatingHandlerHandlerProviderFactory(_loggerFactory.Object, _allRoutesProvider.Object, null);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_all_from_all_routes_provider_and_qos()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var handlers = new List<Func<DelegatingHandler>>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                () => new FakeDelegatingHandler(0),
 | 
				
			||||||
 | 
					                () => new FakeDelegatingHandler(1)
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var request = new Ocelot.Request.Request(new HttpRequestMessage(), true, null, true, true, "", false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.Given(x => GivenTheFollowingRequest(request))
 | 
				
			||||||
 | 
					                .And(x => GivenTheAllRoutesProviderReturns(handlers))
 | 
				
			||||||
 | 
					                .When(x => WhenIGet())
 | 
				
			||||||
 | 
					                .Then(x => ThenThereIsDelegatesInProvider(3))
 | 
				
			||||||
 | 
					                .And(x => ThenTheDelegatesAreAddedCorrectly())
 | 
				
			||||||
 | 
					                .And(x => ThenItIsPolly(2))
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_return_provider_with_no_delegates()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var request = new Ocelot.Request.Request(new HttpRequestMessage(), false, null, true, true, "", false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.Given(x => GivenTheFollowingRequest(request))
 | 
				
			||||||
 | 
					                .And(x => GivenTheAllRoutesProviderReturns())
 | 
				
			||||||
 | 
					                .When(x => WhenIGet())
 | 
				
			||||||
 | 
					                .Then(x => ThenNoDelegatesAreInTheProvider())
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_return_provider_with_qos_delegate()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var request = new Ocelot.Request.Request(new HttpRequestMessage(), true, null, true, true, "", false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.Given(x => GivenTheFollowingRequest(request))
 | 
				
			||||||
 | 
					                .And(x => GivenTheAllRoutesProviderReturns())
 | 
				
			||||||
 | 
					                .When(x => WhenIGet())
 | 
				
			||||||
 | 
					                .Then(x => ThenThereIsDelegatesInProvider(1))
 | 
				
			||||||
 | 
					                .And(x => ThenItIsPolly(0))
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void ThenTheDelegatesAreAddedCorrectly()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var delegates = _provider.Get();
 | 
				
			||||||
 | 
					            var del = delegates[0].Invoke();
 | 
				
			||||||
 | 
					            var handler = (FakeDelegatingHandler) del;
 | 
				
			||||||
 | 
					            handler.Order.ShouldBe(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            del = delegates[1].Invoke();
 | 
				
			||||||
 | 
					            handler = (FakeDelegatingHandler)del;
 | 
				
			||||||
 | 
					            handler.Order.ShouldBe(1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void GivenTheAllRoutesProviderReturns()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _allRoutesProvider.Setup(x => x.Get()).Returns(new List<Func<DelegatingHandler>>());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void GivenTheAllRoutesProviderReturns(List<Func<DelegatingHandler>> handlers)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _allRoutesProvider.Setup(x => x.Get()).Returns(handlers);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void ThenItIsPolly(int i)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var delegates = _provider.Get();
 | 
				
			||||||
 | 
					            var del = delegates[i].Invoke();
 | 
				
			||||||
 | 
					            del.ShouldBeOfType<PollyCircuitBreakingDelegatingHandler>();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void ThenThereIsDelegatesInProvider(int count)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _provider.ShouldNotBeNull();
 | 
				
			||||||
 | 
					            _provider.Get().Count.ShouldBe(count);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void GivenTheFollowingRequest(Ocelot.Request.Request request)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _request = request;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void WhenIGet()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _provider = _factory.Get(_request);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void ThenNoDelegatesAreInTheProvider()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _provider.ShouldNotBeNull();
 | 
				
			||||||
 | 
					            _provider.Get().Count.ShouldBe(0);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,62 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Net.Http;
 | 
				
			||||||
 | 
					using Ocelot.Requester;
 | 
				
			||||||
 | 
					using Shouldly;
 | 
				
			||||||
 | 
					using TestStack.BDDfy;
 | 
				
			||||||
 | 
					using Xunit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ocelot.UnitTests.Requester
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class DelegatingHandlerHandlerProviderTests
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private readonly DelegatingHandlerHandlerProvider _provider;
 | 
				
			||||||
 | 
					        private List<Func<DelegatingHandler>> _handlers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public DelegatingHandlerHandlerProviderTests()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _provider = new DelegatingHandlerHandlerProvider();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_return_empty_list()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.When(x => WhenIGet())
 | 
				
			||||||
 | 
					                .Then(x => ThenAnEmptyListIsReturned())
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_get_delegating_handlers_in_order_first_in_first_out()
 | 
				
			||||||
 | 
					        {   
 | 
				
			||||||
 | 
					            this.Given(x => GivenTheHandlers())
 | 
				
			||||||
 | 
					                .When(x => WhenIGet())
 | 
				
			||||||
 | 
					                .Then(x => ThenTheHandlersAreReturnedInOrder())
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void ThenAnEmptyListIsReturned()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _handlers.Count.ShouldBe(0);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void ThenTheHandlersAreReturnedInOrder()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					             var handler = (FakeDelegatingHandler)_handlers[0].Invoke();
 | 
				
			||||||
 | 
					            handler.Order.ShouldBe(0);
 | 
				
			||||||
 | 
					            handler = (FakeDelegatingHandler)_handlers[1].Invoke();
 | 
				
			||||||
 | 
					            handler.Order.ShouldBe(1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void WhenIGet()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _handlers = _provider.Get();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void GivenTheHandlers()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _provider.Add(() => new FakeDelegatingHandler(0));
 | 
				
			||||||
 | 
					            _provider.Add(() => new FakeDelegatingHandler(1));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										28
									
								
								test/Ocelot.UnitTests/Requester/FakeDelegatingHandler.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								test/Ocelot.UnitTests/Requester/FakeDelegatingHandler.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Net.Http;
 | 
				
			||||||
 | 
					using System.Threading;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ocelot.UnitTests.Requester
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class FakeDelegatingHandler : DelegatingHandler
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public FakeDelegatingHandler()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public FakeDelegatingHandler(int order)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Order = order;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public int Order {get;private set;}
 | 
				
			||||||
 | 
					        public DateTime TimeCalled {get;private set;}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            TimeCalled = DateTime.Now;
 | 
				
			||||||
 | 
					            return new HttpResponseMessage();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										114
									
								
								test/Ocelot.UnitTests/Requester/HttpClientBuilderTests.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								test/Ocelot.UnitTests/Requester/HttpClientBuilderTests.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,114 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Net.Http;
 | 
				
			||||||
 | 
					using Moq;
 | 
				
			||||||
 | 
					using Ocelot.Requester;
 | 
				
			||||||
 | 
					using Ocelot.Responses;
 | 
				
			||||||
 | 
					using Shouldly;
 | 
				
			||||||
 | 
					using TestStack.BDDfy;
 | 
				
			||||||
 | 
					using Xunit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ocelot.UnitTests.Requester
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class HttpClientBuilderTests
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private readonly HttpClientBuilder _builder;
 | 
				
			||||||
 | 
					        private readonly Mock<IDelegatingHandlerHandlerHouse> _house;
 | 
				
			||||||
 | 
					        private readonly Mock<IDelegatingHandlerHandlerProvider> _provider;
 | 
				
			||||||
 | 
					        private IHttpClientBuilder _builderResult;
 | 
				
			||||||
 | 
					        private IHttpClient _httpClient;
 | 
				
			||||||
 | 
					        private HttpResponseMessage _response;
 | 
				
			||||||
 | 
					        private Ocelot.Request.Request _request;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public HttpClientBuilderTests()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _provider = new Mock<IDelegatingHandlerHandlerProvider>();
 | 
				
			||||||
 | 
					            _house = new Mock<IDelegatingHandlerHandlerHouse>();
 | 
				
			||||||
 | 
					            _builder = new HttpClientBuilder(_house.Object);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_build_http_client()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.Given(x => GivenTheProviderReturns())
 | 
				
			||||||
 | 
					                .And(x => GivenARequest())
 | 
				
			||||||
 | 
					                .And(x => GivenTheHouseReturns())
 | 
				
			||||||
 | 
					                .When(x => WhenIBuild())
 | 
				
			||||||
 | 
					                .Then(x => ThenTheHttpClientShouldNotBeNull())
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_call_delegating_handlers_in_order()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var fakeOne = new FakeDelegatingHandler();
 | 
				
			||||||
 | 
					            var fakeTwo = new FakeDelegatingHandler();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var handlers = new List<Func<DelegatingHandler>>()
 | 
				
			||||||
 | 
					            { 
 | 
				
			||||||
 | 
					                () => fakeOne,
 | 
				
			||||||
 | 
					                () => fakeTwo
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.Given(x => GivenTheProviderReturns(handlers))
 | 
				
			||||||
 | 
					                .And(x => GivenARequest())
 | 
				
			||||||
 | 
					                .And(x => GivenTheHouseReturns())
 | 
				
			||||||
 | 
					                .And(x => WhenIBuild())
 | 
				
			||||||
 | 
					                .When(x => WhenICallTheClient())
 | 
				
			||||||
 | 
					                .Then(x => ThenTheFakeAreHandledInOrder(fakeOne, fakeTwo))
 | 
				
			||||||
 | 
					                .And(x => ThenSomethingIsReturned())
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void GivenARequest()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _request = new Ocelot.Request.Request(null, false, null, false, false, "", false);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void GivenTheHouseReturns()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _house
 | 
				
			||||||
 | 
					                .Setup(x => x.Get(It.IsAny<Ocelot.Request.Request>()))
 | 
				
			||||||
 | 
					                .Returns(new OkResponse<IDelegatingHandlerHandlerProvider>(_provider.Object));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void ThenSomethingIsReturned()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _response.ShouldNotBeNull();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void WhenICallTheClient()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _response = _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Get, "http://test.com")).GetAwaiter().GetResult();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void ThenTheFakeAreHandledInOrder(FakeDelegatingHandler fakeOne, FakeDelegatingHandler fakeTwo)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fakeOne.TimeCalled.ShouldBeGreaterThan(fakeTwo.TimeCalled);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void GivenTheProviderReturns()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _provider
 | 
				
			||||||
 | 
					                .Setup(x => x.Get())
 | 
				
			||||||
 | 
					                .Returns(new List<Func<DelegatingHandler>>(){ () => new FakeDelegatingHandler()});
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void GivenTheProviderReturns(List<Func<DelegatingHandler>> handlers)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _provider
 | 
				
			||||||
 | 
					                .Setup(x => x.Get())
 | 
				
			||||||
 | 
					                .Returns(handlers);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void WhenIBuild()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _httpClient = _builder.Create(_request);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void ThenTheHttpClientShouldNotBeNull()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _httpClient.ShouldNotBeNull();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -10,13 +10,15 @@ using System.Net.Http;
 | 
				
			|||||||
using System.Text;
 | 
					using System.Text;
 | 
				
			||||||
using TestStack.BDDfy;
 | 
					using TestStack.BDDfy;
 | 
				
			||||||
using Xunit;
 | 
					using Xunit;
 | 
				
			||||||
 | 
					using Shouldly;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Ocelot.UnitTests.Requester
 | 
					namespace Ocelot.UnitTests.Requester
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public class HttpClientHttpRequesterTest
 | 
					    public class HttpClientHttpRequesterTest
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private readonly Mock<IHttpClientCache> _cacheHandlers;
 | 
					        private readonly Mock<IHttpClientCache> _cacheHandlers;
 | 
				
			||||||
        private Mock<IServiceProvider> _serviceProvider;
 | 
					        private Mock<IDelegatingHandlerHandlerHouse> _house;
 | 
				
			||||||
 | 
					        private Mock<IDelegatingHandlerHandlerProvider> _provider;
 | 
				
			||||||
        private Response<HttpResponseMessage> _response;
 | 
					        private Response<HttpResponseMessage> _response;
 | 
				
			||||||
        private readonly HttpClientHttpRequester _httpClientRequester;
 | 
					        private readonly HttpClientHttpRequester _httpClientRequester;
 | 
				
			||||||
        private Ocelot.Request.Request _request;
 | 
					        private Ocelot.Request.Request _request;
 | 
				
			||||||
@@ -25,29 +27,32 @@ namespace Ocelot.UnitTests.Requester
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        public HttpClientHttpRequesterTest()
 | 
					        public HttpClientHttpRequesterTest()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _serviceProvider = new Mock<IServiceProvider>();
 | 
					            _provider = new Mock<IDelegatingHandlerHandlerProvider>();
 | 
				
			||||||
 | 
					            _provider.Setup(x => x.Get()).Returns(new List<Func<DelegatingHandler>>());
 | 
				
			||||||
 | 
					            _house = new Mock<IDelegatingHandlerHandlerHouse>();
 | 
				
			||||||
 | 
					            _house.Setup(x => x.Get(It.IsAny<Ocelot.Request.Request>())).Returns(new OkResponse<IDelegatingHandlerHandlerProvider>(_provider.Object));
 | 
				
			||||||
            _logger = new Mock<IOcelotLogger>();
 | 
					            _logger = new Mock<IOcelotLogger>();
 | 
				
			||||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
					            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
				
			||||||
            _loggerFactory
 | 
					            _loggerFactory
 | 
				
			||||||
                .Setup(x => x.CreateLogger<HttpClientHttpRequester>())
 | 
					                .Setup(x => x.CreateLogger<HttpClientHttpRequester>())
 | 
				
			||||||
                .Returns(_logger.Object);
 | 
					                .Returns(_logger.Object);
 | 
				
			||||||
            _cacheHandlers = new Mock<IHttpClientCache>();
 | 
					            _cacheHandlers = new Mock<IHttpClientCache>();
 | 
				
			||||||
            _httpClientRequester = new HttpClientHttpRequester(_loggerFactory.Object, _cacheHandlers.Object, _serviceProvider.Object);            
 | 
					            _httpClientRequester = new HttpClientHttpRequester(_loggerFactory.Object, _cacheHandlers.Object, _house.Object);            
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_call_request_correctly()
 | 
					        public void should_call_request_correctly()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            this.Given(x=>x.GivenTheRequestIs(new Ocelot.Request.Request(new HttpRequestMessage() {  RequestUri = new Uri("http://www.bbc.co.uk") }, false, new NoQoSProvider(), false, false, false)))
 | 
					            this.Given(x=>x.GivenTheRequestIs(new Ocelot.Request.Request(new HttpRequestMessage() {  RequestUri = new Uri("http://www.bbc.co.uk") }, false, new NoQoSProvider(), false, false, "", false)))
 | 
				
			||||||
                .When(x=>x.WhenIGetResponse())
 | 
					                .When(x=>x.WhenIGetResponse())
 | 
				
			||||||
                .Then(x => x.ThenTheResponseIsCalledCorrectly())
 | 
					                .Then(x => x.ThenTheResponseIsCalledCorrectly())
 | 
				
			||||||
                .BDDfy();
 | 
					                .BDDfy();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_call_request_UnableToCompleteRequest()
 | 
					        public void should_call_request_unable_to_complete_request()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            this.Given(x => x.GivenTheRequestIs(new Ocelot.Request.Request(new HttpRequestMessage() { RequestUri = new Uri("http://localhost:60080") }, false, new NoQoSProvider(), false, false, false)))
 | 
					            this.Given(x => x.GivenTheRequestIs(new Ocelot.Request.Request(new HttpRequestMessage() { RequestUri = new Uri("http://localhost:60080") }, false, new NoQoSProvider(), false, false, "", false)))
 | 
				
			||||||
                .When(x => x.WhenIGetResponse())
 | 
					                .When(x => x.WhenIGetResponse())
 | 
				
			||||||
                .Then(x => x.ThenTheResponseIsCalledError())
 | 
					                .Then(x => x.ThenTheResponseIsCalledError())
 | 
				
			||||||
                .BDDfy();
 | 
					                .BDDfy();
 | 
				
			||||||
@@ -65,12 +70,12 @@ namespace Ocelot.UnitTests.Requester
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private void ThenTheResponseIsCalledCorrectly()
 | 
					        private void ThenTheResponseIsCalledCorrectly()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Assert.True(_response.IsError == false);
 | 
					            _response.IsError.ShouldBeFalse();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void ThenTheResponseIsCalledError()
 | 
					        private void ThenTheResponseIsCalledError()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Assert.True(_response.IsError == true);
 | 
					            _response.IsError.ShouldBeTrue();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }  
 | 
					    }  
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
namespace Ocelot.UnitTests.Requester
 | 
					namespace Ocelot.UnitTests.Requester
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    using System.Net.Http;
 | 
					    using System.Net.Http;
 | 
				
			||||||
    using Microsoft.AspNetCore.Builder;
 | 
					    using Microsoft.AspNetCore.Builder;
 | 
				
			||||||
@@ -28,7 +28,7 @@
 | 
				
			|||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_call_scoped_data_repository_correctly()
 | 
					        public void should_call_scoped_data_repository_correctly()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            this.Given(x => x.GivenTheRequestIs(new Ocelot.Request.Request(new HttpRequestMessage(),true, new NoQoSProvider(), false, false,false)))
 | 
					            this.Given(x => x.GivenTheRequestIs(new Ocelot.Request.Request(new HttpRequestMessage(),true, new NoQoSProvider(), false, false, "", false)))
 | 
				
			||||||
                .And(x => x.GivenTheRequesterReturns(new HttpResponseMessage()))
 | 
					                .And(x => x.GivenTheRequesterReturns(new HttpResponseMessage()))
 | 
				
			||||||
                .And(x => x.GivenTheScopedRepoReturns())
 | 
					                .And(x => x.GivenTheScopedRepoReturns())
 | 
				
			||||||
                .When(x => x.WhenICallTheMiddleware())
 | 
					                .When(x => x.WhenICallTheMiddleware())
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,8 @@
 | 
				
			|||||||
using Moq;
 | 
					using Moq;
 | 
				
			||||||
using Ocelot.Configuration;
 | 
					using Ocelot.Configuration;
 | 
				
			||||||
using Ocelot.Configuration.Builder;
 | 
					using Ocelot.Configuration.Builder;
 | 
				
			||||||
using Ocelot.LoadBalancer.LoadBalancers;
 | 
					 | 
				
			||||||
using Ocelot.Requester.QoS;
 | 
					using Ocelot.Requester.QoS;
 | 
				
			||||||
using Ocelot.Responses;
 | 
					using Ocelot.Responses;
 | 
				
			||||||
using Ocelot.UnitTests.LoadBalancer;
 | 
					 | 
				
			||||||
using Shouldly;
 | 
					using Shouldly;
 | 
				
			||||||
using TestStack.BDDfy;
 | 
					using TestStack.BDDfy;
 | 
				
			||||||
using Xunit;
 | 
					using Xunit;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -121,7 +121,7 @@ namespace Ocelot.UnitTests.Responder
 | 
				
			|||||||
            // If this test fails then it's because the number of error codes has changed.
 | 
					            // If this test fails then it's because the number of error codes has changed.
 | 
				
			||||||
            // You should make the appropriate changes to the test cases here to ensure
 | 
					            // You should make the appropriate changes to the test cases here to ensure
 | 
				
			||||||
            // they cover all the error codes, and then modify this assertion.
 | 
					            // they cover all the error codes, and then modify this assertion.
 | 
				
			||||||
            Enum.GetNames(typeof(OcelotErrorCode)).Length.ShouldBe(32, "Looks like the number of error codes has changed. Do you need to modify ErrorsToHttpStatusCodeMapper?");
 | 
					            Enum.GetNames(typeof(OcelotErrorCode)).Length.ShouldBe(33, "Looks like the number of error codes has changed. Do you need to modify ErrorsToHttpStatusCodeMapper?");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void ShouldMapErrorToStatusCode(OcelotErrorCode errorCode, HttpStatusCode expectedHttpStatusCode)
 | 
					        private void ShouldMapErrorToStatusCode(OcelotErrorCode errorCode, HttpStatusCode expectedHttpStatusCode)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,212 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.IO;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					using Consul;
 | 
				
			||||||
 | 
					using Microsoft.AspNetCore.Builder;
 | 
				
			||||||
 | 
					using Microsoft.AspNetCore.Hosting;
 | 
				
			||||||
 | 
					using Microsoft.AspNetCore.Http;
 | 
				
			||||||
 | 
					using Moq;
 | 
				
			||||||
 | 
					using Ocelot.Logging;
 | 
				
			||||||
 | 
					using Ocelot.ServiceDiscovery;
 | 
				
			||||||
 | 
					using Ocelot.Values;
 | 
				
			||||||
 | 
					using Xunit;
 | 
				
			||||||
 | 
					using TestStack.BDDfy;
 | 
				
			||||||
 | 
					using Shouldly;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ocelot.UnitTests.ServiceDiscovery
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class ConsulServiceDiscoveryProviderTests : IDisposable
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private IWebHost _fakeConsulBuilder;
 | 
				
			||||||
 | 
					        private readonly List<ServiceEntry> _serviceEntries;
 | 
				
			||||||
 | 
					        private readonly ConsulServiceDiscoveryProvider _provider;
 | 
				
			||||||
 | 
					        private readonly string _serviceName;
 | 
				
			||||||
 | 
					        private readonly int _port;
 | 
				
			||||||
 | 
					        private readonly string _consulHost;
 | 
				
			||||||
 | 
					        private readonly string _fakeConsulServiceDiscoveryUrl;
 | 
				
			||||||
 | 
					        private List<Service> _services;
 | 
				
			||||||
 | 
					        private Mock<IOcelotLoggerFactory> _factory;
 | 
				
			||||||
 | 
					        private readonly Mock<IOcelotLogger> _logger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public ConsulServiceDiscoveryProviderTests()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _serviceName = "test";
 | 
				
			||||||
 | 
					            _port = 8500;
 | 
				
			||||||
 | 
					            _consulHost = "localhost";
 | 
				
			||||||
 | 
					            _fakeConsulServiceDiscoveryUrl = $"http://{_consulHost}:{_port}";
 | 
				
			||||||
 | 
					            _serviceEntries = new List<ServiceEntry>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            _factory = new Mock<IOcelotLoggerFactory>();
 | 
				
			||||||
 | 
					            _logger = new Mock<IOcelotLogger>();
 | 
				
			||||||
 | 
					            _factory.Setup(x => x.CreateLogger<ConsulServiceDiscoveryProvider>()).Returns(_logger.Object);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var config = new ConsulRegistryConfiguration(_consulHost, _port, _serviceName);
 | 
				
			||||||
 | 
					            _provider = new ConsulServiceDiscoveryProvider(config, _factory.Object);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_return_service_from_consul()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var serviceEntryOne = new ServiceEntry()
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Service = new AgentService()
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    Service = _serviceName,
 | 
				
			||||||
 | 
					                    Address = "localhost",
 | 
				
			||||||
 | 
					                    Port = 50881,
 | 
				
			||||||
 | 
					                    ID = Guid.NewGuid().ToString(),
 | 
				
			||||||
 | 
					                    Tags = new string[0]
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.Given(x =>GivenThereIsAFakeConsulServiceDiscoveryProvider(_fakeConsulServiceDiscoveryUrl, _serviceName))
 | 
				
			||||||
 | 
					                .And(x => GivenTheServicesAreRegisteredWithConsul(serviceEntryOne))
 | 
				
			||||||
 | 
					                .When(x => WhenIGetTheServices())
 | 
				
			||||||
 | 
					                .Then(x => ThenTheCountIs(1))
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_not_return_services_with_invalid_address()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var serviceEntryOne = new ServiceEntry()
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Service = new AgentService()
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    Service = _serviceName,
 | 
				
			||||||
 | 
					                    Address = "http://localhost",
 | 
				
			||||||
 | 
					                    Port = 50881,
 | 
				
			||||||
 | 
					                    ID = Guid.NewGuid().ToString(),
 | 
				
			||||||
 | 
					                    Tags = new string[0]
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var serviceEntryTwo = new ServiceEntry()
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Service = new AgentService()
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    Service = _serviceName,
 | 
				
			||||||
 | 
					                    Address = "http://localhost",
 | 
				
			||||||
 | 
					                    Port = 50888,
 | 
				
			||||||
 | 
					                    ID = Guid.NewGuid().ToString(),
 | 
				
			||||||
 | 
					                    Tags = new string[0]
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.Given(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(_fakeConsulServiceDiscoveryUrl, _serviceName))
 | 
				
			||||||
 | 
					                .And(x => GivenTheServicesAreRegisteredWithConsul(serviceEntryOne, serviceEntryTwo))
 | 
				
			||||||
 | 
					                .When(x => WhenIGetTheServices())
 | 
				
			||||||
 | 
					                .Then(x => ThenTheCountIs(0))
 | 
				
			||||||
 | 
					                .And(x => ThenTheLoggerHasBeenCalledCorrectlyForInvalidAddress())
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_not_return_services_with_invalid_port()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var serviceEntryOne = new ServiceEntry()
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Service = new AgentService()
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    Service = _serviceName,
 | 
				
			||||||
 | 
					                    Address = "localhost",
 | 
				
			||||||
 | 
					                    Port = -1,
 | 
				
			||||||
 | 
					                    ID = Guid.NewGuid().ToString(),
 | 
				
			||||||
 | 
					                    Tags = new string[0]
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var serviceEntryTwo = new ServiceEntry()
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Service = new AgentService()
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    Service = _serviceName,
 | 
				
			||||||
 | 
					                    Address = "localhost",
 | 
				
			||||||
 | 
					                    Port = 0,
 | 
				
			||||||
 | 
					                    ID = Guid.NewGuid().ToString(),
 | 
				
			||||||
 | 
					                    Tags = new string[0]
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.Given(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(_fakeConsulServiceDiscoveryUrl, _serviceName))
 | 
				
			||||||
 | 
					                .And(x => GivenTheServicesAreRegisteredWithConsul(serviceEntryOne, serviceEntryTwo))
 | 
				
			||||||
 | 
					                .When(x => WhenIGetTheServices())
 | 
				
			||||||
 | 
					                .Then(x => ThenTheCountIs(0))
 | 
				
			||||||
 | 
					                .And(x => ThenTheLoggerHasBeenCalledCorrectlyForInvalidPorts())
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void ThenTheLoggerHasBeenCalledCorrectlyForInvalidAddress()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _logger.Verify(
 | 
				
			||||||
 | 
					                x => x.LogError(
 | 
				
			||||||
 | 
					                    "Unable to use service Address: http://localhost and Port: 50881 as it is invalid. Address must contain host only e.g. localhost and port must be greater than 0"),
 | 
				
			||||||
 | 
					                Times.Once);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            _logger.Verify(
 | 
				
			||||||
 | 
					                x => x.LogError(
 | 
				
			||||||
 | 
					                    "Unable to use service Address: http://localhost and Port: 50888 as it is invalid. Address must contain host only e.g. localhost and port must be greater than 0"),
 | 
				
			||||||
 | 
					                Times.Once);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void ThenTheLoggerHasBeenCalledCorrectlyForInvalidPorts()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _logger.Verify(
 | 
				
			||||||
 | 
					                x => x.LogError(
 | 
				
			||||||
 | 
					                    "Unable to use service Address: localhost and Port: -1 as it is invalid. Address must contain host only e.g. localhost and port must be greater than 0"),
 | 
				
			||||||
 | 
					                Times.Once);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            _logger.Verify(
 | 
				
			||||||
 | 
					                x => x.LogError(
 | 
				
			||||||
 | 
					                    "Unable to use service Address: localhost and Port: 0 as it is invalid. Address must contain host only e.g. localhost and port must be greater than 0"),
 | 
				
			||||||
 | 
					                Times.Once);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void ThenTheCountIs(int count)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _services.Count.ShouldBe(count);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void WhenIGetTheServices()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _services = _provider.Get().GetAwaiter().GetResult();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void GivenTheServicesAreRegisteredWithConsul(params ServiceEntry[] serviceEntries)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            foreach (var serviceEntry in serviceEntries)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                _serviceEntries.Add(serviceEntry);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void GivenThereIsAFakeConsulServiceDiscoveryProvider(string url, string serviceName)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _fakeConsulBuilder = new WebHostBuilder()
 | 
				
			||||||
 | 
					                .UseUrls(url)
 | 
				
			||||||
 | 
					                .UseKestrel()
 | 
				
			||||||
 | 
					                .UseContentRoot(Directory.GetCurrentDirectory())
 | 
				
			||||||
 | 
					                .UseIISIntegration()
 | 
				
			||||||
 | 
					                .UseUrls(url)
 | 
				
			||||||
 | 
					                .Configure(app =>
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    app.Run(async context =>
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        if (context.Request.Path.Value == $"/v1/health/service/{serviceName}")
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            await context.Response.WriteJsonAsync(_serviceEntries);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            _fakeConsulBuilder.Start();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public void Dispose()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _fakeConsulBuilder?.Dispose();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,7 +1,9 @@
 | 
				
			|||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using Moq;
 | 
				
			||||||
using Ocelot.Configuration;
 | 
					using Ocelot.Configuration;
 | 
				
			||||||
using Ocelot.Configuration.Builder;
 | 
					using Ocelot.Configuration.Builder;
 | 
				
			||||||
 | 
					using Ocelot.Logging;
 | 
				
			||||||
using Ocelot.ServiceDiscovery;
 | 
					using Ocelot.ServiceDiscovery;
 | 
				
			||||||
using Shouldly;
 | 
					using Shouldly;
 | 
				
			||||||
using TestStack.BDDfy;
 | 
					using TestStack.BDDfy;
 | 
				
			||||||
@@ -15,10 +17,12 @@ namespace Ocelot.UnitTests.ServiceDiscovery
 | 
				
			|||||||
        private IServiceDiscoveryProvider _result;
 | 
					        private IServiceDiscoveryProvider _result;
 | 
				
			||||||
        private readonly ServiceDiscoveryProviderFactory _factory;
 | 
					        private readonly ServiceDiscoveryProviderFactory _factory;
 | 
				
			||||||
        private ReRoute _reRoute;
 | 
					        private ReRoute _reRoute;
 | 
				
			||||||
 | 
					        private Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public ServiceProviderFactoryTests()
 | 
					        public ServiceProviderFactoryTests()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _factory = new ServiceDiscoveryProviderFactory();
 | 
					            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
				
			||||||
 | 
					            _factory = new ServiceDiscoveryProviderFactory(_loggerFactory.Object);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user