#474 tests to show how spaces in headers work (#483)

This commit is contained in:
Tom Pallister 2018-07-21 00:10:06 +01:00 committed by GitHub
parent 7dbfc46e7b
commit 079ec0f365
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 177 additions and 105 deletions

View File

@ -1,104 +1,104 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Ocelot.Configuration.Repository; using Ocelot.Configuration.Repository;
using Ocelot.Infrastructure.Extensions; using Ocelot.Infrastructure.Extensions;
using Ocelot.Infrastructure.RequestData; using Ocelot.Infrastructure.RequestData;
using Ocelot.Logging; using Ocelot.Logging;
using Ocelot.Middleware; using Ocelot.Middleware;
namespace Ocelot.Errors.Middleware namespace Ocelot.Errors.Middleware
{ {
using Configuration; using Configuration;
/// <summary> /// <summary>
/// Catches all unhandled exceptions thrown by middleware, logs and returns a 500 /// Catches all unhandled exceptions thrown by middleware, logs and returns a 500
/// </summary> /// </summary>
public class ExceptionHandlerMiddleware : OcelotMiddleware public class ExceptionHandlerMiddleware : OcelotMiddleware
{ {
private readonly OcelotRequestDelegate _next; private readonly OcelotRequestDelegate _next;
private readonly IInternalConfigurationRepository _configRepo; private readonly IInternalConfigurationRepository _configRepo;
private readonly IRequestScopedDataRepository _repo; private readonly IRequestScopedDataRepository _repo;
public ExceptionHandlerMiddleware(OcelotRequestDelegate next, public ExceptionHandlerMiddleware(OcelotRequestDelegate next,
IOcelotLoggerFactory loggerFactory, IOcelotLoggerFactory loggerFactory,
IInternalConfigurationRepository configRepo, IInternalConfigurationRepository configRepo,
IRequestScopedDataRepository repo) IRequestScopedDataRepository repo)
: base(loggerFactory.CreateLogger<ExceptionHandlerMiddleware>()) : base(loggerFactory.CreateLogger<ExceptionHandlerMiddleware>())
{ {
_configRepo = configRepo; _configRepo = configRepo;
_repo = repo; _repo = repo;
_next = next; _next = next;
} }
public async Task Invoke(DownstreamContext context) public async Task Invoke(DownstreamContext context)
{ {
try try
{ {
//try and get the global request id and set it for logs... //try and get the global request id and set it for logs...
//should this basically be immutable per request...i guess it should! //should this basically be immutable per request...i guess it should!
//first thing is get config //first thing is get config
var configuration = _configRepo.Get(); var configuration = _configRepo.Get();
if (configuration.IsError) if (configuration.IsError)
{ {
throw new Exception($"{MiddlewareName} setting pipeline errors. IOcelotConfigurationProvider returned {configuration.Errors.ToErrorString()}"); throw new Exception($"{MiddlewareName} setting pipeline errors. IOcelotConfigurationProvider returned {configuration.Errors.ToErrorString()}");
} }
TrySetGlobalRequestId(context, configuration.Data); TrySetGlobalRequestId(context, configuration.Data);
context.Configuration = configuration.Data; context.Configuration = configuration.Data;
Logger.LogDebug("ocelot pipeline started"); Logger.LogDebug("ocelot pipeline started");
await _next.Invoke(context); await _next.Invoke(context);
} }
catch (Exception e) catch (Exception e)
{ {
Logger.LogDebug("error calling middleware"); Logger.LogDebug("error calling middleware");
var message = CreateMessage(context, e); var message = CreateMessage(context, e);
Logger.LogError(message, e); Logger.LogError(message, e);
SetInternalServerErrorOnResponse(context); SetInternalServerErrorOnResponse(context);
} }
Logger.LogDebug("ocelot pipeline finished"); Logger.LogDebug("ocelot pipeline finished");
} }
private void TrySetGlobalRequestId(DownstreamContext context, IInternalConfiguration configuration) private void TrySetGlobalRequestId(DownstreamContext context, IInternalConfiguration configuration)
{ {
var key = configuration.RequestId; var key = configuration.RequestId;
if (!string.IsNullOrEmpty(key) && context.HttpContext.Request.Headers.TryGetValue(key, out var upstreamRequestIds)) if (!string.IsNullOrEmpty(key) && context.HttpContext.Request.Headers.TryGetValue(key, out var upstreamRequestIds))
{ {
context.HttpContext.TraceIdentifier = upstreamRequestIds.First(); context.HttpContext.TraceIdentifier = upstreamRequestIds.First();
} }
_repo.Add("RequestId", context.HttpContext.TraceIdentifier); _repo.Add("RequestId", context.HttpContext.TraceIdentifier);
} }
private void SetInternalServerErrorOnResponse(DownstreamContext context) private void SetInternalServerErrorOnResponse(DownstreamContext context)
{ {
if (!context.HttpContext.Response.HasStarted) if (!context.HttpContext.Response.HasStarted)
{ {
context.HttpContext.Response.StatusCode = 500; context.HttpContext.Response.StatusCode = 500;
} }
} }
private string CreateMessage(DownstreamContext context, Exception e) private string CreateMessage(DownstreamContext context, Exception e)
{ {
var message = var message =
$"Exception caught in global error handler, exception message: {e.Message}, exception stack: {e.StackTrace}"; $"Exception caught in global error handler, exception message: {e.Message}, exception stack: {e.StackTrace}";
if (e.InnerException != null) if (e.InnerException != null)
{ {
message = message =
$"{message}, inner exception message {e.InnerException.Message}, inner exception stack {e.InnerException.StackTrace}"; $"{message}, inner exception message {e.InnerException.Message}, inner exception stack {e.InnerException.StackTrace}";
} }
return $"{message} RequestId: {context.HttpContext.TraceIdentifier}"; return $"{message} RequestId: {context.HttpContext.TraceIdentifier}";
} }
} }
} }

View File

@ -313,6 +313,78 @@ namespace Ocelot.AcceptanceTests
.BDDfy(); .BDDfy();
} }
[Fact]
public void issue_474_should_not_put_spaces_in_header()
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 51879,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", "/", 200, "Accept"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.And(x => _steps.GivenIAddAHeader("Accept", "text/html,application/xhtml+xml,application/xml;"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("text/html,application/xhtml+xml,application/xml;"))
.BDDfy();
}
[Fact]
public void issue_474_should_put_spaces_in_header()
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 51879,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", "/", 200, "Accept"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.And(x => _steps.GivenIAddAHeader("Accept", "text/html"))
.And(x => _steps.GivenIAddAHeader("Accept", "application/xhtml+xml"))
.And(x => _steps.GivenIAddAHeader("Accept", "application/xml"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("text/html, application/xhtml+xml, application/xml"))
.BDDfy();
}
private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode) private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode)
{ {
_builder = new WebHostBuilder() _builder = new WebHostBuilder()

View File

@ -746,7 +746,7 @@ namespace Ocelot.AcceptanceTests
public void GivenIAddAHeader(string key, string value) public void GivenIAddAHeader(string key, string value)
{ {
_ocelotClient.DefaultRequestHeaders.Add(key, value); _ocelotClient.DefaultRequestHeaders.TryAddWithoutValidation(key, value);
} }
public void WhenIGetUrlOnTheApiGatewayMultipleTimes(string url, int times) public void WhenIGetUrlOnTheApiGatewayMultipleTimes(string url, int times)