bunch of refactoring

This commit is contained in:
TomPallister 2016-10-26 21:38:44 +01:00
parent 9575adc90d
commit 367fa327b3
35 changed files with 264 additions and 157 deletions

View File

@ -13,6 +13,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
build.bat = build.bat build.bat = build.bat
global.json = global.json global.json = global.json
LICENSE.md = LICENSE.md LICENSE.md = LICENSE.md
Ocelot.nuspec = Ocelot.nuspec
push-to-nuget.bat = push-to-nuget.bat
README.md = README.md README.md = README.md
run-benchmarks.bat = run-benchmarks.bat run-benchmarks.bat = run-benchmarks.bat
run-tests.bat = run-tests.bat run-tests.bat = run-tests.bat

View File

@ -54,8 +54,8 @@ namespace Ocelot.DependencyInjection
services.AddSingleton<IAddHeadersToRequest, AddHeadersToRequest>(); services.AddSingleton<IAddHeadersToRequest, AddHeadersToRequest>();
services.AddSingleton<IClaimsParser, ClaimsParser>(); services.AddSingleton<IClaimsParser, ClaimsParser>();
services.AddSingleton<IUrlPathToUrlTemplateMatcher, RegExUrlMatcher>(); services.AddSingleton<IUrlPathToUrlTemplateMatcher, RegExUrlMatcher>();
services.AddSingleton<ITemplateVariableNameAndValueFinder, TemplateVariableNameAndValueFinder>(); services.AddSingleton<IUrlPathPlaceholderNameAndValueFinder, UrlPathPlaceholderNameAndValueFinder>();
services.AddSingleton<IDownstreamUrlTemplateVariableReplacer, DownstreamUrlTemplateVariableReplacer>(); services.AddSingleton<IDownstreamUrlPathPlaceholderReplacer, DownstreamUrlPathPlaceholderReplacer>();
services.AddSingleton<IDownstreamRouteFinder, DownstreamRouteFinder.Finder.DownstreamRouteFinder>(); services.AddSingleton<IDownstreamRouteFinder, DownstreamRouteFinder.Finder.DownstreamRouteFinder>();
services.AddSingleton<IHttpRequester, HttpClientHttpRequester>(); services.AddSingleton<IHttpRequester, HttpClientHttpRequester>();
services.AddSingleton<IHttpResponder, HttpContextResponder>(); services.AddSingleton<IHttpResponder, HttpContextResponder>();

View File

@ -6,12 +6,12 @@ namespace Ocelot.DownstreamRouteFinder
{ {
public class DownstreamRoute public class DownstreamRoute
{ {
public DownstreamRoute(List<TemplateVariableNameAndValue> templateVariableNameAndValues, ReRoute reRoute) public DownstreamRoute(List<UrlPathPlaceholderNameAndValue> templatePlaceholderNameAndValues, ReRoute reRoute)
{ {
TemplateVariableNameAndValues = templateVariableNameAndValues; TemplatePlaceholderNameAndValues = templatePlaceholderNameAndValues;
ReRoute = reRoute; ReRoute = reRoute;
} }
public List<TemplateVariableNameAndValue> TemplateVariableNameAndValues { get; private set; } public List<UrlPathPlaceholderNameAndValue> TemplatePlaceholderNameAndValues { get; private set; }
public ReRoute ReRoute { get; private set; } public ReRoute ReRoute { get; private set; }
} }
} }

View File

@ -12,29 +12,28 @@ namespace Ocelot.DownstreamRouteFinder.Finder
{ {
private readonly IOcelotConfigurationProvider _configProvider; private readonly IOcelotConfigurationProvider _configProvider;
private readonly IUrlPathToUrlTemplateMatcher _urlMatcher; private readonly IUrlPathToUrlTemplateMatcher _urlMatcher;
private readonly ITemplateVariableNameAndValueFinder _templateVariableNameAndValueFinder; private readonly IUrlPathPlaceholderNameAndValueFinder _urlPathPlaceholderNameAndValueFinder;
public DownstreamRouteFinder(IOcelotConfigurationProvider configProvider, IUrlPathToUrlTemplateMatcher urlMatcher, ITemplateVariableNameAndValueFinder templateVariableNameAndValueFinder) public DownstreamRouteFinder(IOcelotConfigurationProvider configProvider, IUrlPathToUrlTemplateMatcher urlMatcher, IUrlPathPlaceholderNameAndValueFinder urlPathPlaceholderNameAndValueFinder)
{ {
_configProvider = configProvider; _configProvider = configProvider;
_urlMatcher = urlMatcher; _urlMatcher = urlMatcher;
_templateVariableNameAndValueFinder = templateVariableNameAndValueFinder; _urlPathPlaceholderNameAndValueFinder = urlPathPlaceholderNameAndValueFinder;
} }
public Response<DownstreamRoute> FindDownstreamRoute(string upstreamUrlPath, string upstreamHttpMethod) public Response<DownstreamRoute> FindDownstreamRoute(string upstreamUrlPath, string upstreamHttpMethod)
{ {
var configuration = _configProvider.Get(); var configuration = _configProvider.Get();
foreach (var template in configuration.Data.ReRoutes.Where(r => string.Equals(r.UpstreamHttpMethod, upstreamHttpMethod, StringComparison.CurrentCultureIgnoreCase))) foreach (var reRoute in configuration.Data.ReRoutes.Where(r => string.Equals(r.UpstreamHttpMethod, upstreamHttpMethod, StringComparison.CurrentCultureIgnoreCase)))
{ {
var urlMatch = _urlMatcher.Match(upstreamUrlPath, template.UpstreamTemplatePattern); var urlMatch = _urlMatcher.Match(upstreamUrlPath, reRoute.UpstreamTemplatePattern);
if (urlMatch.Data.Match) if (urlMatch.Data.Match)
{ {
var templateVariableNameAndValues = _templateVariableNameAndValueFinder.Find(upstreamUrlPath, var templateVariableNameAndValues = _urlPathPlaceholderNameAndValueFinder.Find(upstreamUrlPath, reRoute.UpstreamTemplate);
template.UpstreamTemplate);
return new OkResponse<DownstreamRoute>(new DownstreamRoute(templateVariableNameAndValues.Data, template)); return new OkResponse<DownstreamRoute>(new DownstreamRoute(templateVariableNameAndValues.Data, reRoute));
} }
} }

View File

@ -1,10 +0,0 @@
using System.Collections.Generic;
using Ocelot.Responses;
namespace Ocelot.DownstreamRouteFinder.UrlMatcher
{
public interface ITemplateVariableNameAndValueFinder
{
Response<List<TemplateVariableNameAndValue>> Find(string upstreamUrlPath, string upstreamUrlPathTemplate);
}
}

View File

@ -0,0 +1,10 @@
using System.Collections.Generic;
using Ocelot.Responses;
namespace Ocelot.DownstreamRouteFinder.UrlMatcher
{
public interface IUrlPathPlaceholderNameAndValueFinder
{
Response<List<UrlPathPlaceholderNameAndValue>> Find(string upstreamUrlPath, string upstreamUrlPathTemplate);
}
}

View File

@ -1,8 +1,8 @@
namespace Ocelot.DownstreamRouteFinder.UrlMatcher namespace Ocelot.DownstreamRouteFinder.UrlMatcher
{ {
public class TemplateVariableNameAndValue public class UrlPathPlaceholderNameAndValue
{ {
public TemplateVariableNameAndValue(string templateVariableName, string templateVariableValue) public UrlPathPlaceholderNameAndValue(string templateVariableName, string templateVariableValue)
{ {
TemplateVariableName = templateVariableName; TemplateVariableName = templateVariableName;
TemplateVariableValue = templateVariableValue; TemplateVariableValue = templateVariableValue;

View File

@ -3,11 +3,11 @@ using Ocelot.Responses;
namespace Ocelot.DownstreamRouteFinder.UrlMatcher namespace Ocelot.DownstreamRouteFinder.UrlMatcher
{ {
public class TemplateVariableNameAndValueFinder : ITemplateVariableNameAndValueFinder public class UrlPathPlaceholderNameAndValueFinder : IUrlPathPlaceholderNameAndValueFinder
{ {
public Response<List<TemplateVariableNameAndValue>> Find(string upstreamUrlPath, string upstreamUrlPathTemplate) public Response<List<UrlPathPlaceholderNameAndValue>> Find(string upstreamUrlPath, string upstreamUrlPathTemplate)
{ {
var templateKeysAndValues = new List<TemplateVariableNameAndValue>(); var templateKeysAndValues = new List<UrlPathPlaceholderNameAndValue>();
int counterForUrl = 0; int counterForUrl = 0;
@ -21,7 +21,7 @@ namespace Ocelot.DownstreamRouteFinder.UrlMatcher
var variableValue = GetPlaceholderVariableValue(upstreamUrlPath, counterForUrl); var variableValue = GetPlaceholderVariableValue(upstreamUrlPath, counterForUrl);
var templateVariableNameAndValue = new TemplateVariableNameAndValue(variableName, variableValue); var templateVariableNameAndValue = new UrlPathPlaceholderNameAndValue(variableName, variableValue);
templateKeysAndValues.Add(templateVariableNameAndValue); templateKeysAndValues.Add(templateVariableNameAndValue);
@ -32,12 +32,12 @@ namespace Ocelot.DownstreamRouteFinder.UrlMatcher
continue; continue;
} }
return new OkResponse<List<TemplateVariableNameAndValue>>(templateKeysAndValues); return new OkResponse<List<UrlPathPlaceholderNameAndValue>>(templateKeysAndValues);
} }
counterForUrl++; counterForUrl++;
} }
return new OkResponse<List<TemplateVariableNameAndValue>>(templateKeysAndValues); return new OkResponse<List<UrlPathPlaceholderNameAndValue>>(templateKeysAndValues);
} }
private string GetPlaceholderVariableValue(string urlPath, int counterForUrl) private string GetPlaceholderVariableValue(string urlPath, int counterForUrl)

View File

@ -10,11 +10,11 @@ namespace Ocelot.DownstreamUrlCreator.Middleware
public class DownstreamUrlCreatorMiddleware : OcelotMiddleware public class DownstreamUrlCreatorMiddleware : OcelotMiddleware
{ {
private readonly RequestDelegate _next; private readonly RequestDelegate _next;
private readonly IDownstreamUrlTemplateVariableReplacer _urlReplacer; private readonly IDownstreamUrlPathPlaceholderReplacer _urlReplacer;
private readonly IRequestScopedDataRepository _requestScopedDataRepository; private readonly IRequestScopedDataRepository _requestScopedDataRepository;
public DownstreamUrlCreatorMiddleware(RequestDelegate next, public DownstreamUrlCreatorMiddleware(RequestDelegate next,
IDownstreamUrlTemplateVariableReplacer urlReplacer, IDownstreamUrlPathPlaceholderReplacer urlReplacer,
IRequestScopedDataRepository requestScopedDataRepository) IRequestScopedDataRepository requestScopedDataRepository)
:base(requestScopedDataRepository) :base(requestScopedDataRepository)
{ {
@ -33,7 +33,7 @@ namespace Ocelot.DownstreamUrlCreator.Middleware
return; return;
} }
var downstreamUrl = _urlReplacer.ReplaceTemplateVariables(downstreamRoute.Data); var downstreamUrl = _urlReplacer.Replace(downstreamRoute.Data.ReRoute.DownstreamTemplate, downstreamRoute.Data.TemplatePlaceholderNameAndValues);
if (downstreamUrl.IsError) if (downstreamUrl.IsError)
{ {
@ -41,7 +41,7 @@ namespace Ocelot.DownstreamUrlCreator.Middleware
return; return;
} }
_requestScopedDataRepository.Add("DownstreamUrl", downstreamUrl.Data); _requestScopedDataRepository.Add("DownstreamUrl", downstreamUrl.Data.Value);
await _next.Invoke(context); await _next.Invoke(context);
} }

View File

@ -0,0 +1,12 @@
namespace Ocelot.DownstreamUrlCreator.UrlTemplateReplacer
{
public class DownstreamUrl
{
public DownstreamUrl(string value)
{
Value = value;
}
public string Value { get; private set; }
}
}

View File

@ -1,23 +1,25 @@
using System.Collections.Generic;
using System.Text; using System.Text;
using Ocelot.DownstreamRouteFinder; using Ocelot.DownstreamRouteFinder;
using Ocelot.DownstreamRouteFinder.UrlMatcher;
using Ocelot.Responses; using Ocelot.Responses;
namespace Ocelot.DownstreamUrlCreator.UrlTemplateReplacer namespace Ocelot.DownstreamUrlCreator.UrlTemplateReplacer
{ {
public class DownstreamUrlTemplateVariableReplacer : IDownstreamUrlTemplateVariableReplacer public class DownstreamUrlPathPlaceholderReplacer : IDownstreamUrlPathPlaceholderReplacer
{ {
public Response<string> ReplaceTemplateVariables(DownstreamRoute downstreamRoute) public Response<DownstreamUrl> Replace(string downstreamTemplate, List<UrlPathPlaceholderNameAndValue> urlPathPlaceholderNameAndValues)
{ {
var upstreamUrl = new StringBuilder(); var upstreamUrl = new StringBuilder();
upstreamUrl.Append(downstreamRoute.ReRoute.DownstreamTemplate); upstreamUrl.Append(downstreamTemplate);
foreach (var templateVarAndValue in downstreamRoute.TemplateVariableNameAndValues) foreach (var placeholderVariableAndValue in urlPathPlaceholderNameAndValues)
{ {
upstreamUrl.Replace(templateVarAndValue.TemplateVariableName, templateVarAndValue.TemplateVariableValue); upstreamUrl.Replace(placeholderVariableAndValue.TemplateVariableName, placeholderVariableAndValue.TemplateVariableValue);
} }
return new OkResponse<string>(upstreamUrl.ToString()); return new OkResponse<DownstreamUrl>(new DownstreamUrl(upstreamUrl.ToString()));
} }
} }
} }

View File

@ -1,10 +1,11 @@
using Ocelot.DownstreamRouteFinder; using System.Collections.Generic;
using Ocelot.DownstreamRouteFinder.UrlMatcher;
using Ocelot.Responses; using Ocelot.Responses;
namespace Ocelot.DownstreamUrlCreator.UrlTemplateReplacer namespace Ocelot.DownstreamUrlCreator.UrlTemplateReplacer
{ {
public interface IDownstreamUrlTemplateVariableReplacer public interface IDownstreamUrlPathPlaceholderReplacer
{ {
Response<string> ReplaceTemplateVariables(DownstreamRoute downstreamRoute); Response<DownstreamUrl> Replace(string downstreamTemplate, List<UrlPathPlaceholderNameAndValue> urlPathPlaceholderNameAndValues);
} }
} }

View File

@ -0,0 +1,34 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
namespace Ocelot.Middleware
{
public class ExceptionHandlerMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger _logger;
public ExceptionHandlerMiddleware(RequestDelegate next, ILoggerFactory loggerFactory)
{
_next = next;
_logger = loggerFactory.CreateLogger<ExceptionHandlerMiddleware>();
}
public async Task Invoke(HttpContext context)
{
try
{
await _next.Invoke(context);
}
catch (Exception e)
{
_logger.LogError(new EventId(1, "global error"), "Exception caught in global error handler", e);
context.Response.StatusCode = 500;
context.Response.ContentType = "application/json";
await context.Response.WriteAsync("Internal Server Error");
}
}
}
}

View File

@ -0,0 +1,12 @@
using Microsoft.AspNetCore.Builder;
namespace Ocelot.Middleware
{
public static class ExceptionHandlerMiddlewareExtensions
{
public static IApplicationBuilder UseExceptionHandlerMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<ExceptionHandlerMiddleware>();
}
}
}

View File

@ -19,22 +19,34 @@ namespace Ocelot.Middleware
{ {
public static IApplicationBuilder UseOcelot(this IApplicationBuilder builder) public static IApplicationBuilder UseOcelot(this IApplicationBuilder builder)
{ {
builder.UseHttpResponderMiddleware(); // This is registered to catch any global exceptions that are not handled
builder.UseExceptionHandlerMiddleware();
// This is registered first so it can catch any errors and issue an appropriate response
builder.UseHttpErrorResponderMiddleware();
// Then we get the downstream route information
builder.UseDownstreamRouteFinderMiddleware(); builder.UseDownstreamRouteFinderMiddleware();
// Now we know where the client is going to go we can authenticate them
builder.UseAuthenticationMiddleware(); builder.UseAuthenticationMiddleware();
// The next thing we do is look at any claims transforms in case this is important for authorisation
builder.UseClaimsBuilderMiddleware(); builder.UseClaimsBuilderMiddleware();
// Now we have authenticated and done any claims transformation we can authorise the request
builder.UseAuthorisationMiddleware(); builder.UseAuthorisationMiddleware();
// Now we can run any header transformation logic
builder.UseHttpRequestHeadersBuilderMiddleware(); builder.UseHttpRequestHeadersBuilderMiddleware();
// This takes the downstream route we retrieved earlier and replaces any placeholders with the variables that should be used
builder.UseDownstreamUrlCreatorMiddleware(); builder.UseDownstreamUrlCreatorMiddleware();
// Everything should now be ready to build or HttpRequest
builder.UseHttpRequestBuilderMiddleware(); builder.UseHttpRequestBuilderMiddleware();
//We fire off the request and set the response on the context in this middleware
builder.UseHttpRequesterMiddleware(); builder.UseHttpRequesterMiddleware();
return builder; return builder;
@ -44,7 +56,7 @@ namespace Ocelot.Middleware
{ {
builder.UseIfNotNull(middlewareConfiguration.PreHttpResponderMiddleware); builder.UseIfNotNull(middlewareConfiguration.PreHttpResponderMiddleware);
builder.UseHttpResponderMiddleware(); builder.UseHttpErrorResponderMiddleware();
builder.UseIfNotNull(middlewareConfiguration.PostHttpResponderMiddleware); builder.UseIfNotNull(middlewareConfiguration.PostHttpResponderMiddleware);

View File

@ -22,18 +22,13 @@ namespace Ocelot.RequestBuilder.Builder
if (content != null) if (content != null)
{ {
using (var reader = new StreamReader(content)) httpRequestMessage.Content = new StreamContent(content);
{
var body = await reader.ReadToEndAsync();
httpRequestMessage.Content = new StringContent(body);
}
} }
if (!string.IsNullOrEmpty(contentType)) if (!string.IsNullOrEmpty(contentType))
{ {
var splitCt = contentType.Split(';'); httpRequestMessage.Content.Headers.Remove("Content-Type");
var cT = splitCt[0]; httpRequestMessage.Content.Headers.TryAddWithoutValidation("Content-Type", contentType);
httpRequestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue(cT);
} }
//todo get rid of if //todo get rid of if
@ -50,7 +45,7 @@ namespace Ocelot.RequestBuilder.Builder
//todo get rid of if.. //todo get rid of if..
if (header.Key.ToLower() != "host") if (header.Key.ToLower() != "host")
{ {
httpRequestMessage.Headers.Add(header.Key, header.Value.ToArray()); httpRequestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
} }
} }
} }

View File

@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Http;
using Ocelot.Infrastructure.RequestData; using Ocelot.Infrastructure.RequestData;
using Ocelot.Middleware; using Ocelot.Middleware;
using Ocelot.RequestBuilder; using Ocelot.RequestBuilder;
using Ocelot.Responder;
namespace Ocelot.Requester.Middleware namespace Ocelot.Requester.Middleware
{ {
@ -11,15 +12,18 @@ namespace Ocelot.Requester.Middleware
private readonly RequestDelegate _next; private readonly RequestDelegate _next;
private readonly IHttpRequester _requester; private readonly IHttpRequester _requester;
private readonly IRequestScopedDataRepository _requestScopedDataRepository; private readonly IRequestScopedDataRepository _requestScopedDataRepository;
private readonly IHttpResponder _responder;
public HttpRequesterMiddleware(RequestDelegate next, public HttpRequesterMiddleware(RequestDelegate next,
IHttpRequester requester, IHttpRequester requester,
IRequestScopedDataRepository requestScopedDataRepository) IRequestScopedDataRepository requestScopedDataRepository,
IHttpResponder responder)
:base(requestScopedDataRepository) :base(requestScopedDataRepository)
{ {
_next = next; _next = next;
_requester = requester; _requester = requester;
_requestScopedDataRepository = requestScopedDataRepository; _requestScopedDataRepository = requestScopedDataRepository;
_responder = responder;
} }
public async Task Invoke(HttpContext context) public async Task Invoke(HttpContext context)
@ -40,7 +44,12 @@ namespace Ocelot.Requester.Middleware
return; return;
} }
_requestScopedDataRepository.Add("Response", response.Data); var setResponse = await _responder.SetResponseOnHttpContext(context, response.Data);
if (setResponse.IsError)
{
SetPipelineError(response.Errors);
}
} }
} }
} }

View File

@ -1,6 +1,7 @@
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Ocelot.Responses;
namespace Ocelot.Responder namespace Ocelot.Responder
{ {
@ -10,7 +11,7 @@ namespace Ocelot.Responder
/// </summary> /// </summary>
public class HttpContextResponder : IHttpResponder public class HttpContextResponder : IHttpResponder
{ {
public async Task<HttpContext> CreateResponse(HttpContext context, HttpResponseMessage response) public async Task<Response> SetResponseOnHttpContext(HttpContext context, HttpResponseMessage response)
{ {
context.Response.OnStarting(x => context.Response.OnStarting(x =>
{ {
@ -19,17 +20,17 @@ namespace Ocelot.Responder
}, context); }, context);
await context.Response.WriteAsync(await response.Content.ReadAsStringAsync()); await context.Response.WriteAsync(await response.Content.ReadAsStringAsync());
return context; return new OkResponse();
} }
public async Task<HttpContext> CreateErrorResponse(HttpContext context, int statusCode) public async Task<Response> SetErrorResponseOnContext(HttpContext context, int statusCode)
{ {
context.Response.OnStarting(x => context.Response.OnStarting(x =>
{ {
context.Response.StatusCode = statusCode; context.Response.StatusCode = statusCode;
return Task.CompletedTask; return Task.CompletedTask;
}, context); }, context);
return context; return new OkResponse();
} }
} }
} }

View File

@ -1,12 +1,13 @@
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Ocelot.Responses;
namespace Ocelot.Responder namespace Ocelot.Responder
{ {
public interface IHttpResponder public interface IHttpResponder
{ {
Task<HttpContext> CreateResponse(HttpContext context, HttpResponseMessage response); Task<Response> SetResponseOnHttpContext(HttpContext context, HttpResponseMessage response);
Task<HttpContext> CreateErrorResponse(HttpContext context, int statusCode); Task<Response> SetErrorResponseOnContext(HttpContext context, int statusCode);
} }
} }

View File

@ -6,14 +6,14 @@ using Ocelot.Middleware;
namespace Ocelot.Responder.Middleware namespace Ocelot.Responder.Middleware
{ {
public class HttpResponderMiddleware : OcelotMiddleware public class HttpErrorResponderMiddleware : OcelotMiddleware
{ {
private readonly RequestDelegate _next; private readonly RequestDelegate _next;
private readonly IHttpResponder _responder; private readonly IHttpResponder _responder;
private readonly IRequestScopedDataRepository _requestScopedDataRepository; private readonly IRequestScopedDataRepository _requestScopedDataRepository;
private readonly IErrorsToHttpStatusCodeMapper _codeMapper; private readonly IErrorsToHttpStatusCodeMapper _codeMapper;
public HttpResponderMiddleware(RequestDelegate next, public HttpErrorResponderMiddleware(RequestDelegate next,
IHttpResponder responder, IHttpResponder responder,
IRequestScopedDataRepository requestScopedDataRepository, IRequestScopedDataRepository requestScopedDataRepository,
IErrorsToHttpStatusCodeMapper codeMapper) IErrorsToHttpStatusCodeMapper codeMapper)
@ -37,19 +37,13 @@ namespace Ocelot.Responder.Middleware
if (!statusCode.IsError) if (!statusCode.IsError)
{ {
await _responder.CreateErrorResponse(context, statusCode.Data); await _responder.SetErrorResponseOnContext(context, statusCode.Data);
} }
else else
{ {
await _responder.CreateErrorResponse(context, 500); await _responder.SetErrorResponseOnContext(context, 500);
} }
} }
else
{
var response = _requestScopedDataRepository.Get<HttpResponseMessage>("Response");
await _responder.CreateResponse(context, response.Data);
}
} }
} }
} }

View File

@ -4,9 +4,9 @@ namespace Ocelot.Responder.Middleware
{ {
public static class HttpResponderMiddlewareExtensions public static class HttpResponderMiddlewareExtensions
{ {
public static IApplicationBuilder UseHttpResponderMiddleware(this IApplicationBuilder builder) public static IApplicationBuilder UseHttpErrorResponderMiddleware(this IApplicationBuilder builder)
{ {
return builder.UseMiddleware<HttpResponderMiddleware>(); return builder.UseMiddleware<HttpErrorResponderMiddleware>();
} }
} }
} }

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Net; using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
@ -67,8 +68,7 @@ namespace Ocelot.AcceptanceTests
{ {
PreHttpRequesterMiddleware = async (ctx, next) => PreHttpRequesterMiddleware = async (ctx, next) =>
{ {
var service = ctx.RequestServices.GetService<IRequestScopedDataRepository>(); await ctx.Response.WriteAsync("PreHttpRequesterMiddleware");
service.Add("Response", new HttpResponseMessage {Content = new StringContent("PreHttpRequesterMiddleware")});
} }
}; };
@ -104,9 +104,10 @@ namespace Ocelot.AcceptanceTests
.UseUrls(url) .UseUrls(url)
.Configure(app => .Configure(app =>
{ {
app.Run(async context => app.Run(context =>
{ {
context.Response.StatusCode = statusCode; context.Response.StatusCode = statusCode;
return Task.CompletedTask;
}); });
}) })
.Build(); .Build();

View File

@ -24,3 +24,6 @@ ReRoutes:
- DownstreamTemplate: http://www.bbc.co.uk - DownstreamTemplate: http://www.bbc.co.uk
UpstreamTemplate: / UpstreamTemplate: /
UpstreamHttpMethod: Get UpstreamHttpMethod: Get
- DownstreamTemplate: http://localhost:51879/api/products/{productId}
UpstreamTemplate: /products/{productId}
UpstreamHttpMethod: Get

View File

@ -56,7 +56,7 @@ namespace Ocelot.UnitTests.Authentication
[Fact] [Fact]
public void happy_path() public void happy_path()
{ {
this.Given(x => x.GivenTheDownStreamRouteIs(new DownstreamRoute(new List<TemplateVariableNameAndValue>(), new ReRouteBuilder().Build()))) this.Given(x => x.GivenTheDownStreamRouteIs(new DownstreamRoute(new List<UrlPathPlaceholderNameAndValue>(), new ReRouteBuilder().Build())))
.When(x => x.WhenICallTheMiddleware()) .When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenNoExceptionsAreThrown()) .Then(x => x.ThenNoExceptionsAreThrown())
.BDDfy(); .BDDfy();

View File

@ -58,7 +58,7 @@ namespace Ocelot.UnitTests.Authorization
[Fact] [Fact]
public void happy_path() public void happy_path()
{ {
this.Given(x => x.GivenTheDownStreamRouteIs(new DownstreamRoute(new List<TemplateVariableNameAndValue>(), new ReRouteBuilder().WithIsAuthorised(true).Build()))) this.Given(x => x.GivenTheDownStreamRouteIs(new DownstreamRoute(new List<UrlPathPlaceholderNameAndValue>(), new ReRouteBuilder().WithIsAuthorised(true).Build())))
.And(x => x.GivenTheAuthServiceReturns(new OkResponse<bool>(true))) .And(x => x.GivenTheAuthServiceReturns(new OkResponse<bool>(true)))
.When(x => x.WhenICallTheMiddleware()) .When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheAuthServiceIsCalledCorrectly()) .Then(x => x.ThenTheAuthServiceIsCalledCorrectly())

View File

@ -59,7 +59,7 @@ namespace Ocelot.UnitTests.ClaimsBuilder
[Fact] [Fact]
public void happy_path() public void happy_path()
{ {
var downstreamRoute = new DownstreamRoute(new List<TemplateVariableNameAndValue>(), var downstreamRoute = new DownstreamRoute(new List<UrlPathPlaceholderNameAndValue>(),
new ReRouteBuilder() new ReRouteBuilder()
.WithDownstreamTemplate("any old string") .WithDownstreamTemplate("any old string")
.WithClaimsToClaims(new List<ClaimToThing> .WithClaimsToClaims(new List<ClaimToThing>

View File

@ -57,7 +57,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
[Fact] [Fact]
public void happy_path() public void happy_path()
{ {
this.Given(x => x.GivenTheDownStreamRouteFinderReturns(new DownstreamRoute(new List<TemplateVariableNameAndValue>(), new ReRouteBuilder().WithDownstreamTemplate("any old string").Build()))) this.Given(x => x.GivenTheDownStreamRouteFinderReturns(new DownstreamRoute(new List<UrlPathPlaceholderNameAndValue>(), new ReRouteBuilder().WithDownstreamTemplate("any old string").Build())))
.When(x => x.WhenICallTheMiddleware()) .When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly()) .Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly())
.BDDfy(); .BDDfy();

View File

@ -18,7 +18,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
private readonly IDownstreamRouteFinder _downstreamRouteFinder; private readonly IDownstreamRouteFinder _downstreamRouteFinder;
private readonly Mock<IOcelotConfigurationProvider> _mockConfig; private readonly Mock<IOcelotConfigurationProvider> _mockConfig;
private readonly Mock<IUrlPathToUrlTemplateMatcher> _mockMatcher; private readonly Mock<IUrlPathToUrlTemplateMatcher> _mockMatcher;
private readonly Mock<ITemplateVariableNameAndValueFinder> _finder; private readonly Mock<IUrlPathPlaceholderNameAndValueFinder> _finder;
private string _upstreamUrlPath; private string _upstreamUrlPath;
private Response<DownstreamRoute> _result; private Response<DownstreamRoute> _result;
private List<ReRoute> _reRoutesConfig; private List<ReRoute> _reRoutesConfig;
@ -29,7 +29,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
{ {
_mockConfig = new Mock<IOcelotConfigurationProvider>(); _mockConfig = new Mock<IOcelotConfigurationProvider>();
_mockMatcher = new Mock<IUrlPathToUrlTemplateMatcher>(); _mockMatcher = new Mock<IUrlPathToUrlTemplateMatcher>();
_finder = new Mock<ITemplateVariableNameAndValueFinder>(); _finder = new Mock<IUrlPathPlaceholderNameAndValueFinder>();
_downstreamRouteFinder = new Ocelot.DownstreamRouteFinder.Finder.DownstreamRouteFinder(_mockConfig.Object, _mockMatcher.Object, _finder.Object); _downstreamRouteFinder = new Ocelot.DownstreamRouteFinder.Finder.DownstreamRouteFinder(_mockConfig.Object, _mockMatcher.Object, _finder.Object);
} }
@ -40,7 +40,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.And( .And(
x => x =>
x.GivenTheTemplateVariableAndNameFinderReturns( x.GivenTheTemplateVariableAndNameFinderReturns(
new OkResponse<List<TemplateVariableNameAndValue>>(new List<TemplateVariableNameAndValue>()))) new OkResponse<List<UrlPathPlaceholderNameAndValue>>(new List<UrlPathPlaceholderNameAndValue>())))
.And(x => x.GivenTheConfigurationIs(new List<ReRoute> .And(x => x.GivenTheConfigurationIs(new List<ReRoute>
{ {
new ReRouteBuilder() new ReRouteBuilder()
@ -55,7 +55,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.And(x => x.GivenTheUpstreamHttpMethodIs("Get")) .And(x => x.GivenTheUpstreamHttpMethodIs("Get"))
.When(x => x.WhenICallTheFinder()) .When(x => x.WhenICallTheFinder())
.Then( .Then(
x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List<TemplateVariableNameAndValue>(), x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List<UrlPathPlaceholderNameAndValue>(),
new ReRouteBuilder() new ReRouteBuilder()
.WithDownstreamTemplate("someDownstreamPath") .WithDownstreamTemplate("someDownstreamPath")
.Build() .Build()
@ -71,7 +71,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.And( .And(
x => x =>
x.GivenTheTemplateVariableAndNameFinderReturns( x.GivenTheTemplateVariableAndNameFinderReturns(
new OkResponse<List<TemplateVariableNameAndValue>>(new List<TemplateVariableNameAndValue>()))) new OkResponse<List<UrlPathPlaceholderNameAndValue>>(new List<UrlPathPlaceholderNameAndValue>())))
.And(x => x.GivenTheConfigurationIs(new List<ReRoute> .And(x => x.GivenTheConfigurationIs(new List<ReRoute>
{ {
new ReRouteBuilder() new ReRouteBuilder()
@ -92,7 +92,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.And(x => x.GivenTheUpstreamHttpMethodIs("Post")) .And(x => x.GivenTheUpstreamHttpMethodIs("Post"))
.When(x => x.WhenICallTheFinder()) .When(x => x.WhenICallTheFinder())
.Then( .Then(
x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List<TemplateVariableNameAndValue>(), x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List<UrlPathPlaceholderNameAndValue>(),
new ReRouteBuilder() new ReRouteBuilder()
.WithDownstreamTemplate("someDownstreamPathForAPost") .WithDownstreamTemplate("someDownstreamPathForAPost")
.Build() .Build()
@ -123,7 +123,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.BDDfy(); .BDDfy();
} }
private void GivenTheTemplateVariableAndNameFinderReturns(Response<List<TemplateVariableNameAndValue>> response) private void GivenTheTemplateVariableAndNameFinderReturns(Response<List<UrlPathPlaceholderNameAndValue>> response)
{ {
_finder _finder
.Setup(x => x.Find(It.IsAny<string>(), It.IsAny<string>())) .Setup(x => x.Find(It.IsAny<string>(), It.IsAny<string>()))
@ -176,13 +176,13 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
{ {
_result.Data.ReRoute.DownstreamTemplate.ShouldBe(expected.ReRoute.DownstreamTemplate); _result.Data.ReRoute.DownstreamTemplate.ShouldBe(expected.ReRoute.DownstreamTemplate);
for (int i = 0; i < _result.Data.TemplateVariableNameAndValues.Count; i++) for (int i = 0; i < _result.Data.TemplatePlaceholderNameAndValues.Count; i++)
{ {
_result.Data.TemplateVariableNameAndValues[i].TemplateVariableName.ShouldBe( _result.Data.TemplatePlaceholderNameAndValues[i].TemplateVariableName.ShouldBe(
expected.TemplateVariableNameAndValues[i].TemplateVariableName); expected.TemplatePlaceholderNameAndValues[i].TemplateVariableName);
_result.Data.TemplateVariableNameAndValues[i].TemplateVariableValue.ShouldBe( _result.Data.TemplatePlaceholderNameAndValues[i].TemplateVariableValue.ShouldBe(
expected.TemplateVariableNameAndValues[i].TemplateVariableValue); expected.TemplatePlaceholderNameAndValues[i].TemplateVariableValue);
} }
_result.IsError.ShouldBeFalse(); _result.IsError.ShouldBeFalse();

View File

@ -10,14 +10,14 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
{ {
public class UrlPathToUrlTemplateMatcherTests public class UrlPathToUrlTemplateMatcherTests
{ {
private readonly ITemplateVariableNameAndValueFinder _finder; private readonly IUrlPathPlaceholderNameAndValueFinder _finder;
private string _downstreamUrlPath; private string _downstreamUrlPath;
private string _downstreamPathTemplate; private string _downstreamPathTemplate;
private Response<List<TemplateVariableNameAndValue>> _result; private Response<List<UrlPathPlaceholderNameAndValue>> _result;
public UrlPathToUrlTemplateMatcherTests() public UrlPathToUrlTemplateMatcherTests()
{ {
_finder = new TemplateVariableNameAndValueFinder(); _finder = new UrlPathPlaceholderNameAndValueFinder();
} }
[Fact] [Fact]
@ -26,7 +26,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
this.Given(x => x.GivenIHaveAUpstreamPath("")) this.Given(x => x.GivenIHaveAUpstreamPath(""))
.And(x => x.GivenIHaveAnUpstreamUrlTemplate("")) .And(x => x.GivenIHaveAnUpstreamUrlTemplate(""))
.When(x => x.WhenIFindTheUrlVariableNamesAndValues()) .When(x => x.WhenIFindTheUrlVariableNamesAndValues())
.And(x => x.ThenTheTemplatesVariablesAre(new List<TemplateVariableNameAndValue>())) .And(x => x.ThenTheTemplatesVariablesAre(new List<UrlPathPlaceholderNameAndValue>()))
.BDDfy(); .BDDfy();
} }
@ -36,7 +36,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
this.Given(x => x.GivenIHaveAUpstreamPath("api")) this.Given(x => x.GivenIHaveAUpstreamPath("api"))
.Given(x => x.GivenIHaveAnUpstreamUrlTemplate("api")) .Given(x => x.GivenIHaveAnUpstreamUrlTemplate("api"))
.When(x => x.WhenIFindTheUrlVariableNamesAndValues()) .When(x => x.WhenIFindTheUrlVariableNamesAndValues())
.And(x => x.ThenTheTemplatesVariablesAre(new List<TemplateVariableNameAndValue>())) .And(x => x.ThenTheTemplatesVariablesAre(new List<UrlPathPlaceholderNameAndValue>()))
.BDDfy(); .BDDfy();
} }
@ -46,7 +46,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
this.Given(x => x.GivenIHaveAUpstreamPath("api/")) this.Given(x => x.GivenIHaveAUpstreamPath("api/"))
.Given(x => x.GivenIHaveAnUpstreamUrlTemplate("api/")) .Given(x => x.GivenIHaveAnUpstreamUrlTemplate("api/"))
.When(x => x.WhenIFindTheUrlVariableNamesAndValues()) .When(x => x.WhenIFindTheUrlVariableNamesAndValues())
.And(x => x.ThenTheTemplatesVariablesAre(new List<TemplateVariableNameAndValue>())) .And(x => x.ThenTheTemplatesVariablesAre(new List<UrlPathPlaceholderNameAndValue>()))
.BDDfy(); .BDDfy();
} }
@ -56,16 +56,16 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/")) this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/"))
.Given(x => x.GivenIHaveAnUpstreamUrlTemplate("api/product/products/")) .Given(x => x.GivenIHaveAnUpstreamUrlTemplate("api/product/products/"))
.When(x => x.WhenIFindTheUrlVariableNamesAndValues()) .When(x => x.WhenIFindTheUrlVariableNamesAndValues())
.And(x => x.ThenTheTemplatesVariablesAre(new List<TemplateVariableNameAndValue>())) .And(x => x.ThenTheTemplatesVariablesAre(new List<UrlPathPlaceholderNameAndValue>()))
.BDDfy(); .BDDfy();
} }
[Fact] [Fact]
public void can_match_down_stream_url_with_downstream_template_with_one_place_holder() public void can_match_down_stream_url_with_downstream_template_with_one_place_holder()
{ {
var expectedTemplates = new List<TemplateVariableNameAndValue> var expectedTemplates = new List<UrlPathPlaceholderNameAndValue>
{ {
new TemplateVariableNameAndValue("{productId}", "1") new UrlPathPlaceholderNameAndValue("{productId}", "1")
}; };
this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1")) this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1"))
@ -78,10 +78,10 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
[Fact] [Fact]
public void can_match_down_stream_url_with_downstream_template_with_two_place_holders() public void can_match_down_stream_url_with_downstream_template_with_two_place_holders()
{ {
var expectedTemplates = new List<TemplateVariableNameAndValue> var expectedTemplates = new List<UrlPathPlaceholderNameAndValue>
{ {
new TemplateVariableNameAndValue("{productId}", "1"), new UrlPathPlaceholderNameAndValue("{productId}", "1"),
new TemplateVariableNameAndValue("{categoryId}", "2") new UrlPathPlaceholderNameAndValue("{categoryId}", "2")
}; };
this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/2")) this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/2"))
@ -94,10 +94,10 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
[Fact] [Fact]
public void can_match_down_stream_url_with_downstream_template_with_two_place_holders_seperated_by_something() public void can_match_down_stream_url_with_downstream_template_with_two_place_holders_seperated_by_something()
{ {
var expectedTemplates = new List<TemplateVariableNameAndValue> var expectedTemplates = new List<UrlPathPlaceholderNameAndValue>
{ {
new TemplateVariableNameAndValue("{productId}", "1"), new UrlPathPlaceholderNameAndValue("{productId}", "1"),
new TemplateVariableNameAndValue("{categoryId}", "2") new UrlPathPlaceholderNameAndValue("{categoryId}", "2")
}; };
this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2")) this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2"))
@ -110,11 +110,11 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
[Fact] [Fact]
public void can_match_down_stream_url_with_downstream_template_with_three_place_holders_seperated_by_something() public void can_match_down_stream_url_with_downstream_template_with_three_place_holders_seperated_by_something()
{ {
var expectedTemplates = new List<TemplateVariableNameAndValue> var expectedTemplates = new List<UrlPathPlaceholderNameAndValue>
{ {
new TemplateVariableNameAndValue("{productId}", "1"), new UrlPathPlaceholderNameAndValue("{productId}", "1"),
new TemplateVariableNameAndValue("{categoryId}", "2"), new UrlPathPlaceholderNameAndValue("{categoryId}", "2"),
new TemplateVariableNameAndValue("{variantId}", "123") new UrlPathPlaceholderNameAndValue("{variantId}", "123")
}; };
this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2/variant/123")) this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2/variant/123"))
@ -127,10 +127,10 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
[Fact] [Fact]
public void can_match_down_stream_url_with_downstream_template_with_three_place_holders() public void can_match_down_stream_url_with_downstream_template_with_three_place_holders()
{ {
var expectedTemplates = new List<TemplateVariableNameAndValue> var expectedTemplates = new List<UrlPathPlaceholderNameAndValue>
{ {
new TemplateVariableNameAndValue("{productId}", "1"), new UrlPathPlaceholderNameAndValue("{productId}", "1"),
new TemplateVariableNameAndValue("{categoryId}", "2") new UrlPathPlaceholderNameAndValue("{categoryId}", "2")
}; };
this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2/variant/")) this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2/variant/"))
@ -140,7 +140,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
.BDDfy(); .BDDfy();
} }
private void ThenTheTemplatesVariablesAre(List<TemplateVariableNameAndValue> expectedResults) private void ThenTheTemplatesVariablesAre(List<UrlPathPlaceholderNameAndValue> expectedResults)
{ {
foreach (var expectedResult in expectedResults) foreach (var expectedResult in expectedResults)
{ {

View File

@ -20,19 +20,19 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator
{ {
public class DownstreamUrlCreatorMiddlewareTests : IDisposable public class DownstreamUrlCreatorMiddlewareTests : IDisposable
{ {
private readonly Mock<IDownstreamUrlTemplateVariableReplacer> _downstreamUrlTemplateVariableReplacer; private readonly Mock<IDownstreamUrlPathPlaceholderReplacer> _downstreamUrlTemplateVariableReplacer;
private readonly Mock<IRequestScopedDataRepository> _scopedRepository; private readonly Mock<IRequestScopedDataRepository> _scopedRepository;
private readonly string _url; private readonly string _url;
private readonly TestServer _server; private readonly TestServer _server;
private readonly HttpClient _client; private readonly HttpClient _client;
private Response<DownstreamRoute> _downstreamRoute; private Response<DownstreamRoute> _downstreamRoute;
private HttpResponseMessage _result; private HttpResponseMessage _result;
private OkResponse<string> _downstreamUrl; private OkResponse<DownstreamUrl> _downstreamUrl;
public DownstreamUrlCreatorMiddlewareTests() public DownstreamUrlCreatorMiddlewareTests()
{ {
_url = "http://localhost:51879"; _url = "http://localhost:51879";
_downstreamUrlTemplateVariableReplacer = new Mock<IDownstreamUrlTemplateVariableReplacer>(); _downstreamUrlTemplateVariableReplacer = new Mock<IDownstreamUrlPathPlaceholderReplacer>();
_scopedRepository = new Mock<IRequestScopedDataRepository>(); _scopedRepository = new Mock<IRequestScopedDataRepository>();
var builder = new WebHostBuilder() var builder = new WebHostBuilder()
@ -58,7 +58,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator
[Fact] [Fact]
public void happy_path() public void happy_path()
{ {
this.Given(x => x.GivenTheDownStreamRouteIs(new DownstreamRoute(new List<TemplateVariableNameAndValue>(), new ReRouteBuilder().WithDownstreamTemplate("any old string").Build()))) this.Given(x => x.GivenTheDownStreamRouteIs(new DownstreamRoute(new List<UrlPathPlaceholderNameAndValue>(), new ReRouteBuilder().WithDownstreamTemplate("any old string").Build())))
.And(x => x.TheUrlReplacerReturns("any old string")) .And(x => x.TheUrlReplacerReturns("any old string"))
.When(x => x.WhenICallTheMiddleware()) .When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly()) .Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly())
@ -67,16 +67,16 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator
private void TheUrlReplacerReturns(string downstreamUrl) private void TheUrlReplacerReturns(string downstreamUrl)
{ {
_downstreamUrl = new OkResponse<string>(downstreamUrl); _downstreamUrl = new OkResponse<DownstreamUrl>(new DownstreamUrl(downstreamUrl));
_downstreamUrlTemplateVariableReplacer _downstreamUrlTemplateVariableReplacer
.Setup(x => x.ReplaceTemplateVariables(It.IsAny<DownstreamRoute>())) .Setup(x => x.Replace(It.IsAny<string>(), It.IsAny<List<UrlPathPlaceholderNameAndValue>>()))
.Returns(_downstreamUrl); .Returns(_downstreamUrl);
} }
private void ThenTheScopedDataRepositoryIsCalledCorrectly() private void ThenTheScopedDataRepositoryIsCalledCorrectly()
{ {
_scopedRepository _scopedRepository
.Verify(x => x.Add("DownstreamUrl", _downstreamUrl.Data), Times.Once()); .Verify(x => x.Add("DownstreamUrl", _downstreamUrl.Data.Value), Times.Once());
} }
private void WhenICallTheMiddleware() private void WhenICallTheMiddleware()

View File

@ -13,18 +13,18 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer
public class UpstreamUrlPathTemplateVariableReplacerTests public class UpstreamUrlPathTemplateVariableReplacerTests
{ {
private DownstreamRoute _downstreamRoute; private DownstreamRoute _downstreamRoute;
private Response<string> _result; private Response<DownstreamUrl> _result;
private readonly IDownstreamUrlTemplateVariableReplacer _downstreamUrlPathReplacer; private readonly IDownstreamUrlPathPlaceholderReplacer _downstreamUrlPathReplacer;
public UpstreamUrlPathTemplateVariableReplacerTests() public UpstreamUrlPathTemplateVariableReplacerTests()
{ {
_downstreamUrlPathReplacer = new DownstreamUrlTemplateVariableReplacer(); _downstreamUrlPathReplacer = new DownstreamUrlPathPlaceholderReplacer();
} }
[Fact] [Fact]
public void can_replace_no_template_variables() public void can_replace_no_template_variables()
{ {
this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List<TemplateVariableNameAndValue>(), new ReRouteBuilder().Build()))) this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List<UrlPathPlaceholderNameAndValue>(), new ReRouteBuilder().Build())))
.When(x => x.WhenIReplaceTheTemplateVariables()) .When(x => x.WhenIReplaceTheTemplateVariables())
.Then(x => x.ThenTheDownstreamUrlPathIsReturned("")) .Then(x => x.ThenTheDownstreamUrlPathIsReturned(""))
.BDDfy(); .BDDfy();
@ -33,7 +33,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer
[Fact] [Fact]
public void can_replace_no_template_variables_with_slash() public void can_replace_no_template_variables_with_slash()
{ {
this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List<TemplateVariableNameAndValue>(), new ReRouteBuilder().WithDownstreamTemplate("/").Build()))) this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List<UrlPathPlaceholderNameAndValue>(), new ReRouteBuilder().WithDownstreamTemplate("/").Build())))
.When(x => x.WhenIReplaceTheTemplateVariables()) .When(x => x.WhenIReplaceTheTemplateVariables())
.Then(x => x.ThenTheDownstreamUrlPathIsReturned("/")) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("/"))
.BDDfy(); .BDDfy();
@ -42,7 +42,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer
[Fact] [Fact]
public void can_replace_url_no_slash() public void can_replace_url_no_slash()
{ {
this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List<TemplateVariableNameAndValue>(), new ReRouteBuilder().WithDownstreamTemplate("api").Build()))) this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List<UrlPathPlaceholderNameAndValue>(), new ReRouteBuilder().WithDownstreamTemplate("api").Build())))
.When(x => x.WhenIReplaceTheTemplateVariables()) .When(x => x.WhenIReplaceTheTemplateVariables())
.Then(x => x.ThenTheDownstreamUrlPathIsReturned("api")) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api"))
.BDDfy(); .BDDfy();
@ -51,7 +51,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer
[Fact] [Fact]
public void can_replace_url_one_slash() public void can_replace_url_one_slash()
{ {
this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List<TemplateVariableNameAndValue>(), new ReRouteBuilder().WithDownstreamTemplate("api/").Build()))) this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List<UrlPathPlaceholderNameAndValue>(), new ReRouteBuilder().WithDownstreamTemplate("api/").Build())))
.When(x => x.WhenIReplaceTheTemplateVariables()) .When(x => x.WhenIReplaceTheTemplateVariables())
.Then(x => x.ThenTheDownstreamUrlPathIsReturned("api/")) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api/"))
.BDDfy(); .BDDfy();
@ -60,7 +60,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer
[Fact] [Fact]
public void can_replace_url_multiple_slash() public void can_replace_url_multiple_slash()
{ {
this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List<TemplateVariableNameAndValue>(), new ReRouteBuilder().WithDownstreamTemplate("api/product/products/").Build()))) this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List<UrlPathPlaceholderNameAndValue>(), new ReRouteBuilder().WithDownstreamTemplate("api/product/products/").Build())))
.When(x => x.WhenIReplaceTheTemplateVariables()) .When(x => x.WhenIReplaceTheTemplateVariables())
.Then(x => x.ThenTheDownstreamUrlPathIsReturned("api/product/products/")) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api/product/products/"))
.BDDfy(); .BDDfy();
@ -69,9 +69,9 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer
[Fact] [Fact]
public void can_replace_url_one_template_variable() public void can_replace_url_one_template_variable()
{ {
var templateVariables = new List<TemplateVariableNameAndValue>() var templateVariables = new List<UrlPathPlaceholderNameAndValue>()
{ {
new TemplateVariableNameAndValue("{productId}", "1") new UrlPathPlaceholderNameAndValue("{productId}", "1")
}; };
this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, new ReRouteBuilder().WithDownstreamTemplate("productservice/products/{productId}/").Build()))) this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, new ReRouteBuilder().WithDownstreamTemplate("productservice/products/{productId}/").Build())))
@ -83,9 +83,9 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer
[Fact] [Fact]
public void can_replace_url_one_template_variable_with_path_after() public void can_replace_url_one_template_variable_with_path_after()
{ {
var templateVariables = new List<TemplateVariableNameAndValue>() var templateVariables = new List<UrlPathPlaceholderNameAndValue>()
{ {
new TemplateVariableNameAndValue("{productId}", "1") new UrlPathPlaceholderNameAndValue("{productId}", "1")
}; };
this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, new ReRouteBuilder().WithDownstreamTemplate("productservice/products/{productId}/variants").Build()))) this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, new ReRouteBuilder().WithDownstreamTemplate("productservice/products/{productId}/variants").Build())))
@ -97,10 +97,10 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer
[Fact] [Fact]
public void can_replace_url_two_template_variable() public void can_replace_url_two_template_variable()
{ {
var templateVariables = new List<TemplateVariableNameAndValue>() var templateVariables = new List<UrlPathPlaceholderNameAndValue>()
{ {
new TemplateVariableNameAndValue("{productId}", "1"), new UrlPathPlaceholderNameAndValue("{productId}", "1"),
new TemplateVariableNameAndValue("{variantId}", "12") new UrlPathPlaceholderNameAndValue("{variantId}", "12")
}; };
this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, new ReRouteBuilder().WithDownstreamTemplate("productservice/products/{productId}/variants/{variantId}").Build()))) this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, new ReRouteBuilder().WithDownstreamTemplate("productservice/products/{productId}/variants/{variantId}").Build())))
@ -112,11 +112,11 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer
[Fact] [Fact]
public void can_replace_url_three_template_variable() public void can_replace_url_three_template_variable()
{ {
var templateVariables = new List<TemplateVariableNameAndValue>() var templateVariables = new List<UrlPathPlaceholderNameAndValue>()
{ {
new TemplateVariableNameAndValue("{productId}", "1"), new UrlPathPlaceholderNameAndValue("{productId}", "1"),
new TemplateVariableNameAndValue("{variantId}", "12"), new UrlPathPlaceholderNameAndValue("{variantId}", "12"),
new TemplateVariableNameAndValue("{categoryId}", "34") new UrlPathPlaceholderNameAndValue("{categoryId}", "34")
}; };
this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, new ReRouteBuilder().WithDownstreamTemplate("productservice/category/{categoryId}/products/{productId}/variants/{variantId}").Build()))) this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, new ReRouteBuilder().WithDownstreamTemplate("productservice/category/{categoryId}/products/{productId}/variants/{variantId}").Build())))
@ -132,12 +132,12 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer
private void WhenIReplaceTheTemplateVariables() private void WhenIReplaceTheTemplateVariables()
{ {
_result = _downstreamUrlPathReplacer.ReplaceTemplateVariables(_downstreamRoute); _result = _downstreamUrlPathReplacer.Replace(_downstreamRoute.ReRoute.DownstreamTemplate, _downstreamRoute.TemplatePlaceholderNameAndValues);
} }
private void ThenTheDownstreamUrlPathIsReturned(string expected) private void ThenTheDownstreamUrlPathIsReturned(string expected)
{ {
_result.Data.ShouldBe(expected); _result.Data.Value.ShouldBe(expected);
} }
} }
} }

View File

@ -58,7 +58,7 @@ namespace Ocelot.UnitTests.HeaderBuilder
[Fact] [Fact]
public void happy_path() public void happy_path()
{ {
var downstreamRoute = new DownstreamRoute(new List<TemplateVariableNameAndValue>(), var downstreamRoute = new DownstreamRoute(new List<UrlPathPlaceholderNameAndValue>(),
new ReRouteBuilder() new ReRouteBuilder()
.WithDownstreamTemplate("any old string") .WithDownstreamTemplate("any old string")
.WithClaimsToHeaders(new List<ClaimToThing> .WithClaimsToHeaders(new List<ClaimToThing>

View File

@ -81,6 +81,23 @@ namespace Ocelot.UnitTests.RequestBuilder
.BDDfy(); .BDDfy();
} }
[Fact]
public void should_use_unvalidated_http_content_headers()
{
this.Given(x => x.GivenIHaveHttpMethod("POST"))
.And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk"))
.And(x => x.GivenIHaveTheHttpContent(new StringContent("Hi from Tom")))
.And(x => x.GivenTheContentTypeIs("application/json; charset=utf-8"))
.When(x => x.WhenICreateARequest())
.And(x => x.ThenTheCorrectContentHeadersAreUsed(new HeaderDictionary
{
{
"Content-Type", "application/json; charset=utf-8"
}
}))
.BDDfy();
}
[Fact] [Fact]
public void should_use_headers() public void should_use_headers()
{ {

View File

@ -3,6 +3,7 @@ using System.IO;
using System.Net; using System.Net;
using System.Net.Http; using System.Net.Http;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.TestHost; using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Moq; using Moq;
@ -10,6 +11,7 @@ using Ocelot.Infrastructure.RequestData;
using Ocelot.RequestBuilder; using Ocelot.RequestBuilder;
using Ocelot.Requester; using Ocelot.Requester;
using Ocelot.Requester.Middleware; using Ocelot.Requester.Middleware;
using Ocelot.Responder;
using Ocelot.Responses; using Ocelot.Responses;
using TestStack.BDDfy; using TestStack.BDDfy;
using Xunit; using Xunit;
@ -26,16 +28,19 @@ namespace Ocelot.UnitTests.Requester
private HttpResponseMessage _result; private HttpResponseMessage _result;
private OkResponse<HttpResponseMessage> _response; private OkResponse<HttpResponseMessage> _response;
private OkResponse<Request> _request; private OkResponse<Request> _request;
private readonly Mock<IHttpResponder> _responder;
public HttpRequesterMiddlewareTests() public HttpRequesterMiddlewareTests()
{ {
_url = "http://localhost:51879"; _url = "http://localhost:51879";
_requester = new Mock<IHttpRequester>(); _requester = new Mock<IHttpRequester>();
_scopedRepository = new Mock<IRequestScopedDataRepository>(); _scopedRepository = new Mock<IRequestScopedDataRepository>();
_responder = new Mock<IHttpResponder>();
var builder = new WebHostBuilder() var builder = new WebHostBuilder()
.ConfigureServices(x => .ConfigureServices(x =>
{ {
x.AddSingleton(_responder.Object);
x.AddSingleton(_requester.Object); x.AddSingleton(_requester.Object);
x.AddSingleton(_scopedRepository.Object); x.AddSingleton(_scopedRepository.Object);
}) })
@ -58,8 +63,9 @@ namespace Ocelot.UnitTests.Requester
{ {
this.Given(x => x.GivenTheRequestIs(new Request(new HttpRequestMessage(),new CookieContainer()))) this.Given(x => x.GivenTheRequestIs(new Request(new HttpRequestMessage(),new CookieContainer())))
.And(x => x.GivenTheRequesterReturns(new HttpResponseMessage())) .And(x => x.GivenTheRequesterReturns(new HttpResponseMessage()))
.And(x => x.GivenTheResponderReturns())
.When(x => x.WhenICallTheMiddleware()) .When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly()) .Then(x => x.ThenTheResponderIsCalledCorrectly())
.BDDfy(); .BDDfy();
} }
@ -71,10 +77,17 @@ namespace Ocelot.UnitTests.Requester
.ReturnsAsync(_response); .ReturnsAsync(_response);
} }
private void ThenTheScopedDataRepositoryIsCalledCorrectly() private void GivenTheResponderReturns()
{ {
_scopedRepository _responder
.Verify(x => x.Add("Response", _response.Data), Times.Once()); .Setup(x => x.SetResponseOnHttpContext(It.IsAny<HttpContext>(), _response.Data))
.ReturnsAsync(new OkResponse());
}
private void ThenTheResponderIsCalledCorrectly()
{
_responder
.Verify(x => x.SetResponseOnHttpContext(It.IsAny<HttpContext>(), _response.Data), Times.Once());
} }
private void WhenICallTheMiddleware() private void WhenICallTheMiddleware()

View File

@ -15,7 +15,7 @@ using Xunit;
namespace Ocelot.UnitTests.Responder namespace Ocelot.UnitTests.Responder
{ {
public class HttpResponderMiddlewareTests : IDisposable public class HttpErrorResponderMiddlewareTests : IDisposable
{ {
private readonly Mock<IHttpResponder> _responder; private readonly Mock<IHttpResponder> _responder;
private readonly Mock<IRequestScopedDataRepository> _scopedRepository; private readonly Mock<IRequestScopedDataRepository> _scopedRepository;
@ -26,7 +26,7 @@ namespace Ocelot.UnitTests.Responder
private HttpResponseMessage _result; private HttpResponseMessage _result;
private OkResponse<HttpResponseMessage> _response; private OkResponse<HttpResponseMessage> _response;
public HttpResponderMiddlewareTests() public HttpErrorResponderMiddlewareTests()
{ {
_url = "http://localhost:51879"; _url = "http://localhost:51879";
_responder = new Mock<IHttpResponder>(); _responder = new Mock<IHttpResponder>();
@ -47,7 +47,7 @@ namespace Ocelot.UnitTests.Responder
.UseUrls(_url) .UseUrls(_url)
.Configure(app => .Configure(app =>
{ {
app.UseHttpResponderMiddleware(); app.UseHttpErrorResponderMiddleware();
}); });
_server = new TestServer(builder); _server = new TestServer(builder);
@ -60,7 +60,7 @@ namespace Ocelot.UnitTests.Responder
this.Given(x => x.GivenTheHttpResponseMessageIs(new HttpResponseMessage())) this.Given(x => x.GivenTheHttpResponseMessageIs(new HttpResponseMessage()))
.And(x => x.GivenThereAreNoPipelineErrors()) .And(x => x.GivenThereAreNoPipelineErrors())
.When(x => x.WhenICallTheMiddleware()) .When(x => x.WhenICallTheMiddleware())
.Then(x => x.TheResponderIsCalledCorrectly()) .Then(x => x.ThenThereAreNoErrors())
.BDDfy(); .BDDfy();
} }
@ -71,10 +71,9 @@ namespace Ocelot.UnitTests.Responder
.Returns(new OkResponse<bool>(false)); .Returns(new OkResponse<bool>(false));
} }
private void TheResponderIsCalledCorrectly() private void ThenThereAreNoErrors()
{ {
_responder //todo a better assert?
.Verify(x => x.CreateResponse(It.IsAny<HttpContext>(), _response.Data), Times.Once);
} }
private void WhenICallTheMiddleware() private void WhenICallTheMiddleware()