mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-11-04 09:15:27 +08:00 
			
		
		
		
	Merge branch 'develop' into feature/Optimization-HttpClient-instance
This commit is contained in:
		
							
								
								
									
										71
									
								
								src/Ocelot/Configuration/Builder/RateLimitOptionsBuilder.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								src/Ocelot/Configuration/Builder/RateLimitOptionsBuilder.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,71 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Configuration.Builder
 | 
			
		||||
{
 | 
			
		||||
    public class RateLimitOptionsBuilder
 | 
			
		||||
    {
 | 
			
		||||
        private bool _enableRateLimiting;
 | 
			
		||||
        private string _clientIdHeader;
 | 
			
		||||
        private List<string> _clientWhitelist;
 | 
			
		||||
        private bool _disableRateLimitHeaders;
 | 
			
		||||
        private string _quotaExceededMessage;
 | 
			
		||||
        private string _rateLimitCounterPrefix;
 | 
			
		||||
        private RateLimitRule _rateLimitRule;
 | 
			
		||||
        private int _httpStatusCode;
 | 
			
		||||
 | 
			
		||||
        public RateLimitOptionsBuilder WithEnableRateLimiting(bool enableRateLimiting)
 | 
			
		||||
        {
 | 
			
		||||
            _enableRateLimiting = enableRateLimiting;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public RateLimitOptionsBuilder WithClientIdHeader(string clientIdheader)
 | 
			
		||||
        {
 | 
			
		||||
            _clientIdHeader = clientIdheader;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public RateLimitOptionsBuilder WithClientWhiteList(List<string> clientWhitelist)
 | 
			
		||||
        {
 | 
			
		||||
            _clientWhitelist = clientWhitelist;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public RateLimitOptionsBuilder WithDisableRateLimitHeaders(bool disableRateLimitHeaders)
 | 
			
		||||
        {
 | 
			
		||||
            _disableRateLimitHeaders = disableRateLimitHeaders;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public RateLimitOptionsBuilder WithQuotaExceededMessage(string quotaExceededMessage)
 | 
			
		||||
        {
 | 
			
		||||
            _quotaExceededMessage = quotaExceededMessage;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public RateLimitOptionsBuilder WithRateLimitCounterPrefix(string rateLimitCounterPrefix)
 | 
			
		||||
        {
 | 
			
		||||
            _rateLimitCounterPrefix = rateLimitCounterPrefix;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public RateLimitOptionsBuilder WithRateLimitRule(RateLimitRule rateLimitRule)
 | 
			
		||||
        {
 | 
			
		||||
            _rateLimitRule = rateLimitRule;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public RateLimitOptionsBuilder WithHttpStatusCode(int httpStatusCode)
 | 
			
		||||
        {
 | 
			
		||||
            _httpStatusCode = httpStatusCode;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public RateLimitOptions Build()
 | 
			
		||||
        {
 | 
			
		||||
            return new RateLimitOptions(_enableRateLimiting, _clientIdHeader, _clientWhitelist, 
 | 
			
		||||
                _disableRateLimitHeaders, _quotaExceededMessage, _rateLimitCounterPrefix, 
 | 
			
		||||
                _rateLimitRule, _httpStatusCode);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -25,7 +25,7 @@ namespace Ocelot.Configuration.Builder
 | 
			
		||||
        private string _downstreamHost;
 | 
			
		||||
        private int _downstreamPort;
 | 
			
		||||
        private string _loadBalancer;
 | 
			
		||||
        private ServiceProviderConfiguraion _serviceProviderConfiguraion;
 | 
			
		||||
        private ServiceProviderConfiguration _serviceProviderConfiguraion;
 | 
			
		||||
        private bool _useQos;
 | 
			
		||||
        private QoSOptions _qosOptions;
 | 
			
		||||
        public bool _enableRateLimiting;
 | 
			
		||||
@@ -150,7 +150,7 @@ namespace Ocelot.Configuration.Builder
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public ReRouteBuilder WithServiceProviderConfiguraion(ServiceProviderConfiguraion serviceProviderConfiguraion)
 | 
			
		||||
        public ReRouteBuilder WithServiceProviderConfiguraion(ServiceProviderConfiguration serviceProviderConfiguraion)
 | 
			
		||||
        {
 | 
			
		||||
            _serviceProviderConfiguraion = serviceProviderConfiguraion;
 | 
			
		||||
            return this;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										46
									
								
								src/Ocelot/Configuration/Builder/ReRouteOptionsBuilder.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/Ocelot/Configuration/Builder/ReRouteOptionsBuilder.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
			
		||||
namespace Ocelot.Configuration.Builder
 | 
			
		||||
{
 | 
			
		||||
    public class ReRouteOptionsBuilder
 | 
			
		||||
    {
 | 
			
		||||
        private bool _isAuthenticated;
 | 
			
		||||
        private bool _isAuthorised;
 | 
			
		||||
        private bool _isCached;
 | 
			
		||||
        private bool _isQoS;
 | 
			
		||||
        private bool _enableRateLimiting;
 | 
			
		||||
 | 
			
		||||
        public ReRouteOptionsBuilder WithIsCached(bool isCached)
 | 
			
		||||
        {
 | 
			
		||||
            _isCached = isCached;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public ReRouteOptionsBuilder WithIsAuthenticated(bool isAuthenticated)
 | 
			
		||||
        {
 | 
			
		||||
            _isAuthenticated = isAuthenticated;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public ReRouteOptionsBuilder WithIsAuthorised(bool isAuthorised)
 | 
			
		||||
        {
 | 
			
		||||
            _isAuthorised = isAuthorised;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public ReRouteOptionsBuilder WithIsQos(bool isQoS)
 | 
			
		||||
        {
 | 
			
		||||
            _isQoS = isQoS;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public ReRouteOptionsBuilder WithRateLimiting(bool enableRateLimiting)
 | 
			
		||||
        {
 | 
			
		||||
            _enableRateLimiting = enableRateLimiting;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public ReRouteOptions Build()
 | 
			
		||||
        {
 | 
			
		||||
            return new ReRouteOptions(_isAuthenticated, _isAuthorised, _isCached, _isQoS, _enableRateLimiting);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
namespace Ocelot.Configuration.Builder
 | 
			
		||||
{
 | 
			
		||||
    public class ServiceProviderConfiguraionBuilder
 | 
			
		||||
    public class ServiceProviderConfigurationBuilder
 | 
			
		||||
    {
 | 
			
		||||
        private string _serviceName;
 | 
			
		||||
        private string _downstreamHost;
 | 
			
		||||
@@ -10,52 +10,52 @@ namespace Ocelot.Configuration.Builder
 | 
			
		||||
        private string _serviceDiscoveryProviderHost;
 | 
			
		||||
        private int _serviceDiscoveryProviderPort;
 | 
			
		||||
 | 
			
		||||
        public ServiceProviderConfiguraionBuilder WithServiceName(string serviceName)
 | 
			
		||||
        public ServiceProviderConfigurationBuilder WithServiceName(string serviceName)
 | 
			
		||||
        {
 | 
			
		||||
            _serviceName = serviceName;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public ServiceProviderConfiguraionBuilder WithDownstreamHost(string downstreamHost)
 | 
			
		||||
        public ServiceProviderConfigurationBuilder WithDownstreamHost(string downstreamHost)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamHost = downstreamHost;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public ServiceProviderConfiguraionBuilder WithDownstreamPort(int downstreamPort)
 | 
			
		||||
        public ServiceProviderConfigurationBuilder WithDownstreamPort(int downstreamPort)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamPort = downstreamPort;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public ServiceProviderConfiguraionBuilder WithUseServiceDiscovery(bool userServiceDiscovery)
 | 
			
		||||
        public ServiceProviderConfigurationBuilder WithUseServiceDiscovery(bool userServiceDiscovery)
 | 
			
		||||
        {
 | 
			
		||||
            _userServiceDiscovery = userServiceDiscovery;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public ServiceProviderConfiguraionBuilder WithServiceDiscoveryProvider(string serviceDiscoveryProvider)
 | 
			
		||||
        public ServiceProviderConfigurationBuilder WithServiceDiscoveryProvider(string serviceDiscoveryProvider)
 | 
			
		||||
        {
 | 
			
		||||
            _serviceDiscoveryProvider = serviceDiscoveryProvider;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public ServiceProviderConfiguraionBuilder WithServiceDiscoveryProviderHost(string serviceDiscoveryProviderHost)
 | 
			
		||||
        public ServiceProviderConfigurationBuilder WithServiceDiscoveryProviderHost(string serviceDiscoveryProviderHost)
 | 
			
		||||
        {
 | 
			
		||||
            _serviceDiscoveryProviderHost = serviceDiscoveryProviderHost;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public ServiceProviderConfiguraionBuilder WithServiceDiscoveryProviderPort(int serviceDiscoveryProviderPort)
 | 
			
		||||
        public ServiceProviderConfigurationBuilder WithServiceDiscoveryProviderPort(int serviceDiscoveryProviderPort)
 | 
			
		||||
        {
 | 
			
		||||
            _serviceDiscoveryProviderPort = serviceDiscoveryProviderPort;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        public ServiceProviderConfiguraion Build()
 | 
			
		||||
        public ServiceProviderConfiguration Build()
 | 
			
		||||
        {
 | 
			
		||||
            return new ServiceProviderConfiguraion(_serviceName, _downstreamHost, _downstreamPort, _userServiceDiscovery,
 | 
			
		||||
            return new ServiceProviderConfiguration(_serviceName, _downstreamHost, _downstreamPort, _userServiceDiscovery,
 | 
			
		||||
            _serviceDiscoveryProvider, _serviceDiscoveryProviderHost,_serviceDiscoveryProviderPort);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -0,0 +1,20 @@
 | 
			
		||||
using Ocelot.Configuration.Builder;
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Configuration.Creator
 | 
			
		||||
{
 | 
			
		||||
    public class AuthenticationOptionsCreator : IAuthenticationOptionsCreator
 | 
			
		||||
    {
 | 
			
		||||
        public AuthenticationOptions Create(FileReRoute fileReRoute)
 | 
			
		||||
        {
 | 
			
		||||
            return new AuthenticationOptionsBuilder()
 | 
			
		||||
                                        .WithProvider(fileReRoute.AuthenticationOptions?.Provider)
 | 
			
		||||
                                        .WithProviderRootUrl(fileReRoute.AuthenticationOptions?.ProviderRootUrl)
 | 
			
		||||
                                        .WithScopeName(fileReRoute.AuthenticationOptions?.ScopeName)
 | 
			
		||||
                                        .WithRequireHttps(fileReRoute.AuthenticationOptions.RequireHttps)
 | 
			
		||||
                                        .WithAdditionalScopes(fileReRoute.AuthenticationOptions?.AdditionalScopes)
 | 
			
		||||
                                        .WithScopeSecret(fileReRoute.AuthenticationOptions?.ScopeSecret)
 | 
			
		||||
                                        .Build();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										41
									
								
								src/Ocelot/Configuration/Creator/ClaimsToThingCreator.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/Ocelot/Configuration/Creator/ClaimsToThingCreator.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using Ocelot.Configuration.Parser;
 | 
			
		||||
using Ocelot.Logging;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Configuration.Creator
 | 
			
		||||
{
 | 
			
		||||
    public class ClaimsToThingCreator : IClaimsToThingCreator
 | 
			
		||||
    {
 | 
			
		||||
        private readonly IClaimToThingConfigurationParser _claimToThingConfigParser;
 | 
			
		||||
        private readonly IOcelotLogger _logger;
 | 
			
		||||
 | 
			
		||||
        public ClaimsToThingCreator(IClaimToThingConfigurationParser claimToThingConfigurationParser,
 | 
			
		||||
            IOcelotLoggerFactory loggerFactory)
 | 
			
		||||
        {
 | 
			
		||||
            _logger = loggerFactory.CreateLogger<ClaimsToThingCreator>();
 | 
			
		||||
            _claimToThingConfigParser = claimToThingConfigurationParser;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public List<ClaimToThing> Create(Dictionary<string,string> inputToBeParsed)
 | 
			
		||||
        {
 | 
			
		||||
            var claimsToThings = new List<ClaimToThing>();
 | 
			
		||||
 | 
			
		||||
            foreach (var input in inputToBeParsed)
 | 
			
		||||
            {
 | 
			
		||||
                var claimToThing = _claimToThingConfigParser.Extract(input.Key, input.Value);
 | 
			
		||||
 | 
			
		||||
                if (claimToThing.IsError)
 | 
			
		||||
                {
 | 
			
		||||
                    _logger.LogDebug("ClaimsToThingCreator.BuildAddThingsToRequest",
 | 
			
		||||
                        $"Unable to extract configuration for key: {input.Key} and value: {input.Value} your configuration file is incorrect");
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    claimsToThings.Add(claimToThing.Data);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return claimsToThings;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -22,36 +22,53 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
    {
 | 
			
		||||
        private readonly IOptions<FileConfiguration> _options;
 | 
			
		||||
        private readonly IConfigurationValidator _configurationValidator;
 | 
			
		||||
        private const string RegExMatchEverything = ".*";
 | 
			
		||||
        private const string RegExMatchEndString = "$";
 | 
			
		||||
        private const string RegExIgnoreCase = "(?i)";
 | 
			
		||||
        private const string RegExForwardSlashOnly = "^/$";
 | 
			
		||||
 | 
			
		||||
        private readonly IClaimToThingConfigurationParser _claimToThingConfigurationParser;
 | 
			
		||||
        private readonly ILogger<FileOcelotConfigurationCreator> _logger;
 | 
			
		||||
        private readonly ILoadBalancerFactory _loadBalanceFactory;
 | 
			
		||||
        private readonly ILoadBalancerHouse _loadBalancerHouse;
 | 
			
		||||
        private readonly IQoSProviderFactory _qoSProviderFactory;
 | 
			
		||||
        private readonly IQosProviderHouse _qosProviderHouse;
 | 
			
		||||
        private readonly IClaimsToThingCreator _claimsToThingCreator;
 | 
			
		||||
        private readonly IAuthenticationOptionsCreator _authOptionsCreator;
 | 
			
		||||
        private IUpstreamTemplatePatternCreator _upstreamTemplatePatternCreator;
 | 
			
		||||
        private IRequestIdKeyCreator _requestIdKeyCreator;
 | 
			
		||||
        private IServiceProviderConfigurationCreator _serviceProviderConfigCreator;
 | 
			
		||||
        private IQoSOptionsCreator _qosOptionsCreator;
 | 
			
		||||
        private IReRouteOptionsCreator _fileReRouteOptionsCreator;
 | 
			
		||||
        private IRateLimitOptionsCreator _rateLimitOptionsCreator;
 | 
			
		||||
 | 
			
		||||
        public FileOcelotConfigurationCreator(
 | 
			
		||||
            IOptions<FileConfiguration> options, 
 | 
			
		||||
            IConfigurationValidator configurationValidator, 
 | 
			
		||||
            IClaimToThingConfigurationParser claimToThingConfigurationParser, 
 | 
			
		||||
            ILogger<FileOcelotConfigurationCreator> logger,
 | 
			
		||||
            ILoadBalancerFactory loadBalancerFactory,
 | 
			
		||||
            ILoadBalancerHouse loadBalancerHouse, 
 | 
			
		||||
            IQoSProviderFactory qoSProviderFactory, 
 | 
			
		||||
            IQosProviderHouse qosProviderHouse)
 | 
			
		||||
            IQosProviderHouse qosProviderHouse,
 | 
			
		||||
            IClaimsToThingCreator claimsToThingCreator,
 | 
			
		||||
            IAuthenticationOptionsCreator authOptionsCreator,
 | 
			
		||||
            IUpstreamTemplatePatternCreator upstreamTemplatePatternCreator,
 | 
			
		||||
            IRequestIdKeyCreator requestIdKeyCreator,
 | 
			
		||||
            IServiceProviderConfigurationCreator serviceProviderConfigCreator,
 | 
			
		||||
            IQoSOptionsCreator qosOptionsCreator,
 | 
			
		||||
            IReRouteOptionsCreator fileReRouteOptionsCreator,
 | 
			
		||||
            IRateLimitOptionsCreator rateLimitOptionsCreator
 | 
			
		||||
            )
 | 
			
		||||
        {
 | 
			
		||||
            _rateLimitOptionsCreator = rateLimitOptionsCreator;
 | 
			
		||||
            _requestIdKeyCreator = requestIdKeyCreator;
 | 
			
		||||
            _upstreamTemplatePatternCreator = upstreamTemplatePatternCreator;
 | 
			
		||||
            _authOptionsCreator = authOptionsCreator;
 | 
			
		||||
            _loadBalanceFactory = loadBalancerFactory;
 | 
			
		||||
            _loadBalancerHouse = loadBalancerHouse;
 | 
			
		||||
            _qoSProviderFactory = qoSProviderFactory;
 | 
			
		||||
            _qosProviderHouse = qosProviderHouse;
 | 
			
		||||
            _options = options;
 | 
			
		||||
            _configurationValidator = configurationValidator;
 | 
			
		||||
            _claimToThingConfigurationParser = claimToThingConfigurationParser;
 | 
			
		||||
            _logger = logger;
 | 
			
		||||
            _claimsToThingCreator = claimsToThingCreator;
 | 
			
		||||
            _serviceProviderConfigCreator = serviceProviderConfigCreator;
 | 
			
		||||
            _qosOptionsCreator = qosOptionsCreator;
 | 
			
		||||
            _fileReRouteOptionsCreator = fileReRouteOptionsCreator;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task<Response<IOcelotConfiguration>> Create()
 | 
			
		||||
@@ -97,50 +114,42 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
 | 
			
		||||
        private async Task<ReRoute> SetUpReRoute(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration)
 | 
			
		||||
        {
 | 
			
		||||
            var isAuthenticated = IsAuthenticated(fileReRoute);
 | 
			
		||||
            var fileReRouteOptions = _fileReRouteOptionsCreator.Create(fileReRoute);
 | 
			
		||||
 | 
			
		||||
            var isAuthorised = IsAuthorised(fileReRoute);
 | 
			
		||||
            var requestIdKey = _requestIdKeyCreator.Create(fileReRoute, globalConfiguration);
 | 
			
		||||
 | 
			
		||||
            var isCached = IsCached(fileReRoute);
 | 
			
		||||
            var reRouteKey = CreateReRouteKey(fileReRoute);
 | 
			
		||||
 | 
			
		||||
            var requestIdKey = BuildRequestId(fileReRoute, globalConfiguration);
 | 
			
		||||
            var upstreamTemplatePattern = _upstreamTemplatePatternCreator.Create(fileReRoute);
 | 
			
		||||
 | 
			
		||||
            var reRouteKey = BuildReRouteKey(fileReRoute);
 | 
			
		||||
            var serviceProviderConfiguration = _serviceProviderConfigCreator.Create(fileReRoute, globalConfiguration);
 | 
			
		||||
 | 
			
		||||
            var upstreamTemplatePattern = BuildUpstreamTemplatePattern(fileReRoute);
 | 
			
		||||
            var authOptionsForRoute = _authOptionsCreator.Create(fileReRoute);
 | 
			
		||||
 | 
			
		||||
            var isQos = IsQoS(fileReRoute);
 | 
			
		||||
            var claimsToHeaders = _claimsToThingCreator.Create(fileReRoute.AddHeadersToRequest);
 | 
			
		||||
 | 
			
		||||
            var serviceProviderConfiguration = BuildServiceProviderConfiguration(fileReRoute, globalConfiguration);
 | 
			
		||||
            var claimsToClaims = _claimsToThingCreator.Create(fileReRoute.AddClaimsToRequest);
 | 
			
		||||
 | 
			
		||||
            var authOptionsForRoute = BuildAuthenticationOptions(fileReRoute);
 | 
			
		||||
            var claimsToQueries = _claimsToThingCreator.Create(fileReRoute.AddQueriesToRequest);
 | 
			
		||||
 | 
			
		||||
            var claimsToHeaders = BuildAddThingsToRequest(fileReRoute.AddHeadersToRequest);
 | 
			
		||||
            var qosOptions = _qosOptionsCreator.Create(fileReRoute);
 | 
			
		||||
 | 
			
		||||
            var claimsToClaims = BuildAddThingsToRequest(fileReRoute.AddClaimsToRequest);
 | 
			
		||||
 | 
			
		||||
            var claimsToQueries = BuildAddThingsToRequest(fileReRoute.AddQueriesToRequest);
 | 
			
		||||
 | 
			
		||||
            var qosOptions = BuildQoSOptions(fileReRoute);
 | 
			
		||||
 | 
			
		||||
            var enableRateLimiting = IsEnableRateLimiting(fileReRoute);
 | 
			
		||||
 | 
			
		||||
            var rateLimitOption = BuildRateLimitOptions(fileReRoute, globalConfiguration, enableRateLimiting);
 | 
			
		||||
            var rateLimitOption = _rateLimitOptionsCreator.Create(fileReRoute, globalConfiguration, fileReRouteOptions.EnableRateLimiting);
 | 
			
		||||
 | 
			
		||||
            var reRoute = new ReRouteBuilder()
 | 
			
		||||
                .WithDownstreamPathTemplate(fileReRoute.DownstreamPathTemplate)
 | 
			
		||||
                .WithUpstreamPathTemplate(fileReRoute.UpstreamPathTemplate)
 | 
			
		||||
                .WithUpstreamHttpMethod(fileReRoute.UpstreamHttpMethod)
 | 
			
		||||
                .WithUpstreamTemplatePattern(upstreamTemplatePattern)
 | 
			
		||||
                .WithIsAuthenticated(isAuthenticated)
 | 
			
		||||
                .WithIsAuthenticated(fileReRouteOptions.IsAuthenticated)
 | 
			
		||||
                .WithAuthenticationOptions(authOptionsForRoute)
 | 
			
		||||
                .WithClaimsToHeaders(claimsToHeaders)
 | 
			
		||||
                .WithClaimsToClaims(claimsToClaims)
 | 
			
		||||
                .WithRouteClaimsRequirement(fileReRoute.RouteClaimsRequirement)
 | 
			
		||||
                .WithIsAuthorised(isAuthorised)
 | 
			
		||||
                .WithIsAuthorised(fileReRouteOptions.IsAuthorised)
 | 
			
		||||
                .WithClaimsToQueries(claimsToQueries)
 | 
			
		||||
                .WithRequestIdKey(requestIdKey)
 | 
			
		||||
                .WithIsCached(isCached)
 | 
			
		||||
                .WithIsCached(fileReRouteOptions.IsCached)
 | 
			
		||||
                .WithCacheOptions(new CacheOptions(fileReRoute.FileCacheOptions.TtlSeconds))
 | 
			
		||||
                .WithDownstreamScheme(fileReRoute.DownstreamScheme)
 | 
			
		||||
                .WithLoadBalancer(fileReRoute.LoadBalancer)
 | 
			
		||||
@@ -148,95 +157,24 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
                .WithDownstreamPort(fileReRoute.DownstreamPort)
 | 
			
		||||
                .WithLoadBalancerKey(reRouteKey)
 | 
			
		||||
                .WithServiceProviderConfiguraion(serviceProviderConfiguration)
 | 
			
		||||
                .WithIsQos(isQos)
 | 
			
		||||
                .WithIsQos(fileReRouteOptions.IsQos)
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithEnableRateLimiting(enableRateLimiting)
 | 
			
		||||
                .WithEnableRateLimiting(fileReRouteOptions.EnableRateLimiting)
 | 
			
		||||
                .WithRateLimitOptions(rateLimitOption)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            await SetupLoadBalancer(reRoute);
 | 
			
		||||
            SetupQosProvider(reRoute);
 | 
			
		||||
            return reRoute;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static RateLimitOptions BuildRateLimitOptions(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration, bool enableRateLimiting)
 | 
			
		||||
        {
 | 
			
		||||
            RateLimitOptions rateLimitOption = null;
 | 
			
		||||
            if (enableRateLimiting)
 | 
			
		||||
            {
 | 
			
		||||
                rateLimitOption = new RateLimitOptions(enableRateLimiting, globalConfiguration.RateLimitOptions.ClientIdHeader,
 | 
			
		||||
                   fileReRoute.RateLimitOptions.ClientWhitelist, globalConfiguration.RateLimitOptions.DisableRateLimitHeaders,
 | 
			
		||||
                   globalConfiguration.RateLimitOptions.QuotaExceededMessage, globalConfiguration.RateLimitOptions.RateLimitCounterPrefix,
 | 
			
		||||
                   new RateLimitRule(fileReRoute.RateLimitOptions.Period, TimeSpan.FromSeconds(fileReRoute.RateLimitOptions.PeriodTimespan), fileReRoute.RateLimitOptions.Limit)
 | 
			
		||||
                   , globalConfiguration.RateLimitOptions.HttpStatusCode);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return rateLimitOption;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static bool IsEnableRateLimiting(FileReRoute fileReRoute)
 | 
			
		||||
        {
 | 
			
		||||
            return (fileReRoute.RateLimitOptions != null && fileReRoute.RateLimitOptions.EnableRateLimiting) ? true : false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private QoSOptions BuildQoSOptions(FileReRoute fileReRoute)
 | 
			
		||||
        {
 | 
			
		||||
            return new QoSOptionsBuilder()
 | 
			
		||||
                .WithExceptionsAllowedBeforeBreaking(fileReRoute.QoSOptions.ExceptionsAllowedBeforeBreaking)
 | 
			
		||||
                .WithDurationOfBreak(fileReRoute.QoSOptions.DurationOfBreak)
 | 
			
		||||
                .WithTimeoutValue(fileReRoute.QoSOptions.TimeoutValue)
 | 
			
		||||
                .Build();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private bool IsQoS(FileReRoute fileReRoute)
 | 
			
		||||
        {
 | 
			
		||||
            return fileReRoute.QoSOptions?.ExceptionsAllowedBeforeBreaking > 0 && fileReRoute.QoSOptions?.TimeoutValue > 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private bool IsAuthenticated(FileReRoute fileReRoute)
 | 
			
		||||
        {
 | 
			
		||||
            return !string.IsNullOrEmpty(fileReRoute.AuthenticationOptions?.Provider);
 | 
			
		||||
        }
 | 
			
		||||
      
 | 
			
		||||
        private bool IsAuthorised(FileReRoute fileReRoute)
 | 
			
		||||
        {
 | 
			
		||||
            return fileReRoute.RouteClaimsRequirement?.Count > 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private bool IsCached(FileReRoute fileReRoute)
 | 
			
		||||
        {
 | 
			
		||||
            return fileReRoute.FileCacheOptions.TtlSeconds > 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private string BuildRequestId(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration)
 | 
			
		||||
        {
 | 
			
		||||
            var globalRequestIdConfiguration = !string.IsNullOrEmpty(globalConfiguration?.RequestIdKey);
 | 
			
		||||
 | 
			
		||||
             var requestIdKey = globalRequestIdConfiguration
 | 
			
		||||
                ? globalConfiguration.RequestIdKey
 | 
			
		||||
                : fileReRoute.RequestIdKey;
 | 
			
		||||
 | 
			
		||||
                return requestIdKey;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private string BuildReRouteKey(FileReRoute fileReRoute)
 | 
			
		||||
        private string CreateReRouteKey(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}{fileReRoute.UpstreamHttpMethod}";
 | 
			
		||||
            return loadBalancerKey;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private AuthenticationOptions BuildAuthenticationOptions(FileReRoute fileReRoute)
 | 
			
		||||
        {
 | 
			
		||||
            return new AuthenticationOptionsBuilder()
 | 
			
		||||
                                        .WithProvider(fileReRoute.AuthenticationOptions?.Provider)
 | 
			
		||||
                                        .WithProviderRootUrl(fileReRoute.AuthenticationOptions?.ProviderRootUrl)
 | 
			
		||||
                                        .WithScopeName(fileReRoute.AuthenticationOptions?.ScopeName)
 | 
			
		||||
                                        .WithRequireHttps(fileReRoute.AuthenticationOptions.RequireHttps)
 | 
			
		||||
                                        .WithAdditionalScopes(fileReRoute.AuthenticationOptions?.AdditionalScopes)
 | 
			
		||||
                                        .WithScopeSecret(fileReRoute.AuthenticationOptions?.ScopeSecret)
 | 
			
		||||
                                        .Build();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async Task SetupLoadBalancer(ReRoute reRoute)
 | 
			
		||||
        {
 | 
			
		||||
            var loadBalancer = await _loadBalanceFactory.Get(reRoute);
 | 
			
		||||
@@ -248,85 +186,5 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
            var loadBalancer = _qoSProviderFactory.Get(reRoute);
 | 
			
		||||
            _qosProviderHouse.Add(reRoute.ReRouteKey, loadBalancer);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private ServiceProviderConfiguraion BuildServiceProviderConfiguration(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration)
 | 
			
		||||
        {
 | 
			
		||||
            var useServiceDiscovery = !string.IsNullOrEmpty(fileReRoute.ServiceName)
 | 
			
		||||
                && !string.IsNullOrEmpty(globalConfiguration?.ServiceDiscoveryProvider?.Provider);
 | 
			
		||||
 | 
			
		||||
            var serviceProviderPort = globalConfiguration?.ServiceDiscoveryProvider?.Port ?? 0;
 | 
			
		||||
 | 
			
		||||
            return new ServiceProviderConfiguraionBuilder()
 | 
			
		||||
                    .WithServiceName(fileReRoute.ServiceName)
 | 
			
		||||
                    .WithDownstreamHost(fileReRoute.DownstreamHost)
 | 
			
		||||
                    .WithDownstreamPort(fileReRoute.DownstreamPort)
 | 
			
		||||
                    .WithUseServiceDiscovery(useServiceDiscovery)
 | 
			
		||||
                    .WithServiceDiscoveryProvider(globalConfiguration?.ServiceDiscoveryProvider?.Provider)
 | 
			
		||||
                    .WithServiceDiscoveryProviderHost(globalConfiguration?.ServiceDiscoveryProvider?.Host)
 | 
			
		||||
                    .WithServiceDiscoveryProviderPort(serviceProviderPort)
 | 
			
		||||
                    .Build();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private string BuildUpstreamTemplatePattern(FileReRoute reRoute)
 | 
			
		||||
        {
 | 
			
		||||
            var upstreamTemplate = reRoute.UpstreamPathTemplate;
 | 
			
		||||
 | 
			
		||||
            upstreamTemplate = upstreamTemplate.SetLastCharacterAs('/');
 | 
			
		||||
 | 
			
		||||
            var placeholders = new List<string>();
 | 
			
		||||
 | 
			
		||||
            for (var i = 0; i < upstreamTemplate.Length; i++)
 | 
			
		||||
            {
 | 
			
		||||
                if (IsPlaceHolder(upstreamTemplate, i))
 | 
			
		||||
                {
 | 
			
		||||
                    var postitionOfPlaceHolderClosingBracket = upstreamTemplate.IndexOf('}', i);
 | 
			
		||||
                    var difference = postitionOfPlaceHolderClosingBracket - i + 1;
 | 
			
		||||
                    var variableName = upstreamTemplate.Substring(i, difference);
 | 
			
		||||
                    placeholders.Add(variableName);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            foreach (var placeholder in placeholders)
 | 
			
		||||
            {
 | 
			
		||||
                upstreamTemplate = upstreamTemplate.Replace(placeholder, RegExMatchEverything);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (upstreamTemplate == "/")
 | 
			
		||||
            {
 | 
			
		||||
                return RegExForwardSlashOnly;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var route = reRoute.ReRouteIsCaseSensitive 
 | 
			
		||||
                ? $"{upstreamTemplate}{RegExMatchEndString}" 
 | 
			
		||||
                : $"{RegExIgnoreCase}{upstreamTemplate}{RegExMatchEndString}";
 | 
			
		||||
 | 
			
		||||
            return route;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private List<ClaimToThing> BuildAddThingsToRequest(Dictionary<string,string> thingBeingAdded)
 | 
			
		||||
        {
 | 
			
		||||
            var claimsToTHings = new List<ClaimToThing>();
 | 
			
		||||
 | 
			
		||||
            foreach (var add in thingBeingAdded)
 | 
			
		||||
            {
 | 
			
		||||
                var claimToHeader = _claimToThingConfigurationParser.Extract(add.Key, add.Value);
 | 
			
		||||
 | 
			
		||||
                if (claimToHeader.IsError)
 | 
			
		||||
                {
 | 
			
		||||
                    _logger.LogCritical(new EventId(1, "Application Failed to start"),
 | 
			
		||||
                        $"Unable to extract configuration for key: {add.Key} and value: {add.Value} your configuration file is incorrect");
 | 
			
		||||
 | 
			
		||||
                    throw new Exception(claimToHeader.Errors[0].Message);
 | 
			
		||||
                }
 | 
			
		||||
                claimsToTHings.Add(claimToHeader.Data);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return claimsToTHings;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private bool IsPlaceHolder(string upstreamTemplate, int i)
 | 
			
		||||
        {
 | 
			
		||||
            return upstreamTemplate[i] == '{';
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,9 @@
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Configuration.Creator
 | 
			
		||||
{
 | 
			
		||||
    public interface IAuthenticationOptionsCreator
 | 
			
		||||
    {
 | 
			
		||||
        AuthenticationOptions Create(FileReRoute fileReRoute);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,9 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Configuration.Creator
 | 
			
		||||
{
 | 
			
		||||
    public interface IClaimsToThingCreator
 | 
			
		||||
    {
 | 
			
		||||
        List<ClaimToThing> Create(Dictionary<string,string> thingsBeingAdded);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										9
									
								
								src/Ocelot/Configuration/Creator/IQoSOptionsCreator.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/Ocelot/Configuration/Creator/IQoSOptionsCreator.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Configuration.Creator
 | 
			
		||||
{
 | 
			
		||||
    public interface IQoSOptionsCreator
 | 
			
		||||
    {
 | 
			
		||||
        QoSOptions Create(FileReRoute fileReRoute);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,9 @@
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Configuration.Creator
 | 
			
		||||
{
 | 
			
		||||
    public interface IRateLimitOptionsCreator
 | 
			
		||||
    {
 | 
			
		||||
        RateLimitOptions Create(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration, bool enableRateLimiting);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,9 @@
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Configuration.Creator
 | 
			
		||||
{
 | 
			
		||||
    public interface IReRouteOptionsCreator
 | 
			
		||||
    {
 | 
			
		||||
        ReRouteOptions Create(FileReRoute fileReRoute);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										9
									
								
								src/Ocelot/Configuration/Creator/IRequestIdKeyCreator.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/Ocelot/Configuration/Creator/IRequestIdKeyCreator.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Configuration.Creator
 | 
			
		||||
{
 | 
			
		||||
    public interface IRequestIdKeyCreator
 | 
			
		||||
    {
 | 
			
		||||
        string Create(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,9 @@
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Configuration.Creator
 | 
			
		||||
{
 | 
			
		||||
    public interface IServiceProviderConfigurationCreator
 | 
			
		||||
    {
 | 
			
		||||
        ServiceProviderConfiguration Create(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,9 @@
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Configuration.Creator
 | 
			
		||||
{
 | 
			
		||||
    public interface IUpstreamTemplatePatternCreator
 | 
			
		||||
    {
 | 
			
		||||
        string Create(FileReRoute reRoute);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										17
									
								
								src/Ocelot/Configuration/Creator/QoSOptionsCreator.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/Ocelot/Configuration/Creator/QoSOptionsCreator.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
using Ocelot.Configuration.Builder;
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Configuration.Creator
 | 
			
		||||
{
 | 
			
		||||
    public class QoSOptionsCreator : IQoSOptionsCreator
 | 
			
		||||
    {
 | 
			
		||||
        public QoSOptions Create(FileReRoute fileReRoute)
 | 
			
		||||
        {
 | 
			
		||||
            return new QoSOptionsBuilder()
 | 
			
		||||
                .WithExceptionsAllowedBeforeBreaking(fileReRoute.QoSOptions.ExceptionsAllowedBeforeBreaking)
 | 
			
		||||
                .WithDurationOfBreak(fileReRoute.QoSOptions.DurationOfBreak)
 | 
			
		||||
                .WithTimeoutValue(fileReRoute.QoSOptions.TimeoutValue)
 | 
			
		||||
                .Build();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										32
									
								
								src/Ocelot/Configuration/Creator/RateLimitOptionsCreator.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/Ocelot/Configuration/Creator/RateLimitOptionsCreator.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Ocelot.Configuration.Builder;
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Configuration.Creator
 | 
			
		||||
{
 | 
			
		||||
    public class RateLimitOptionsCreator : IRateLimitOptionsCreator
 | 
			
		||||
    {
 | 
			
		||||
        public RateLimitOptions Create(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration, bool enableRateLimiting)
 | 
			
		||||
        {
 | 
			
		||||
            RateLimitOptions rateLimitOption = null;
 | 
			
		||||
 | 
			
		||||
            if (enableRateLimiting)
 | 
			
		||||
            {
 | 
			
		||||
                rateLimitOption = new RateLimitOptionsBuilder()
 | 
			
		||||
                    .WithClientIdHeader(globalConfiguration.RateLimitOptions.ClientIdHeader)
 | 
			
		||||
                    .WithClientWhiteList(fileReRoute.RateLimitOptions.ClientWhitelist)
 | 
			
		||||
                    .WithDisableRateLimitHeaders(globalConfiguration.RateLimitOptions.DisableRateLimitHeaders)
 | 
			
		||||
                    .WithEnableRateLimiting(fileReRoute.RateLimitOptions.EnableRateLimiting)
 | 
			
		||||
                    .WithHttpStatusCode(globalConfiguration.RateLimitOptions.HttpStatusCode)
 | 
			
		||||
                    .WithQuotaExceededMessage(globalConfiguration.RateLimitOptions.QuotaExceededMessage)
 | 
			
		||||
                    .WithRateLimitCounterPrefix(globalConfiguration.RateLimitOptions.RateLimitCounterPrefix)
 | 
			
		||||
                    .WithRateLimitRule(new RateLimitRule(fileReRoute.RateLimitOptions.Period,
 | 
			
		||||
                        TimeSpan.FromSeconds(fileReRoute.RateLimitOptions.PeriodTimespan),
 | 
			
		||||
                        fileReRoute.RateLimitOptions.Limit))
 | 
			
		||||
                    .Build();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return rateLimitOption;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										52
									
								
								src/Ocelot/Configuration/Creator/ReRouteOptionsCreator.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								src/Ocelot/Configuration/Creator/ReRouteOptionsCreator.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
			
		||||
using Ocelot.Configuration.Builder;
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Configuration.Creator
 | 
			
		||||
{
 | 
			
		||||
    public class ReRouteOptionsCreator : IReRouteOptionsCreator
 | 
			
		||||
    {
 | 
			
		||||
        public ReRouteOptions Create(FileReRoute fileReRoute)
 | 
			
		||||
        {
 | 
			
		||||
            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();
 | 
			
		||||
            
 | 
			
		||||
            return options;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static bool IsEnableRateLimiting(FileReRoute fileReRoute)
 | 
			
		||||
        {
 | 
			
		||||
            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?.Provider);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private bool IsAuthorised(FileReRoute fileReRoute)
 | 
			
		||||
        {
 | 
			
		||||
            return fileReRoute.RouteClaimsRequirement?.Count > 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private bool IsCached(FileReRoute fileReRoute)
 | 
			
		||||
        {
 | 
			
		||||
            return fileReRoute.FileCacheOptions.TtlSeconds > 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										18
									
								
								src/Ocelot/Configuration/Creator/RequestIdKeyCreator.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/Ocelot/Configuration/Creator/RequestIdKeyCreator.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Configuration.Creator
 | 
			
		||||
{
 | 
			
		||||
    public class RequestIdKeyCreator : IRequestIdKeyCreator
 | 
			
		||||
    {
 | 
			
		||||
        public string Create(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration)
 | 
			
		||||
        {
 | 
			
		||||
            var globalRequestIdConfiguration = !string.IsNullOrEmpty(globalConfiguration?.RequestIdKey);
 | 
			
		||||
 | 
			
		||||
             var requestIdKey = globalRequestIdConfiguration
 | 
			
		||||
                ? globalConfiguration.RequestIdKey
 | 
			
		||||
                : fileReRoute.RequestIdKey;
 | 
			
		||||
 | 
			
		||||
                return requestIdKey;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,26 @@
 | 
			
		||||
using Ocelot.Configuration.Builder;
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Configuration.Creator
 | 
			
		||||
{
 | 
			
		||||
    public class ServiceProviderConfigurationCreator : IServiceProviderConfigurationCreator
 | 
			
		||||
    {
 | 
			
		||||
        public ServiceProviderConfiguration Create(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration)
 | 
			
		||||
        {
 | 
			
		||||
            var useServiceDiscovery = !string.IsNullOrEmpty(fileReRoute.ServiceName)
 | 
			
		||||
                && !string.IsNullOrEmpty(globalConfiguration?.ServiceDiscoveryProvider?.Provider);
 | 
			
		||||
 | 
			
		||||
            var serviceProviderPort = globalConfiguration?.ServiceDiscoveryProvider?.Port ?? 0;
 | 
			
		||||
 | 
			
		||||
            return new ServiceProviderConfigurationBuilder()
 | 
			
		||||
                    .WithServiceName(fileReRoute.ServiceName)
 | 
			
		||||
                    .WithDownstreamHost(fileReRoute.DownstreamHost)
 | 
			
		||||
                    .WithDownstreamPort(fileReRoute.DownstreamPort)
 | 
			
		||||
                    .WithUseServiceDiscovery(useServiceDiscovery)
 | 
			
		||||
                    .WithServiceDiscoveryProvider(globalConfiguration?.ServiceDiscoveryProvider?.Provider)
 | 
			
		||||
                    .WithServiceDiscoveryProviderHost(globalConfiguration?.ServiceDiscoveryProvider?.Host)
 | 
			
		||||
                    .WithServiceDiscoveryProviderPort(serviceProviderPort)
 | 
			
		||||
                    .Build();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,56 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
using Ocelot.Utilities;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Configuration.Creator
 | 
			
		||||
{
 | 
			
		||||
    public class UpstreamTemplatePatternCreator : IUpstreamTemplatePatternCreator
 | 
			
		||||
    {
 | 
			
		||||
        private const string RegExMatchEverything = ".*";
 | 
			
		||||
        private const string RegExMatchEndString = "$";
 | 
			
		||||
        private const string RegExIgnoreCase = "(?i)";
 | 
			
		||||
        private const string RegExForwardSlashOnly = "^/$";
 | 
			
		||||
 | 
			
		||||
        public string Create(FileReRoute reRoute)
 | 
			
		||||
        {
 | 
			
		||||
            var upstreamTemplate = reRoute.UpstreamPathTemplate;
 | 
			
		||||
 | 
			
		||||
            upstreamTemplate = upstreamTemplate.SetLastCharacterAs('/');
 | 
			
		||||
 | 
			
		||||
            var placeholders = new List<string>();
 | 
			
		||||
 | 
			
		||||
            for (var i = 0; i < upstreamTemplate.Length; i++)
 | 
			
		||||
            {
 | 
			
		||||
                if (IsPlaceHolder(upstreamTemplate, i))
 | 
			
		||||
                {
 | 
			
		||||
                    var postitionOfPlaceHolderClosingBracket = upstreamTemplate.IndexOf('}', i);
 | 
			
		||||
                    var difference = postitionOfPlaceHolderClosingBracket - i + 1;
 | 
			
		||||
                    var variableName = upstreamTemplate.Substring(i, difference);
 | 
			
		||||
                    placeholders.Add(variableName);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            foreach (var placeholder in placeholders)
 | 
			
		||||
            {
 | 
			
		||||
                upstreamTemplate = upstreamTemplate.Replace(placeholder, RegExMatchEverything);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (upstreamTemplate == "/")
 | 
			
		||||
            {
 | 
			
		||||
                return RegExForwardSlashOnly;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var route = reRoute.ReRouteIsCaseSensitive 
 | 
			
		||||
                ? $"{upstreamTemplate}{RegExMatchEndString}" 
 | 
			
		||||
                : $"{RegExIgnoreCase}{upstreamTemplate}{RegExMatchEndString}";
 | 
			
		||||
 | 
			
		||||
            return route;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        private bool IsPlaceHolder(string upstreamTemplate, int i)
 | 
			
		||||
        {
 | 
			
		||||
            return upstreamTemplate[i] == '{';
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -25,7 +25,7 @@ namespace Ocelot.Configuration
 | 
			
		||||
            string downstreamHost, 
 | 
			
		||||
            int downstreamPort, 
 | 
			
		||||
            string reRouteKey, 
 | 
			
		||||
            ServiceProviderConfiguraion serviceProviderConfiguraion,
 | 
			
		||||
            ServiceProviderConfiguration serviceProviderConfiguraion,
 | 
			
		||||
            bool isQos,
 | 
			
		||||
            QoSOptions qos,
 | 
			
		||||
            bool enableRateLimit,
 | 
			
		||||
@@ -81,7 +81,7 @@ namespace Ocelot.Configuration
 | 
			
		||||
        public string LoadBalancer {get;private set;}
 | 
			
		||||
        public string DownstreamHost { get; private set; }
 | 
			
		||||
        public int DownstreamPort { get; private set; }
 | 
			
		||||
        public ServiceProviderConfiguraion ServiceProviderConfiguraion { get; private set; }
 | 
			
		||||
        public ServiceProviderConfiguration ServiceProviderConfiguraion { get; private set; }
 | 
			
		||||
        public bool EnableEndpointRateLimiting { get; private set; }
 | 
			
		||||
        public RateLimitOptions RateLimitOptions { get; private set; }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										20
									
								
								src/Ocelot/Configuration/ReRouteOptions.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/Ocelot/Configuration/ReRouteOptions.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
namespace Ocelot.Configuration
 | 
			
		||||
{
 | 
			
		||||
    public class ReRouteOptions
 | 
			
		||||
    {
 | 
			
		||||
        public ReRouteOptions(bool isAuthenticated, bool isAuthorised, bool isCached, bool isQos, 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; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,8 +1,8 @@
 | 
			
		||||
namespace Ocelot.Configuration
 | 
			
		||||
{
 | 
			
		||||
    public class ServiceProviderConfiguraion
 | 
			
		||||
    public class ServiceProviderConfiguration
 | 
			
		||||
    {
 | 
			
		||||
        public ServiceProviderConfiguraion(string serviceName, string downstreamHost,
 | 
			
		||||
        public ServiceProviderConfiguration(string serviceName, string downstreamHost,
 | 
			
		||||
            int downstreamPort, bool useServiceDiscovery, string serviceDiscoveryProvider, string serviceProviderHost, int serviceProviderPort)
 | 
			
		||||
        {
 | 
			
		||||
            ServiceName = serviceName;
 | 
			
		||||
 
 | 
			
		||||
@@ -60,6 +60,14 @@ namespace Ocelot.DependencyInjection
 | 
			
		||||
            services.AddSingleton<IOcelotConfigurationRepository, InMemoryOcelotConfigurationRepository>();
 | 
			
		||||
            services.AddSingleton<IConfigurationValidator, FileConfigurationValidator>();
 | 
			
		||||
            services.AddSingleton<IBaseUrlFinder, BaseUrlFinder>();
 | 
			
		||||
            services.AddSingleton<IClaimsToThingCreator, ClaimsToThingCreator>();
 | 
			
		||||
            services.AddSingleton<IAuthenticationOptionsCreator, AuthenticationOptionsCreator>();
 | 
			
		||||
            services.AddSingleton<IUpstreamTemplatePatternCreator, UpstreamTemplatePatternCreator>();
 | 
			
		||||
            services.AddSingleton<IRequestIdKeyCreator, RequestIdKeyCreator>();
 | 
			
		||||
            services.AddSingleton<IServiceProviderConfigurationCreator,ServiceProviderConfigurationCreator>();
 | 
			
		||||
            services.AddSingleton<IQoSOptionsCreator, QoSOptionsCreator>();
 | 
			
		||||
            services.AddSingleton<IReRouteOptionsCreator, ReRouteOptionsCreator>();
 | 
			
		||||
            services.AddSingleton<IRateLimitOptionsCreator, RateLimitOptionsCreator>();
 | 
			
		||||
 | 
			
		||||
            var identityServerConfiguration = IdentityServerConfigurationCreator.GetIdentityServerConfiguration();
 | 
			
		||||
            
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,6 @@ namespace Ocelot.Request.Builder
 | 
			
		||||
            string downstreamUrl, 
 | 
			
		||||
            Stream content, 
 | 
			
		||||
            IHeaderDictionary headers,
 | 
			
		||||
            IRequestCookieCollection cookies, 
 | 
			
		||||
            QueryString queryString, 
 | 
			
		||||
            string contentType, 
 | 
			
		||||
            RequestId.RequestId requestId,
 | 
			
		||||
@@ -29,7 +28,6 @@ namespace Ocelot.Request.Builder
 | 
			
		||||
                .WithContentType(contentType)
 | 
			
		||||
                .WithHeaders(headers)
 | 
			
		||||
                .WithRequestId(requestId)
 | 
			
		||||
                .WithCookies(cookies)
 | 
			
		||||
                .WithIsQos(isQos)
 | 
			
		||||
                .WithQos(qosProvider)
 | 
			
		||||
                .Build();
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,6 @@ namespace Ocelot.Request.Builder
 | 
			
		||||
            string downstreamUrl,
 | 
			
		||||
            Stream content,
 | 
			
		||||
            IHeaderDictionary headers,
 | 
			
		||||
            IRequestCookieCollection cookies,
 | 
			
		||||
            QueryString queryString,
 | 
			
		||||
            string contentType,
 | 
			
		||||
            RequestId.RequestId requestId,
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,6 @@ namespace Ocelot.Request.Builder
 | 
			
		||||
        private string _contentType;
 | 
			
		||||
        private IHeaderDictionary _headers;
 | 
			
		||||
        private RequestId.RequestId _requestId;
 | 
			
		||||
        private IRequestCookieCollection _cookies;
 | 
			
		||||
        private readonly string[] _unsupportedHeaders = {"host"};
 | 
			
		||||
        private bool _isQos;
 | 
			
		||||
        private IQoSProvider _qoSProvider;
 | 
			
		||||
@@ -68,12 +67,6 @@ namespace Ocelot.Request.Builder
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public RequestBuilder WithCookies(IRequestCookieCollection cookies)
 | 
			
		||||
        {
 | 
			
		||||
            _cookies = cookies;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public RequestBuilder WithIsQos(bool isqos)
 | 
			
		||||
        {
 | 
			
		||||
            _isQos = isqos;
 | 
			
		||||
@@ -103,9 +96,7 @@ namespace Ocelot.Request.Builder
 | 
			
		||||
                AddRequestIdHeader(_requestId, httpRequestMessage);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var cookieContainer = CreateCookieContainer(uri);
 | 
			
		||||
 | 
			
		||||
            return new Request(httpRequestMessage, cookieContainer,_isQos, _qoSProvider);
 | 
			
		||||
            return new Request(httpRequestMessage,_isQos, _qoSProvider);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private Uri CreateUri()
 | 
			
		||||
@@ -153,21 +144,6 @@ namespace Ocelot.Request.Builder
 | 
			
		||||
            return !_unsupportedHeaders.Contains(header.Key.ToLower());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private CookieContainer CreateCookieContainer(Uri uri)
 | 
			
		||||
        {
 | 
			
		||||
            var cookieContainer = new CookieContainer();
 | 
			
		||||
 | 
			
		||||
            if (_cookies != null)
 | 
			
		||||
            {
 | 
			
		||||
                foreach (var cookie in _cookies)
 | 
			
		||||
                {
 | 
			
		||||
                    cookieContainer.Add(uri, new Cookie(cookie.Key, cookie.Value));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return cookieContainer;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void AddRequestIdHeader(RequestId.RequestId requestId, HttpRequestMessage httpRequestMessage)
 | 
			
		||||
        {
 | 
			
		||||
            httpRequestMessage.Headers.Add(requestId.RequestIdKey, requestId.RequestIdValue);
 | 
			
		||||
 
 | 
			
		||||
@@ -48,7 +48,6 @@ namespace Ocelot.Request.Middleware
 | 
			
		||||
                    DownstreamUrl,
 | 
			
		||||
                    context.Request.Body,
 | 
			
		||||
                    context.Request.Headers,
 | 
			
		||||
                    context.Request.Cookies,
 | 
			
		||||
                    context.Request.QueryString,
 | 
			
		||||
                    context.Request.ContentType,
 | 
			
		||||
                    new RequestId.RequestId(DownstreamRoute?.ReRoute?.RequestIdKey, context.TraceIdentifier),
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,4 @@
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Values;
 | 
			
		||||
using System.Net;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using Ocelot.Requester.QoS;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Request
 | 
			
		||||
@@ -10,18 +7,15 @@ namespace Ocelot.Request
 | 
			
		||||
    {
 | 
			
		||||
        public Request(
 | 
			
		||||
            HttpRequestMessage httpRequestMessage, 
 | 
			
		||||
            CookieContainer cookieContainer,
 | 
			
		||||
            bool isQos,
 | 
			
		||||
            IQoSProvider qosProvider)
 | 
			
		||||
        {
 | 
			
		||||
            HttpRequestMessage = httpRequestMessage;
 | 
			
		||||
            CookieContainer = cookieContainer;
 | 
			
		||||
            IsQos = isQos;
 | 
			
		||||
            QosProvider = qosProvider;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public HttpRequestMessage HttpRequestMessage { get; private set; }
 | 
			
		||||
        public CookieContainer CookieContainer { get; private set; }
 | 
			
		||||
        public bool IsQos { get; private set; }
 | 
			
		||||
        public IQoSProvider QosProvider { get; private set; }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -14,14 +14,14 @@ namespace Ocelot.Requester
 | 
			
		||||
        private readonly Dictionary<int, Func<DelegatingHandler>> _handlers = new Dictionary<int, Func<DelegatingHandler>>();
 | 
			
		||||
        private Dictionary<string, string> _defaultHeaders;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        public  IHttpClientBuilder WithQos(IQoSProvider qosProvider, IOcelotLogger logger)
 | 
			
		||||
        {
 | 
			
		||||
            _handlers.Add(5000, () => new PollyCircuitBreakingDelegatingHandler(qosProvider, logger));
 | 
			
		||||
 | 
			
		||||
            return this;
 | 
			
		||||
 | 
			
		||||
        }  
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        public IHttpClient Create()
 | 
			
		||||
        {
 | 
			
		||||
            var httpclientHandler = new HttpClientHandler();
 | 
			
		||||
 
 | 
			
		||||
@@ -55,7 +55,7 @@ namespace Ocelot.Requester
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private string GetCacheKey(Request.Request request, HttpClientBuilder builder)
 | 
			
		||||
        private string GetCacheKey(Request.Request request, IHttpClientBuilder builder)
 | 
			
		||||
        {
 | 
			
		||||
            string baseUrl = $"{request.HttpRequestMessage.RequestUri.Scheme}://{request.HttpRequestMessage.RequestUri.Authority}";
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,9 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.ServiceDiscovery
 | 
			
		||||
{
 | 
			
		||||
    public interface IServiceDiscoveryProviderFactory
 | 
			
		||||
    {
 | 
			
		||||
        IServiceDiscoveryProvider Get(ServiceProviderConfiguraion serviceConfig);
 | 
			
		||||
        IServiceDiscoveryProvider Get(ServiceProviderConfiguration serviceConfig);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -6,7 +6,7 @@ namespace Ocelot.ServiceDiscovery
 | 
			
		||||
{
 | 
			
		||||
    public class ServiceDiscoveryProviderFactory : IServiceDiscoveryProviderFactory
 | 
			
		||||
    {
 | 
			
		||||
        public  IServiceDiscoveryProvider Get(ServiceProviderConfiguraion serviceConfig)
 | 
			
		||||
        public  IServiceDiscoveryProvider Get(ServiceProviderConfiguration serviceConfig)
 | 
			
		||||
        {
 | 
			
		||||
            if (serviceConfig.UseServiceDiscovery)
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user