mirror of
https://github.com/nsnail/Ocelot.git
synced 2025-04-22 06:22:50 +08:00
commit
9e5faa268f
@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Http;
|
|||||||
using Ocelot.Authentication.Handler.Factory;
|
using Ocelot.Authentication.Handler.Factory;
|
||||||
using Ocelot.Configuration;
|
using Ocelot.Configuration;
|
||||||
using Ocelot.Errors;
|
using Ocelot.Errors;
|
||||||
|
using Ocelot.Infrastructure.Extensions;
|
||||||
using Ocelot.Infrastructure.RequestData;
|
using Ocelot.Infrastructure.RequestData;
|
||||||
using Ocelot.Logging;
|
using Ocelot.Logging;
|
||||||
using Ocelot.Middleware;
|
using Ocelot.Middleware;
|
||||||
@ -33,47 +34,57 @@ namespace Ocelot.Authentication.Middleware
|
|||||||
|
|
||||||
public async Task Invoke(HttpContext context)
|
public async Task Invoke(HttpContext context)
|
||||||
{
|
{
|
||||||
_logger.LogDebug("started authentication");
|
_logger.TraceMiddlewareEntry();
|
||||||
|
|
||||||
if (IsAuthenticatedRoute(DownstreamRoute.ReRoute))
|
if (IsAuthenticatedRoute(DownstreamRoute.ReRoute))
|
||||||
{
|
{
|
||||||
|
_logger.LogDebug($"{context.Request.Path} is an authenticated route. {MiddlwareName} checking if client is authenticated");
|
||||||
|
|
||||||
var authenticationHandler = _authHandlerFactory.Get(_app, DownstreamRoute.ReRoute.AuthenticationOptions);
|
var authenticationHandler = _authHandlerFactory.Get(_app, DownstreamRoute.ReRoute.AuthenticationOptions);
|
||||||
|
|
||||||
if (!authenticationHandler.IsError)
|
if (authenticationHandler.IsError)
|
||||||
{
|
{
|
||||||
_logger.LogDebug("calling authentication handler for ReRoute");
|
_logger.LogError($"Error getting authentication handler for {context.Request.Path}. {authenticationHandler.Errors.ToErrorString()}");
|
||||||
|
|
||||||
await authenticationHandler.Data.Handler.Handle(context);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.LogDebug("there was an error getting authentication handler for ReRoute");
|
|
||||||
|
|
||||||
SetPipelineError(authenticationHandler.Errors);
|
SetPipelineError(authenticationHandler.Errors);
|
||||||
|
_logger.TraceMiddlewareCompleted();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await authenticationHandler.Data.Handler.Handle(context);
|
||||||
|
|
||||||
|
|
||||||
if (context.User.Identity.IsAuthenticated)
|
if (context.User.Identity.IsAuthenticated)
|
||||||
{
|
{
|
||||||
_logger.LogDebug("the user was authenticated");
|
_logger.LogDebug($"Client has been authenticated for {context.Request.Path}");
|
||||||
|
|
||||||
await _next.Invoke(context);
|
_logger.TraceInvokeNext();
|
||||||
|
await _next.Invoke(context);
|
||||||
_logger.LogDebug("succesfully called next middleware");
|
_logger.TraceInvokeNextCompleted();
|
||||||
|
_logger.TraceMiddlewareCompleted();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_logger.LogDebug("the user was not authenticated");
|
var error = new List<Error>
|
||||||
|
{
|
||||||
|
new UnauthenticatedError(
|
||||||
|
$"Request for authenticated route {context.Request.Path} by {context.User.Identity.Name} was unauthenticated")
|
||||||
|
};
|
||||||
|
|
||||||
SetPipelineError(new List<Error> { new UnauthenticatedError($"Request for authenticated route {context.Request.Path} by {context.User.Identity.Name} was unauthenticated") });
|
_logger.LogError($"Client has NOT been authenticated for {context.Request.Path} and pipeline error set. {error.ToErrorString()}");
|
||||||
|
SetPipelineError(error);
|
||||||
|
|
||||||
|
_logger.TraceMiddlewareCompleted();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_logger.LogDebug("calling next middleware");
|
_logger.LogTrace($"No authentication needed for {context.Request.Path}");
|
||||||
|
|
||||||
await _next.Invoke(context);
|
_logger.TraceInvokeNext();
|
||||||
|
await _next.Invoke(context);
|
||||||
_logger.LogDebug("succesfully called next middleware");
|
_logger.TraceInvokeNextCompleted();
|
||||||
|
_logger.TraceMiddlewareCompleted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,3 +94,4 @@ namespace Ocelot.Authentication.Middleware
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ using Ocelot.Configuration.File;
|
|||||||
using Ocelot.Configuration.Parser;
|
using Ocelot.Configuration.Parser;
|
||||||
using Ocelot.Configuration.Validator;
|
using Ocelot.Configuration.Validator;
|
||||||
using Ocelot.LoadBalancer.LoadBalancers;
|
using Ocelot.LoadBalancer.LoadBalancers;
|
||||||
|
using Ocelot.Logging;
|
||||||
using Ocelot.Requester.QoS;
|
using Ocelot.Requester.QoS;
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
using Ocelot.Utilities;
|
using Ocelot.Utilities;
|
||||||
@ -22,7 +23,7 @@ namespace Ocelot.Configuration.Creator
|
|||||||
{
|
{
|
||||||
private readonly IOptions<FileConfiguration> _options;
|
private readonly IOptions<FileConfiguration> _options;
|
||||||
private readonly IConfigurationValidator _configurationValidator;
|
private readonly IConfigurationValidator _configurationValidator;
|
||||||
private readonly ILogger<FileOcelotConfigurationCreator> _logger;
|
private readonly IOcelotLogger _logger;
|
||||||
private readonly ILoadBalancerFactory _loadBalanceFactory;
|
private readonly ILoadBalancerFactory _loadBalanceFactory;
|
||||||
private readonly ILoadBalancerHouse _loadBalancerHouse;
|
private readonly ILoadBalancerHouse _loadBalancerHouse;
|
||||||
private readonly IQoSProviderFactory _qoSProviderFactory;
|
private readonly IQoSProviderFactory _qoSProviderFactory;
|
||||||
@ -39,7 +40,7 @@ namespace Ocelot.Configuration.Creator
|
|||||||
public FileOcelotConfigurationCreator(
|
public FileOcelotConfigurationCreator(
|
||||||
IOptions<FileConfiguration> options,
|
IOptions<FileConfiguration> options,
|
||||||
IConfigurationValidator configurationValidator,
|
IConfigurationValidator configurationValidator,
|
||||||
ILogger<FileOcelotConfigurationCreator> logger,
|
IOcelotLoggerFactory loggerFactory,
|
||||||
ILoadBalancerFactory loadBalancerFactory,
|
ILoadBalancerFactory loadBalancerFactory,
|
||||||
ILoadBalancerHouse loadBalancerHouse,
|
ILoadBalancerHouse loadBalancerHouse,
|
||||||
IQoSProviderFactory qoSProviderFactory,
|
IQoSProviderFactory qoSProviderFactory,
|
||||||
@ -64,7 +65,7 @@ namespace Ocelot.Configuration.Creator
|
|||||||
_qosProviderHouse = qosProviderHouse;
|
_qosProviderHouse = qosProviderHouse;
|
||||||
_options = options;
|
_options = options;
|
||||||
_configurationValidator = configurationValidator;
|
_configurationValidator = configurationValidator;
|
||||||
_logger = logger;
|
_logger = loggerFactory.CreateLogger<FileOcelotConfigurationCreator>();
|
||||||
_claimsToThingCreator = claimsToThingCreator;
|
_claimsToThingCreator = claimsToThingCreator;
|
||||||
_serviceProviderConfigCreator = serviceProviderConfigCreator;
|
_serviceProviderConfigCreator = serviceProviderConfigCreator;
|
||||||
_qosOptionsCreator = qosOptionsCreator;
|
_qosOptionsCreator = qosOptionsCreator;
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Ocelot.DownstreamRouteFinder.Finder;
|
using Ocelot.DownstreamRouteFinder.Finder;
|
||||||
|
using Ocelot.Infrastructure.Extensions;
|
||||||
using Ocelot.Infrastructure.RequestData;
|
using Ocelot.Infrastructure.RequestData;
|
||||||
using Ocelot.Logging;
|
using Ocelot.Logging;
|
||||||
using Ocelot.Middleware;
|
using Ocelot.Middleware;
|
||||||
@ -27,7 +30,7 @@ namespace Ocelot.DownstreamRouteFinder.Middleware
|
|||||||
|
|
||||||
public async Task Invoke(HttpContext context)
|
public async Task Invoke(HttpContext context)
|
||||||
{
|
{
|
||||||
_logger.LogDebug("started calling downstream route finder middleware");
|
_logger.TraceMiddlewareEntry();
|
||||||
|
|
||||||
var upstreamUrlPath = context.Request.Path.ToString().SetLastCharacterAs('/');
|
var upstreamUrlPath = context.Request.Path.ToString().SetLastCharacterAs('/');
|
||||||
|
|
||||||
@ -37,9 +40,11 @@ namespace Ocelot.DownstreamRouteFinder.Middleware
|
|||||||
|
|
||||||
if (downstreamRoute.IsError)
|
if (downstreamRoute.IsError)
|
||||||
{
|
{
|
||||||
_logger.LogDebug("IDownstreamRouteFinder returned an error, setting pipeline error");
|
_logger.LogError($"{MiddlwareName} setting pipeline errors. IDownstreamRouteFinder returned {downstreamRoute.Errors.ToErrorString()}");
|
||||||
|
|
||||||
SetPipelineError(downstreamRoute.Errors);
|
SetPipelineError(downstreamRoute.Errors);
|
||||||
|
|
||||||
|
_logger.TraceMiddlewareCompleted();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,12 +52,12 @@ namespace Ocelot.DownstreamRouteFinder.Middleware
|
|||||||
|
|
||||||
SetDownstreamRouteForThisRequest(downstreamRoute.Data);
|
SetDownstreamRouteForThisRequest(downstreamRoute.Data);
|
||||||
|
|
||||||
_logger.LogDebug("calling next middleware");
|
_logger.TraceInvokeNext();
|
||||||
|
|
||||||
await _next.Invoke(context);
|
await _next.Invoke(context);
|
||||||
|
|
||||||
_logger.LogDebug("succesfully called next middleware");
|
_logger.TraceInvokeNextCompleted();
|
||||||
|
_logger.TraceMiddlewareCompleted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,6 +6,9 @@ using Ocelot.Logging;
|
|||||||
|
|
||||||
namespace Ocelot.Errors.Middleware
|
namespace Ocelot.Errors.Middleware
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Catches all unhandled exceptions thrown by middleware, logs and returns a 500
|
||||||
|
/// </summary>
|
||||||
public class ExceptionHandlerMiddleware
|
public class ExceptionHandlerMiddleware
|
||||||
{
|
{
|
||||||
private readonly RequestDelegate _next;
|
private readonly RequestDelegate _next;
|
||||||
|
18
src/Ocelot/Infrastructure/Extensions/ErrorListExtensions.cs
Normal file
18
src/Ocelot/Infrastructure/Extensions/ErrorListExtensions.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
|
using Ocelot.Errors;
|
||||||
|
|
||||||
|
namespace Ocelot.Infrastructure.Extensions
|
||||||
|
{
|
||||||
|
public static class ErrorListExtensions
|
||||||
|
{
|
||||||
|
public static string ToErrorString(this List<Error> errors)
|
||||||
|
{
|
||||||
|
var listOfErrorStrings = errors.Select(x => "Error Code: " + x.Code.ToString() + " Message: " + x.Message);
|
||||||
|
return string.Join(" ", listOfErrorStrings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
52
src/Ocelot/Logging/AspDotNetLogger.cs
Normal file
52
src/Ocelot/Logging/AspDotNetLogger.cs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Ocelot.Infrastructure.RequestData;
|
||||||
|
|
||||||
|
namespace Ocelot.Logging
|
||||||
|
{
|
||||||
|
public class AspDotNetLogger : IOcelotLogger
|
||||||
|
{
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
private readonly IRequestScopedDataRepository _scopedDataRepository;
|
||||||
|
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
public AspDotNetLogger(ILogger logger, IRequestScopedDataRepository scopedDataRepository, string typeName)
|
||||||
|
{
|
||||||
|
Name = typeName;
|
||||||
|
_logger = logger;
|
||||||
|
_scopedDataRepository = scopedDataRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LogTrace(string message, params object[] args)
|
||||||
|
{
|
||||||
|
_logger.LogTrace(GetMessageWithOcelotRequestId(message), args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LogDebug(string message, params object[] args)
|
||||||
|
{
|
||||||
|
_logger.LogDebug(GetMessageWithOcelotRequestId(message), args);
|
||||||
|
}
|
||||||
|
public void LogError(string message, Exception exception)
|
||||||
|
{
|
||||||
|
_logger.LogError(GetMessageWithOcelotRequestId(message), exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LogError(string message, params object[] args)
|
||||||
|
{
|
||||||
|
_logger.LogError(GetMessageWithOcelotRequestId(message), args);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetMessageWithOcelotRequestId(string message)
|
||||||
|
{
|
||||||
|
var requestId = _scopedDataRepository.Get<string>("RequestId");
|
||||||
|
|
||||||
|
if (requestId == null || requestId.IsError)
|
||||||
|
{
|
||||||
|
return $"{message} : OcelotRequestId - not set";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $"{message} : OcelotRequestId - {requestId.Data}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
src/Ocelot/Logging/AspDotNetLoggerFactory.cs
Normal file
23
src/Ocelot/Logging/AspDotNetLoggerFactory.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Ocelot.Infrastructure.RequestData;
|
||||||
|
|
||||||
|
namespace Ocelot.Logging
|
||||||
|
{
|
||||||
|
public class AspDotNetLoggerFactory : IOcelotLoggerFactory
|
||||||
|
{
|
||||||
|
private readonly ILoggerFactory _loggerFactory;
|
||||||
|
private readonly IRequestScopedDataRepository _scopedDataRepository;
|
||||||
|
|
||||||
|
public AspDotNetLoggerFactory(ILoggerFactory loggerFactory, IRequestScopedDataRepository scopedDataRepository)
|
||||||
|
{
|
||||||
|
_loggerFactory = loggerFactory;
|
||||||
|
_scopedDataRepository = scopedDataRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IOcelotLogger CreateLogger<T>()
|
||||||
|
{
|
||||||
|
var logger = _loggerFactory.CreateLogger<T>();
|
||||||
|
return new AspDotNetLogger(logger, _scopedDataRepository, typeof(T).Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Ocelot.Infrastructure.RequestData;
|
|
||||||
|
|
||||||
namespace Ocelot.Logging
|
namespace Ocelot.Logging
|
||||||
{
|
{
|
||||||
@ -8,62 +6,19 @@ namespace Ocelot.Logging
|
|||||||
{
|
{
|
||||||
IOcelotLogger CreateLogger<T>();
|
IOcelotLogger CreateLogger<T>();
|
||||||
}
|
}
|
||||||
|
/// <summary>
|
||||||
public class AspDotNetLoggerFactory : IOcelotLoggerFactory
|
/// Thin wrapper around the DotNet core logging framework, used to allow the scopedDataRepository to be injected giving access to the Ocelot RequestId
|
||||||
{
|
/// </summary>
|
||||||
private readonly ILoggerFactory _loggerFactory;
|
|
||||||
private readonly IRequestScopedDataRepository _scopedDataRepository;
|
|
||||||
|
|
||||||
public AspDotNetLoggerFactory(ILoggerFactory loggerFactory, IRequestScopedDataRepository scopedDataRepository)
|
|
||||||
{
|
|
||||||
_loggerFactory = loggerFactory;
|
|
||||||
_scopedDataRepository = scopedDataRepository;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IOcelotLogger CreateLogger<T>()
|
|
||||||
{
|
|
||||||
var logger = _loggerFactory.CreateLogger<T>();
|
|
||||||
return new AspDotNetLogger(logger, _scopedDataRepository);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface IOcelotLogger
|
public interface IOcelotLogger
|
||||||
{
|
{
|
||||||
|
void LogTrace(string message, params object[] args);
|
||||||
void LogDebug(string message, params object[] args);
|
void LogDebug(string message, params object[] args);
|
||||||
void LogError(string message, Exception exception);
|
void LogError(string message, Exception exception);
|
||||||
}
|
void LogError(string message, params object[] args);
|
||||||
|
|
||||||
public class AspDotNetLogger : IOcelotLogger
|
/// <summary>
|
||||||
{
|
/// The name of the type the logger has been built for.
|
||||||
private readonly ILogger _logger;
|
/// </summary>
|
||||||
private readonly IRequestScopedDataRepository _scopedDataRepository;
|
string Name { get; }
|
||||||
|
|
||||||
public AspDotNetLogger(ILogger logger, IRequestScopedDataRepository scopedDataRepository)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
_scopedDataRepository = scopedDataRepository;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LogDebug(string message, params object[] args)
|
|
||||||
{
|
|
||||||
_logger.LogDebug(GetMessageWithOcelotRequestId(message), args);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LogError(string message, Exception exception)
|
|
||||||
{
|
|
||||||
_logger.LogError(GetMessageWithOcelotRequestId(message), exception);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetMessageWithOcelotRequestId(string message)
|
|
||||||
{
|
|
||||||
var requestId = _scopedDataRepository.Get<string>("RequestId");
|
|
||||||
|
|
||||||
if (requestId != null && !requestId.IsError)
|
|
||||||
{
|
|
||||||
return $"{message} : OcelotRequestId - {requestId.Data}";
|
|
||||||
|
|
||||||
}
|
|
||||||
return $"{message} : OcelotRequestId - not set";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
29
src/Ocelot/Logging/OcelotLoggerExtensions.cs
Normal file
29
src/Ocelot/Logging/OcelotLoggerExtensions.cs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Ocelot.Logging
|
||||||
|
{
|
||||||
|
public static class OcelotLoggerExtensions
|
||||||
|
{
|
||||||
|
public static void TraceMiddlewareEntry(this IOcelotLogger logger)
|
||||||
|
{
|
||||||
|
logger.LogTrace($"entered {logger.Name}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void TraceInvokeNext(this IOcelotLogger logger)
|
||||||
|
{
|
||||||
|
logger.LogTrace($"invoking next middleware from {logger.Name}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void TraceInvokeNextCompleted(this IOcelotLogger logger)
|
||||||
|
{
|
||||||
|
logger.LogTrace($"returned to {logger.Name} after next middleware completed");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void TraceMiddlewareCompleted(this IOcelotLogger logger)
|
||||||
|
{
|
||||||
|
logger.LogTrace($"completed {logger.Name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -14,8 +14,11 @@ namespace Ocelot.Middleware
|
|||||||
protected OcelotMiddleware(IRequestScopedDataRepository requestScopedDataRepository)
|
protected OcelotMiddleware(IRequestScopedDataRepository requestScopedDataRepository)
|
||||||
{
|
{
|
||||||
_requestScopedDataRepository = requestScopedDataRepository;
|
_requestScopedDataRepository = requestScopedDataRepository;
|
||||||
|
MiddlwareName = this.GetType().Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string MiddlwareName { get; }
|
||||||
|
|
||||||
public bool PipelineError
|
public bool PipelineError
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
@ -31,12 +31,18 @@ namespace Ocelot.RateLimit.Middleware
|
|||||||
|
|
||||||
public async Task Invoke(HttpContext context)
|
public async Task Invoke(HttpContext context)
|
||||||
{
|
{
|
||||||
_logger.LogDebug("started calling RateLimit middleware");
|
_logger.TraceMiddlewareEntry();
|
||||||
|
|
||||||
var options = DownstreamRoute.ReRoute.RateLimitOptions;
|
var options = DownstreamRoute.ReRoute.RateLimitOptions;
|
||||||
// check if rate limiting is enabled
|
// check if rate limiting is enabled
|
||||||
if (!DownstreamRoute.ReRoute.EnableEndpointRateLimiting)
|
if (!DownstreamRoute.ReRoute.EnableEndpointRateLimiting)
|
||||||
{
|
{
|
||||||
await _next.Invoke(context);
|
_logger.LogDebug($"EndpointRateLimiting is not enabled for {DownstreamRoute.ReRoute.DownstreamPathTemplate}");
|
||||||
|
|
||||||
|
_logger.TraceInvokeNext();
|
||||||
|
await _next.Invoke(context);
|
||||||
|
_logger.TraceInvokeNextCompleted();
|
||||||
|
_logger.TraceMiddlewareCompleted();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// compute identity from request
|
// compute identity from request
|
||||||
@ -45,7 +51,12 @@ namespace Ocelot.RateLimit.Middleware
|
|||||||
// check white list
|
// check white list
|
||||||
if (IsWhitelisted(identity, options))
|
if (IsWhitelisted(identity, options))
|
||||||
{
|
{
|
||||||
await _next.Invoke(context);
|
_logger.LogDebug($"{DownstreamRoute.ReRoute.DownstreamPathTemplate} is white listed from rate limiting");
|
||||||
|
|
||||||
|
_logger.TraceInvokeNext();
|
||||||
|
await _next.Invoke(context);
|
||||||
|
_logger.TraceInvokeNextCompleted();
|
||||||
|
_logger.TraceMiddlewareCompleted();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,6 +77,7 @@ namespace Ocelot.RateLimit.Middleware
|
|||||||
|
|
||||||
// break execution
|
// break execution
|
||||||
await ReturnQuotaExceededResponse(context, options, retryAfter);
|
await ReturnQuotaExceededResponse(context, options, retryAfter);
|
||||||
|
_logger.TraceMiddlewareCompleted();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -76,7 +88,10 @@ namespace Ocelot.RateLimit.Middleware
|
|||||||
context.Response.OnStarting(SetRateLimitHeaders, state: headers);
|
context.Response.OnStarting(SetRateLimitHeaders, state: headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
await _next.Invoke(context);
|
_logger.TraceInvokeNext();
|
||||||
|
await _next.Invoke(context);
|
||||||
|
_logger.TraceInvokeNextCompleted();
|
||||||
|
_logger.TraceMiddlewareCompleted();
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual ClientRequestIdentity SetIdentity(HttpContext httpContext, RateLimitOptions option)
|
public virtual ClientRequestIdentity SetIdentity(HttpContext httpContext, RateLimitOptions option)
|
||||||
|
@ -26,17 +26,16 @@ namespace Ocelot.RequestId.Middleware
|
|||||||
|
|
||||||
public async Task Invoke(HttpContext context)
|
public async Task Invoke(HttpContext context)
|
||||||
{
|
{
|
||||||
_logger.LogDebug("started calling request id middleware");
|
_logger.TraceMiddlewareEntry();
|
||||||
|
|
||||||
SetOcelotRequestId(context);
|
SetOcelotRequestId(context);
|
||||||
|
|
||||||
_logger.LogDebug("set request id");
|
_logger.LogDebug("set requestId");
|
||||||
|
|
||||||
_logger.LogDebug("calling next middleware");
|
_logger.TraceInvokeNext();
|
||||||
|
await _next.Invoke(context);
|
||||||
await _next.Invoke(context);
|
_logger.TraceInvokeNextCompleted();
|
||||||
|
_logger.TraceMiddlewareCompleted();
|
||||||
_logger.LogDebug("succesfully called next middleware");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetOcelotRequestId(HttpContext context)
|
private void SetOcelotRequestId(HttpContext context)
|
||||||
|
@ -26,6 +26,11 @@ namespace Ocelot.Responder
|
|||||||
return 503;
|
return 503;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (errors.Any(e => e.Code == OcelotErrorCode.UnableToFindDownstreamRouteError))
|
||||||
|
{
|
||||||
|
return 404;
|
||||||
|
}
|
||||||
|
|
||||||
return 404;
|
return 404;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Ocelot.Errors;
|
using Ocelot.Errors;
|
||||||
using Ocelot.Infrastructure.RequestData;
|
using Ocelot.Infrastructure.RequestData;
|
||||||
using Ocelot.Logging;
|
using Ocelot.Logging;
|
||||||
@ -9,6 +8,9 @@ using Ocelot.Middleware;
|
|||||||
|
|
||||||
namespace Ocelot.Responder.Middleware
|
namespace Ocelot.Responder.Middleware
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Completes and returns the request and request body, if any pipeline errors occured then sets the appropriate HTTP status code instead.
|
||||||
|
/// </summary>
|
||||||
public class ResponderMiddleware : OcelotMiddleware
|
public class ResponderMiddleware : OcelotMiddleware
|
||||||
{
|
{
|
||||||
private readonly RequestDelegate _next;
|
private readonly RequestDelegate _next;
|
||||||
@ -21,7 +23,7 @@ namespace Ocelot.Responder.Middleware
|
|||||||
IOcelotLoggerFactory loggerFactory,
|
IOcelotLoggerFactory loggerFactory,
|
||||||
IRequestScopedDataRepository requestScopedDataRepository,
|
IRequestScopedDataRepository requestScopedDataRepository,
|
||||||
IErrorsToHttpStatusCodeMapper codeMapper)
|
IErrorsToHttpStatusCodeMapper codeMapper)
|
||||||
: base(requestScopedDataRepository)
|
:base(requestScopedDataRepository)
|
||||||
{
|
{
|
||||||
_next = next;
|
_next = next;
|
||||||
_responder = responder;
|
_responder = responder;
|
||||||
@ -32,28 +34,24 @@ namespace Ocelot.Responder.Middleware
|
|||||||
|
|
||||||
public async Task Invoke(HttpContext context)
|
public async Task Invoke(HttpContext context)
|
||||||
{
|
{
|
||||||
_logger.LogDebug("started error responder middleware");
|
_logger.TraceMiddlewareEntry();
|
||||||
|
_logger.TraceInvokeNext();
|
||||||
await _next.Invoke(context);
|
await _next.Invoke(context);
|
||||||
|
_logger.TraceInvokeNextCompleted();
|
||||||
_logger.LogDebug("calling next middleware");
|
|
||||||
|
|
||||||
if (PipelineError)
|
if (PipelineError)
|
||||||
{
|
{
|
||||||
_logger.LogDebug("there is a pipeline error, getting errors");
|
|
||||||
|
|
||||||
var errors = PipelineErrors;
|
var errors = PipelineErrors;
|
||||||
|
_logger.LogError($"{errors.Count} pipeline errors found in {MiddlwareName}. Setting error response status code");
|
||||||
_logger.LogDebug("received errors setting error response");
|
|
||||||
|
|
||||||
SetErrorResponse(context, errors);
|
SetErrorResponse(context, errors);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_logger.LogDebug("no pipeline error, setting response");
|
_logger.LogDebug("no pipeline errors, setting and returning completed response");
|
||||||
|
|
||||||
await _responder.SetResponseOnHttpContext(context, HttpResponseMessage);
|
await _responder.SetResponseOnHttpContext(context, HttpResponseMessage);
|
||||||
}
|
}
|
||||||
|
_logger.TraceMiddlewareCompleted();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetErrorResponse(HttpContext context, List<Error> errors)
|
private void SetErrorResponse(HttpContext context, List<Error> errors)
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"Logging": {
|
"Logging": {
|
||||||
"IncludeScopes": true,
|
"IncludeScopes": true,
|
||||||
"LogLevel": {
|
"LogLevel": {
|
||||||
"Default": "Debug",
|
"Default": "Error",
|
||||||
"System": "Information",
|
"System": "Information",
|
||||||
"Microsoft": "Information"
|
"Microsoft": "Information"
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"Logging": {
|
"Logging": {
|
||||||
"IncludeScopes": true,
|
"IncludeScopes": true,
|
||||||
"LogLevel": {
|
"LogLevel": {
|
||||||
"Default": "Debug",
|
"Default": "Trace",
|
||||||
"System": "Information",
|
"System": "Information",
|
||||||
"Microsoft": "Information"
|
"Microsoft": "Information"
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ using Ocelot.Configuration.Creator;
|
|||||||
using Ocelot.Configuration.File;
|
using Ocelot.Configuration.File;
|
||||||
using Ocelot.Configuration.Validator;
|
using Ocelot.Configuration.Validator;
|
||||||
using Ocelot.LoadBalancer.LoadBalancers;
|
using Ocelot.LoadBalancer.LoadBalancers;
|
||||||
|
using Ocelot.Logging;
|
||||||
using Ocelot.Requester.QoS;
|
using Ocelot.Requester.QoS;
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
using Shouldly;
|
using Shouldly;
|
||||||
@ -22,7 +23,7 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
private readonly Mock<IConfigurationValidator> _validator;
|
private readonly Mock<IConfigurationValidator> _validator;
|
||||||
private Response<IOcelotConfiguration> _config;
|
private Response<IOcelotConfiguration> _config;
|
||||||
private FileConfiguration _fileConfiguration;
|
private FileConfiguration _fileConfiguration;
|
||||||
private readonly Mock<ILogger<FileOcelotConfigurationCreator>> _logger;
|
private readonly Mock<IOcelotLoggerFactory> _logger;
|
||||||
private readonly FileOcelotConfigurationCreator _ocelotConfigurationCreator;
|
private readonly FileOcelotConfigurationCreator _ocelotConfigurationCreator;
|
||||||
private readonly Mock<ILoadBalancerFactory> _loadBalancerFactory;
|
private readonly Mock<ILoadBalancerFactory> _loadBalancerFactory;
|
||||||
private readonly Mock<ILoadBalancerHouse> _loadBalancerHouse;
|
private readonly Mock<ILoadBalancerHouse> _loadBalancerHouse;
|
||||||
@ -44,7 +45,7 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
_qosProviderFactory = new Mock<IQoSProviderFactory>();
|
_qosProviderFactory = new Mock<IQoSProviderFactory>();
|
||||||
_qosProviderHouse = new Mock<IQosProviderHouse>();
|
_qosProviderHouse = new Mock<IQosProviderHouse>();
|
||||||
_qosProvider = new Mock<IQoSProvider>();
|
_qosProvider = new Mock<IQoSProvider>();
|
||||||
_logger = new Mock<ILogger<FileOcelotConfigurationCreator>>();
|
_logger = new Mock<IOcelotLoggerFactory>();
|
||||||
_validator = new Mock<IConfigurationValidator>();
|
_validator = new Mock<IConfigurationValidator>();
|
||||||
_fileConfig = new Mock<IOptions<FileConfiguration>>();
|
_fileConfig = new Mock<IOptions<FileConfiguration>>();
|
||||||
_loadBalancerFactory = new Mock<ILoadBalancerFactory>();
|
_loadBalancerFactory = new Mock<ILoadBalancerFactory>();
|
||||||
|
@ -0,0 +1,73 @@
|
|||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Ocelot.Infrastructure.RequestData;
|
||||||
|
using Ocelot.Responses;
|
||||||
|
using Shouldly;
|
||||||
|
using TestStack.BDDfy;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Ocelot.UnitTests.Infrastructure
|
||||||
|
{
|
||||||
|
public class HttpDataRepositoryTests
|
||||||
|
{
|
||||||
|
private HttpContext _httpContext;
|
||||||
|
private IHttpContextAccessor _httpContextAccessor;
|
||||||
|
private HttpDataRepository _httpDataRepository;
|
||||||
|
private object _result;
|
||||||
|
|
||||||
|
public HttpDataRepositoryTests()
|
||||||
|
{
|
||||||
|
_httpContext = new DefaultHttpContext();
|
||||||
|
_httpContextAccessor = new HttpContextAccessor{HttpContext = _httpContext};
|
||||||
|
_httpDataRepository = new HttpDataRepository(_httpContextAccessor);
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO - Additional tests -> Type mistmatch aka Add string, request int
|
||||||
|
//TODO - Additional tests -> HttpContent null. This should never happen
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Get_returns_correct_key_from_http_context()
|
||||||
|
{
|
||||||
|
|
||||||
|
this.Given(x => x.GivenAHttpContextContaining("key", "string"))
|
||||||
|
.When(x => x.GetIsCalledWithKey<string>("key"))
|
||||||
|
.Then(x => x.ThenTheResultIsAnOkResponse<string>("string"))
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Get_returns_error_response_if_the_key_is_not_found() //Therefore does not return null
|
||||||
|
{
|
||||||
|
this.Given(x => x.GivenAHttpContextContaining("key", "string"))
|
||||||
|
.When(x => x.GetIsCalledWithKey<string>("keyDoesNotExist"))
|
||||||
|
.Then(x => x.ThenTheResultIsAnErrorReposnse<string>("string1"))
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GivenAHttpContextContaining(string key, object o)
|
||||||
|
{
|
||||||
|
_httpContext.Items.Add(key, o);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GetIsCalledWithKey<T>(string key)
|
||||||
|
{
|
||||||
|
_result = _httpDataRepository.Get<T>(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThenTheResultIsAnErrorReposnse<T>(object resultValue)
|
||||||
|
{
|
||||||
|
_result.ShouldBeOfType<ErrorResponse<T>>();
|
||||||
|
((ErrorResponse<T>) _result).Data.ShouldBeNull();
|
||||||
|
((ErrorResponse<T>)_result).IsError.ShouldBe(true);
|
||||||
|
((ErrorResponse<T>) _result).Errors.ShouldHaveSingleItem()
|
||||||
|
.ShouldBeOfType<CannotFindDataError>()
|
||||||
|
.Message.ShouldStartWith("Unable to find data for key: ");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThenTheResultIsAnOkResponse<T>(object resultValue)
|
||||||
|
{
|
||||||
|
_result.ShouldBeOfType<OkResponse<T>>();
|
||||||
|
((OkResponse<T>)_result).Data.ShouldBe(resultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user