diff --git a/Ocelot.sln b/Ocelot.sln index 44348365..0291ddb1 100644 --- a/Ocelot.sln +++ b/Ocelot.sln @@ -13,6 +13,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution build.bat = build.bat global.json = global.json LICENSE.md = LICENSE.md + Ocelot.nuspec = Ocelot.nuspec + push-to-nuget.bat = push-to-nuget.bat README.md = README.md run-benchmarks.bat = run-benchmarks.bat run-tests.bat = run-tests.bat diff --git a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs index f9afbfb4..1aac38cc 100644 --- a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs @@ -54,8 +54,8 @@ namespace Ocelot.DependencyInjection services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/src/Ocelot/DownstreamRouteFinder/DownstreamRoute.cs b/src/Ocelot/DownstreamRouteFinder/DownstreamRoute.cs index 7e9f0189..d4a117c0 100644 --- a/src/Ocelot/DownstreamRouteFinder/DownstreamRoute.cs +++ b/src/Ocelot/DownstreamRouteFinder/DownstreamRoute.cs @@ -6,12 +6,12 @@ namespace Ocelot.DownstreamRouteFinder { public class DownstreamRoute { - public DownstreamRoute(List templateVariableNameAndValues, ReRoute reRoute) + public DownstreamRoute(List templatePlaceholderNameAndValues, ReRoute reRoute) { - TemplateVariableNameAndValues = templateVariableNameAndValues; + TemplatePlaceholderNameAndValues = templatePlaceholderNameAndValues; ReRoute = reRoute; } - public List TemplateVariableNameAndValues { get; private set; } + public List TemplatePlaceholderNameAndValues { get; private set; } public ReRoute ReRoute { get; private set; } } } \ No newline at end of file diff --git a/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs b/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs index 39164068..81390cfe 100644 --- a/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs +++ b/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs @@ -12,29 +12,28 @@ namespace Ocelot.DownstreamRouteFinder.Finder { private readonly IOcelotConfigurationProvider _configProvider; 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; _urlMatcher = urlMatcher; - _templateVariableNameAndValueFinder = templateVariableNameAndValueFinder; + _urlPathPlaceholderNameAndValueFinder = urlPathPlaceholderNameAndValueFinder; } public Response FindDownstreamRoute(string upstreamUrlPath, string upstreamHttpMethod) { 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) { - var templateVariableNameAndValues = _templateVariableNameAndValueFinder.Find(upstreamUrlPath, - template.UpstreamTemplate); + var templateVariableNameAndValues = _urlPathPlaceholderNameAndValueFinder.Find(upstreamUrlPath, reRoute.UpstreamTemplate); - return new OkResponse(new DownstreamRoute(templateVariableNameAndValues.Data, template)); + return new OkResponse(new DownstreamRoute(templateVariableNameAndValues.Data, reRoute)); } } diff --git a/src/Ocelot/DownstreamRouteFinder/UrlMatcher/ITemplateVariableNameAndValueFinder.cs b/src/Ocelot/DownstreamRouteFinder/UrlMatcher/ITemplateVariableNameAndValueFinder.cs deleted file mode 100644 index 638b2c40..00000000 --- a/src/Ocelot/DownstreamRouteFinder/UrlMatcher/ITemplateVariableNameAndValueFinder.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Collections.Generic; -using Ocelot.Responses; - -namespace Ocelot.DownstreamRouteFinder.UrlMatcher -{ - public interface ITemplateVariableNameAndValueFinder - { - Response> Find(string upstreamUrlPath, string upstreamUrlPathTemplate); - } -} diff --git a/src/Ocelot/DownstreamRouteFinder/UrlMatcher/IUrlPathPlaceholderNameAndValueFinder.cs b/src/Ocelot/DownstreamRouteFinder/UrlMatcher/IUrlPathPlaceholderNameAndValueFinder.cs new file mode 100644 index 00000000..788299cb --- /dev/null +++ b/src/Ocelot/DownstreamRouteFinder/UrlMatcher/IUrlPathPlaceholderNameAndValueFinder.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; +using Ocelot.Responses; + +namespace Ocelot.DownstreamRouteFinder.UrlMatcher +{ + public interface IUrlPathPlaceholderNameAndValueFinder + { + Response> Find(string upstreamUrlPath, string upstreamUrlPathTemplate); + } +} diff --git a/src/Ocelot/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValue.cs b/src/Ocelot/DownstreamRouteFinder/UrlMatcher/UrlPathPlaceholderNameAndValue.cs similarity index 68% rename from src/Ocelot/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValue.cs rename to src/Ocelot/DownstreamRouteFinder/UrlMatcher/UrlPathPlaceholderNameAndValue.cs index 7ddd2448..cb690666 100644 --- a/src/Ocelot/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValue.cs +++ b/src/Ocelot/DownstreamRouteFinder/UrlMatcher/UrlPathPlaceholderNameAndValue.cs @@ -1,8 +1,8 @@ namespace Ocelot.DownstreamRouteFinder.UrlMatcher { - public class TemplateVariableNameAndValue + public class UrlPathPlaceholderNameAndValue { - public TemplateVariableNameAndValue(string templateVariableName, string templateVariableValue) + public UrlPathPlaceholderNameAndValue(string templateVariableName, string templateVariableValue) { TemplateVariableName = templateVariableName; TemplateVariableValue = templateVariableValue; diff --git a/src/Ocelot/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValueFinder.cs b/src/Ocelot/DownstreamRouteFinder/UrlMatcher/UrlPathPlaceholderNameAndValueFinder.cs similarity index 82% rename from src/Ocelot/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValueFinder.cs rename to src/Ocelot/DownstreamRouteFinder/UrlMatcher/UrlPathPlaceholderNameAndValueFinder.cs index f2d3fa79..249b153e 100644 --- a/src/Ocelot/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValueFinder.cs +++ b/src/Ocelot/DownstreamRouteFinder/UrlMatcher/UrlPathPlaceholderNameAndValueFinder.cs @@ -3,11 +3,11 @@ using Ocelot.Responses; namespace Ocelot.DownstreamRouteFinder.UrlMatcher { - public class TemplateVariableNameAndValueFinder : ITemplateVariableNameAndValueFinder + public class UrlPathPlaceholderNameAndValueFinder : IUrlPathPlaceholderNameAndValueFinder { - public Response> Find(string upstreamUrlPath, string upstreamUrlPathTemplate) + public Response> Find(string upstreamUrlPath, string upstreamUrlPathTemplate) { - var templateKeysAndValues = new List(); + var templateKeysAndValues = new List(); int counterForUrl = 0; @@ -21,7 +21,7 @@ namespace Ocelot.DownstreamRouteFinder.UrlMatcher var variableValue = GetPlaceholderVariableValue(upstreamUrlPath, counterForUrl); - var templateVariableNameAndValue = new TemplateVariableNameAndValue(variableName, variableValue); + var templateVariableNameAndValue = new UrlPathPlaceholderNameAndValue(variableName, variableValue); templateKeysAndValues.Add(templateVariableNameAndValue); @@ -32,12 +32,12 @@ namespace Ocelot.DownstreamRouteFinder.UrlMatcher continue; } - return new OkResponse>(templateKeysAndValues); + return new OkResponse>(templateKeysAndValues); } counterForUrl++; } - return new OkResponse>(templateKeysAndValues); + return new OkResponse>(templateKeysAndValues); } private string GetPlaceholderVariableValue(string urlPath, int counterForUrl) diff --git a/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs b/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs index 691fa6c0..8dd56598 100644 --- a/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs +++ b/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs @@ -10,11 +10,11 @@ namespace Ocelot.DownstreamUrlCreator.Middleware public class DownstreamUrlCreatorMiddleware : OcelotMiddleware { private readonly RequestDelegate _next; - private readonly IDownstreamUrlTemplateVariableReplacer _urlReplacer; + private readonly IDownstreamUrlPathPlaceholderReplacer _urlReplacer; private readonly IRequestScopedDataRepository _requestScopedDataRepository; public DownstreamUrlCreatorMiddleware(RequestDelegate next, - IDownstreamUrlTemplateVariableReplacer urlReplacer, + IDownstreamUrlPathPlaceholderReplacer urlReplacer, IRequestScopedDataRepository requestScopedDataRepository) :base(requestScopedDataRepository) { @@ -33,7 +33,7 @@ namespace Ocelot.DownstreamUrlCreator.Middleware return; } - var downstreamUrl = _urlReplacer.ReplaceTemplateVariables(downstreamRoute.Data); + var downstreamUrl = _urlReplacer.Replace(downstreamRoute.Data.ReRoute.DownstreamTemplate, downstreamRoute.Data.TemplatePlaceholderNameAndValues); if (downstreamUrl.IsError) { @@ -41,7 +41,7 @@ namespace Ocelot.DownstreamUrlCreator.Middleware return; } - _requestScopedDataRepository.Add("DownstreamUrl", downstreamUrl.Data); + _requestScopedDataRepository.Add("DownstreamUrl", downstreamUrl.Data.Value); await _next.Invoke(context); } diff --git a/src/Ocelot/DownstreamUrlCreator/UrlTemplateReplacer/DownstreamUrl.cs b/src/Ocelot/DownstreamUrlCreator/UrlTemplateReplacer/DownstreamUrl.cs new file mode 100644 index 00000000..ea90179e --- /dev/null +++ b/src/Ocelot/DownstreamUrlCreator/UrlTemplateReplacer/DownstreamUrl.cs @@ -0,0 +1,12 @@ +namespace Ocelot.DownstreamUrlCreator.UrlTemplateReplacer +{ + public class DownstreamUrl + { + public DownstreamUrl(string value) + { + Value = value; + } + + public string Value { get; private set; } + } +} diff --git a/src/Ocelot/DownstreamUrlCreator/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs b/src/Ocelot/DownstreamUrlCreator/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs index 83570008..9c19f2f9 100644 --- a/src/Ocelot/DownstreamUrlCreator/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs +++ b/src/Ocelot/DownstreamUrlCreator/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs @@ -1,23 +1,25 @@ +using System.Collections.Generic; using System.Text; using Ocelot.DownstreamRouteFinder; +using Ocelot.DownstreamRouteFinder.UrlMatcher; using Ocelot.Responses; namespace Ocelot.DownstreamUrlCreator.UrlTemplateReplacer { - public class DownstreamUrlTemplateVariableReplacer : IDownstreamUrlTemplateVariableReplacer + public class DownstreamUrlPathPlaceholderReplacer : IDownstreamUrlPathPlaceholderReplacer { - public Response ReplaceTemplateVariables(DownstreamRoute downstreamRoute) + public Response Replace(string downstreamTemplate, List urlPathPlaceholderNameAndValues) { 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(upstreamUrl.ToString()); + return new OkResponse(new DownstreamUrl(upstreamUrl.ToString())); } } } \ No newline at end of file diff --git a/src/Ocelot/DownstreamUrlCreator/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs b/src/Ocelot/DownstreamUrlCreator/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs index 83b93d00..164c42ef 100644 --- a/src/Ocelot/DownstreamUrlCreator/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs +++ b/src/Ocelot/DownstreamUrlCreator/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs @@ -1,10 +1,11 @@ -using Ocelot.DownstreamRouteFinder; +using System.Collections.Generic; +using Ocelot.DownstreamRouteFinder.UrlMatcher; using Ocelot.Responses; namespace Ocelot.DownstreamUrlCreator.UrlTemplateReplacer { - public interface IDownstreamUrlTemplateVariableReplacer + public interface IDownstreamUrlPathPlaceholderReplacer { - Response ReplaceTemplateVariables(DownstreamRoute downstreamRoute); + Response Replace(string downstreamTemplate, List urlPathPlaceholderNameAndValues); } } \ No newline at end of file diff --git a/src/Ocelot/Middleware/ExceptionHandlerMiddleware.cs b/src/Ocelot/Middleware/ExceptionHandlerMiddleware.cs new file mode 100644 index 00000000..7c222fa9 --- /dev/null +++ b/src/Ocelot/Middleware/ExceptionHandlerMiddleware.cs @@ -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(); + } + + 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"); + } + } + } +} diff --git a/src/Ocelot/Middleware/ExceptionHandlerMiddlewareExtensions.cs b/src/Ocelot/Middleware/ExceptionHandlerMiddlewareExtensions.cs new file mode 100644 index 00000000..c2513f69 --- /dev/null +++ b/src/Ocelot/Middleware/ExceptionHandlerMiddlewareExtensions.cs @@ -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(); + } + } +} diff --git a/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs b/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs index 8fe0877f..ba5e6782 100644 --- a/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs +++ b/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs @@ -19,22 +19,34 @@ namespace Ocelot.Middleware { 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(); + // Now we know where the client is going to go we can authenticate them builder.UseAuthenticationMiddleware(); + // The next thing we do is look at any claims transforms in case this is important for authorisation builder.UseClaimsBuilderMiddleware(); + // Now we have authenticated and done any claims transformation we can authorise the request builder.UseAuthorisationMiddleware(); + // Now we can run any header transformation logic builder.UseHttpRequestHeadersBuilderMiddleware(); + // This takes the downstream route we retrieved earlier and replaces any placeholders with the variables that should be used builder.UseDownstreamUrlCreatorMiddleware(); + // Everything should now be ready to build or HttpRequest builder.UseHttpRequestBuilderMiddleware(); + //We fire off the request and set the response on the context in this middleware builder.UseHttpRequesterMiddleware(); return builder; @@ -44,7 +56,7 @@ namespace Ocelot.Middleware { builder.UseIfNotNull(middlewareConfiguration.PreHttpResponderMiddleware); - builder.UseHttpResponderMiddleware(); + builder.UseHttpErrorResponderMiddleware(); builder.UseIfNotNull(middlewareConfiguration.PostHttpResponderMiddleware); diff --git a/src/Ocelot/RequestBuilder/Builder/HttpRequestBuilder.cs b/src/Ocelot/RequestBuilder/Builder/HttpRequestBuilder.cs index bda2914d..ebd5f9ff 100644 --- a/src/Ocelot/RequestBuilder/Builder/HttpRequestBuilder.cs +++ b/src/Ocelot/RequestBuilder/Builder/HttpRequestBuilder.cs @@ -22,18 +22,13 @@ namespace Ocelot.RequestBuilder.Builder if (content != null) { - using (var reader = new StreamReader(content)) - { - var body = await reader.ReadToEndAsync(); - httpRequestMessage.Content = new StringContent(body); - } + httpRequestMessage.Content = new StreamContent(content); } if (!string.IsNullOrEmpty(contentType)) { - var splitCt = contentType.Split(';'); - var cT = splitCt[0]; - httpRequestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue(cT); + httpRequestMessage.Content.Headers.Remove("Content-Type"); + httpRequestMessage.Content.Headers.TryAddWithoutValidation("Content-Type", contentType); } //todo get rid of if @@ -50,7 +45,7 @@ namespace Ocelot.RequestBuilder.Builder //todo get rid of if.. if (header.Key.ToLower() != "host") { - httpRequestMessage.Headers.Add(header.Key, header.Value.ToArray()); + httpRequestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray()); } } } diff --git a/src/Ocelot/Requester/Middleware/HttpRequesterMiddleware.cs b/src/Ocelot/Requester/Middleware/HttpRequesterMiddleware.cs index d42839c9..0bec7ff4 100644 --- a/src/Ocelot/Requester/Middleware/HttpRequesterMiddleware.cs +++ b/src/Ocelot/Requester/Middleware/HttpRequesterMiddleware.cs @@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Http; using Ocelot.Infrastructure.RequestData; using Ocelot.Middleware; using Ocelot.RequestBuilder; +using Ocelot.Responder; namespace Ocelot.Requester.Middleware { @@ -11,15 +12,18 @@ namespace Ocelot.Requester.Middleware private readonly RequestDelegate _next; private readonly IHttpRequester _requester; private readonly IRequestScopedDataRepository _requestScopedDataRepository; + private readonly IHttpResponder _responder; public HttpRequesterMiddleware(RequestDelegate next, IHttpRequester requester, - IRequestScopedDataRepository requestScopedDataRepository) + IRequestScopedDataRepository requestScopedDataRepository, + IHttpResponder responder) :base(requestScopedDataRepository) { _next = next; _requester = requester; _requestScopedDataRepository = requestScopedDataRepository; + _responder = responder; } public async Task Invoke(HttpContext context) @@ -40,7 +44,12 @@ namespace Ocelot.Requester.Middleware return; } - _requestScopedDataRepository.Add("Response", response.Data); + var setResponse = await _responder.SetResponseOnHttpContext(context, response.Data); + + if (setResponse.IsError) + { + SetPipelineError(response.Errors); + } } } } \ No newline at end of file diff --git a/src/Ocelot/Responder/HttpContextResponder.cs b/src/Ocelot/Responder/HttpContextResponder.cs index 46779deb..2f381ea2 100644 --- a/src/Ocelot/Responder/HttpContextResponder.cs +++ b/src/Ocelot/Responder/HttpContextResponder.cs @@ -1,6 +1,7 @@ using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; +using Ocelot.Responses; namespace Ocelot.Responder { @@ -10,7 +11,7 @@ namespace Ocelot.Responder /// public class HttpContextResponder : IHttpResponder { - public async Task CreateResponse(HttpContext context, HttpResponseMessage response) + public async Task SetResponseOnHttpContext(HttpContext context, HttpResponseMessage response) { context.Response.OnStarting(x => { @@ -19,17 +20,17 @@ namespace Ocelot.Responder }, context); await context.Response.WriteAsync(await response.Content.ReadAsStringAsync()); - return context; + return new OkResponse(); } - public async Task CreateErrorResponse(HttpContext context, int statusCode) + public async Task SetErrorResponseOnContext(HttpContext context, int statusCode) { context.Response.OnStarting(x => { context.Response.StatusCode = statusCode; return Task.CompletedTask; }, context); - return context; + return new OkResponse(); } } } \ No newline at end of file diff --git a/src/Ocelot/Responder/IHttpResponder.cs b/src/Ocelot/Responder/IHttpResponder.cs index 4cf6d1b2..5292f4df 100644 --- a/src/Ocelot/Responder/IHttpResponder.cs +++ b/src/Ocelot/Responder/IHttpResponder.cs @@ -1,12 +1,13 @@ using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; +using Ocelot.Responses; namespace Ocelot.Responder { public interface IHttpResponder { - Task CreateResponse(HttpContext context, HttpResponseMessage response); - Task CreateErrorResponse(HttpContext context, int statusCode); + Task SetResponseOnHttpContext(HttpContext context, HttpResponseMessage response); + Task SetErrorResponseOnContext(HttpContext context, int statusCode); } } diff --git a/src/Ocelot/Responder/Middleware/HttpResponderMiddleware.cs b/src/Ocelot/Responder/Middleware/HttpErrorResponderMiddleware.cs similarity index 72% rename from src/Ocelot/Responder/Middleware/HttpResponderMiddleware.cs rename to src/Ocelot/Responder/Middleware/HttpErrorResponderMiddleware.cs index 4dfc65dd..aaa67d6b 100644 --- a/src/Ocelot/Responder/Middleware/HttpResponderMiddleware.cs +++ b/src/Ocelot/Responder/Middleware/HttpErrorResponderMiddleware.cs @@ -6,14 +6,14 @@ using Ocelot.Middleware; namespace Ocelot.Responder.Middleware { - public class HttpResponderMiddleware : OcelotMiddleware + public class HttpErrorResponderMiddleware : OcelotMiddleware { private readonly RequestDelegate _next; private readonly IHttpResponder _responder; private readonly IRequestScopedDataRepository _requestScopedDataRepository; private readonly IErrorsToHttpStatusCodeMapper _codeMapper; - public HttpResponderMiddleware(RequestDelegate next, + public HttpErrorResponderMiddleware(RequestDelegate next, IHttpResponder responder, IRequestScopedDataRepository requestScopedDataRepository, IErrorsToHttpStatusCodeMapper codeMapper) @@ -37,19 +37,13 @@ namespace Ocelot.Responder.Middleware if (!statusCode.IsError) { - await _responder.CreateErrorResponse(context, statusCode.Data); + await _responder.SetErrorResponseOnContext(context, statusCode.Data); } else { - await _responder.CreateErrorResponse(context, 500); + await _responder.SetErrorResponseOnContext(context, 500); } } - else - { - var response = _requestScopedDataRepository.Get("Response"); - - await _responder.CreateResponse(context, response.Data); - } } } } \ No newline at end of file diff --git a/src/Ocelot/Responder/Middleware/HttpResponderMiddlewareExtensions.cs b/src/Ocelot/Responder/Middleware/HttpResponderMiddlewareExtensions.cs index 3739efbd..aad14839 100644 --- a/src/Ocelot/Responder/Middleware/HttpResponderMiddlewareExtensions.cs +++ b/src/Ocelot/Responder/Middleware/HttpResponderMiddlewareExtensions.cs @@ -4,9 +4,9 @@ namespace Ocelot.Responder.Middleware { public static class HttpResponderMiddlewareExtensions { - public static IApplicationBuilder UseHttpResponderMiddleware(this IApplicationBuilder builder) + public static IApplicationBuilder UseHttpErrorResponderMiddleware(this IApplicationBuilder builder) { - return builder.UseMiddleware(); + return builder.UseMiddleware(); } } } \ No newline at end of file diff --git a/test/Ocelot.AcceptanceTests/CustomMiddlewareTests.cs b/test/Ocelot.AcceptanceTests/CustomMiddlewareTests.cs index 50252090..9f8d0392 100644 --- a/test/Ocelot.AcceptanceTests/CustomMiddlewareTests.cs +++ b/test/Ocelot.AcceptanceTests/CustomMiddlewareTests.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Net; using System.Net.Http; +using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; @@ -67,8 +68,7 @@ namespace Ocelot.AcceptanceTests { PreHttpRequesterMiddleware = async (ctx, next) => { - var service = ctx.RequestServices.GetService(); - service.Add("Response", new HttpResponseMessage {Content = new StringContent("PreHttpRequesterMiddleware")}); + await ctx.Response.WriteAsync("PreHttpRequesterMiddleware"); } }; @@ -104,9 +104,10 @@ namespace Ocelot.AcceptanceTests .UseUrls(url) .Configure(app => { - app.Run(async context => + app.Run(context => { context.Response.StatusCode = statusCode; + return Task.CompletedTask; }); }) .Build(); diff --git a/test/Ocelot.ManualTest/configuration.yaml b/test/Ocelot.ManualTest/configuration.yaml index 3fd2f69d..7cf620e2 100644 --- a/test/Ocelot.ManualTest/configuration.yaml +++ b/test/Ocelot.ManualTest/configuration.yaml @@ -24,3 +24,6 @@ ReRoutes: - DownstreamTemplate: http://www.bbc.co.uk UpstreamTemplate: / UpstreamHttpMethod: Get +- DownstreamTemplate: http://localhost:51879/api/products/{productId} + UpstreamTemplate: /products/{productId} + UpstreamHttpMethod: Get diff --git a/test/Ocelot.UnitTests/Authentication/AuthenticationMiddlewareTests.cs b/test/Ocelot.UnitTests/Authentication/AuthenticationMiddlewareTests.cs index 6cc0d120..06a67d0d 100644 --- a/test/Ocelot.UnitTests/Authentication/AuthenticationMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Authentication/AuthenticationMiddlewareTests.cs @@ -56,7 +56,7 @@ namespace Ocelot.UnitTests.Authentication [Fact] public void happy_path() { - this.Given(x => x.GivenTheDownStreamRouteIs(new DownstreamRoute(new List(), new ReRouteBuilder().Build()))) + this.Given(x => x.GivenTheDownStreamRouteIs(new DownstreamRoute(new List(), new ReRouteBuilder().Build()))) .When(x => x.WhenICallTheMiddleware()) .Then(x => x.ThenNoExceptionsAreThrown()) .BDDfy(); diff --git a/test/Ocelot.UnitTests/Authorization/AuthorisationMiddlewareTests.cs b/test/Ocelot.UnitTests/Authorization/AuthorisationMiddlewareTests.cs index 3bb5c465..77a43505 100644 --- a/test/Ocelot.UnitTests/Authorization/AuthorisationMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Authorization/AuthorisationMiddlewareTests.cs @@ -58,7 +58,7 @@ namespace Ocelot.UnitTests.Authorization [Fact] public void happy_path() { - this.Given(x => x.GivenTheDownStreamRouteIs(new DownstreamRoute(new List(), new ReRouteBuilder().WithIsAuthorised(true).Build()))) + this.Given(x => x.GivenTheDownStreamRouteIs(new DownstreamRoute(new List(), new ReRouteBuilder().WithIsAuthorised(true).Build()))) .And(x => x.GivenTheAuthServiceReturns(new OkResponse(true))) .When(x => x.WhenICallTheMiddleware()) .Then(x => x.ThenTheAuthServiceIsCalledCorrectly()) diff --git a/test/Ocelot.UnitTests/ClaimsBuilder/ClaimsBuilderMiddlewareTests.cs b/test/Ocelot.UnitTests/ClaimsBuilder/ClaimsBuilderMiddlewareTests.cs index 2fa9605e..708b5107 100644 --- a/test/Ocelot.UnitTests/ClaimsBuilder/ClaimsBuilderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/ClaimsBuilder/ClaimsBuilderMiddlewareTests.cs @@ -59,7 +59,7 @@ namespace Ocelot.UnitTests.ClaimsBuilder [Fact] public void happy_path() { - var downstreamRoute = new DownstreamRoute(new List(), + var downstreamRoute = new DownstreamRoute(new List(), new ReRouteBuilder() .WithDownstreamTemplate("any old string") .WithClaimsToClaims(new List diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs index c8733f65..fc2e49e3 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs @@ -57,7 +57,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder [Fact] public void happy_path() { - this.Given(x => x.GivenTheDownStreamRouteFinderReturns(new DownstreamRoute(new List(), new ReRouteBuilder().WithDownstreamTemplate("any old string").Build()))) + this.Given(x => x.GivenTheDownStreamRouteFinderReturns(new DownstreamRoute(new List(), new ReRouteBuilder().WithDownstreamTemplate("any old string").Build()))) .When(x => x.WhenICallTheMiddleware()) .Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly()) .BDDfy(); diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs index 8f4b57aa..bb390d32 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs @@ -18,7 +18,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder private readonly IDownstreamRouteFinder _downstreamRouteFinder; private readonly Mock _mockConfig; private readonly Mock _mockMatcher; - private readonly Mock _finder; + private readonly Mock _finder; private string _upstreamUrlPath; private Response _result; private List _reRoutesConfig; @@ -29,7 +29,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder { _mockConfig = new Mock(); _mockMatcher = new Mock(); - _finder = new Mock(); + _finder = new Mock(); _downstreamRouteFinder = new Ocelot.DownstreamRouteFinder.Finder.DownstreamRouteFinder(_mockConfig.Object, _mockMatcher.Object, _finder.Object); } @@ -40,7 +40,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .And( x => x.GivenTheTemplateVariableAndNameFinderReturns( - new OkResponse>(new List()))) + new OkResponse>(new List()))) .And(x => x.GivenTheConfigurationIs(new List { new ReRouteBuilder() @@ -55,7 +55,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .And(x => x.GivenTheUpstreamHttpMethodIs("Get")) .When(x => x.WhenICallTheFinder()) .Then( - x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List(), + x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List(), new ReRouteBuilder() .WithDownstreamTemplate("someDownstreamPath") .Build() @@ -71,7 +71,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .And( x => x.GivenTheTemplateVariableAndNameFinderReturns( - new OkResponse>(new List()))) + new OkResponse>(new List()))) .And(x => x.GivenTheConfigurationIs(new List { new ReRouteBuilder() @@ -92,7 +92,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .And(x => x.GivenTheUpstreamHttpMethodIs("Post")) .When(x => x.WhenICallTheFinder()) .Then( - x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List(), + x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List(), new ReRouteBuilder() .WithDownstreamTemplate("someDownstreamPathForAPost") .Build() @@ -123,7 +123,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .BDDfy(); } - private void GivenTheTemplateVariableAndNameFinderReturns(Response> response) + private void GivenTheTemplateVariableAndNameFinderReturns(Response> response) { _finder .Setup(x => x.Find(It.IsAny(), It.IsAny())) @@ -176,13 +176,13 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder { _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( - expected.TemplateVariableNameAndValues[i].TemplateVariableName); + _result.Data.TemplatePlaceholderNameAndValues[i].TemplateVariableName.ShouldBe( + expected.TemplatePlaceholderNameAndValues[i].TemplateVariableName); - _result.Data.TemplateVariableNameAndValues[i].TemplateVariableValue.ShouldBe( - expected.TemplateVariableNameAndValues[i].TemplateVariableValue); + _result.Data.TemplatePlaceholderNameAndValues[i].TemplateVariableValue.ShouldBe( + expected.TemplatePlaceholderNameAndValues[i].TemplateVariableValue); } _result.IsError.ShouldBeFalse(); diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValueFinderTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValueFinderTests.cs index bab6ef7e..cf71c809 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValueFinderTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValueFinderTests.cs @@ -10,14 +10,14 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher { public class UrlPathToUrlTemplateMatcherTests { - private readonly ITemplateVariableNameAndValueFinder _finder; + private readonly IUrlPathPlaceholderNameAndValueFinder _finder; private string _downstreamUrlPath; private string _downstreamPathTemplate; - private Response> _result; + private Response> _result; public UrlPathToUrlTemplateMatcherTests() { - _finder = new TemplateVariableNameAndValueFinder(); + _finder = new UrlPathPlaceholderNameAndValueFinder(); } [Fact] @@ -26,7 +26,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher this.Given(x => x.GivenIHaveAUpstreamPath("")) .And(x => x.GivenIHaveAnUpstreamUrlTemplate("")) .When(x => x.WhenIFindTheUrlVariableNamesAndValues()) - .And(x => x.ThenTheTemplatesVariablesAre(new List())) + .And(x => x.ThenTheTemplatesVariablesAre(new List())) .BDDfy(); } @@ -36,7 +36,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher this.Given(x => x.GivenIHaveAUpstreamPath("api")) .Given(x => x.GivenIHaveAnUpstreamUrlTemplate("api")) .When(x => x.WhenIFindTheUrlVariableNamesAndValues()) - .And(x => x.ThenTheTemplatesVariablesAre(new List())) + .And(x => x.ThenTheTemplatesVariablesAre(new List())) .BDDfy(); } @@ -46,7 +46,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher this.Given(x => x.GivenIHaveAUpstreamPath("api/")) .Given(x => x.GivenIHaveAnUpstreamUrlTemplate("api/")) .When(x => x.WhenIFindTheUrlVariableNamesAndValues()) - .And(x => x.ThenTheTemplatesVariablesAre(new List())) + .And(x => x.ThenTheTemplatesVariablesAre(new List())) .BDDfy(); } @@ -56,16 +56,16 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/")) .Given(x => x.GivenIHaveAnUpstreamUrlTemplate("api/product/products/")) .When(x => x.WhenIFindTheUrlVariableNamesAndValues()) - .And(x => x.ThenTheTemplatesVariablesAre(new List())) + .And(x => x.ThenTheTemplatesVariablesAre(new List())) .BDDfy(); } [Fact] public void can_match_down_stream_url_with_downstream_template_with_one_place_holder() { - var expectedTemplates = new List + var expectedTemplates = new List { - new TemplateVariableNameAndValue("{productId}", "1") + new UrlPathPlaceholderNameAndValue("{productId}", "1") }; this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1")) @@ -78,10 +78,10 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher [Fact] public void can_match_down_stream_url_with_downstream_template_with_two_place_holders() { - var expectedTemplates = new List + var expectedTemplates = new List { - new TemplateVariableNameAndValue("{productId}", "1"), - new TemplateVariableNameAndValue("{categoryId}", "2") + new UrlPathPlaceholderNameAndValue("{productId}", "1"), + new UrlPathPlaceholderNameAndValue("{categoryId}", "2") }; this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/2")) @@ -94,10 +94,10 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher [Fact] public void can_match_down_stream_url_with_downstream_template_with_two_place_holders_seperated_by_something() { - var expectedTemplates = new List + var expectedTemplates = new List { - new TemplateVariableNameAndValue("{productId}", "1"), - new TemplateVariableNameAndValue("{categoryId}", "2") + new UrlPathPlaceholderNameAndValue("{productId}", "1"), + new UrlPathPlaceholderNameAndValue("{categoryId}", "2") }; this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2")) @@ -110,11 +110,11 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher [Fact] public void can_match_down_stream_url_with_downstream_template_with_three_place_holders_seperated_by_something() { - var expectedTemplates = new List + var expectedTemplates = new List { - new TemplateVariableNameAndValue("{productId}", "1"), - new TemplateVariableNameAndValue("{categoryId}", "2"), - new TemplateVariableNameAndValue("{variantId}", "123") + new UrlPathPlaceholderNameAndValue("{productId}", "1"), + new UrlPathPlaceholderNameAndValue("{categoryId}", "2"), + new UrlPathPlaceholderNameAndValue("{variantId}", "123") }; this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2/variant/123")) @@ -127,10 +127,10 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher [Fact] public void can_match_down_stream_url_with_downstream_template_with_three_place_holders() { - var expectedTemplates = new List + var expectedTemplates = new List { - new TemplateVariableNameAndValue("{productId}", "1"), - new TemplateVariableNameAndValue("{categoryId}", "2") + new UrlPathPlaceholderNameAndValue("{productId}", "1"), + new UrlPathPlaceholderNameAndValue("{categoryId}", "2") }; this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2/variant/")) @@ -140,7 +140,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher .BDDfy(); } - private void ThenTheTemplatesVariablesAre(List expectedResults) + private void ThenTheTemplatesVariablesAre(List expectedResults) { foreach (var expectedResult in expectedResults) { diff --git a/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs b/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs index 7207e3f0..4039a4fb 100644 --- a/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs @@ -20,19 +20,19 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator { public class DownstreamUrlCreatorMiddlewareTests : IDisposable { - private readonly Mock _downstreamUrlTemplateVariableReplacer; + private readonly Mock _downstreamUrlTemplateVariableReplacer; private readonly Mock _scopedRepository; private readonly string _url; private readonly TestServer _server; private readonly HttpClient _client; private Response _downstreamRoute; private HttpResponseMessage _result; - private OkResponse _downstreamUrl; + private OkResponse _downstreamUrl; public DownstreamUrlCreatorMiddlewareTests() { _url = "http://localhost:51879"; - _downstreamUrlTemplateVariableReplacer = new Mock(); + _downstreamUrlTemplateVariableReplacer = new Mock(); _scopedRepository = new Mock(); var builder = new WebHostBuilder() @@ -58,7 +58,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator [Fact] public void happy_path() { - this.Given(x => x.GivenTheDownStreamRouteIs(new DownstreamRoute(new List(), new ReRouteBuilder().WithDownstreamTemplate("any old string").Build()))) + this.Given(x => x.GivenTheDownStreamRouteIs(new DownstreamRoute(new List(), new ReRouteBuilder().WithDownstreamTemplate("any old string").Build()))) .And(x => x.TheUrlReplacerReturns("any old string")) .When(x => x.WhenICallTheMiddleware()) .Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly()) @@ -67,16 +67,16 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator private void TheUrlReplacerReturns(string downstreamUrl) { - _downstreamUrl = new OkResponse(downstreamUrl); + _downstreamUrl = new OkResponse(new DownstreamUrl(downstreamUrl)); _downstreamUrlTemplateVariableReplacer - .Setup(x => x.ReplaceTemplateVariables(It.IsAny())) + .Setup(x => x.Replace(It.IsAny(), It.IsAny>())) .Returns(_downstreamUrl); } private void ThenTheScopedDataRepositoryIsCalledCorrectly() { _scopedRepository - .Verify(x => x.Add("DownstreamUrl", _downstreamUrl.Data), Times.Once()); + .Verify(x => x.Add("DownstreamUrl", _downstreamUrl.Data.Value), Times.Once()); } private void WhenICallTheMiddleware() diff --git a/test/Ocelot.UnitTests/DownstreamUrlCreator/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs b/test/Ocelot.UnitTests/DownstreamUrlCreator/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs index 4bc8f19f..b1ad369b 100644 --- a/test/Ocelot.UnitTests/DownstreamUrlCreator/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs +++ b/test/Ocelot.UnitTests/DownstreamUrlCreator/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs @@ -13,18 +13,18 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer public class UpstreamUrlPathTemplateVariableReplacerTests { private DownstreamRoute _downstreamRoute; - private Response _result; - private readonly IDownstreamUrlTemplateVariableReplacer _downstreamUrlPathReplacer; + private Response _result; + private readonly IDownstreamUrlPathPlaceholderReplacer _downstreamUrlPathReplacer; public UpstreamUrlPathTemplateVariableReplacerTests() { - _downstreamUrlPathReplacer = new DownstreamUrlTemplateVariableReplacer(); + _downstreamUrlPathReplacer = new DownstreamUrlPathPlaceholderReplacer(); } [Fact] public void can_replace_no_template_variables() { - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), new ReRouteBuilder().Build()))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), new ReRouteBuilder().Build()))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("")) .BDDfy(); @@ -33,7 +33,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer [Fact] public void can_replace_no_template_variables_with_slash() { - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), new ReRouteBuilder().WithDownstreamTemplate("/").Build()))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), new ReRouteBuilder().WithDownstreamTemplate("/").Build()))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("/")) .BDDfy(); @@ -42,7 +42,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer [Fact] public void can_replace_url_no_slash() { - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), new ReRouteBuilder().WithDownstreamTemplate("api").Build()))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), new ReRouteBuilder().WithDownstreamTemplate("api").Build()))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api")) .BDDfy(); @@ -51,7 +51,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer [Fact] public void can_replace_url_one_slash() { - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), new ReRouteBuilder().WithDownstreamTemplate("api/").Build()))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), new ReRouteBuilder().WithDownstreamTemplate("api/").Build()))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api/")) .BDDfy(); @@ -60,7 +60,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer [Fact] public void can_replace_url_multiple_slash() { - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), new ReRouteBuilder().WithDownstreamTemplate("api/product/products/").Build()))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), new ReRouteBuilder().WithDownstreamTemplate("api/product/products/").Build()))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api/product/products/")) .BDDfy(); @@ -69,9 +69,9 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer [Fact] public void can_replace_url_one_template_variable() { - var templateVariables = new List() + var templateVariables = new List() { - new TemplateVariableNameAndValue("{productId}", "1") + new UrlPathPlaceholderNameAndValue("{productId}", "1") }; 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] public void can_replace_url_one_template_variable_with_path_after() { - var templateVariables = new List() + var templateVariables = new List() { - new TemplateVariableNameAndValue("{productId}", "1") + new UrlPathPlaceholderNameAndValue("{productId}", "1") }; 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] public void can_replace_url_two_template_variable() { - var templateVariables = new List() + var templateVariables = new List() { - new TemplateVariableNameAndValue("{productId}", "1"), - new TemplateVariableNameAndValue("{variantId}", "12") + new UrlPathPlaceholderNameAndValue("{productId}", "1"), + new UrlPathPlaceholderNameAndValue("{variantId}", "12") }; 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] public void can_replace_url_three_template_variable() { - var templateVariables = new List() + var templateVariables = new List() { - new TemplateVariableNameAndValue("{productId}", "1"), - new TemplateVariableNameAndValue("{variantId}", "12"), - new TemplateVariableNameAndValue("{categoryId}", "34") + new UrlPathPlaceholderNameAndValue("{productId}", "1"), + new UrlPathPlaceholderNameAndValue("{variantId}", "12"), + new UrlPathPlaceholderNameAndValue("{categoryId}", "34") }; 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() { - _result = _downstreamUrlPathReplacer.ReplaceTemplateVariables(_downstreamRoute); + _result = _downstreamUrlPathReplacer.Replace(_downstreamRoute.ReRoute.DownstreamTemplate, _downstreamRoute.TemplatePlaceholderNameAndValues); } private void ThenTheDownstreamUrlPathIsReturned(string expected) { - _result.Data.ShouldBe(expected); + _result.Data.Value.ShouldBe(expected); } } } diff --git a/test/Ocelot.UnitTests/HeaderBuilder/HttpRequestHeadersBuilderMiddlewareTests.cs b/test/Ocelot.UnitTests/HeaderBuilder/HttpRequestHeadersBuilderMiddlewareTests.cs index ee8fae7c..e3f8b771 100644 --- a/test/Ocelot.UnitTests/HeaderBuilder/HttpRequestHeadersBuilderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/HeaderBuilder/HttpRequestHeadersBuilderMiddlewareTests.cs @@ -58,7 +58,7 @@ namespace Ocelot.UnitTests.HeaderBuilder [Fact] public void happy_path() { - var downstreamRoute = new DownstreamRoute(new List(), + var downstreamRoute = new DownstreamRoute(new List(), new ReRouteBuilder() .WithDownstreamTemplate("any old string") .WithClaimsToHeaders(new List diff --git a/test/Ocelot.UnitTests/RequestBuilder/RequestBuilderTests.cs b/test/Ocelot.UnitTests/RequestBuilder/RequestBuilderTests.cs index d7945136..098cbd8f 100644 --- a/test/Ocelot.UnitTests/RequestBuilder/RequestBuilderTests.cs +++ b/test/Ocelot.UnitTests/RequestBuilder/RequestBuilderTests.cs @@ -81,6 +81,23 @@ namespace Ocelot.UnitTests.RequestBuilder .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] public void should_use_headers() { diff --git a/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs b/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs index fde81909..56e03b83 100644 --- a/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs @@ -3,6 +3,7 @@ using System.IO; using System.Net; using System.Net.Http; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Moq; @@ -10,6 +11,7 @@ using Ocelot.Infrastructure.RequestData; using Ocelot.RequestBuilder; using Ocelot.Requester; using Ocelot.Requester.Middleware; +using Ocelot.Responder; using Ocelot.Responses; using TestStack.BDDfy; using Xunit; @@ -26,16 +28,19 @@ namespace Ocelot.UnitTests.Requester private HttpResponseMessage _result; private OkResponse _response; private OkResponse _request; + private readonly Mock _responder; public HttpRequesterMiddlewareTests() { _url = "http://localhost:51879"; _requester = new Mock(); _scopedRepository = new Mock(); + _responder = new Mock(); var builder = new WebHostBuilder() .ConfigureServices(x => { + x.AddSingleton(_responder.Object); x.AddSingleton(_requester.Object); x.AddSingleton(_scopedRepository.Object); }) @@ -58,8 +63,9 @@ namespace Ocelot.UnitTests.Requester { this.Given(x => x.GivenTheRequestIs(new Request(new HttpRequestMessage(),new CookieContainer()))) .And(x => x.GivenTheRequesterReturns(new HttpResponseMessage())) + .And(x => x.GivenTheResponderReturns()) .When(x => x.WhenICallTheMiddleware()) - .Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly()) + .Then(x => x.ThenTheResponderIsCalledCorrectly()) .BDDfy(); } @@ -71,10 +77,17 @@ namespace Ocelot.UnitTests.Requester .ReturnsAsync(_response); } - private void ThenTheScopedDataRepositoryIsCalledCorrectly() + private void GivenTheResponderReturns() { - _scopedRepository - .Verify(x => x.Add("Response", _response.Data), Times.Once()); + _responder + .Setup(x => x.SetResponseOnHttpContext(It.IsAny(), _response.Data)) + .ReturnsAsync(new OkResponse()); + } + + private void ThenTheResponderIsCalledCorrectly() + { + _responder + .Verify(x => x.SetResponseOnHttpContext(It.IsAny(), _response.Data), Times.Once()); } private void WhenICallTheMiddleware() diff --git a/test/Ocelot.UnitTests/Responder/HttpResponderMiddlewareTests.cs b/test/Ocelot.UnitTests/Responder/HttpErrorResponderMiddlewareTests.cs similarity index 87% rename from test/Ocelot.UnitTests/Responder/HttpResponderMiddlewareTests.cs rename to test/Ocelot.UnitTests/Responder/HttpErrorResponderMiddlewareTests.cs index 20793726..7edabd62 100644 --- a/test/Ocelot.UnitTests/Responder/HttpResponderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Responder/HttpErrorResponderMiddlewareTests.cs @@ -15,7 +15,7 @@ using Xunit; namespace Ocelot.UnitTests.Responder { - public class HttpResponderMiddlewareTests : IDisposable + public class HttpErrorResponderMiddlewareTests : IDisposable { private readonly Mock _responder; private readonly Mock _scopedRepository; @@ -26,7 +26,7 @@ namespace Ocelot.UnitTests.Responder private HttpResponseMessage _result; private OkResponse _response; - public HttpResponderMiddlewareTests() + public HttpErrorResponderMiddlewareTests() { _url = "http://localhost:51879"; _responder = new Mock(); @@ -47,7 +47,7 @@ namespace Ocelot.UnitTests.Responder .UseUrls(_url) .Configure(app => { - app.UseHttpResponderMiddleware(); + app.UseHttpErrorResponderMiddleware(); }); _server = new TestServer(builder); @@ -60,7 +60,7 @@ namespace Ocelot.UnitTests.Responder this.Given(x => x.GivenTheHttpResponseMessageIs(new HttpResponseMessage())) .And(x => x.GivenThereAreNoPipelineErrors()) .When(x => x.WhenICallTheMiddleware()) - .Then(x => x.TheResponderIsCalledCorrectly()) + .Then(x => x.ThenThereAreNoErrors()) .BDDfy(); } @@ -71,10 +71,9 @@ namespace Ocelot.UnitTests.Responder .Returns(new OkResponse(false)); } - private void TheResponderIsCalledCorrectly() + private void ThenThereAreNoErrors() { - _responder - .Verify(x => x.CreateResponse(It.IsAny(), _response.Data), Times.Once); + //todo a better assert? } private void WhenICallTheMiddleware()