mirror of
https://github.com/nsnail/Ocelot.git
synced 2025-06-19 17:28:16 +08:00
Feature/automatic routes with sd (#351)
* #340 started looking at supporting automatic routing when using service discovery * #340 getting old routing tests to pass * #340 renamed stuff to provider rather than finder, as its not longer finding anything * #340 working towards supporting dynamic routing * #340 loads of refactoring to make configuration work with dynamic routing * #340 refactor consul config code so the registry class owns it * #340 default to consul to maintain backwards compat * #340 added docs, finished this branches todos
This commit is contained in:
@ -9,7 +9,7 @@ namespace Ocelot.Configuration.Builder
|
||||
public class DownstreamReRouteBuilder
|
||||
{
|
||||
private AuthenticationOptions _authenticationOptions;
|
||||
private string _reRouteKey;
|
||||
private string _loadBalancerKey;
|
||||
private string _downstreamPathTemplate;
|
||||
private string _upstreamTemplate;
|
||||
private UpstreamPathTemplate _upstreamTemplatePattern;
|
||||
@ -25,7 +25,6 @@ namespace Ocelot.Configuration.Builder
|
||||
private CacheOptions _fileCacheOptions;
|
||||
private string _downstreamScheme;
|
||||
private LoadBalancerOptions _loadBalancerOptions;
|
||||
private bool _useQos;
|
||||
private QoSOptions _qosOptions;
|
||||
private HttpHandlerOptions _httpHandlerOptions;
|
||||
private bool _enableRateLimiting;
|
||||
@ -41,7 +40,6 @@ namespace Ocelot.Configuration.Builder
|
||||
private List<AddHeader> _addHeadersToDownstream;
|
||||
private List<AddHeader> _addHeadersToUpstream;
|
||||
private bool _dangerousAcceptAnyServerCertificateValidator;
|
||||
private string _qosKey;
|
||||
|
||||
public DownstreamReRouteBuilder()
|
||||
{
|
||||
@ -153,27 +151,15 @@ namespace Ocelot.Configuration.Builder
|
||||
return this;
|
||||
}
|
||||
|
||||
public DownstreamReRouteBuilder WithIsQos(bool input)
|
||||
{
|
||||
_useQos = input;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DownstreamReRouteBuilder WithQosOptions(QoSOptions input)
|
||||
{
|
||||
_qosOptions = input;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DownstreamReRouteBuilder WithReRouteKey(string reRouteKey)
|
||||
public DownstreamReRouteBuilder WithLoadBalancerKey(string loadBalancerKey)
|
||||
{
|
||||
_reRouteKey = reRouteKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DownstreamReRouteBuilder WithQosKey(string qosKey)
|
||||
{
|
||||
_qosKey = qosKey;
|
||||
_loadBalancerKey = loadBalancerKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -267,7 +253,6 @@ namespace Ocelot.Configuration.Builder
|
||||
_httpHandlerOptions,
|
||||
_useServiceDiscovery,
|
||||
_enableRateLimiting,
|
||||
_useQos,
|
||||
_qosOptions,
|
||||
_downstreamScheme,
|
||||
_requestIdHeaderKey,
|
||||
@ -283,12 +268,11 @@ namespace Ocelot.Configuration.Builder
|
||||
_isAuthorised,
|
||||
_authenticationOptions,
|
||||
new PathTemplate(_downstreamPathTemplate),
|
||||
_reRouteKey,
|
||||
_loadBalancerKey,
|
||||
_delegatingHandlers,
|
||||
_addHeadersToDownstream,
|
||||
_addHeadersToUpstream,
|
||||
_dangerousAcceptAnyServerCertificateValidator,
|
||||
_qosKey);
|
||||
_dangerousAcceptAnyServerCertificateValidator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,9 @@
|
||||
|
||||
private int _durationOfBreak;
|
||||
|
||||
private int _timeoutValue;
|
||||
private int _timeoutValue;
|
||||
|
||||
private string _key;
|
||||
|
||||
public QoSOptionsBuilder WithExceptionsAllowedBeforeBreaking(int exceptionsAllowedBeforeBreaking)
|
||||
{
|
||||
@ -26,9 +28,15 @@
|
||||
return this;
|
||||
}
|
||||
|
||||
public QoSOptionsBuilder WithKey(string input)
|
||||
{
|
||||
_key = input;
|
||||
return this;
|
||||
}
|
||||
|
||||
public QoSOptions Build()
|
||||
{
|
||||
return new QoSOptions(_exceptionsAllowedBeforeBreaking, _durationOfBreak, _timeoutValue);
|
||||
return new QoSOptions(_exceptionsAllowedBeforeBreaking, _durationOfBreak, _timeoutValue, _key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ namespace Ocelot.Configuration.Builder
|
||||
private bool _isAuthenticated;
|
||||
private bool _isAuthorised;
|
||||
private bool _isCached;
|
||||
private bool _isQoS;
|
||||
private bool _enableRateLimiting;
|
||||
|
||||
public ReRouteOptionsBuilder WithIsCached(bool isCached)
|
||||
@ -26,12 +25,6 @@ namespace Ocelot.Configuration.Builder
|
||||
return this;
|
||||
}
|
||||
|
||||
public ReRouteOptionsBuilder WithIsQos(bool isQoS)
|
||||
{
|
||||
_isQoS = isQoS;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ReRouteOptionsBuilder WithRateLimiting(bool enableRateLimiting)
|
||||
{
|
||||
_enableRateLimiting = enableRateLimiting;
|
||||
@ -40,7 +33,7 @@ namespace Ocelot.Configuration.Builder
|
||||
|
||||
public ReRouteOptions Build()
|
||||
{
|
||||
return new ReRouteOptions(_isAuthenticated, _isAuthorised, _isCached, _isQoS, _enableRateLimiting);
|
||||
return new ReRouteOptions(_isAuthenticated, _isAuthorised, _isCached, _enableRateLimiting);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -104,8 +104,22 @@ namespace Ocelot.Configuration.Creator
|
||||
}
|
||||
|
||||
var serviceProviderConfiguration = _serviceProviderConfigCreator.Create(fileConfiguration.GlobalConfiguration);
|
||||
|
||||
var config = new InternalConfiguration(reRoutes, _adminPath.Path, serviceProviderConfiguration, fileConfiguration.GlobalConfiguration.RequestIdKey);
|
||||
|
||||
var lbOptions = CreateLoadBalancerOptions(fileConfiguration.GlobalConfiguration.LoadBalancerOptions);
|
||||
|
||||
var qosOptions = _qosOptionsCreator.Create(fileConfiguration.GlobalConfiguration.QoSOptions);
|
||||
|
||||
var httpHandlerOptions = _httpHandlerOptionsCreator.Create(fileConfiguration.GlobalConfiguration.HttpHandlerOptions);
|
||||
|
||||
var config = new InternalConfiguration(reRoutes,
|
||||
_adminPath.Path,
|
||||
serviceProviderConfiguration,
|
||||
fileConfiguration.GlobalConfiguration.RequestIdKey,
|
||||
lbOptions,
|
||||
fileConfiguration.GlobalConfiguration.DownstreamScheme,
|
||||
qosOptions,
|
||||
httpHandlerOptions
|
||||
);
|
||||
|
||||
return new OkResponse<IInternalConfiguration>(config);
|
||||
}
|
||||
@ -160,8 +174,6 @@ namespace Ocelot.Configuration.Creator
|
||||
|
||||
var reRouteKey = CreateReRouteKey(fileReRoute);
|
||||
|
||||
var qosKey = CreateQosKey(fileReRoute);
|
||||
|
||||
var upstreamTemplatePattern = _upstreamTemplatePatternCreator.Create(fileReRoute);
|
||||
|
||||
var authOptionsForRoute = _authOptionsCreator.Create(fileReRoute);
|
||||
@ -172,19 +184,19 @@ namespace Ocelot.Configuration.Creator
|
||||
|
||||
var claimsToQueries = _claimsToThingCreator.Create(fileReRoute.AddQueriesToRequest);
|
||||
|
||||
var qosOptions = _qosOptionsCreator.Create(fileReRoute);
|
||||
var qosOptions = _qosOptionsCreator.Create(fileReRoute.QoSOptions, fileReRoute.UpstreamPathTemplate, fileReRoute.UpstreamHttpMethod.ToArray());
|
||||
|
||||
var rateLimitOption = _rateLimitOptionsCreator.Create(fileReRoute, globalConfiguration, fileReRouteOptions.EnableRateLimiting);
|
||||
|
||||
var region = _regionCreator.Create(fileReRoute);
|
||||
|
||||
var httpHandlerOptions = _httpHandlerOptionsCreator.Create(fileReRoute);
|
||||
var httpHandlerOptions = _httpHandlerOptionsCreator.Create(fileReRoute.HttpHandlerOptions);
|
||||
|
||||
var hAndRs = _headerFAndRCreator.Create(fileReRoute);
|
||||
|
||||
var downstreamAddresses = _downstreamAddressesCreator.Create(fileReRoute);
|
||||
|
||||
var lbOptions = CreateLoadBalancerOptions(fileReRoute);
|
||||
var lbOptions = CreateLoadBalancerOptions(fileReRoute.LoadBalancerOptions);
|
||||
|
||||
var reRoute = new DownstreamReRouteBuilder()
|
||||
.WithKey(fileReRoute.Key)
|
||||
@ -205,9 +217,7 @@ namespace Ocelot.Configuration.Creator
|
||||
.WithDownstreamScheme(fileReRoute.DownstreamScheme)
|
||||
.WithLoadBalancerOptions(lbOptions)
|
||||
.WithDownstreamAddresses(downstreamAddresses)
|
||||
.WithReRouteKey(reRouteKey)
|
||||
.WithQosKey(qosKey)
|
||||
.WithIsQos(fileReRouteOptions.IsQos)
|
||||
.WithLoadBalancerKey(reRouteKey)
|
||||
.WithQosOptions(qosOptions)
|
||||
.WithEnableRateLimiting(fileReRouteOptions.EnableRateLimiting)
|
||||
.WithRateLimitOptions(rateLimitOption)
|
||||
@ -226,9 +236,13 @@ namespace Ocelot.Configuration.Creator
|
||||
return reRoute;
|
||||
}
|
||||
|
||||
private LoadBalancerOptions CreateLoadBalancerOptions(FileReRoute fileReRoute)
|
||||
private LoadBalancerOptions CreateLoadBalancerOptions(FileLoadBalancerOptions options)
|
||||
{
|
||||
return new LoadBalancerOptions(fileReRoute.LoadBalancerOptions.Type, fileReRoute.LoadBalancerOptions.Key, fileReRoute.LoadBalancerOptions.Expiry);
|
||||
return new LoadBalancerOptionsBuilder()
|
||||
.WithType(options.Type)
|
||||
.WithKey(options.Key)
|
||||
.WithExpiryInMs(options.Expiry)
|
||||
.Build();
|
||||
}
|
||||
|
||||
private string CreateReRouteKey(FileReRoute fileReRoute)
|
||||
@ -238,14 +252,7 @@ namespace Ocelot.Configuration.Creator
|
||||
return $"{nameof(CookieStickySessions)}:{fileReRoute.LoadBalancerOptions.Key}";
|
||||
}
|
||||
|
||||
return CreateQosKey(fileReRoute);
|
||||
}
|
||||
|
||||
private string CreateQosKey(FileReRoute fileReRoute)
|
||||
{
|
||||
//note - not sure if this is the correct key, but this is probably the only unique key i can think of given my poor brain
|
||||
var loadBalancerKey = $"{fileReRoute.UpstreamPathTemplate}|{string.Join(",", fileReRoute.UpstreamHttpMethod)}";
|
||||
return loadBalancerKey;
|
||||
return $"{fileReRoute.UpstreamPathTemplate}|{string.Join(",", fileReRoute.UpstreamHttpMethod)}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,19 +6,19 @@ namespace Ocelot.Configuration.Creator
|
||||
{
|
||||
public class HttpHandlerOptionsCreator : IHttpHandlerOptionsCreator
|
||||
{
|
||||
private IServiceTracer _tracer;
|
||||
private readonly IServiceTracer _tracer;
|
||||
|
||||
public HttpHandlerOptionsCreator(IServiceTracer tracer)
|
||||
{
|
||||
_tracer = tracer;
|
||||
}
|
||||
|
||||
public HttpHandlerOptions Create(FileReRoute fileReRoute)
|
||||
public HttpHandlerOptions Create(FileHttpHandlerOptions options)
|
||||
{
|
||||
var useTracing = _tracer.GetType() != typeof(FakeServiceTracer) ? fileReRoute.HttpHandlerOptions.UseTracing : false;
|
||||
var useTracing = _tracer.GetType() != typeof(FakeServiceTracer) && options.UseTracing;
|
||||
|
||||
return new HttpHandlerOptions(fileReRoute.HttpHandlerOptions.AllowAutoRedirect,
|
||||
fileReRoute.HttpHandlerOptions.UseCookieContainer, useTracing);
|
||||
return new HttpHandlerOptions(options.AllowAutoRedirect,
|
||||
options.UseCookieContainer, useTracing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,6 @@ namespace Ocelot.Configuration.Creator
|
||||
/// </summary>
|
||||
public interface IHttpHandlerOptionsCreator
|
||||
{
|
||||
HttpHandlerOptions Create(FileReRoute fileReRoute);
|
||||
HttpHandlerOptions Create(FileHttpHandlerOptions fileReRoute);
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,8 @@ namespace Ocelot.Configuration.Creator
|
||||
{
|
||||
public interface IQoSOptionsCreator
|
||||
{
|
||||
QoSOptions Create(FileReRoute fileReRoute);
|
||||
QoSOptions Create(FileQoSOptions options);
|
||||
QoSOptions Create(FileQoSOptions options, string pathTemplate, string[] httpMethods);
|
||||
QoSOptions Create(QoSOptions options, string pathTemplate, string[] httpMethods);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,4 +6,4 @@ namespace Ocelot.Configuration.Creator
|
||||
{
|
||||
ReRouteOptions Create(FileReRoute fileReRoute);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,47 @@
|
||||
using Ocelot.Configuration.Builder;
|
||||
using Ocelot.Configuration.File;
|
||||
|
||||
namespace Ocelot.Configuration.Creator
|
||||
{
|
||||
using Ocelot.Configuration.Builder;
|
||||
using Ocelot.Configuration.File;
|
||||
using System.Linq;
|
||||
|
||||
public class QoSOptionsCreator : IQoSOptionsCreator
|
||||
{
|
||||
public QoSOptions Create(FileReRoute fileReRoute)
|
||||
public QoSOptions Create(FileQoSOptions options)
|
||||
{
|
||||
return new QoSOptionsBuilder()
|
||||
.WithExceptionsAllowedBeforeBreaking(fileReRoute.QoSOptions.ExceptionsAllowedBeforeBreaking)
|
||||
.WithDurationOfBreak(fileReRoute.QoSOptions.DurationOfBreak)
|
||||
.WithTimeoutValue(fileReRoute.QoSOptions.TimeoutValue)
|
||||
.WithExceptionsAllowedBeforeBreaking(options.ExceptionsAllowedBeforeBreaking)
|
||||
.WithDurationOfBreak(options.DurationOfBreak)
|
||||
.WithTimeoutValue(options.TimeoutValue)
|
||||
.Build();
|
||||
}
|
||||
|
||||
public QoSOptions Create(FileQoSOptions options, string pathTemplate, string[] httpMethods)
|
||||
{
|
||||
var key = CreateKey(pathTemplate, httpMethods);
|
||||
|
||||
return Map(key, options.TimeoutValue, options.DurationOfBreak, options.ExceptionsAllowedBeforeBreaking);
|
||||
}
|
||||
|
||||
public QoSOptions Create(QoSOptions options, string pathTemplate, string[] httpMethods)
|
||||
{
|
||||
var key = CreateKey(pathTemplate, httpMethods);
|
||||
|
||||
return Map(key, options.TimeoutValue, options.DurationOfBreak, options.ExceptionsAllowedBeforeBreaking);
|
||||
}
|
||||
|
||||
private QoSOptions Map(string key, int timeoutValue, int durationOfBreak, int exceptionsAllowedBeforeBreaking)
|
||||
{
|
||||
return new QoSOptionsBuilder()
|
||||
.WithExceptionsAllowedBeforeBreaking(exceptionsAllowedBeforeBreaking)
|
||||
.WithDurationOfBreak(durationOfBreak)
|
||||
.WithTimeoutValue(timeoutValue)
|
||||
.WithKey(key)
|
||||
.Build();
|
||||
}
|
||||
|
||||
private string CreateKey(string pathTemplate, string[] httpMethods)
|
||||
{
|
||||
return $"{pathTemplate.FirstOrDefault()}|{string.Join(",", httpMethods)}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,14 +10,12 @@ namespace Ocelot.Configuration.Creator
|
||||
var isAuthenticated = IsAuthenticated(fileReRoute);
|
||||
var isAuthorised = IsAuthorised(fileReRoute);
|
||||
var isCached = IsCached(fileReRoute);
|
||||
var isQos = IsQoS(fileReRoute);
|
||||
var enableRateLimiting = IsEnableRateLimiting(fileReRoute);
|
||||
|
||||
var options = new ReRouteOptionsBuilder()
|
||||
.WithIsAuthenticated(isAuthenticated)
|
||||
.WithIsAuthorised(isAuthorised)
|
||||
.WithIsCached(isCached)
|
||||
.WithIsQos(isQos)
|
||||
.WithRateLimiting(enableRateLimiting)
|
||||
.Build();
|
||||
|
||||
@ -29,11 +27,6 @@ namespace Ocelot.Configuration.Creator
|
||||
return (fileReRoute.RateLimitOptions != null && fileReRoute.RateLimitOptions.EnableRateLimiting) ? true : false;
|
||||
}
|
||||
|
||||
private bool IsQoS(FileReRoute fileReRoute)
|
||||
{
|
||||
return fileReRoute.QoSOptions?.ExceptionsAllowedBeforeBreaking > 0 && fileReRoute.QoSOptions?.TimeoutValue > 0;
|
||||
}
|
||||
|
||||
private bool IsAuthenticated(FileReRoute fileReRoute)
|
||||
{
|
||||
return !string.IsNullOrEmpty(fileReRoute.AuthenticationOptions?.AuthenticationProviderKey);
|
||||
@ -48,5 +41,5 @@ namespace Ocelot.Configuration.Creator
|
||||
{
|
||||
return fileReRoute.FileCacheOptions.TtlSeconds > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,12 +7,12 @@ namespace Ocelot.Configuration.Creator
|
||||
{
|
||||
public ServiceProviderConfiguration Create(FileGlobalConfiguration globalConfiguration)
|
||||
{
|
||||
//todo log or return error here dont just default to something that wont work..
|
||||
var serviceProviderPort = globalConfiguration?.ServiceDiscoveryProvider?.Port ?? 0;
|
||||
var port = globalConfiguration?.ServiceDiscoveryProvider?.Port ?? 0;
|
||||
var host = globalConfiguration?.ServiceDiscoveryProvider?.Host ?? "consul";
|
||||
|
||||
return new ServiceProviderConfigurationBuilder()
|
||||
.WithHost(globalConfiguration?.ServiceDiscoveryProvider?.Host)
|
||||
.WithPort(serviceProviderPort)
|
||||
.WithHost(host)
|
||||
.WithPort(port)
|
||||
.WithType(globalConfiguration?.ServiceDiscoveryProvider?.Type)
|
||||
.WithToken(globalConfiguration?.ServiceDiscoveryProvider?.Token)
|
||||
.WithConfigurationKey(globalConfiguration?.ServiceDiscoveryProvider?.ConfigurationKey)
|
||||
|
@ -16,8 +16,7 @@ namespace Ocelot.Configuration
|
||||
HttpHandlerOptions httpHandlerOptions,
|
||||
bool useServiceDiscovery,
|
||||
bool enableEndpointEndpointRateLimiting,
|
||||
bool isQos,
|
||||
QoSOptions qosOptionsOptions,
|
||||
QoSOptions qosOptions,
|
||||
string downstreamScheme,
|
||||
string requestIdKey,
|
||||
bool isCached,
|
||||
@ -36,8 +35,7 @@ namespace Ocelot.Configuration
|
||||
List<string> delegatingHandlers,
|
||||
List<AddHeader> addHeadersToDownstream,
|
||||
List<AddHeader> addHeadersToUpstream,
|
||||
bool dangerousAcceptAnyServerCertificateValidator,
|
||||
string qosKey)
|
||||
bool dangerousAcceptAnyServerCertificateValidator)
|
||||
{
|
||||
DangerousAcceptAnyServerCertificateValidator = dangerousAcceptAnyServerCertificateValidator;
|
||||
AddHeadersToDownstream = addHeadersToDownstream;
|
||||
@ -51,8 +49,7 @@ namespace Ocelot.Configuration
|
||||
HttpHandlerOptions = httpHandlerOptions;
|
||||
UseServiceDiscovery = useServiceDiscovery;
|
||||
EnableEndpointEndpointRateLimiting = enableEndpointEndpointRateLimiting;
|
||||
IsQos = isQos;
|
||||
QosOptionsOptions = qosOptionsOptions;
|
||||
QosOptions = qosOptions;
|
||||
DownstreamScheme = downstreamScheme;
|
||||
RequestIdKey = requestIdKey;
|
||||
IsCached = isCached;
|
||||
@ -69,10 +66,8 @@ namespace Ocelot.Configuration
|
||||
DownstreamPathTemplate = downstreamPathTemplate;
|
||||
LoadBalancerKey = loadBalancerKey;
|
||||
AddHeadersToUpstream = addHeadersToUpstream;
|
||||
QosKey = qosKey;
|
||||
}
|
||||
|
||||
public string QosKey { get; }
|
||||
public string Key { get; }
|
||||
public PathTemplate UpstreamPathTemplate { get; }
|
||||
public List<HeaderFindAndReplace> UpstreamHeadersFindAndReplace { get; }
|
||||
@ -82,8 +77,7 @@ namespace Ocelot.Configuration
|
||||
public HttpHandlerOptions HttpHandlerOptions { get; }
|
||||
public bool UseServiceDiscovery { get; }
|
||||
public bool EnableEndpointEndpointRateLimiting { get; }
|
||||
public bool IsQos { get; }
|
||||
public QoSOptions QosOptionsOptions { get; }
|
||||
public QoSOptions QosOptions { get; }
|
||||
public string DownstreamScheme { get; }
|
||||
public string RequestIdKey { get; }
|
||||
public bool IsCached { get; }
|
||||
|
@ -6,6 +6,9 @@
|
||||
{
|
||||
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider();
|
||||
RateLimitOptions = new FileRateLimitOptions();
|
||||
LoadBalancerOptions = new FileLoadBalancerOptions();
|
||||
QoSOptions = new FileQoSOptions();
|
||||
HttpHandlerOptions = new FileHttpHandlerOptions();
|
||||
}
|
||||
|
||||
public string RequestIdKey { get; set; }
|
||||
@ -13,7 +16,15 @@
|
||||
public FileServiceDiscoveryProvider ServiceDiscoveryProvider { get;set; }
|
||||
|
||||
public FileRateLimitOptions RateLimitOptions { get; set; }
|
||||
|
||||
|
||||
public FileQoSOptions QoSOptions { get; set; }
|
||||
|
||||
public string BaseUrl { get ;set; }
|
||||
|
||||
public FileLoadBalancerOptions LoadBalancerOptions { get; set; }
|
||||
|
||||
public string DownstreamScheme { get; set; }
|
||||
|
||||
public FileHttpHandlerOptions HttpHandlerOptions { get; set; }
|
||||
}
|
||||
}
|
||||
|
32
src/Ocelot/Configuration/HttpHandlerOptionsBuilder.cs
Normal file
32
src/Ocelot/Configuration/HttpHandlerOptionsBuilder.cs
Normal file
@ -0,0 +1,32 @@
|
||||
namespace Ocelot.Configuration
|
||||
{
|
||||
public class HttpHandlerOptionsBuilder
|
||||
{
|
||||
private bool _allowAutoRedirect;
|
||||
private bool _useCookieContainer;
|
||||
private bool _useTracing;
|
||||
|
||||
public HttpHandlerOptionsBuilder WithAllowAutoRedirect(bool input)
|
||||
{
|
||||
_allowAutoRedirect = input;
|
||||
return this;
|
||||
}
|
||||
|
||||
public HttpHandlerOptionsBuilder WithUseCookieContainer(bool input)
|
||||
{
|
||||
_useCookieContainer = input;
|
||||
return this;
|
||||
}
|
||||
|
||||
public HttpHandlerOptionsBuilder WithUseTracing(bool input)
|
||||
{
|
||||
_useTracing = input;
|
||||
return this;
|
||||
}
|
||||
|
||||
public HttpHandlerOptions Build()
|
||||
{
|
||||
return new HttpHandlerOptions(_allowAutoRedirect, _useCookieContainer, _useTracing);
|
||||
}
|
||||
}
|
||||
}
|
@ -5,8 +5,19 @@ namespace Ocelot.Configuration
|
||||
public interface IInternalConfiguration
|
||||
{
|
||||
List<ReRoute> ReRoutes { get; }
|
||||
|
||||
string AdministrationPath {get;}
|
||||
|
||||
ServiceProviderConfiguration ServiceProviderConfiguration {get;}
|
||||
|
||||
string RequestId {get;}
|
||||
|
||||
LoadBalancerOptions LoadBalancerOptions { get; }
|
||||
|
||||
string DownstreamScheme { get; }
|
||||
|
||||
QoSOptions QoSOptions { get; }
|
||||
|
||||
HttpHandlerOptions HttpHandlerOptions { get; }
|
||||
}
|
||||
}
|
||||
|
@ -4,17 +4,33 @@ namespace Ocelot.Configuration
|
||||
{
|
||||
public class InternalConfiguration : IInternalConfiguration
|
||||
{
|
||||
public InternalConfiguration(List<ReRoute> reRoutes, string administrationPath, ServiceProviderConfiguration serviceProviderConfiguration, string requestId)
|
||||
public InternalConfiguration(
|
||||
List<ReRoute> reRoutes,
|
||||
string administrationPath,
|
||||
ServiceProviderConfiguration serviceProviderConfiguration,
|
||||
string requestId,
|
||||
LoadBalancerOptions loadBalancerOptions,
|
||||
string downstreamScheme,
|
||||
QoSOptions qoSOptions,
|
||||
HttpHandlerOptions httpHandlerOptions)
|
||||
{
|
||||
ReRoutes = reRoutes;
|
||||
AdministrationPath = administrationPath;
|
||||
ServiceProviderConfiguration = serviceProviderConfiguration;
|
||||
RequestId = requestId;
|
||||
LoadBalancerOptions = loadBalancerOptions;
|
||||
DownstreamScheme = downstreamScheme;
|
||||
QoSOptions = qoSOptions;
|
||||
HttpHandlerOptions = httpHandlerOptions;
|
||||
}
|
||||
|
||||
public List<ReRoute> ReRoutes { get; }
|
||||
public string AdministrationPath {get;}
|
||||
public ServiceProviderConfiguration ServiceProviderConfiguration {get;}
|
||||
public string RequestId {get;}
|
||||
public LoadBalancerOptions LoadBalancerOptions { get; }
|
||||
public string DownstreamScheme { get; }
|
||||
public QoSOptions QoSOptions { get; }
|
||||
public HttpHandlerOptions HttpHandlerOptions { get; }
|
||||
}
|
||||
}
|
||||
|
32
src/Ocelot/Configuration/LoadBalancerOptionsBuilder.cs
Normal file
32
src/Ocelot/Configuration/LoadBalancerOptionsBuilder.cs
Normal file
@ -0,0 +1,32 @@
|
||||
namespace Ocelot.Configuration
|
||||
{
|
||||
public class LoadBalancerOptionsBuilder
|
||||
{
|
||||
private string _type;
|
||||
private string _key;
|
||||
private int _expiryInMs;
|
||||
|
||||
public LoadBalancerOptionsBuilder WithType(string type)
|
||||
{
|
||||
_type = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LoadBalancerOptionsBuilder WithKey(string key)
|
||||
{
|
||||
_key = key;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LoadBalancerOptionsBuilder WithExpiryInMs(int expiryInMs)
|
||||
{
|
||||
_expiryInMs = expiryInMs;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LoadBalancerOptions Build()
|
||||
{
|
||||
return new LoadBalancerOptions(_type, _key, _expiryInMs);
|
||||
}
|
||||
}
|
||||
}
|
@ -8,12 +8,14 @@ namespace Ocelot.Configuration
|
||||
int exceptionsAllowedBeforeBreaking,
|
||||
int durationofBreak,
|
||||
int timeoutValue,
|
||||
string key,
|
||||
TimeoutStrategy timeoutStrategy = TimeoutStrategy.Pessimistic)
|
||||
{
|
||||
ExceptionsAllowedBeforeBreaking = exceptionsAllowedBeforeBreaking;
|
||||
DurationOfBreak = durationofBreak;
|
||||
TimeoutValue = timeoutValue;
|
||||
TimeoutStrategy = timeoutStrategy;
|
||||
Key = key;
|
||||
}
|
||||
|
||||
public int ExceptionsAllowedBeforeBreaking { get; }
|
||||
@ -23,5 +25,8 @@ namespace Ocelot.Configuration
|
||||
public int TimeoutValue { get; }
|
||||
|
||||
public TimeoutStrategy TimeoutStrategy { get; }
|
||||
|
||||
public bool UseQos => ExceptionsAllowedBeforeBreaking > 0 && TimeoutValue > 0;
|
||||
public string Key { get; }
|
||||
}
|
||||
}
|
||||
|
@ -2,19 +2,17 @@ namespace Ocelot.Configuration
|
||||
{
|
||||
public class ReRouteOptions
|
||||
{
|
||||
public ReRouteOptions(bool isAuthenticated, bool isAuthorised, bool isCached, bool isQos, bool isEnableRateLimiting)
|
||||
public ReRouteOptions(bool isAuthenticated, bool isAuthorised, bool isCached, bool isEnableRateLimiting)
|
||||
{
|
||||
IsAuthenticated = isAuthenticated;
|
||||
IsAuthorised = isAuthorised;
|
||||
IsCached = isCached;
|
||||
IsQos = isQos;
|
||||
EnableRateLimiting = isEnableRateLimiting;
|
||||
}
|
||||
|
||||
public bool IsAuthenticated { get; private set; }
|
||||
public bool IsAuthorised { get; private set; }
|
||||
public bool IsCached { get; private set; }
|
||||
public bool IsQos { get; private set; }
|
||||
public bool EnableRateLimiting { get; private set; }
|
||||
}
|
||||
}
|
||||
|
@ -30,20 +30,18 @@ namespace Ocelot.Configuration.Repository
|
||||
var internalConfig = repo.Get();
|
||||
|
||||
_configurationKey = "InternalConfiguration";
|
||||
var consulHost = "localhost";
|
||||
var consulPort = 8500;
|
||||
|
||||
string token = null;
|
||||
|
||||
if (!internalConfig.IsError)
|
||||
{
|
||||
consulHost = string.IsNullOrEmpty(internalConfig.Data.ServiceProviderConfiguration?.Host) ? consulHost : internalConfig.Data.ServiceProviderConfiguration?.Host;
|
||||
consulPort = internalConfig.Data.ServiceProviderConfiguration?.Port ?? consulPort;
|
||||
token = internalConfig.Data.ServiceProviderConfiguration?.Token;
|
||||
_configurationKey = !string.IsNullOrEmpty(internalConfig.Data.ServiceProviderConfiguration?.ConfigurationKey) ?
|
||||
internalConfig.Data.ServiceProviderConfiguration?.ConfigurationKey : _configurationKey;
|
||||
token = internalConfig.Data.ServiceProviderConfiguration.Token;
|
||||
_configurationKey = !string.IsNullOrEmpty(internalConfig.Data.ServiceProviderConfiguration.ConfigurationKey) ?
|
||||
internalConfig.Data.ServiceProviderConfiguration.ConfigurationKey : _configurationKey;
|
||||
}
|
||||
|
||||
var config = new ConsulRegistryConfiguration(consulHost, consulPort, _configurationKey, token);
|
||||
var config = new ConsulRegistryConfiguration(internalConfig.Data.ServiceProviderConfiguration.Host,
|
||||
internalConfig.Data.ServiceProviderConfiguration.Port, _configurationKey, token);
|
||||
|
||||
_consul = factory.Get(config);
|
||||
}
|
||||
|
@ -103,7 +103,9 @@ namespace Ocelot.DependencyInjection
|
||||
_services.TryAddSingleton<IUrlPathToUrlTemplateMatcher, RegExUrlMatcher>();
|
||||
_services.TryAddSingleton<IPlaceholderNameAndValueFinder, UrlPathPlaceholderNameAndValueFinder>();
|
||||
_services.TryAddSingleton<IDownstreamPathPlaceholderReplacer, DownstreamTemplatePathPlaceholderReplacer>();
|
||||
_services.TryAddSingleton<IDownstreamRouteFinder, DownstreamRouteFinder>();
|
||||
_services.AddSingleton<IDownstreamRouteProvider, DownstreamRouteFinder>();
|
||||
_services.AddSingleton<IDownstreamRouteProvider, Ocelot.DownstreamRouteFinder.Finder.DownstreamRouteCreator>();
|
||||
_services.TryAddSingleton<IDownstreamRouteProviderFactory, Ocelot.DownstreamRouteFinder.Finder.DownstreamRouteProviderFactory>();
|
||||
_services.TryAddSingleton<IHttpRequester, HttpClientHttpRequester>();
|
||||
_services.TryAddSingleton<IHttpResponder, HttpContextResponder>();
|
||||
_services.TryAddSingleton<IErrorsToHttpStatusCodeMapper, ErrorsToHttpStatusCodeMapper>();
|
||||
|
@ -0,0 +1,97 @@
|
||||
namespace Ocelot.DownstreamRouteFinder.Finder
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using Configuration;
|
||||
using Configuration.Builder;
|
||||
using Configuration.Creator;
|
||||
using Configuration.File;
|
||||
using LoadBalancer.LoadBalancers;
|
||||
using Responses;
|
||||
using UrlMatcher;
|
||||
|
||||
public class DownstreamRouteCreator : IDownstreamRouteProvider
|
||||
{
|
||||
private readonly IQoSOptionsCreator _qoSOptionsCreator;
|
||||
|
||||
public DownstreamRouteCreator(IQoSOptionsCreator qoSOptionsCreator)
|
||||
{
|
||||
_qoSOptionsCreator = qoSOptionsCreator;
|
||||
}
|
||||
|
||||
public Response<DownstreamRoute> Get(string upstreamUrlPath, string upstreamHttpMethod, IInternalConfiguration configuration, string upstreamHost)
|
||||
{
|
||||
var serviceName = GetServiceName(upstreamUrlPath);
|
||||
|
||||
var downstreamPath = GetDownstreamPath(upstreamUrlPath);
|
||||
|
||||
if(HasQueryString(downstreamPath))
|
||||
{
|
||||
downstreamPath = RemoveQueryString(downstreamPath);
|
||||
}
|
||||
|
||||
var downstreamPathForKeys = $"/{serviceName}{downstreamPath}";
|
||||
|
||||
var loadBalancerKey = CreateLoadBalancerKey(downstreamPathForKeys, upstreamHttpMethod, configuration.LoadBalancerOptions);
|
||||
|
||||
var qosOptions = _qoSOptionsCreator.Create(configuration.QoSOptions, downstreamPathForKeys, new []{ upstreamHttpMethod });
|
||||
|
||||
var downstreamReRoute = new DownstreamReRouteBuilder()
|
||||
.WithServiceName(serviceName)
|
||||
.WithLoadBalancerKey(loadBalancerKey)
|
||||
.WithDownstreamPathTemplate(downstreamPath)
|
||||
.WithUseServiceDiscovery(true)
|
||||
.WithHttpHandlerOptions(configuration.HttpHandlerOptions)
|
||||
.WithQosOptions(qosOptions)
|
||||
.WithDownstreamScheme(configuration.DownstreamScheme)
|
||||
.WithLoadBalancerOptions(configuration.LoadBalancerOptions)
|
||||
.Build();
|
||||
|
||||
var reRoute = new ReRouteBuilder()
|
||||
.WithDownstreamReRoute(downstreamReRoute)
|
||||
.WithUpstreamHttpMethod(new List<string>(){ upstreamHttpMethod })
|
||||
.Build();
|
||||
|
||||
return new OkResponse<DownstreamRoute>(new DownstreamRoute(new List<PlaceholderNameAndValue>(), reRoute));
|
||||
}
|
||||
|
||||
private static string RemoveQueryString(string downstreamPath)
|
||||
{
|
||||
return downstreamPath
|
||||
.Substring(0, downstreamPath.IndexOf('?'));
|
||||
}
|
||||
|
||||
private static bool HasQueryString(string downstreamPath)
|
||||
{
|
||||
return downstreamPath.Contains("?");
|
||||
}
|
||||
|
||||
private static string GetDownstreamPath(string upstreamUrlPath)
|
||||
{
|
||||
return upstreamUrlPath
|
||||
.Substring(upstreamUrlPath.IndexOf('/', 1));
|
||||
}
|
||||
|
||||
private static string GetServiceName(string upstreamUrlPath)
|
||||
{
|
||||
return upstreamUrlPath
|
||||
.Substring(1, upstreamUrlPath.IndexOf('/', 1))
|
||||
.TrimEnd('/');
|
||||
}
|
||||
|
||||
private string CreateLoadBalancerKey(string downstreamTemplatePath, string httpMethod, LoadBalancerOptions loadBalancerOptions)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(loadBalancerOptions.Type) && !string.IsNullOrEmpty(loadBalancerOptions.Key) && loadBalancerOptions.Type == nameof(CookieStickySessions))
|
||||
{
|
||||
return $"{nameof(CookieStickySessions)}:{loadBalancerOptions.Key}";
|
||||
}
|
||||
|
||||
return CreateQoSKey(downstreamTemplatePath, httpMethod);
|
||||
}
|
||||
|
||||
private string CreateQoSKey(string downstreamTemplatePath, string httpMethod)
|
||||
{
|
||||
var loadBalancerKey = $"{downstreamTemplatePath}|{httpMethod}";
|
||||
return loadBalancerKey;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,62 +1,62 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Ocelot.Configuration;
|
||||
using Ocelot.DownstreamRouteFinder.UrlMatcher;
|
||||
using Ocelot.Errors;
|
||||
using Ocelot.Responses;
|
||||
|
||||
namespace Ocelot.DownstreamRouteFinder.Finder
|
||||
{
|
||||
public class DownstreamRouteFinder : IDownstreamRouteFinder
|
||||
{
|
||||
private readonly IUrlPathToUrlTemplateMatcher _urlMatcher;
|
||||
private readonly IPlaceholderNameAndValueFinder _placeholderNameAndValueFinder;
|
||||
|
||||
public DownstreamRouteFinder(IUrlPathToUrlTemplateMatcher urlMatcher, IPlaceholderNameAndValueFinder urlPathPlaceholderNameAndValueFinder)
|
||||
{
|
||||
_urlMatcher = urlMatcher;
|
||||
_placeholderNameAndValueFinder = urlPathPlaceholderNameAndValueFinder;
|
||||
}
|
||||
|
||||
public Response<DownstreamRoute> FindDownstreamRoute(string path, string httpMethod, IInternalConfiguration configuration, string upstreamHost)
|
||||
{
|
||||
var downstreamRoutes = new List<DownstreamRoute>();
|
||||
|
||||
var applicableReRoutes = configuration.ReRoutes
|
||||
.Where(r => RouteIsApplicableToThisRequest(r, httpMethod, upstreamHost))
|
||||
.OrderByDescending(x => x.UpstreamTemplatePattern.Priority);
|
||||
|
||||
foreach (var reRoute in applicableReRoutes)
|
||||
{
|
||||
var urlMatch = _urlMatcher.Match(path, reRoute.UpstreamTemplatePattern.Template);
|
||||
|
||||
if (urlMatch.Data.Match)
|
||||
{
|
||||
downstreamRoutes.Add(GetPlaceholderNamesAndValues(path, reRoute));
|
||||
}
|
||||
}
|
||||
|
||||
if (downstreamRoutes.Any())
|
||||
{
|
||||
var notNullOption = downstreamRoutes.FirstOrDefault(x => !string.IsNullOrEmpty(x.ReRoute.UpstreamHost));
|
||||
var nullOption = downstreamRoutes.FirstOrDefault(x => string.IsNullOrEmpty(x.ReRoute.UpstreamHost));
|
||||
|
||||
return notNullOption != null ? new OkResponse<DownstreamRoute>(notNullOption) : new OkResponse<DownstreamRoute>(nullOption);
|
||||
}
|
||||
|
||||
return new ErrorResponse<DownstreamRoute>(new UnableToFindDownstreamRouteError(path, httpMethod));
|
||||
}
|
||||
|
||||
private bool RouteIsApplicableToThisRequest(ReRoute reRoute, string httpMethod, string upstreamHost)
|
||||
{
|
||||
return reRoute.UpstreamHttpMethod.Count == 0 || reRoute.UpstreamHttpMethod.Select(x => x.Method.ToLower()).Contains(httpMethod.ToLower()) && !(!string.IsNullOrEmpty(reRoute.UpstreamHost) && reRoute.UpstreamHost != upstreamHost);
|
||||
}
|
||||
|
||||
private DownstreamRoute GetPlaceholderNamesAndValues(string path, ReRoute reRoute)
|
||||
{
|
||||
var templatePlaceholderNameAndValues = _placeholderNameAndValueFinder.Find(path, reRoute.UpstreamPathTemplate.Value);
|
||||
|
||||
return new DownstreamRoute(templatePlaceholderNameAndValues.Data, reRoute);
|
||||
}
|
||||
}
|
||||
}
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Ocelot.Configuration;
|
||||
using Ocelot.DownstreamRouteFinder.UrlMatcher;
|
||||
using Ocelot.Errors;
|
||||
using Ocelot.Responses;
|
||||
|
||||
namespace Ocelot.DownstreamRouteFinder.Finder
|
||||
{
|
||||
public class DownstreamRouteFinder : IDownstreamRouteProvider
|
||||
{
|
||||
private readonly IUrlPathToUrlTemplateMatcher _urlMatcher;
|
||||
private readonly IPlaceholderNameAndValueFinder _placeholderNameAndValueFinder;
|
||||
|
||||
public DownstreamRouteFinder(IUrlPathToUrlTemplateMatcher urlMatcher, IPlaceholderNameAndValueFinder urlPathPlaceholderNameAndValueFinder)
|
||||
{
|
||||
_urlMatcher = urlMatcher;
|
||||
_placeholderNameAndValueFinder = urlPathPlaceholderNameAndValueFinder;
|
||||
}
|
||||
|
||||
public Response<DownstreamRoute> Get(string path, string httpMethod, IInternalConfiguration configuration, string upstreamHost)
|
||||
{
|
||||
var downstreamRoutes = new List<DownstreamRoute>();
|
||||
|
||||
var applicableReRoutes = configuration.ReRoutes
|
||||
.Where(r => RouteIsApplicableToThisRequest(r, httpMethod, upstreamHost))
|
||||
.OrderByDescending(x => x.UpstreamTemplatePattern.Priority);
|
||||
|
||||
foreach (var reRoute in applicableReRoutes)
|
||||
{
|
||||
var urlMatch = _urlMatcher.Match(path, reRoute.UpstreamTemplatePattern.Template);
|
||||
|
||||
if (urlMatch.Data.Match)
|
||||
{
|
||||
downstreamRoutes.Add(GetPlaceholderNamesAndValues(path, reRoute));
|
||||
}
|
||||
}
|
||||
|
||||
if (downstreamRoutes.Any())
|
||||
{
|
||||
var notNullOption = downstreamRoutes.FirstOrDefault(x => !string.IsNullOrEmpty(x.ReRoute.UpstreamHost));
|
||||
var nullOption = downstreamRoutes.FirstOrDefault(x => string.IsNullOrEmpty(x.ReRoute.UpstreamHost));
|
||||
|
||||
return notNullOption != null ? new OkResponse<DownstreamRoute>(notNullOption) : new OkResponse<DownstreamRoute>(nullOption);
|
||||
}
|
||||
|
||||
return new ErrorResponse<DownstreamRoute>(new UnableToFindDownstreamRouteError(path, httpMethod));
|
||||
}
|
||||
|
||||
private bool RouteIsApplicableToThisRequest(ReRoute reRoute, string httpMethod, string upstreamHost)
|
||||
{
|
||||
return reRoute.UpstreamHttpMethod.Count == 0 || reRoute.UpstreamHttpMethod.Select(x => x.Method.ToLower()).Contains(httpMethod.ToLower()) && !(!string.IsNullOrEmpty(reRoute.UpstreamHost) && reRoute.UpstreamHost != upstreamHost);
|
||||
}
|
||||
|
||||
private DownstreamRoute GetPlaceholderNamesAndValues(string path, ReRoute reRoute)
|
||||
{
|
||||
var templatePlaceholderNameAndValues = _placeholderNameAndValueFinder.Find(path, reRoute.UpstreamPathTemplate.Value);
|
||||
|
||||
return new DownstreamRoute(templatePlaceholderNameAndValues.Data, reRoute);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,38 @@
|
||||
namespace Ocelot.DownstreamRouteFinder.Finder
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
public class DownstreamRouteProviderFactory : IDownstreamRouteProviderFactory
|
||||
{
|
||||
private readonly Dictionary<string, IDownstreamRouteProvider> _providers;
|
||||
|
||||
public DownstreamRouteProviderFactory(IServiceProvider provider)
|
||||
{
|
||||
_providers = provider.GetServices<IDownstreamRouteProvider>().ToDictionary(x => x.GetType().Name);
|
||||
}
|
||||
|
||||
public IDownstreamRouteProvider Get(IInternalConfiguration config)
|
||||
{
|
||||
if(!config.ReRoutes.Any() && IsServiceDiscovery(config.ServiceProviderConfiguration))
|
||||
{
|
||||
return _providers[nameof(DownstreamRouteCreator)];
|
||||
}
|
||||
|
||||
return _providers[nameof(DownstreamRouteFinder)];
|
||||
}
|
||||
|
||||
private bool IsServiceDiscovery(ServiceProviderConfiguration config)
|
||||
{
|
||||
if(!string.IsNullOrEmpty(config?.Host) || config?.Port > 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
using System.Threading.Tasks;
|
||||
using Ocelot.Configuration;
|
||||
using Ocelot.Responses;
|
||||
|
||||
namespace Ocelot.DownstreamRouteFinder.Finder
|
||||
{
|
||||
public interface IDownstreamRouteFinder
|
||||
{
|
||||
Response<DownstreamRoute> FindDownstreamRoute(string upstreamUrlPath, string upstreamHttpMethod, IInternalConfiguration configuration, string upstreamHost);
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
using System.Threading.Tasks;
|
||||
using Ocelot.Configuration;
|
||||
using Ocelot.Responses;
|
||||
|
||||
namespace Ocelot.DownstreamRouteFinder.Finder
|
||||
{
|
||||
public interface IDownstreamRouteProvider
|
||||
{
|
||||
Response<DownstreamRoute> Get(string upstreamUrlPath, string upstreamHttpMethod, IInternalConfiguration configuration, string upstreamHost);
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
namespace Ocelot.DownstreamRouteFinder.Finder
|
||||
{
|
||||
using Configuration;
|
||||
|
||||
public interface IDownstreamRouteProviderFactory
|
||||
{
|
||||
IDownstreamRouteProvider Get(IInternalConfiguration config);
|
||||
}
|
||||
}
|
@ -1,69 +1,60 @@
|
||||
using System.Threading.Tasks;
|
||||
using System.Linq;
|
||||
using Ocelot.Configuration.Repository;
|
||||
using Ocelot.DownstreamRouteFinder.Finder;
|
||||
using Ocelot.Infrastructure.Extensions;
|
||||
using Ocelot.Logging;
|
||||
using Ocelot.Middleware;
|
||||
using Ocelot.Middleware.Multiplexer;
|
||||
|
||||
namespace Ocelot.DownstreamRouteFinder.Middleware
|
||||
{
|
||||
public class DownstreamRouteFinderMiddleware : OcelotMiddleware
|
||||
{
|
||||
private readonly OcelotRequestDelegate _next;
|
||||
private readonly IDownstreamRouteFinder _downstreamRouteFinder;
|
||||
private readonly IInternalConfigurationRepository _repo;
|
||||
private readonly IMultiplexer _multiplexer;
|
||||
|
||||
public DownstreamRouteFinderMiddleware(OcelotRequestDelegate next,
|
||||
IOcelotLoggerFactory loggerFactory,
|
||||
IDownstreamRouteFinder downstreamRouteFinder,
|
||||
IInternalConfigurationRepository repo,
|
||||
IMultiplexer multiplexer)
|
||||
:base(loggerFactory.CreateLogger<DownstreamRouteFinderMiddleware>())
|
||||
{
|
||||
_repo = repo;
|
||||
_multiplexer = multiplexer;
|
||||
_next = next;
|
||||
_downstreamRouteFinder = downstreamRouteFinder;
|
||||
}
|
||||
|
||||
public async Task Invoke(DownstreamContext context)
|
||||
{
|
||||
var upstreamUrlPath = context.HttpContext.Request.Path.ToString();
|
||||
|
||||
var upstreamHost = context.HttpContext.Request.Headers["Host"];
|
||||
|
||||
var configuration = _repo.Get();
|
||||
|
||||
if (configuration.IsError)
|
||||
{
|
||||
Logger.LogWarning($"{MiddlewareName} setting pipeline errors. IOcelotConfigurationProvider returned {configuration.Errors.ToErrorString()}");
|
||||
SetPipelineError(context, configuration.Errors);
|
||||
return;
|
||||
}
|
||||
|
||||
context.ServiceProviderConfiguration = configuration.Data.ServiceProviderConfiguration;
|
||||
|
||||
Logger.LogDebug($"Upstream url path is {upstreamUrlPath}");
|
||||
|
||||
var downstreamRoute = _downstreamRouteFinder.FindDownstreamRoute(upstreamUrlPath, context.HttpContext.Request.Method, configuration.Data, upstreamHost);
|
||||
|
||||
if (downstreamRoute.IsError)
|
||||
{
|
||||
Logger.LogWarning($"{MiddlewareName} setting pipeline errors. IDownstreamRouteFinder returned {downstreamRoute.Errors.ToErrorString()}");
|
||||
|
||||
SetPipelineError(context, downstreamRoute.Errors);
|
||||
return;
|
||||
}
|
||||
|
||||
var downstreamPathTemplates = string.Join(", ", downstreamRoute.Data.ReRoute.DownstreamReRoute.Select(r => r.DownstreamPathTemplate.Value));
|
||||
Logger.LogDebug($"downstream templates are {downstreamPathTemplates}");
|
||||
|
||||
context.TemplatePlaceholderNameAndValues = downstreamRoute.Data.TemplatePlaceholderNameAndValues;
|
||||
|
||||
await _multiplexer.Multiplex(context, downstreamRoute.Data.ReRoute, _next);
|
||||
}
|
||||
}
|
||||
}
|
||||
using System.Threading.Tasks;
|
||||
using System.Linq;
|
||||
using Ocelot.Configuration.Repository;
|
||||
using Ocelot.DownstreamRouteFinder.Finder;
|
||||
using Ocelot.Infrastructure.Extensions;
|
||||
using Ocelot.Logging;
|
||||
using Ocelot.Middleware;
|
||||
using Ocelot.Middleware.Multiplexer;
|
||||
|
||||
namespace Ocelot.DownstreamRouteFinder.Middleware
|
||||
{
|
||||
public class DownstreamRouteFinderMiddleware : OcelotMiddleware
|
||||
{
|
||||
private readonly OcelotRequestDelegate _next;
|
||||
private readonly IDownstreamRouteProviderFactory _factory;
|
||||
private readonly IInternalConfigurationRepository _repo;
|
||||
private readonly IMultiplexer _multiplexer;
|
||||
|
||||
public DownstreamRouteFinderMiddleware(OcelotRequestDelegate next,
|
||||
IOcelotLoggerFactory loggerFactory,
|
||||
IDownstreamRouteProviderFactory downstreamRouteFinder,
|
||||
IInternalConfigurationRepository repo,
|
||||
IMultiplexer multiplexer)
|
||||
:base(loggerFactory.CreateLogger<DownstreamRouteFinderMiddleware>())
|
||||
{
|
||||
_repo = repo;
|
||||
_multiplexer = multiplexer;
|
||||
_next = next;
|
||||
_factory = downstreamRouteFinder;
|
||||
}
|
||||
|
||||
public async Task Invoke(DownstreamContext context)
|
||||
{
|
||||
var upstreamUrlPath = context.HttpContext.Request.Path.ToString();
|
||||
|
||||
var upstreamHost = context.HttpContext.Request.Headers["Host"];
|
||||
|
||||
Logger.LogDebug($"Upstream url path is {upstreamUrlPath}");
|
||||
|
||||
var provider = _factory.Get(context.Configuration);
|
||||
|
||||
var downstreamRoute = provider.Get(upstreamUrlPath, context.HttpContext.Request.Method, context.Configuration, upstreamHost);
|
||||
|
||||
if (downstreamRoute.IsError)
|
||||
{
|
||||
Logger.LogWarning($"{MiddlewareName} setting pipeline errors. IDownstreamRouteFinder returned {downstreamRoute.Errors.ToErrorString()}");
|
||||
|
||||
SetPipelineError(context, downstreamRoute.Errors);
|
||||
return;
|
||||
}
|
||||
|
||||
var downstreamPathTemplates = string.Join(", ", downstreamRoute.Data.ReRoute.DownstreamReRoute.Select(r => r.DownstreamPathTemplate.Value));
|
||||
Logger.LogDebug($"downstream templates are {downstreamPathTemplates}");
|
||||
|
||||
context.TemplatePlaceholderNameAndValues = downstreamRoute.Data.TemplatePlaceholderNameAndValues;
|
||||
|
||||
await _multiplexer.Multiplex(context, downstreamRoute.Data.ReRoute, _next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ namespace Ocelot.DownstreamUrlCreator.Middleware
|
||||
|
||||
private static bool ServiceFabricRequest(DownstreamContext context)
|
||||
{
|
||||
return context.ServiceProviderConfiguration.Type == "ServiceFabric" && context.DownstreamReRoute.UseServiceDiscovery;
|
||||
return context.Configuration.ServiceProviderConfiguration.Type == "ServiceFabric" && context.DownstreamReRoute.UseServiceDiscovery;
|
||||
}
|
||||
|
||||
private static bool RequestForStatefullService(string query)
|
||||
|
@ -9,6 +9,8 @@ using Ocelot.Middleware;
|
||||
|
||||
namespace Ocelot.Errors.Middleware
|
||||
{
|
||||
using Configuration;
|
||||
|
||||
/// <summary>
|
||||
/// Catches all unhandled exceptions thrown by middleware, logs and returns a 500
|
||||
/// </summary>
|
||||
@ -32,8 +34,20 @@ namespace Ocelot.Errors.Middleware
|
||||
public async Task Invoke(DownstreamContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
TrySetGlobalRequestId(context);
|
||||
{
|
||||
//try and get the global request id and set it for logs...
|
||||
//should this basically be immutable per request...i guess it should!
|
||||
//first thing is get config
|
||||
var configuration = _configRepo.Get();
|
||||
|
||||
if (configuration.IsError)
|
||||
{
|
||||
throw new Exception($"{MiddlewareName} setting pipeline errors. IOcelotConfigurationProvider returned {configuration.Errors.ToErrorString()}");
|
||||
}
|
||||
|
||||
TrySetGlobalRequestId(context, configuration.Data);
|
||||
|
||||
context.Configuration = configuration.Data;
|
||||
|
||||
Logger.LogDebug("ocelot pipeline started");
|
||||
|
||||
@ -53,19 +67,9 @@ namespace Ocelot.Errors.Middleware
|
||||
Logger.LogDebug("ocelot pipeline finished");
|
||||
}
|
||||
|
||||
private void TrySetGlobalRequestId(DownstreamContext context)
|
||||
private void TrySetGlobalRequestId(DownstreamContext context, IInternalConfiguration configuration)
|
||||
{
|
||||
//try and get the global request id and set it for logs...
|
||||
//should this basically be immutable per request...i guess it should!
|
||||
//first thing is get config
|
||||
var configuration = _configRepo.Get();
|
||||
|
||||
if(configuration.IsError)
|
||||
{
|
||||
throw new Exception($"{MiddlewareName} setting pipeline errors. IOcelotConfigurationProvider returned {configuration.Errors.ToErrorString()}");
|
||||
}
|
||||
|
||||
var key = configuration.Data.RequestId;
|
||||
var key = configuration.RequestId;
|
||||
|
||||
if (!string.IsNullOrEmpty(key) && context.HttpContext.Request.Headers.TryGetValue(key, out var upstreamRequestIds))
|
||||
{
|
||||
|
@ -18,7 +18,7 @@ namespace Ocelot.LoadBalancer.LoadBalancers
|
||||
|
||||
public async Task<Response<ServiceHostAndPort>> Lease(DownstreamContext downstreamContext)
|
||||
{
|
||||
//todo no point spinning a task up here, also first or default could be null..
|
||||
//todo first or default could be null..
|
||||
if (_services == null || _services.Count == 0)
|
||||
{
|
||||
return new ErrorResponse<ServiceHostAndPort>(new ServicesAreEmptyError("There were no services in NoLoadBalancer"));
|
||||
|
@ -22,7 +22,7 @@ namespace Ocelot.LoadBalancer.Middleware
|
||||
|
||||
public async Task Invoke(DownstreamContext context)
|
||||
{
|
||||
var loadBalancer = await _loadBalancerHouse.Get(context.DownstreamReRoute, context.ServiceProviderConfiguration);
|
||||
var loadBalancer = await _loadBalancerHouse.Get(context.DownstreamReRoute, context.Configuration.ServiceProviderConfiguration);
|
||||
if(loadBalancer.IsError)
|
||||
{
|
||||
Logger.LogDebug("there was an error retriving the loadbalancer, setting pipeline error");
|
||||
|
@ -1,11 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Ocelot.Configuration;
|
||||
using Ocelot.DownstreamRouteFinder.UrlMatcher;
|
||||
using Ocelot.Errors;
|
||||
using Ocelot.Middleware.Multiplexer;
|
||||
using Ocelot.Request.Middleware;
|
||||
|
||||
namespace Ocelot.Middleware
|
||||
@ -20,8 +17,6 @@ namespace Ocelot.Middleware
|
||||
|
||||
public List<PlaceholderNameAndValue> TemplatePlaceholderNameAndValues { get; set; }
|
||||
|
||||
public ServiceProviderConfiguration ServiceProviderConfiguration {get; set;}
|
||||
|
||||
public HttpContext HttpContext { get; }
|
||||
|
||||
public DownstreamReRoute DownstreamReRoute { get; set; }
|
||||
@ -32,6 +27,8 @@ namespace Ocelot.Middleware
|
||||
|
||||
public List<Error> Errors { get; }
|
||||
|
||||
public IInternalConfiguration Configuration { get; set; }
|
||||
|
||||
public bool IsError => Errors.Count > 0;
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ namespace Ocelot.Middleware.Multiplexer
|
||||
var downstreamContext = new DownstreamContext(context.HttpContext)
|
||||
{
|
||||
TemplatePlaceholderNameAndValues = context.TemplatePlaceholderNameAndValues,
|
||||
ServiceProviderConfiguration = context.ServiceProviderConfiguration,
|
||||
Configuration = context.Configuration,
|
||||
DownstreamReRoute = reRoute.DownstreamReRoute[i],
|
||||
};
|
||||
|
||||
|
@ -68,7 +68,7 @@ namespace Ocelot.Requester
|
||||
handlers.Add(() => (DelegatingHandler)_factory.Get());
|
||||
}
|
||||
|
||||
if (request.IsQos)
|
||||
if (request.QosOptions.UseQos)
|
||||
{
|
||||
var qosProvider = _qosProviderHouse.Get(request);
|
||||
|
||||
|
@ -58,9 +58,9 @@ namespace Ocelot.Requester
|
||||
.LogWarning($"You have ignored all SSL warnings by using DangerousAcceptAnyServerCertificateValidator for this DownstreamReRoute, UpstreamPathTemplate: {context.DownstreamReRoute.UpstreamPathTemplate}, DownstreamPathTemplate: {context.DownstreamReRoute.DownstreamPathTemplate}");
|
||||
}
|
||||
|
||||
var timeout = context.DownstreamReRoute.QosOptionsOptions.TimeoutValue == 0
|
||||
var timeout = context.DownstreamReRoute.QosOptions.TimeoutValue == 0
|
||||
? _defaultTimeout
|
||||
: TimeSpan.FromMilliseconds(context.DownstreamReRoute.QosOptionsOptions.TimeoutValue);
|
||||
: TimeSpan.FromMilliseconds(context.DownstreamReRoute.QosOptions.TimeoutValue);
|
||||
|
||||
_httpClient = new HttpClient(CreateHttpMessageHandler(httpclientHandler, context.DownstreamReRoute))
|
||||
{
|
||||
|
@ -19,15 +19,15 @@ namespace Ocelot.Requester.QoS
|
||||
{
|
||||
_logger = loggerFactory.CreateLogger<PollyQoSProvider>();
|
||||
|
||||
_timeoutPolicy = Policy.TimeoutAsync(TimeSpan.FromMilliseconds(reRoute.QosOptionsOptions.TimeoutValue), reRoute.QosOptionsOptions.TimeoutStrategy);
|
||||
_timeoutPolicy = Policy.TimeoutAsync(TimeSpan.FromMilliseconds(reRoute.QosOptions.TimeoutValue), reRoute.QosOptions.TimeoutStrategy);
|
||||
|
||||
_circuitBreakerPolicy = Policy
|
||||
.Handle<HttpRequestException>()
|
||||
.Or<TimeoutRejectedException>()
|
||||
.Or<TimeoutException>()
|
||||
.CircuitBreakerAsync(
|
||||
exceptionsAllowedBeforeBreaking: reRoute.QosOptionsOptions.ExceptionsAllowedBeforeBreaking,
|
||||
durationOfBreak: TimeSpan.FromMilliseconds(reRoute.QosOptionsOptions.DurationOfBreak),
|
||||
exceptionsAllowedBeforeBreaking: reRoute.QosOptions.ExceptionsAllowedBeforeBreaking,
|
||||
durationOfBreak: TimeSpan.FromMilliseconds(reRoute.QosOptions.DurationOfBreak),
|
||||
onBreak: (ex, breakDelay) =>
|
||||
{
|
||||
_logger.LogError(
|
||||
|
@ -14,7 +14,7 @@ namespace Ocelot.Requester.QoS
|
||||
|
||||
public IQoSProvider Get(DownstreamReRoute reRoute)
|
||||
{
|
||||
if (reRoute.IsQos)
|
||||
if (reRoute.QosOptions.UseQos)
|
||||
{
|
||||
return new PollyQoSProvider(reRoute, _loggerFactory);
|
||||
}
|
||||
|
@ -21,26 +21,26 @@ namespace Ocelot.Requester.QoS
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_qoSProviders.TryGetValue(reRoute.QosKey, out var qosProvider))
|
||||
if (_qoSProviders.TryGetValue(reRoute.QosOptions.Key, out var qosProvider))
|
||||
{
|
||||
if (reRoute.IsQos && qosProvider.CircuitBreaker == null)
|
||||
if (reRoute.QosOptions.UseQos && qosProvider.CircuitBreaker == null)
|
||||
{
|
||||
qosProvider = _qoSProviderFactory.Get(reRoute);
|
||||
Add(reRoute.QosKey, qosProvider);
|
||||
Add(reRoute.QosOptions.Key, qosProvider);
|
||||
}
|
||||
|
||||
return new OkResponse<IQoSProvider>(_qoSProviders[reRoute.QosKey]);
|
||||
return new OkResponse<IQoSProvider>(_qoSProviders[reRoute.QosOptions.Key]);
|
||||
}
|
||||
|
||||
qosProvider = _qoSProviderFactory.Get(reRoute);
|
||||
Add(reRoute.QosKey, qosProvider);
|
||||
Add(reRoute.QosOptions.Key, qosProvider);
|
||||
return new OkResponse<IQoSProvider>(qosProvider);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ErrorResponse<IQoSProvider>(new List<Ocelot.Errors.Error>()
|
||||
{
|
||||
new UnableToFindQoSProviderError($"unabe to find qos provider for {reRoute.QosKey}, exception was {ex}")
|
||||
new UnableToFindQoSProviderError($"unabe to find qos provider for {reRoute.QosOptions.Key}, exception was {ex}")
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -4,8 +4,8 @@ namespace Ocelot.ServiceDiscovery.Configuration
|
||||
{
|
||||
public ConsulRegistryConfiguration(string host, int port, string keyOfServiceInConsul, string token)
|
||||
{
|
||||
Host = host;
|
||||
Port = port;
|
||||
Host = string.IsNullOrEmpty(host) ? "localhost" : host;
|
||||
Port = port > 0 ? port : 8500;
|
||||
KeyOfServiceInConsul = keyOfServiceInConsul;
|
||||
Token = token;
|
||||
}
|
||||
|
@ -22,12 +22,7 @@ namespace Ocelot.ServiceDiscovery.Providers
|
||||
{;
|
||||
_logger = factory.CreateLogger<ConsulServiceDiscoveryProvider>();
|
||||
|
||||
var consulHost = string.IsNullOrEmpty(config?.Host) ? "localhost" : config.Host;
|
||||
|
||||
var consulPort = config?.Port ?? 8500;
|
||||
|
||||
_config = new ConsulRegistryConfiguration(consulHost, consulPort, config?.KeyOfServiceInConsul, config?.Token);
|
||||
|
||||
_config = config;
|
||||
_consul = clientFactory.Get(_config);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user