From 3777e8c0c82c92acde7ab826438b94d0e5a4bd74 Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Sat, 2 Jul 2016 16:09:54 +0100 Subject: [PATCH 001/183] added some router thing and removed loads of crap --- .vscode/launch.json | 49 ++++ src/Ocelot.ApiGateway/AddRouteHandler.cs | 19 -- .../Infrastructure/Responses/Error.cs | 12 + .../Infrastructure/Responses/ErrorResponse.cs | 11 + .../Responses/ErrorResponseGeneric.cs | 11 + .../Infrastructure/Responses/OkResponse.cs | 9 + .../Responses/OkResponseGeneric.cs | 9 + .../Infrastructure/Responses/Response.cs | 19 ++ .../Responses/ResponseGeneric.cs | 18 ++ .../Infrastructure/Router/IRouterService.cs | 10 + .../Router/InMemoryRouterService.cs | 41 +++ .../Infrastructure/Router/Route.cs | 14 ++ .../Router/RouteKeyAlreadyExists.cs | 12 + .../Router/RouteKeyDoesNotExist.cs | 12 + .../Infrastructure/Router/RouterTests.cs | 111 +++++++++ .../Middleware/ProxyExtensions.cs | 12 + .../Middleware/ProxyMiddleware.cs | 20 ++ .../Middleware/RequestLoggerExtensions.cs | 12 + .../Middleware/RequestLoggerMiddleware.cs | 25 ++ src/Ocelot.ApiGateway/Routers.cs | 24 -- src/Ocelot.ApiGateway/Startup.cs | 21 +- src/Ocelot.ApiGateway/project.json | 6 +- src/Ocelot.Library/.gitignore | 234 ------------------ src/Ocelot.Library/RouterMiddleware.cs | 16 -- src/Ocelot.Library/project.json | 17 -- test/Ocelot.UnitTests/.gitignore | 234 ------------------ test/Ocelot.UnitTests/RouterMiddlwareTests.cs | 16 -- test/Ocelot.UnitTests/project.json | 21 -- 28 files changed, 425 insertions(+), 590 deletions(-) create mode 100644 .vscode/launch.json delete mode 100644 src/Ocelot.ApiGateway/AddRouteHandler.cs create mode 100644 src/Ocelot.ApiGateway/Infrastructure/Responses/Error.cs create mode 100644 src/Ocelot.ApiGateway/Infrastructure/Responses/ErrorResponse.cs create mode 100644 src/Ocelot.ApiGateway/Infrastructure/Responses/ErrorResponseGeneric.cs create mode 100644 src/Ocelot.ApiGateway/Infrastructure/Responses/OkResponse.cs create mode 100644 src/Ocelot.ApiGateway/Infrastructure/Responses/OkResponseGeneric.cs create mode 100644 src/Ocelot.ApiGateway/Infrastructure/Responses/Response.cs create mode 100644 src/Ocelot.ApiGateway/Infrastructure/Responses/ResponseGeneric.cs create mode 100644 src/Ocelot.ApiGateway/Infrastructure/Router/IRouterService.cs create mode 100644 src/Ocelot.ApiGateway/Infrastructure/Router/InMemoryRouterService.cs create mode 100644 src/Ocelot.ApiGateway/Infrastructure/Router/Route.cs create mode 100644 src/Ocelot.ApiGateway/Infrastructure/Router/RouteKeyAlreadyExists.cs create mode 100644 src/Ocelot.ApiGateway/Infrastructure/Router/RouteKeyDoesNotExist.cs create mode 100644 src/Ocelot.ApiGateway/Infrastructure/Router/RouterTests.cs create mode 100644 src/Ocelot.ApiGateway/Middleware/ProxyExtensions.cs create mode 100644 src/Ocelot.ApiGateway/Middleware/ProxyMiddleware.cs create mode 100644 src/Ocelot.ApiGateway/Middleware/RequestLoggerExtensions.cs create mode 100644 src/Ocelot.ApiGateway/Middleware/RequestLoggerMiddleware.cs delete mode 100644 src/Ocelot.ApiGateway/Routers.cs delete mode 100644 src/Ocelot.Library/.gitignore delete mode 100644 src/Ocelot.Library/RouterMiddleware.cs delete mode 100644 src/Ocelot.Library/project.json delete mode 100644 test/Ocelot.UnitTests/.gitignore delete mode 100644 test/Ocelot.UnitTests/RouterMiddlwareTests.cs delete mode 100644 test/Ocelot.UnitTests/project.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..50f9b3d8 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,49 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": ".NET Core Launch (console)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + "program": "${workspaceRoot}/bin/Debug//", + "args": [], + "cwd": "${workspaceRoot}", + "stopAtEntry": false, + "externalConsole": false + }, + { + "name": ".NET Core Launch (web)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + "program": "${workspaceRoot}/bin/Debug//", + "args": [], + "cwd": "${workspaceRoot}", + "stopAtEntry": false, + "launchBrowser": { + "enabled": true, + "args": "${auto-detect-url}", + "windows": { + "command": "cmd.exe", + "args": "/C start ${auto-detect-url}" + }, + "osx": { + "command": "open" + }, + "linux": { + "command": "xdg-open" + } + }, + "env": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + { + "name": ".NET Core Attach", + "type": "coreclr", + "request": "attach", + "processId": 0 + } + ] +} \ No newline at end of file diff --git a/src/Ocelot.ApiGateway/AddRouteHandler.cs b/src/Ocelot.ApiGateway/AddRouteHandler.cs deleted file mode 100644 index baaa05a4..00000000 --- a/src/Ocelot.ApiGateway/AddRouteHandler.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Routing; -using Microsoft.Extensions.DependencyInjection; - -namespace Ocelot.ApiGateway -{ - public static class HelloExtensions - { - public static IRouteBuilder AddRouter(this IRouteBuilder routeBuilder, - IApplicationBuilder app) - { - routeBuilder.Routes.Add(new Route(new Router(), - "{*url}", - app.ApplicationServices.GetService())); - - return routeBuilder; - } - } -} \ No newline at end of file diff --git a/src/Ocelot.ApiGateway/Infrastructure/Responses/Error.cs b/src/Ocelot.ApiGateway/Infrastructure/Responses/Error.cs new file mode 100644 index 00000000..e66a9bf8 --- /dev/null +++ b/src/Ocelot.ApiGateway/Infrastructure/Responses/Error.cs @@ -0,0 +1,12 @@ +namespace Ocelot.ApiGateway.Infrastructure.Responses +{ + public abstract class Error + { + public Error(string message) + { + Message = message; + } + + public string Message { get; private set; } + } +} \ No newline at end of file diff --git a/src/Ocelot.ApiGateway/Infrastructure/Responses/ErrorResponse.cs b/src/Ocelot.ApiGateway/Infrastructure/Responses/ErrorResponse.cs new file mode 100644 index 00000000..884c4ac0 --- /dev/null +++ b/src/Ocelot.ApiGateway/Infrastructure/Responses/ErrorResponse.cs @@ -0,0 +1,11 @@ +namespace Ocelot.ApiGateway.Infrastructure.Responses +{ + using System.Collections.Generic; + + public class ErrorResponse : Response + { + public ErrorResponse(List errors) : base(errors) + { + } + } +} \ No newline at end of file diff --git a/src/Ocelot.ApiGateway/Infrastructure/Responses/ErrorResponseGeneric.cs b/src/Ocelot.ApiGateway/Infrastructure/Responses/ErrorResponseGeneric.cs new file mode 100644 index 00000000..cb1ddb05 --- /dev/null +++ b/src/Ocelot.ApiGateway/Infrastructure/Responses/ErrorResponseGeneric.cs @@ -0,0 +1,11 @@ +namespace Ocelot.ApiGateway.Infrastructure.Responses +{ + using System.Collections.Generic; + + public class ErrorResponse : Response + { + public ErrorResponse(List errors) : base(errors) + { + } + } +} \ No newline at end of file diff --git a/src/Ocelot.ApiGateway/Infrastructure/Responses/OkResponse.cs b/src/Ocelot.ApiGateway/Infrastructure/Responses/OkResponse.cs new file mode 100644 index 00000000..1f02b6e5 --- /dev/null +++ b/src/Ocelot.ApiGateway/Infrastructure/Responses/OkResponse.cs @@ -0,0 +1,9 @@ +namespace Ocelot.ApiGateway.Infrastructure.Responses +{ + public class OkResponse : Response + { + public OkResponse() + { + } + } +} \ No newline at end of file diff --git a/src/Ocelot.ApiGateway/Infrastructure/Responses/OkResponseGeneric.cs b/src/Ocelot.ApiGateway/Infrastructure/Responses/OkResponseGeneric.cs new file mode 100644 index 00000000..010a28a9 --- /dev/null +++ b/src/Ocelot.ApiGateway/Infrastructure/Responses/OkResponseGeneric.cs @@ -0,0 +1,9 @@ +namespace Ocelot.ApiGateway.Infrastructure.Responses +{ + public class OkResponse : Response + { + public OkResponse(T data) : base(data) + { + } + } +} \ No newline at end of file diff --git a/src/Ocelot.ApiGateway/Infrastructure/Responses/Response.cs b/src/Ocelot.ApiGateway/Infrastructure/Responses/Response.cs new file mode 100644 index 00000000..091d6f98 --- /dev/null +++ b/src/Ocelot.ApiGateway/Infrastructure/Responses/Response.cs @@ -0,0 +1,19 @@ +namespace Ocelot.ApiGateway.Infrastructure.Responses +{ + using System.Collections.Generic; + + public abstract class Response + { + protected Response() + { + Errors = new List(); + } + + protected Response(List errors) + { + Errors = errors ?? new List(); + } + + public List Errors { get; private set; } + } +} \ No newline at end of file diff --git a/src/Ocelot.ApiGateway/Infrastructure/Responses/ResponseGeneric.cs b/src/Ocelot.ApiGateway/Infrastructure/Responses/ResponseGeneric.cs new file mode 100644 index 00000000..c78c8b6d --- /dev/null +++ b/src/Ocelot.ApiGateway/Infrastructure/Responses/ResponseGeneric.cs @@ -0,0 +1,18 @@ +namespace Ocelot.ApiGateway.Infrastructure.Responses +{ + using System.Collections.Generic; + + public abstract class Response : Response + { + protected Response(T data) + { + Data = data; + } + + protected Response(List errors) : base(errors) + { + } + + public T Data { get; private set; } + } +} \ No newline at end of file diff --git a/src/Ocelot.ApiGateway/Infrastructure/Router/IRouterService.cs b/src/Ocelot.ApiGateway/Infrastructure/Router/IRouterService.cs new file mode 100644 index 00000000..aa68859b --- /dev/null +++ b/src/Ocelot.ApiGateway/Infrastructure/Router/IRouterService.cs @@ -0,0 +1,10 @@ +using Ocelot.ApiGateway.Infrastructure.Responses; + +namespace Ocelot.ApiGateway.Infrastructure.Router +{ + public interface IRouterService + { + Response AddRoute(string apiKey, string upstreamApiBaseUrl); + Response GetRoute(string apiKey); + } +} \ No newline at end of file diff --git a/src/Ocelot.ApiGateway/Infrastructure/Router/InMemoryRouterService.cs b/src/Ocelot.ApiGateway/Infrastructure/Router/InMemoryRouterService.cs new file mode 100644 index 00000000..4394e667 --- /dev/null +++ b/src/Ocelot.ApiGateway/Infrastructure/Router/InMemoryRouterService.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using Ocelot.ApiGateway.Infrastructure.Responses; + +namespace Ocelot.ApiGateway.Infrastructure.Router +{ + public class InMemoryRouterService : IRouterService + { + private Dictionary _routes; + public InMemoryRouterService() + { + _routes = new Dictionary(); + } + public Response AddRoute(string apiKey, string upstreamApiBaseUrl) + { + if(_routes.ContainsKey(apiKey)) + { + return new ErrorResponse(new List(){new RouteKeyAlreadyExists("This key has already been used")}); + } + + _routes.Add(apiKey, upstreamApiBaseUrl); + + return new OkResponse(); + } + + public Response GetRoute(string apiKey) + { + Console.WriteLine("looking for {0}", apiKey); + string upstreamApiBaseUrl = null; + + if(_routes.TryGetValue(apiKey, out upstreamApiBaseUrl)) + { + return new OkResponse(new Route(apiKey, upstreamApiBaseUrl)); + } + + Console.WriteLine("Couldnt find it"); + + return new ErrorResponse(new List(){new RouteKeyDoesNotExist("This key does not exist")}); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.ApiGateway/Infrastructure/Router/Route.cs b/src/Ocelot.ApiGateway/Infrastructure/Router/Route.cs new file mode 100644 index 00000000..0edae1ef --- /dev/null +++ b/src/Ocelot.ApiGateway/Infrastructure/Router/Route.cs @@ -0,0 +1,14 @@ +namespace Ocelot.ApiGateway.Infrastructure.Router +{ + public class Route + { + public Route(string apiKey, string upstreamRoute) + { + ApiKey = apiKey; + UpstreamRoute = upstreamRoute; + } + + public string ApiKey {get;private set;} + public string UpstreamRoute {get;private set;} + } +} \ No newline at end of file diff --git a/src/Ocelot.ApiGateway/Infrastructure/Router/RouteKeyAlreadyExists.cs b/src/Ocelot.ApiGateway/Infrastructure/Router/RouteKeyAlreadyExists.cs new file mode 100644 index 00000000..0a89b302 --- /dev/null +++ b/src/Ocelot.ApiGateway/Infrastructure/Router/RouteKeyAlreadyExists.cs @@ -0,0 +1,12 @@ +using Ocelot.ApiGateway.Infrastructure.Responses; + +namespace Ocelot.ApiGateway.Infrastructure.Router +{ + public class RouteKeyAlreadyExists : Error + { + public RouteKeyAlreadyExists(string message) + : base(message) + { + } + } +} \ No newline at end of file diff --git a/src/Ocelot.ApiGateway/Infrastructure/Router/RouteKeyDoesNotExist.cs b/src/Ocelot.ApiGateway/Infrastructure/Router/RouteKeyDoesNotExist.cs new file mode 100644 index 00000000..9b745f00 --- /dev/null +++ b/src/Ocelot.ApiGateway/Infrastructure/Router/RouteKeyDoesNotExist.cs @@ -0,0 +1,12 @@ +using Ocelot.ApiGateway.Infrastructure.Responses; + +namespace Ocelot.ApiGateway.Infrastructure.Router +{ + public class RouteKeyDoesNotExist : Error + { + public RouteKeyDoesNotExist(string message) + : base(message) + { + } + } +} \ No newline at end of file diff --git a/src/Ocelot.ApiGateway/Infrastructure/Router/RouterTests.cs b/src/Ocelot.ApiGateway/Infrastructure/Router/RouterTests.cs new file mode 100644 index 00000000..4cf1e1b1 --- /dev/null +++ b/src/Ocelot.ApiGateway/Infrastructure/Router/RouterTests.cs @@ -0,0 +1,111 @@ +using System; +using Ocelot.ApiGateway.Infrastructure.Responses; +using Shouldly; +using Xunit; + +namespace Ocelot.ApiGateway.Infrastructure.Router +{ + public class RouterTests + { + private string _upstreamApiUrl; + private string _apiKey; + private IRouterService _router; + private Response _response; + private Response _getRouteResponse; + + public RouterTests() + { + _router = new InMemoryRouterService(); + } + + [Fact] + public void can_add_route() + { + GivenIHaveAnUpstreamApi("http://www.someapi.com/api1"); + GivenIWantToRouteRequestsToMyUpstreamApi("api"); + WhenIAddTheConfiguration(); + ThenTheResponseIsSuccesful(); + } + + [Fact] + public void can_get_route_by_key() + { + GivenIHaveSetUpAnApiKeyAndUpstreamUrl("api2", "http://www.someapi.com/api2"); + WhenIRetrieveTheRouteByKey(); + ThenTheRouteIsReturned(); + } + + [Fact] + public void should_return_error_response_when_key_already_used() + { + GivenIHaveSetUpAnApiKeyAndUpstreamUrl("api2", "http://www.someapi.com/api2"); + WhenITryToUseTheSameKey(); + ThenTheKeyHasAlreadyBeenUsed(); + } + + [Fact] + public void should_return_error_response_if_key_doesnt_exist() + { + GivenIWantToRouteRequestsToMyUpstreamApi("api"); + WhenIRetrieveTheRouteByKey(); + ThenTheKeyDoesNotExist(); + } + + private void WhenITryToUseTheSameKey() + { + WhenIAddTheConfiguration(); + } + + private void ThenTheKeyHasAlreadyBeenUsed() + { + _response.ShouldNotBeNull(); + _response.ShouldBeOfType(); + _response.Errors[0].Message.ShouldBe("This key has already been used"); + } + + private void ThenTheKeyDoesNotExist() + { + _getRouteResponse.ShouldNotBeNull(); + _getRouteResponse.ShouldBeOfType>(); + _getRouteResponse.Errors[0].Message.ShouldBe("This key does not exist"); + } + + private void WhenIRetrieveTheRouteByKey() + { + _getRouteResponse = _router.GetRoute(_apiKey); + } + + private void ThenTheRouteIsReturned() + { + _getRouteResponse.Data.ApiKey.ShouldBe(_apiKey); + _getRouteResponse.Data.UpstreamRoute.ShouldBe(_upstreamApiUrl); + } + + private void GivenIHaveSetUpAnApiKeyAndUpstreamUrl(string apiKey, string upstreamUrl) + { + GivenIHaveAnUpstreamApi(upstreamUrl); + GivenIWantToRouteRequestsToMyUpstreamApi(apiKey); + WhenIAddTheConfiguration(); + } + + private void GivenIHaveAnUpstreamApi(string upstreamApiUrl) + { + _upstreamApiUrl = upstreamApiUrl; + } + + private void GivenIWantToRouteRequestsToMyUpstreamApi(string apiKey) + { + _apiKey = apiKey; + } + + private void WhenIAddTheConfiguration() + { + _response = _router.AddRoute(_apiKey, _upstreamApiUrl); + } + + private void ThenTheResponseIsSuccesful() + { + _response.ShouldBeOfType(); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.ApiGateway/Middleware/ProxyExtensions.cs b/src/Ocelot.ApiGateway/Middleware/ProxyExtensions.cs new file mode 100644 index 00000000..444afa20 --- /dev/null +++ b/src/Ocelot.ApiGateway/Middleware/ProxyExtensions.cs @@ -0,0 +1,12 @@ +using Microsoft.AspNetCore.Builder; + +namespace Ocelot.ApiGateway.Middleware +{ + public static class ProxyExtensions + { + public static IApplicationBuilder UseProxy(this IApplicationBuilder builder) + { + return builder.UseMiddleware(); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.ApiGateway/Middleware/ProxyMiddleware.cs b/src/Ocelot.ApiGateway/Middleware/ProxyMiddleware.cs new file mode 100644 index 00000000..a904a816 --- /dev/null +++ b/src/Ocelot.ApiGateway/Middleware/ProxyMiddleware.cs @@ -0,0 +1,20 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; + +namespace Ocelot.ApiGateway.Middleware +{ + public class ProxyMiddleware + { + private readonly RequestDelegate _next; + + public ProxyMiddleware(RequestDelegate next) + { + _next = next; + } + + public async Task Invoke(HttpContext context) + { + await _next.Invoke(context); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.ApiGateway/Middleware/RequestLoggerExtensions.cs b/src/Ocelot.ApiGateway/Middleware/RequestLoggerExtensions.cs new file mode 100644 index 00000000..24aa764a --- /dev/null +++ b/src/Ocelot.ApiGateway/Middleware/RequestLoggerExtensions.cs @@ -0,0 +1,12 @@ +using Microsoft.AspNetCore.Builder; + +namespace Ocelot.ApiGateway.Middleware +{ + public static class RequestLoggerExtensions + { + public static IApplicationBuilder UseRequestLogger(this IApplicationBuilder builder) + { + return builder.UseMiddleware(); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.ApiGateway/Middleware/RequestLoggerMiddleware.cs b/src/Ocelot.ApiGateway/Middleware/RequestLoggerMiddleware.cs new file mode 100644 index 00000000..5780bfdc --- /dev/null +++ b/src/Ocelot.ApiGateway/Middleware/RequestLoggerMiddleware.cs @@ -0,0 +1,25 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; + +namespace Ocelot.ApiGateway.Middleware +{ + public class RequestLoggerMiddleware + { + private readonly RequestDelegate _next; + private readonly ILogger _logger; + + public RequestLoggerMiddleware(RequestDelegate next, ILoggerFactory loggerFactory) + { + _next = next; + _logger = loggerFactory.CreateLogger(); + } + + public async Task Invoke(HttpContext context) + { + _logger.LogInformation("Handling request: " + context.Request.Path); + await _next.Invoke(context); + _logger.LogInformation("Finished handling request."); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.ApiGateway/Routers.cs b/src/Ocelot.ApiGateway/Routers.cs deleted file mode 100644 index af8881bc..00000000 --- a/src/Ocelot.ApiGateway/Routers.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing; - -namespace Ocelot.ApiGateway -{ - public class Router : IRouter - { - public Task RouteAsync(RouteContext context) - { - context.Handler = async c => - { - await c.Response.WriteAsync($"Hi, Tom!"); - }; - - return Task.FromResult(0); - } - - public VirtualPathData GetVirtualPath(VirtualPathContext context) - { - return null; - } - } -} \ No newline at end of file diff --git a/src/Ocelot.ApiGateway/Startup.cs b/src/Ocelot.ApiGateway/Startup.cs index c3c49020..c163c10b 100644 --- a/src/Ocelot.ApiGateway/Startup.cs +++ b/src/Ocelot.ApiGateway/Startup.cs @@ -4,9 +4,11 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.AspNetCore.Routing; +using Ocelot.ApiGateway.Middleware; +using Microsoft.AspNetCore.Http; namespace Ocelot.ApiGateway -{ +{ public class Startup { public Startup(IHostingEnvironment env) @@ -26,19 +28,22 @@ namespace Ocelot.ApiGateway { services.AddRouting(); } - + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(Configuration.GetSection("Logging")); + + app.UseRequestLogger(); + app.UseProxy(); loggerFactory.AddDebug(); - - var routeBuilder = new RouteBuilder(app); - - routeBuilder.AddRouter(app); - - app.UseRouter(routeBuilder.Build()); + + app.Run(async context => + { + await context.Response.WriteAsync("Hello from Tom"); + }); } } } + \ No newline at end of file diff --git a/src/Ocelot.ApiGateway/project.json b/src/Ocelot.ApiGateway/project.json index 05f7e266..9e614198 100644 --- a/src/Ocelot.ApiGateway/project.json +++ b/src/Ocelot.ApiGateway/project.json @@ -13,8 +13,12 @@ "Microsoft.Extensions.Logging": "1.0.0-rc2-final", "Microsoft.Extensions.Logging.Console": "1.0.0-rc2-final", "Microsoft.Extensions.Logging.Debug": "1.0.0-rc2-final", - "Microsoft.AspNetCore.Routing": "1.0.0-rc2-final" + "xunit": "2.1.0", + "dotnet-test-xunit": "1.0.0-rc2-final", + "Shouldly": "2.8.0" }, + + "testRunner":"xunit", "tools": { "Microsoft.AspNetCore.Server.IISIntegration.Tools": { diff --git a/src/Ocelot.Library/.gitignore b/src/Ocelot.Library/.gitignore deleted file mode 100644 index 0ca27f04..00000000 --- a/src/Ocelot.Library/.gitignore +++ /dev/null @@ -1,234 +0,0 @@ -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. - -# User-specific files -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -build/ -bld/ -[Bb]in/ -[Oo]bj/ - -# Visual Studio 2015 cache/options directory -.vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUNIT -*.VisualState.xml -TestResult.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# DNX -project.lock.json -artifacts/ - -*_i.c -*_p.c -*_i.h -*.ilk -*.meta -*.obj -*.pch -*.pdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# JustCode is a .NET coding add-in -.JustCode - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# TODO: Comment the next line if you want to checkin your web deploy settings -# but database connection strings (with potential passwords) will be unencrypted -*.pubxml -*.publishproj - -# NuGet Packages -*.nupkg -# The packages folder can be ignored because of Package Restore -**/packages/* -# except build/, which is used as an MSBuild target. -!**/packages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/packages/repositories.config - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Microsoft Azure ApplicationInsights config file -ApplicationInsights.config - -# Windows Store app package directory -AppPackages/ -BundleArtifacts/ - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.pfx -*.publishsettings -node_modules/ -orleans.codegen.cs - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm - -# SQL Server files -*.mdf -*.ldf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# Paket dependency manager -.paket/paket.exe - -# FAKE - F# Make -.fake/ diff --git a/src/Ocelot.Library/RouterMiddleware.cs b/src/Ocelot.Library/RouterMiddleware.cs deleted file mode 100644 index d4474325..00000000 --- a/src/Ocelot.Library/RouterMiddleware.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Ocelot.Library -{ - // This project can output the Class library as a NuGet Package. - // To enable this option, right-click on the project and select the Properties menu item. In the Build tab select "Produce outputs on build". - public class RouterMiddleware - { - public RouterMiddleware() - { - } - } -} diff --git a/src/Ocelot.Library/project.json b/src/Ocelot.Library/project.json deleted file mode 100644 index b72a5c6a..00000000 --- a/src/Ocelot.Library/project.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "version": "1.0.0-*", - - "dependencies": { - "NETStandard.Library": "1.5.0-rc2-24027" - }, - - "frameworks": { - "netstandard1.5": { - "imports": "dnxcore50" - } - }, - - "tooling": { - "defaultNamespace": "Ocelot.Library" - } -} diff --git a/test/Ocelot.UnitTests/.gitignore b/test/Ocelot.UnitTests/.gitignore deleted file mode 100644 index 0ca27f04..00000000 --- a/test/Ocelot.UnitTests/.gitignore +++ /dev/null @@ -1,234 +0,0 @@ -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. - -# User-specific files -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -build/ -bld/ -[Bb]in/ -[Oo]bj/ - -# Visual Studio 2015 cache/options directory -.vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUNIT -*.VisualState.xml -TestResult.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# DNX -project.lock.json -artifacts/ - -*_i.c -*_p.c -*_i.h -*.ilk -*.meta -*.obj -*.pch -*.pdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# JustCode is a .NET coding add-in -.JustCode - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# TODO: Comment the next line if you want to checkin your web deploy settings -# but database connection strings (with potential passwords) will be unencrypted -*.pubxml -*.publishproj - -# NuGet Packages -*.nupkg -# The packages folder can be ignored because of Package Restore -**/packages/* -# except build/, which is used as an MSBuild target. -!**/packages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/packages/repositories.config - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Microsoft Azure ApplicationInsights config file -ApplicationInsights.config - -# Windows Store app package directory -AppPackages/ -BundleArtifacts/ - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.pfx -*.publishsettings -node_modules/ -orleans.codegen.cs - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm - -# SQL Server files -*.mdf -*.ldf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# Paket dependency manager -.paket/paket.exe - -# FAKE - F# Make -.fake/ diff --git a/test/Ocelot.UnitTests/RouterMiddlwareTests.cs b/test/Ocelot.UnitTests/RouterMiddlwareTests.cs deleted file mode 100644 index 42fca0cb..00000000 --- a/test/Ocelot.UnitTests/RouterMiddlwareTests.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Ocelot.UnitTests -{ - // This project can output the Class library as a NuGet Package. - // To enable this option, right-click on the project and select the Properties menu item. In the Build tab select "Produce outputs on build". - public class RouterMiddlwareTests - { - public RouterMiddlwareTests() - { - } - } -} diff --git a/test/Ocelot.UnitTests/project.json b/test/Ocelot.UnitTests/project.json deleted file mode 100644 index ae4974e0..00000000 --- a/test/Ocelot.UnitTests/project.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "version": "1.0.0-*", - - "dependencies": { - "NETStandard.Library": "1.5.0-rc2-24027", - "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-rc2-final", - "Microsoft.AspNetCore.Routing": "1.0.0-rc2-final", - "Microsoft.Extensions.Logging.Console": "1.0.0-rc2-final", - "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0-rc2-final" - }, - - "frameworks": { - "netstandard1.5": { - "imports": "dnxcore50" - } - }, - - "tooling": { - "defaultNamespace": "Ocelot.UnitTests" - } -} From c512a772d4d9ada79c64d9db0221f95e04c33834 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Sun, 3 Jul 2016 20:39:08 +0100 Subject: [PATCH 002/183] after hours of pissing around on the mac...gave up..so got this configured how i wanted in VS2015 now to see if it works on the mac --- .../.gitignore => .gitignore | 0 .vscode/launch.json | 49 -------------- Ocelot.sln | 50 ++++++++++++++ global.json | 6 ++ src/Ocelot.ApiGateway/Dockerfile | 11 ---- src/Ocelot.ApiGateway/project.json | 65 ------------------- .../Infrastructure/Responses/Error.cs | 2 +- .../Infrastructure/Responses/ErrorResponse.cs | 6 +- .../Responses/ErrorResponseGeneric.cs | 6 +- .../Infrastructure/Responses/OkResponse.cs | 2 +- .../Responses/OkResponseGeneric.cs | 2 +- .../Infrastructure/Responses/Response.cs | 6 +- .../Responses/ResponseGeneric.cs | 6 +- .../Infrastructure/Router/IRouterService.cs | 4 +- .../Router/InMemoryRouterService.cs | 6 +- .../Infrastructure/Router/Route.cs | 2 +- .../Router/RouteKeyAlreadyExists.cs | 4 +- .../Router/RouteKeyDoesNotExist.cs | 4 +- .../Middleware/ProxyExtensions.cs | 2 +- .../Middleware/ProxyMiddleware.cs | 2 +- .../Middleware/RequestLoggerExtensions.cs | 2 +- .../Middleware/RequestLoggerMiddleware.cs | 2 +- src/Ocelot.Library/Ocelot.Library.xproj | 21 ++++++ src/Ocelot.Library/Properties/AssemblyInfo.cs | 19 ++++++ src/Ocelot.Library/project.json | 30 +++++++++ src/Ocelot/Ocelot.xproj | 19 ++++++ src/{Ocelot.ApiGateway => Ocelot}/Program.cs | 6 +- .../Properties/launchSettings.json | 10 +-- src/{Ocelot.ApiGateway => Ocelot}/Startup.cs | 26 +++----- .../appsettings.json | 20 +++--- src/Ocelot/project.json | 58 +++++++++++++++++ src/{Ocelot.ApiGateway => Ocelot}/web.config | 28 ++++---- test/Ocelot.UnitTests/Ocelot.UnitTests.xproj | 22 +++++++ .../Properties/AssemblyInfo.cs | 19 ++++++ .../Ocelot.UnitTests}/RouterTests.cs | 12 ++-- test/Ocelot.UnitTests/project.json | 36 ++++++++++ 36 files changed, 359 insertions(+), 206 deletions(-) rename src/Ocelot.ApiGateway/.gitignore => .gitignore (100%) delete mode 100644 .vscode/launch.json create mode 100644 Ocelot.sln create mode 100644 global.json delete mode 100644 src/Ocelot.ApiGateway/Dockerfile delete mode 100644 src/Ocelot.ApiGateway/project.json rename src/{Ocelot.ApiGateway => Ocelot.Library}/Infrastructure/Responses/Error.cs (78%) rename src/{Ocelot.ApiGateway => Ocelot.Library}/Infrastructure/Responses/ErrorResponse.cs (60%) rename src/{Ocelot.ApiGateway => Ocelot.Library}/Infrastructure/Responses/ErrorResponseGeneric.cs (61%) rename src/{Ocelot.ApiGateway => Ocelot.Library}/Infrastructure/Responses/OkResponse.cs (65%) rename src/{Ocelot.ApiGateway => Ocelot.Library}/Infrastructure/Responses/OkResponseGeneric.cs (70%) rename src/{Ocelot.ApiGateway => Ocelot.Library}/Infrastructure/Responses/Response.cs (77%) rename src/{Ocelot.ApiGateway => Ocelot.Library}/Infrastructure/Responses/ResponseGeneric.cs (75%) rename src/{Ocelot.ApiGateway => Ocelot.Library}/Infrastructure/Router/IRouterService.cs (62%) rename src/{Ocelot.ApiGateway => Ocelot.Library}/Infrastructure/Router/InMemoryRouterService.cs (88%) rename src/{Ocelot.ApiGateway => Ocelot.Library}/Infrastructure/Router/Route.cs (85%) rename src/{Ocelot.ApiGateway => Ocelot.Library}/Infrastructure/Router/RouteKeyAlreadyExists.cs (62%) rename src/{Ocelot.ApiGateway => Ocelot.Library}/Infrastructure/Router/RouteKeyDoesNotExist.cs (61%) rename src/{Ocelot.ApiGateway => Ocelot.Library}/Middleware/ProxyExtensions.cs (86%) rename src/{Ocelot.ApiGateway => Ocelot.Library}/Middleware/ProxyMiddleware.cs (90%) rename src/{Ocelot.ApiGateway => Ocelot.Library}/Middleware/RequestLoggerExtensions.cs (87%) rename src/{Ocelot.ApiGateway => Ocelot.Library}/Middleware/RequestLoggerMiddleware.cs (94%) create mode 100644 src/Ocelot.Library/Ocelot.Library.xproj create mode 100644 src/Ocelot.Library/Properties/AssemblyInfo.cs create mode 100644 src/Ocelot.Library/project.json create mode 100644 src/Ocelot/Ocelot.xproj rename src/{Ocelot.ApiGateway => Ocelot}/Program.cs (79%) rename src/{Ocelot.ApiGateway => Ocelot}/Properties/launchSettings.json (77%) rename src/{Ocelot.ApiGateway => Ocelot}/Startup.cs (82%) rename src/{Ocelot.ApiGateway => Ocelot}/appsettings.json (93%) mode change 100755 => 100644 create mode 100644 src/Ocelot/project.json rename src/{Ocelot.ApiGateway => Ocelot}/web.config (80%) create mode 100644 test/Ocelot.UnitTests/Ocelot.UnitTests.xproj create mode 100644 test/Ocelot.UnitTests/Properties/AssemblyInfo.cs rename {src/Ocelot.ApiGateway/Infrastructure/Router => test/Ocelot.UnitTests}/RouterTests.cs (95%) create mode 100644 test/Ocelot.UnitTests/project.json diff --git a/src/Ocelot.ApiGateway/.gitignore b/.gitignore similarity index 100% rename from src/Ocelot.ApiGateway/.gitignore rename to .gitignore diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 50f9b3d8..00000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - { - "name": ".NET Core Launch (console)", - "type": "coreclr", - "request": "launch", - "preLaunchTask": "build", - "program": "${workspaceRoot}/bin/Debug//", - "args": [], - "cwd": "${workspaceRoot}", - "stopAtEntry": false, - "externalConsole": false - }, - { - "name": ".NET Core Launch (web)", - "type": "coreclr", - "request": "launch", - "preLaunchTask": "build", - "program": "${workspaceRoot}/bin/Debug//", - "args": [], - "cwd": "${workspaceRoot}", - "stopAtEntry": false, - "launchBrowser": { - "enabled": true, - "args": "${auto-detect-url}", - "windows": { - "command": "cmd.exe", - "args": "/C start ${auto-detect-url}" - }, - "osx": { - "command": "open" - }, - "linux": { - "command": "xdg-open" - } - }, - "env": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - { - "name": ".NET Core Attach", - "type": "coreclr", - "request": "attach", - "processId": 0 - } - ] -} \ No newline at end of file diff --git a/Ocelot.sln b/Ocelot.sln new file mode 100644 index 00000000..848e011d --- /dev/null +++ b/Ocelot.sln @@ -0,0 +1,50 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{5CFB79B7-C9DC-45A4-9A75-625D92471702}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3FA7C349-DBE8-4904-A2CE-015B8869CE6C}" + ProjectSection(SolutionItems) = preProject + global.json = global.json + LICENSE.md = LICENSE.md + README.md = README.md + EndProjectSection +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Ocelot", "src\Ocelot\Ocelot.xproj", "{AEC8FB40-B370-48A6-9B38-78E560041F01}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Ocelot.Library", "src\Ocelot.Library\Ocelot.Library.xproj", "{D6DF4206-0DBA-41D8-884D-C3E08290FDBB}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{5B401523-36DA-4491-B73A-7590A26E420B}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Ocelot.UnitTests", "test\Ocelot.UnitTests\Ocelot.UnitTests.xproj", "{54E84F1A-E525-4443-96EC-039CBD50C263}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {AEC8FB40-B370-48A6-9B38-78E560041F01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AEC8FB40-B370-48A6-9B38-78E560041F01}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AEC8FB40-B370-48A6-9B38-78E560041F01}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AEC8FB40-B370-48A6-9B38-78E560041F01}.Release|Any CPU.Build.0 = Release|Any CPU + {D6DF4206-0DBA-41D8-884D-C3E08290FDBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D6DF4206-0DBA-41D8-884D-C3E08290FDBB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D6DF4206-0DBA-41D8-884D-C3E08290FDBB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D6DF4206-0DBA-41D8-884D-C3E08290FDBB}.Release|Any CPU.Build.0 = Release|Any CPU + {54E84F1A-E525-4443-96EC-039CBD50C263}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {54E84F1A-E525-4443-96EC-039CBD50C263}.Debug|Any CPU.Build.0 = Debug|Any CPU + {54E84F1A-E525-4443-96EC-039CBD50C263}.Release|Any CPU.ActiveCfg = Release|Any CPU + {54E84F1A-E525-4443-96EC-039CBD50C263}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {AEC8FB40-B370-48A6-9B38-78E560041F01} = {5CFB79B7-C9DC-45A4-9A75-625D92471702} + {D6DF4206-0DBA-41D8-884D-C3E08290FDBB} = {5CFB79B7-C9DC-45A4-9A75-625D92471702} + {54E84F1A-E525-4443-96EC-039CBD50C263} = {5B401523-36DA-4491-B73A-7590A26E420B} + EndGlobalSection +EndGlobal diff --git a/global.json b/global.json new file mode 100644 index 00000000..0d315988 --- /dev/null +++ b/global.json @@ -0,0 +1,6 @@ + { + "projects": [ "src", "test" ], + "sdk": { + "version": "1.0.0-preview2-003121" + } +} diff --git a/src/Ocelot.ApiGateway/Dockerfile b/src/Ocelot.ApiGateway/Dockerfile deleted file mode 100644 index 5ea50452..00000000 --- a/src/Ocelot.ApiGateway/Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM microsoft/aspnet:1.0.0-rc1-update1 - -RUN printf "deb http://ftp.us.debian.org/debian jessie main\n" >> /etc/apt/sources.list -RUN apt-get -qq update && apt-get install -qqy sqlite3 libsqlite3-dev && rm -rf /var/lib/apt/lists/* - -COPY . /app -WORKDIR /app -RUN ["dnu", "restore"] - -EXPOSE 5000/tcp -ENTRYPOINT ["dnx", "-p", "project.json", "Microsoft.AspNet.Server.Kestrel", "--server.urls", "http://0.0.0.0:5000"] diff --git a/src/Ocelot.ApiGateway/project.json b/src/Ocelot.ApiGateway/project.json deleted file mode 100644 index 9e614198..00000000 --- a/src/Ocelot.ApiGateway/project.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.0.0-rc2-3002702", - "type": "platform" - }, - "Microsoft.AspNetCore.Mvc": "1.0.0-rc2-final", - "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0-rc2-final", - "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-rc2-final", - "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0-rc2-final", - "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0-rc2-final", - "Microsoft.Extensions.Configuration.Json": "1.0.0-rc2-final", - "Microsoft.Extensions.Logging": "1.0.0-rc2-final", - "Microsoft.Extensions.Logging.Console": "1.0.0-rc2-final", - "Microsoft.Extensions.Logging.Debug": "1.0.0-rc2-final", - "xunit": "2.1.0", - "dotnet-test-xunit": "1.0.0-rc2-final", - "Shouldly": "2.8.0" - }, - - "testRunner":"xunit", - - "tools": { - "Microsoft.AspNetCore.Server.IISIntegration.Tools": { - "version": "1.0.0-preview1-final", - "imports": "portable-net45+win8+dnxcore50" - } - }, - - "frameworks": { - "netcoreapp1.0": { - "imports": [ - "dotnet5.6", - "dnxcore50", - "portable-net45+win8" - ] - } - }, - - "buildOptions": { - "emitEntryPoint": true, - "preserveCompilationContext": true - }, - - "runtimeOptions": { - "gcServer": true - }, - - "publishOptions": { - "include": [ - "wwwroot", - "Views", - "appsettings.json", - "web.config" - ] - }, - - "scripts": { - "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ] - }, - - "tooling": { - "defaultNamespace": "Ocelot.ApiGateway" - } -} diff --git a/src/Ocelot.ApiGateway/Infrastructure/Responses/Error.cs b/src/Ocelot.Library/Infrastructure/Responses/Error.cs similarity index 78% rename from src/Ocelot.ApiGateway/Infrastructure/Responses/Error.cs rename to src/Ocelot.Library/Infrastructure/Responses/Error.cs index e66a9bf8..57684854 100644 --- a/src/Ocelot.ApiGateway/Infrastructure/Responses/Error.cs +++ b/src/Ocelot.Library/Infrastructure/Responses/Error.cs @@ -1,4 +1,4 @@ -namespace Ocelot.ApiGateway.Infrastructure.Responses +namespace Ocelot.Library.Infrastructure.Responses { public abstract class Error { diff --git a/src/Ocelot.ApiGateway/Infrastructure/Responses/ErrorResponse.cs b/src/Ocelot.Library/Infrastructure/Responses/ErrorResponse.cs similarity index 60% rename from src/Ocelot.ApiGateway/Infrastructure/Responses/ErrorResponse.cs rename to src/Ocelot.Library/Infrastructure/Responses/ErrorResponse.cs index 884c4ac0..5233f358 100644 --- a/src/Ocelot.ApiGateway/Infrastructure/Responses/ErrorResponse.cs +++ b/src/Ocelot.Library/Infrastructure/Responses/ErrorResponse.cs @@ -1,7 +1,7 @@ -namespace Ocelot.ApiGateway.Infrastructure.Responses -{ - using System.Collections.Generic; +using System.Collections.Generic; +namespace Ocelot.Library.Infrastructure.Responses +{ public class ErrorResponse : Response { public ErrorResponse(List errors) : base(errors) diff --git a/src/Ocelot.ApiGateway/Infrastructure/Responses/ErrorResponseGeneric.cs b/src/Ocelot.Library/Infrastructure/Responses/ErrorResponseGeneric.cs similarity index 61% rename from src/Ocelot.ApiGateway/Infrastructure/Responses/ErrorResponseGeneric.cs rename to src/Ocelot.Library/Infrastructure/Responses/ErrorResponseGeneric.cs index cb1ddb05..95bda1b7 100644 --- a/src/Ocelot.ApiGateway/Infrastructure/Responses/ErrorResponseGeneric.cs +++ b/src/Ocelot.Library/Infrastructure/Responses/ErrorResponseGeneric.cs @@ -1,7 +1,7 @@ -namespace Ocelot.ApiGateway.Infrastructure.Responses -{ - using System.Collections.Generic; +using System.Collections.Generic; +namespace Ocelot.Library.Infrastructure.Responses +{ public class ErrorResponse : Response { public ErrorResponse(List errors) : base(errors) diff --git a/src/Ocelot.ApiGateway/Infrastructure/Responses/OkResponse.cs b/src/Ocelot.Library/Infrastructure/Responses/OkResponse.cs similarity index 65% rename from src/Ocelot.ApiGateway/Infrastructure/Responses/OkResponse.cs rename to src/Ocelot.Library/Infrastructure/Responses/OkResponse.cs index 1f02b6e5..0b71f0d0 100644 --- a/src/Ocelot.ApiGateway/Infrastructure/Responses/OkResponse.cs +++ b/src/Ocelot.Library/Infrastructure/Responses/OkResponse.cs @@ -1,4 +1,4 @@ -namespace Ocelot.ApiGateway.Infrastructure.Responses +namespace Ocelot.Library.Infrastructure.Responses { public class OkResponse : Response { diff --git a/src/Ocelot.ApiGateway/Infrastructure/Responses/OkResponseGeneric.cs b/src/Ocelot.Library/Infrastructure/Responses/OkResponseGeneric.cs similarity index 70% rename from src/Ocelot.ApiGateway/Infrastructure/Responses/OkResponseGeneric.cs rename to src/Ocelot.Library/Infrastructure/Responses/OkResponseGeneric.cs index 010a28a9..a18ac11f 100644 --- a/src/Ocelot.ApiGateway/Infrastructure/Responses/OkResponseGeneric.cs +++ b/src/Ocelot.Library/Infrastructure/Responses/OkResponseGeneric.cs @@ -1,4 +1,4 @@ -namespace Ocelot.ApiGateway.Infrastructure.Responses +namespace Ocelot.Library.Infrastructure.Responses { public class OkResponse : Response { diff --git a/src/Ocelot.ApiGateway/Infrastructure/Responses/Response.cs b/src/Ocelot.Library/Infrastructure/Responses/Response.cs similarity index 77% rename from src/Ocelot.ApiGateway/Infrastructure/Responses/Response.cs rename to src/Ocelot.Library/Infrastructure/Responses/Response.cs index 091d6f98..6651c0f7 100644 --- a/src/Ocelot.ApiGateway/Infrastructure/Responses/Response.cs +++ b/src/Ocelot.Library/Infrastructure/Responses/Response.cs @@ -1,7 +1,7 @@ -namespace Ocelot.ApiGateway.Infrastructure.Responses -{ - using System.Collections.Generic; +using System.Collections.Generic; +namespace Ocelot.Library.Infrastructure.Responses +{ public abstract class Response { protected Response() diff --git a/src/Ocelot.ApiGateway/Infrastructure/Responses/ResponseGeneric.cs b/src/Ocelot.Library/Infrastructure/Responses/ResponseGeneric.cs similarity index 75% rename from src/Ocelot.ApiGateway/Infrastructure/Responses/ResponseGeneric.cs rename to src/Ocelot.Library/Infrastructure/Responses/ResponseGeneric.cs index c78c8b6d..97e72e10 100644 --- a/src/Ocelot.ApiGateway/Infrastructure/Responses/ResponseGeneric.cs +++ b/src/Ocelot.Library/Infrastructure/Responses/ResponseGeneric.cs @@ -1,7 +1,7 @@ -namespace Ocelot.ApiGateway.Infrastructure.Responses -{ - using System.Collections.Generic; +using System.Collections.Generic; +namespace Ocelot.Library.Infrastructure.Responses +{ public abstract class Response : Response { protected Response(T data) diff --git a/src/Ocelot.ApiGateway/Infrastructure/Router/IRouterService.cs b/src/Ocelot.Library/Infrastructure/Router/IRouterService.cs similarity index 62% rename from src/Ocelot.ApiGateway/Infrastructure/Router/IRouterService.cs rename to src/Ocelot.Library/Infrastructure/Router/IRouterService.cs index aa68859b..61f7b48d 100644 --- a/src/Ocelot.ApiGateway/Infrastructure/Router/IRouterService.cs +++ b/src/Ocelot.Library/Infrastructure/Router/IRouterService.cs @@ -1,6 +1,6 @@ -using Ocelot.ApiGateway.Infrastructure.Responses; +using Ocelot.Library.Infrastructure.Responses; -namespace Ocelot.ApiGateway.Infrastructure.Router +namespace Ocelot.Library.Infrastructure.Router { public interface IRouterService { diff --git a/src/Ocelot.ApiGateway/Infrastructure/Router/InMemoryRouterService.cs b/src/Ocelot.Library/Infrastructure/Router/InMemoryRouterService.cs similarity index 88% rename from src/Ocelot.ApiGateway/Infrastructure/Router/InMemoryRouterService.cs rename to src/Ocelot.Library/Infrastructure/Router/InMemoryRouterService.cs index 4394e667..d3e73746 100644 --- a/src/Ocelot.ApiGateway/Infrastructure/Router/InMemoryRouterService.cs +++ b/src/Ocelot.Library/Infrastructure/Router/InMemoryRouterService.cs @@ -1,12 +1,12 @@ using System; using System.Collections.Generic; -using Ocelot.ApiGateway.Infrastructure.Responses; +using Ocelot.Library.Infrastructure.Responses; -namespace Ocelot.ApiGateway.Infrastructure.Router +namespace Ocelot.Library.Infrastructure.Router { public class InMemoryRouterService : IRouterService { - private Dictionary _routes; + private readonly Dictionary _routes; public InMemoryRouterService() { _routes = new Dictionary(); diff --git a/src/Ocelot.ApiGateway/Infrastructure/Router/Route.cs b/src/Ocelot.Library/Infrastructure/Router/Route.cs similarity index 85% rename from src/Ocelot.ApiGateway/Infrastructure/Router/Route.cs rename to src/Ocelot.Library/Infrastructure/Router/Route.cs index 0edae1ef..f76f6173 100644 --- a/src/Ocelot.ApiGateway/Infrastructure/Router/Route.cs +++ b/src/Ocelot.Library/Infrastructure/Router/Route.cs @@ -1,4 +1,4 @@ -namespace Ocelot.ApiGateway.Infrastructure.Router +namespace Ocelot.Library.Infrastructure.Router { public class Route { diff --git a/src/Ocelot.ApiGateway/Infrastructure/Router/RouteKeyAlreadyExists.cs b/src/Ocelot.Library/Infrastructure/Router/RouteKeyAlreadyExists.cs similarity index 62% rename from src/Ocelot.ApiGateway/Infrastructure/Router/RouteKeyAlreadyExists.cs rename to src/Ocelot.Library/Infrastructure/Router/RouteKeyAlreadyExists.cs index 0a89b302..1ae13795 100644 --- a/src/Ocelot.ApiGateway/Infrastructure/Router/RouteKeyAlreadyExists.cs +++ b/src/Ocelot.Library/Infrastructure/Router/RouteKeyAlreadyExists.cs @@ -1,6 +1,6 @@ -using Ocelot.ApiGateway.Infrastructure.Responses; +using Ocelot.Library.Infrastructure.Responses; -namespace Ocelot.ApiGateway.Infrastructure.Router +namespace Ocelot.Library.Infrastructure.Router { public class RouteKeyAlreadyExists : Error { diff --git a/src/Ocelot.ApiGateway/Infrastructure/Router/RouteKeyDoesNotExist.cs b/src/Ocelot.Library/Infrastructure/Router/RouteKeyDoesNotExist.cs similarity index 61% rename from src/Ocelot.ApiGateway/Infrastructure/Router/RouteKeyDoesNotExist.cs rename to src/Ocelot.Library/Infrastructure/Router/RouteKeyDoesNotExist.cs index 9b745f00..f38aea5e 100644 --- a/src/Ocelot.ApiGateway/Infrastructure/Router/RouteKeyDoesNotExist.cs +++ b/src/Ocelot.Library/Infrastructure/Router/RouteKeyDoesNotExist.cs @@ -1,6 +1,6 @@ -using Ocelot.ApiGateway.Infrastructure.Responses; +using Ocelot.Library.Infrastructure.Responses; -namespace Ocelot.ApiGateway.Infrastructure.Router +namespace Ocelot.Library.Infrastructure.Router { public class RouteKeyDoesNotExist : Error { diff --git a/src/Ocelot.ApiGateway/Middleware/ProxyExtensions.cs b/src/Ocelot.Library/Middleware/ProxyExtensions.cs similarity index 86% rename from src/Ocelot.ApiGateway/Middleware/ProxyExtensions.cs rename to src/Ocelot.Library/Middleware/ProxyExtensions.cs index 444afa20..83777448 100644 --- a/src/Ocelot.ApiGateway/Middleware/ProxyExtensions.cs +++ b/src/Ocelot.Library/Middleware/ProxyExtensions.cs @@ -1,6 +1,6 @@ using Microsoft.AspNetCore.Builder; -namespace Ocelot.ApiGateway.Middleware +namespace Ocelot.Library.Middleware { public static class ProxyExtensions { diff --git a/src/Ocelot.ApiGateway/Middleware/ProxyMiddleware.cs b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs similarity index 90% rename from src/Ocelot.ApiGateway/Middleware/ProxyMiddleware.cs rename to src/Ocelot.Library/Middleware/ProxyMiddleware.cs index a904a816..a8698273 100644 --- a/src/Ocelot.ApiGateway/Middleware/ProxyMiddleware.cs +++ b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs @@ -1,7 +1,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; -namespace Ocelot.ApiGateway.Middleware +namespace Ocelot.Library.Middleware { public class ProxyMiddleware { diff --git a/src/Ocelot.ApiGateway/Middleware/RequestLoggerExtensions.cs b/src/Ocelot.Library/Middleware/RequestLoggerExtensions.cs similarity index 87% rename from src/Ocelot.ApiGateway/Middleware/RequestLoggerExtensions.cs rename to src/Ocelot.Library/Middleware/RequestLoggerExtensions.cs index 24aa764a..0d1a0027 100644 --- a/src/Ocelot.ApiGateway/Middleware/RequestLoggerExtensions.cs +++ b/src/Ocelot.Library/Middleware/RequestLoggerExtensions.cs @@ -1,6 +1,6 @@ using Microsoft.AspNetCore.Builder; -namespace Ocelot.ApiGateway.Middleware +namespace Ocelot.Library.Middleware { public static class RequestLoggerExtensions { diff --git a/src/Ocelot.ApiGateway/Middleware/RequestLoggerMiddleware.cs b/src/Ocelot.Library/Middleware/RequestLoggerMiddleware.cs similarity index 94% rename from src/Ocelot.ApiGateway/Middleware/RequestLoggerMiddleware.cs rename to src/Ocelot.Library/Middleware/RequestLoggerMiddleware.cs index 5780bfdc..554433b2 100644 --- a/src/Ocelot.ApiGateway/Middleware/RequestLoggerMiddleware.cs +++ b/src/Ocelot.Library/Middleware/RequestLoggerMiddleware.cs @@ -2,7 +2,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; -namespace Ocelot.ApiGateway.Middleware +namespace Ocelot.Library.Middleware { public class RequestLoggerMiddleware { diff --git a/src/Ocelot.Library/Ocelot.Library.xproj b/src/Ocelot.Library/Ocelot.Library.xproj new file mode 100644 index 00000000..d5f127c2 --- /dev/null +++ b/src/Ocelot.Library/Ocelot.Library.xproj @@ -0,0 +1,21 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + d6df4206-0dba-41d8-884d-c3e08290fdbb + Ocelot.Library + .\obj + .\bin\ + v4.5 + + + + 2.0 + + + diff --git a/src/Ocelot.Library/Properties/AssemblyInfo.cs b/src/Ocelot.Library/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..cf59e825 --- /dev/null +++ b/src/Ocelot.Library/Properties/AssemblyInfo.cs @@ -0,0 +1,19 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Ocelot.Library")] +[assembly: AssemblyTrademark("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("d6df4206-0dba-41d8-884d-c3e08290fdbb")] diff --git a/src/Ocelot.Library/project.json b/src/Ocelot.Library/project.json new file mode 100644 index 00000000..ca884c95 --- /dev/null +++ b/src/Ocelot.Library/project.json @@ -0,0 +1,30 @@ +{ + "version": "1.0.0-*", + + "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.0.0", + "type": "platform" + }, + "Microsoft.AspNetCore.Mvc": "1.0.0", + "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", + "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", + "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0", + "Microsoft.Extensions.Configuration.Json": "1.0.0", + "Microsoft.Extensions.Logging": "1.0.0", + "Microsoft.Extensions.Logging.Console": "1.0.0", + "Microsoft.Extensions.Logging.Debug": "1.0.0", + "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", + "Microsoft.AspNetCore.Http": "1.0.0" + }, + + "frameworks": { + "netcoreapp1.0": { + "imports": [ + "dotnet5.6", + "portable-net45+win8" + ] + } + } +} diff --git a/src/Ocelot/Ocelot.xproj b/src/Ocelot/Ocelot.xproj new file mode 100644 index 00000000..86842479 --- /dev/null +++ b/src/Ocelot/Ocelot.xproj @@ -0,0 +1,19 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + aec8fb40-b370-48a6-9b38-78e560041f01 + Ocelot + .\obj + .\bin\ + v4.5.2 + + + 2.0 + + + diff --git a/src/Ocelot.ApiGateway/Program.cs b/src/Ocelot/Program.cs similarity index 79% rename from src/Ocelot.ApiGateway/Program.cs rename to src/Ocelot/Program.cs index b5404270..e8777ea7 100644 --- a/src/Ocelot.ApiGateway/Program.cs +++ b/src/Ocelot/Program.cs @@ -1,8 +1,12 @@ +using System; +using System.Collections.Generic; using System.IO; +using System.Linq; +using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Builder; -namespace Ocelot.ApiGateway +namespace Ocelot { public class Program { diff --git a/src/Ocelot.ApiGateway/Properties/launchSettings.json b/src/Ocelot/Properties/launchSettings.json similarity index 77% rename from src/Ocelot.ApiGateway/Properties/launchSettings.json rename to src/Ocelot/Properties/launchSettings.json index 3f72d44b..7fc77fcd 100644 --- a/src/Ocelot.ApiGateway/Properties/launchSettings.json +++ b/src/Ocelot/Properties/launchSettings.json @@ -3,20 +3,20 @@ "windowsAuthentication": false, "anonymousAuthentication": true, "iisExpress": { - "applicationUrl": "http://localhost:55368/", + "applicationUrl": "http://localhost:1798/", "sslPort": 0 } }, "profiles": { "IIS Express": { - "commandName" : "IISExpress", + "commandName": "IISExpress", "launchBrowser": true, "launchUrl": "api/values", - "environmentVariables" : { + "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } }, - "Ocelot.ApiGateway": { + "Ocelot": { "commandName": "Project", "launchBrowser": true, "launchUrl": "http://localhost:5000/api/values", @@ -25,4 +25,4 @@ } } } -} +} \ No newline at end of file diff --git a/src/Ocelot.ApiGateway/Startup.cs b/src/Ocelot/Startup.cs similarity index 82% rename from src/Ocelot.ApiGateway/Startup.cs rename to src/Ocelot/Startup.cs index c163c10b..990e0cd5 100644 --- a/src/Ocelot.ApiGateway/Startup.cs +++ b/src/Ocelot/Startup.cs @@ -1,14 +1,12 @@ -using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Microsoft.AspNetCore.Routing; -using Ocelot.ApiGateway.Middleware; -using Microsoft.AspNetCore.Http; -namespace Ocelot.ApiGateway -{ +namespace Ocelot +{ public class Startup { public Startup(IHostingEnvironment env) @@ -20,30 +18,26 @@ namespace Ocelot.ApiGateway .AddEnvironmentVariables(); Configuration = builder.Build(); } - + public IConfigurationRoot Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { - services.AddRouting(); + // Add framework services. + } - + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(Configuration.GetSection("Logging")); - - app.UseRequestLogger(); - app.UseProxy(); - loggerFactory.AddDebug(); - - app.Run(async context => + + app.Run(async context => { await context.Response.WriteAsync("Hello from Tom"); }); } } } - \ No newline at end of file diff --git a/src/Ocelot.ApiGateway/appsettings.json b/src/Ocelot/appsettings.json old mode 100755 new mode 100644 similarity index 93% rename from src/Ocelot.ApiGateway/appsettings.json rename to src/Ocelot/appsettings.json index cb1818e7..fa8ce71a --- a/src/Ocelot.ApiGateway/appsettings.json +++ b/src/Ocelot/appsettings.json @@ -1,10 +1,10 @@ -{ - "Logging": { - "IncludeScopes": false, - "LogLevel": { - "Default": "Debug", - "System": "Information", - "Microsoft": "Information" - } - } -} +{ + "Logging": { + "IncludeScopes": false, + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + } + } +} diff --git a/src/Ocelot/project.json b/src/Ocelot/project.json new file mode 100644 index 00000000..ba309f23 --- /dev/null +++ b/src/Ocelot/project.json @@ -0,0 +1,58 @@ +{ + "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.0.0", + "type": "platform" + }, + "Microsoft.AspNetCore.Mvc": "1.0.0", + "Microsoft.AspNetCore.Http": "1.0.0", + "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", + "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", + "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0", + "Microsoft.Extensions.Configuration.Json": "1.0.0", + "Microsoft.Extensions.Logging": "1.0.0", + "Microsoft.Extensions.Logging.Console": "1.0.0", + "Microsoft.Extensions.Logging.Debug": "1.0.0", + "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", + "Ocelot.Library": "1.0.0-*" + }, + + "tools": { + "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final" + }, + + "frameworks": { + "netcoreapp1.0": { + "imports": [ + "dotnet5.6", + "portable-net45+win8" + ] + } + }, + + "buildOptions": { + "emitEntryPoint": true, + "preserveCompilationContext": true + }, + + "runtimeOptions": { + "configProperties": { + "System.GC.Server": true + } + }, + + "publishOptions": { + "include": [ + "wwwroot", + "Views", + "Areas/**/Views", + "appsettings.json", + "web.config" + ] + }, + + "scripts": { + "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ] + } +} diff --git a/src/Ocelot.ApiGateway/web.config b/src/Ocelot/web.config similarity index 80% rename from src/Ocelot.ApiGateway/web.config rename to src/Ocelot/web.config index 68ab630e..dc0514fc 100644 --- a/src/Ocelot.ApiGateway/web.config +++ b/src/Ocelot/web.config @@ -1,14 +1,14 @@ - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/test/Ocelot.UnitTests/Ocelot.UnitTests.xproj b/test/Ocelot.UnitTests/Ocelot.UnitTests.xproj new file mode 100644 index 00000000..0936ae02 --- /dev/null +++ b/test/Ocelot.UnitTests/Ocelot.UnitTests.xproj @@ -0,0 +1,22 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 54e84f1a-e525-4443-96ec-039cbd50c263 + Ocelot.UnitTests + .\obj + .\bin\ + v4.5 + + + 2.0 + + + + + + \ No newline at end of file diff --git a/test/Ocelot.UnitTests/Properties/AssemblyInfo.cs b/test/Ocelot.UnitTests/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..a2be759e --- /dev/null +++ b/test/Ocelot.UnitTests/Properties/AssemblyInfo.cs @@ -0,0 +1,19 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Ocelot.UnitTests")] +[assembly: AssemblyTrademark("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("54e84f1a-e525-4443-96ec-039cbd50c263")] diff --git a/src/Ocelot.ApiGateway/Infrastructure/Router/RouterTests.cs b/test/Ocelot.UnitTests/RouterTests.cs similarity index 95% rename from src/Ocelot.ApiGateway/Infrastructure/Router/RouterTests.cs rename to test/Ocelot.UnitTests/RouterTests.cs index 4cf1e1b1..e9f32823 100644 --- a/src/Ocelot.ApiGateway/Infrastructure/Router/RouterTests.cs +++ b/test/Ocelot.UnitTests/RouterTests.cs @@ -1,9 +1,9 @@ -using System; -using Ocelot.ApiGateway.Infrastructure.Responses; +using Ocelot.Library.Infrastructure.Responses; +using Ocelot.Library.Infrastructure.Router; using Shouldly; using Xunit; -namespace Ocelot.ApiGateway.Infrastructure.Router +namespace Ocelot.UnitTests { public class RouterTests { @@ -45,7 +45,7 @@ namespace Ocelot.ApiGateway.Infrastructure.Router [Fact] public void should_return_error_response_if_key_doesnt_exist() - { + { GivenIWantToRouteRequestsToMyUpstreamApi("api"); WhenIRetrieveTheRouteByKey(); ThenTheKeyDoesNotExist(); @@ -54,7 +54,7 @@ namespace Ocelot.ApiGateway.Infrastructure.Router private void WhenITryToUseTheSameKey() { WhenIAddTheConfiguration(); - } + } private void ThenTheKeyHasAlreadyBeenUsed() { @@ -101,7 +101,7 @@ namespace Ocelot.ApiGateway.Infrastructure.Router private void WhenIAddTheConfiguration() { _response = _router.AddRoute(_apiKey, _upstreamApiUrl); - } + } private void ThenTheResponseIsSuccesful() { diff --git a/test/Ocelot.UnitTests/project.json b/test/Ocelot.UnitTests/project.json new file mode 100644 index 00000000..926c8e73 --- /dev/null +++ b/test/Ocelot.UnitTests/project.json @@ -0,0 +1,36 @@ +{ + "version": "1.0.0-*", + + "testRunner": "xunit", + + "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.0.0", + "type": "platform" + }, + "Microsoft.AspNetCore.Mvc": "1.0.0", + "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", + "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", + "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0", + "Microsoft.Extensions.Configuration.Json": "1.0.0", + "Microsoft.Extensions.Logging": "1.0.0", + "Microsoft.Extensions.Logging.Console": "1.0.0", + "Microsoft.Extensions.Logging.Debug": "1.0.0", + "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", + "Microsoft.AspNetCore.Http": "1.0.0", + "Ocelot.Library": "1.0.0-*", + "xunit": "2.1.0", + "dotnet-test-xunit": "2.2.0-preview2-build1029", + "Shouldly": "2.8.0" + }, + + "frameworks": { + "netcoreapp1.0": { + "imports": [ + "dotnet5.6", + "portable-net45+win8" + ] + } + } +} From 8cd1629118f36efad8c40170dc9dde4f3c3f693f Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Sun, 3 Jul 2016 21:48:49 +0100 Subject: [PATCH 003/183] gitignore appeard on mac osx??? --- test/Ocelot.UnitTests/.gitignore | 234 +++++++++++++++++++++++++++++++ 1 file changed, 234 insertions(+) create mode 100644 test/Ocelot.UnitTests/.gitignore diff --git a/test/Ocelot.UnitTests/.gitignore b/test/Ocelot.UnitTests/.gitignore new file mode 100644 index 00000000..0ca27f04 --- /dev/null +++ b/test/Ocelot.UnitTests/.gitignore @@ -0,0 +1,234 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +build/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Microsoft Azure ApplicationInsights config file +ApplicationInsights.config + +# Windows Store app package directory +AppPackages/ +BundleArtifacts/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe + +# FAKE - F# Make +.fake/ From 7332da72301318737061ee34bb9c1001a8529da8 Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Sun, 3 Jul 2016 21:52:38 +0100 Subject: [PATCH 004/183] removed --- test/Ocelot.UnitTests/.gitignore | 234 ------------------------------- 1 file changed, 234 deletions(-) delete mode 100644 test/Ocelot.UnitTests/.gitignore diff --git a/test/Ocelot.UnitTests/.gitignore b/test/Ocelot.UnitTests/.gitignore deleted file mode 100644 index 0ca27f04..00000000 --- a/test/Ocelot.UnitTests/.gitignore +++ /dev/null @@ -1,234 +0,0 @@ -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. - -# User-specific files -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -build/ -bld/ -[Bb]in/ -[Oo]bj/ - -# Visual Studio 2015 cache/options directory -.vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUNIT -*.VisualState.xml -TestResult.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# DNX -project.lock.json -artifacts/ - -*_i.c -*_p.c -*_i.h -*.ilk -*.meta -*.obj -*.pch -*.pdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# JustCode is a .NET coding add-in -.JustCode - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# TODO: Comment the next line if you want to checkin your web deploy settings -# but database connection strings (with potential passwords) will be unencrypted -*.pubxml -*.publishproj - -# NuGet Packages -*.nupkg -# The packages folder can be ignored because of Package Restore -**/packages/* -# except build/, which is used as an MSBuild target. -!**/packages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/packages/repositories.config - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Microsoft Azure ApplicationInsights config file -ApplicationInsights.config - -# Windows Store app package directory -AppPackages/ -BundleArtifacts/ - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.pfx -*.publishsettings -node_modules/ -orleans.codegen.cs - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm - -# SQL Server files -*.mdf -*.ldf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# Paket dependency manager -.paket/paket.exe - -# FAKE - F# Make -.fake/ From 4f2d94ceba0ddc71c4754fda28e46100f9cc1ab5 Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Fri, 8 Jul 2016 19:33:22 +0100 Subject: [PATCH 005/183] method to match urls and template urls --- .../Infrastructure/Router/IRouterService.cs | 10 - .../Router/InMemoryRouterService.cs | 41 --- .../Infrastructure/Router/Route.cs | 14 -- .../Router/RouteKeyAlreadyExists.cs | 12 - .../Router/RouteKeyDoesNotExist.cs | 12 - .../Router/UpstreamRouter/IUpstreamRouter.cs | 10 + .../UpstreamRouter/InMemoryUpstreamRouter.cs | 38 +++ .../Router/UpstreamRouter/Route.cs | 14 ++ .../UpstreamRouter/RouteKeyAlreadyExists.cs | 12 + .../UpstreamRouter/RouteKeyDoesNotExist.cs | 12 + .../DownstreamUrlPathAlreadyExists.cs | 12 + .../DownstreamUrlPathDoesNotExist.cs | 12 + .../Router/UrlPathRouter/IUrlPathRouter.cs | 10 + .../UrlPathRouter/InMemoryUrlPathRouter.cs | 38 +++ .../Router/UrlPathRouter/UrlPath.cs | 14 ++ test/Ocelot.AcceptanceTests/.gitignore | 234 ++++++++++++++++++ test/Ocelot.AcceptanceTests/RouterTests.cs | 24 ++ test/Ocelot.AcceptanceTests/project.json | 37 +++ ...{RouterTests.cs => UpstreamRouterTests.cs} | 14 +- test/Ocelot.UnitTests/UrlMapperTests.cs | 133 ++++++++++ test/Ocelot.UnitTests/UrlPathRouterTests.cs | 111 +++++++++ 21 files changed, 718 insertions(+), 96 deletions(-) delete mode 100644 src/Ocelot.Library/Infrastructure/Router/IRouterService.cs delete mode 100644 src/Ocelot.Library/Infrastructure/Router/InMemoryRouterService.cs delete mode 100644 src/Ocelot.Library/Infrastructure/Router/Route.cs delete mode 100644 src/Ocelot.Library/Infrastructure/Router/RouteKeyAlreadyExists.cs delete mode 100644 src/Ocelot.Library/Infrastructure/Router/RouteKeyDoesNotExist.cs create mode 100644 src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/IUpstreamRouter.cs create mode 100644 src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/InMemoryUpstreamRouter.cs create mode 100644 src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/Route.cs create mode 100644 src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/RouteKeyAlreadyExists.cs create mode 100644 src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/RouteKeyDoesNotExist.cs create mode 100644 src/Ocelot.Library/Infrastructure/Router/UrlPathRouter/DownstreamUrlPathAlreadyExists.cs create mode 100644 src/Ocelot.Library/Infrastructure/Router/UrlPathRouter/DownstreamUrlPathDoesNotExist.cs create mode 100644 src/Ocelot.Library/Infrastructure/Router/UrlPathRouter/IUrlPathRouter.cs create mode 100644 src/Ocelot.Library/Infrastructure/Router/UrlPathRouter/InMemoryUrlPathRouter.cs create mode 100644 src/Ocelot.Library/Infrastructure/Router/UrlPathRouter/UrlPath.cs create mode 100644 test/Ocelot.AcceptanceTests/.gitignore create mode 100644 test/Ocelot.AcceptanceTests/RouterTests.cs create mode 100644 test/Ocelot.AcceptanceTests/project.json rename test/Ocelot.UnitTests/{RouterTests.cs => UpstreamRouterTests.cs} (90%) create mode 100644 test/Ocelot.UnitTests/UrlMapperTests.cs create mode 100644 test/Ocelot.UnitTests/UrlPathRouterTests.cs diff --git a/src/Ocelot.Library/Infrastructure/Router/IRouterService.cs b/src/Ocelot.Library/Infrastructure/Router/IRouterService.cs deleted file mode 100644 index 61f7b48d..00000000 --- a/src/Ocelot.Library/Infrastructure/Router/IRouterService.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.Router -{ - public interface IRouterService - { - Response AddRoute(string apiKey, string upstreamApiBaseUrl); - Response GetRoute(string apiKey); - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Router/InMemoryRouterService.cs b/src/Ocelot.Library/Infrastructure/Router/InMemoryRouterService.cs deleted file mode 100644 index d3e73746..00000000 --- a/src/Ocelot.Library/Infrastructure/Router/InMemoryRouterService.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.Collections.Generic; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.Router -{ - public class InMemoryRouterService : IRouterService - { - private readonly Dictionary _routes; - public InMemoryRouterService() - { - _routes = new Dictionary(); - } - public Response AddRoute(string apiKey, string upstreamApiBaseUrl) - { - if(_routes.ContainsKey(apiKey)) - { - return new ErrorResponse(new List(){new RouteKeyAlreadyExists("This key has already been used")}); - } - - _routes.Add(apiKey, upstreamApiBaseUrl); - - return new OkResponse(); - } - - public Response GetRoute(string apiKey) - { - Console.WriteLine("looking for {0}", apiKey); - string upstreamApiBaseUrl = null; - - if(_routes.TryGetValue(apiKey, out upstreamApiBaseUrl)) - { - return new OkResponse(new Route(apiKey, upstreamApiBaseUrl)); - } - - Console.WriteLine("Couldnt find it"); - - return new ErrorResponse(new List(){new RouteKeyDoesNotExist("This key does not exist")}); - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Router/Route.cs b/src/Ocelot.Library/Infrastructure/Router/Route.cs deleted file mode 100644 index f76f6173..00000000 --- a/src/Ocelot.Library/Infrastructure/Router/Route.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Ocelot.Library.Infrastructure.Router -{ - public class Route - { - public Route(string apiKey, string upstreamRoute) - { - ApiKey = apiKey; - UpstreamRoute = upstreamRoute; - } - - public string ApiKey {get;private set;} - public string UpstreamRoute {get;private set;} - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Router/RouteKeyAlreadyExists.cs b/src/Ocelot.Library/Infrastructure/Router/RouteKeyAlreadyExists.cs deleted file mode 100644 index 1ae13795..00000000 --- a/src/Ocelot.Library/Infrastructure/Router/RouteKeyAlreadyExists.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.Router -{ - public class RouteKeyAlreadyExists : Error - { - public RouteKeyAlreadyExists(string message) - : base(message) - { - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Router/RouteKeyDoesNotExist.cs b/src/Ocelot.Library/Infrastructure/Router/RouteKeyDoesNotExist.cs deleted file mode 100644 index f38aea5e..00000000 --- a/src/Ocelot.Library/Infrastructure/Router/RouteKeyDoesNotExist.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.Router -{ - public class RouteKeyDoesNotExist : Error - { - public RouteKeyDoesNotExist(string message) - : base(message) - { - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/IUpstreamRouter.cs b/src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/IUpstreamRouter.cs new file mode 100644 index 00000000..25323b8b --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/IUpstreamRouter.cs @@ -0,0 +1,10 @@ +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.Router.UpstreamRouter +{ + public interface IUpstreamRouter + { + Response AddRoute(string downstreamUrl, string upstreamUrl); + Response GetRoute(string downstreamUrl); + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/InMemoryUpstreamRouter.cs b/src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/InMemoryUpstreamRouter.cs new file mode 100644 index 00000000..7767dc41 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/InMemoryUpstreamRouter.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.Router.UpstreamRouter +{ + public class InMemoryUpstreamRouter : IUpstreamRouter + { + private readonly Dictionary _routes; + public InMemoryUpstreamRouter() + { + _routes = new Dictionary(); + } + public Response AddRoute(string downstreamUrl, string upstreamUrl) + { + if(_routes.ContainsKey(downstreamUrl)) + { + return new ErrorResponse(new List(){new RouteKeyAlreadyExists()}); + } + + _routes.Add(downstreamUrl, upstreamUrl); + + return new OkResponse(); + } + + public Response GetRoute(string downstreamUrl) + { + string upstreamUrl = null; + + if(_routes.TryGetValue(downstreamUrl, out upstreamUrl)) + { + return new OkResponse(new Route(downstreamUrl, upstreamUrl)); + } + + return new ErrorResponse(new List(){new RouteKeyDoesNotExist()}); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/Route.cs b/src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/Route.cs new file mode 100644 index 00000000..6b14d307 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/Route.cs @@ -0,0 +1,14 @@ +namespace Ocelot.Library.Infrastructure.Router.UpstreamRouter +{ + public class Route + { + public Route(string downstreamUrl, string upstreamUrl) + { + DownstreamUrl = downstreamUrl; + UpstreamUrl = upstreamUrl; + } + + public string DownstreamUrl {get;private set;} + public string UpstreamUrl {get;private set;} + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/RouteKeyAlreadyExists.cs b/src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/RouteKeyAlreadyExists.cs new file mode 100644 index 00000000..19a436cc --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/RouteKeyAlreadyExists.cs @@ -0,0 +1,12 @@ +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.Router.UpstreamRouter +{ + public class RouteKeyAlreadyExists : Error + { + public RouteKeyAlreadyExists() + : base("This key has already been used") + { + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/RouteKeyDoesNotExist.cs b/src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/RouteKeyDoesNotExist.cs new file mode 100644 index 00000000..fe4c90ba --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/RouteKeyDoesNotExist.cs @@ -0,0 +1,12 @@ +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.Router.UpstreamRouter +{ + public class RouteKeyDoesNotExist : Error + { + public RouteKeyDoesNotExist() + : base("This key does not exist") + { + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Router/UrlPathRouter/DownstreamUrlPathAlreadyExists.cs b/src/Ocelot.Library/Infrastructure/Router/UrlPathRouter/DownstreamUrlPathAlreadyExists.cs new file mode 100644 index 00000000..3dc099a7 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Router/UrlPathRouter/DownstreamUrlPathAlreadyExists.cs @@ -0,0 +1,12 @@ +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.Router.UrlPathRouter +{ + public class DownstreamUrlPathTemplateAlreadyExists : Error + { + public DownstreamUrlPathTemplateAlreadyExists() + : base("This key has already been used") + { + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Router/UrlPathRouter/DownstreamUrlPathDoesNotExist.cs b/src/Ocelot.Library/Infrastructure/Router/UrlPathRouter/DownstreamUrlPathDoesNotExist.cs new file mode 100644 index 00000000..4c05e3d2 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Router/UrlPathRouter/DownstreamUrlPathDoesNotExist.cs @@ -0,0 +1,12 @@ +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.Router.UrlPathRouter +{ + public class DownstreamUrlPathTemplateDoesNotExist : Error + { + public DownstreamUrlPathTemplateDoesNotExist() + : base("This key does not exist") + { + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Router/UrlPathRouter/IUrlPathRouter.cs b/src/Ocelot.Library/Infrastructure/Router/UrlPathRouter/IUrlPathRouter.cs new file mode 100644 index 00000000..c39be36b --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Router/UrlPathRouter/IUrlPathRouter.cs @@ -0,0 +1,10 @@ +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.Router.UrlPathRouter +{ + public interface IUrlPathRouter + { + Response AddRoute(string downstreamUrlPathTemplate, string upstreamUrlPathTemplate); + Response GetRoute(string downstreamUrlPathTemplate); + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Router/UrlPathRouter/InMemoryUrlPathRouter.cs b/src/Ocelot.Library/Infrastructure/Router/UrlPathRouter/InMemoryUrlPathRouter.cs new file mode 100644 index 00000000..73c358f2 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Router/UrlPathRouter/InMemoryUrlPathRouter.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.Router.UrlPathRouter +{ + public class InMemoryUrlPathRouter : IUrlPathRouter + { + private readonly Dictionary _routes; + public InMemoryUrlPathRouter() + { + _routes = new Dictionary(); + } + public Response AddRoute(string downstreamUrlPathTemplate, string upstreamUrlPathTemplate) + { + if(_routes.ContainsKey(downstreamUrlPathTemplate)) + { + return new ErrorResponse(new List(){new DownstreamUrlPathTemplateAlreadyExists()}); + } + + _routes.Add(downstreamUrlPathTemplate, upstreamUrlPathTemplate); + + return new OkResponse(); + } + + public Response GetRoute(string downstreamUrlPathTemplate) + { + string upstreamUrlPathTemplate = null; + + if(_routes.TryGetValue(downstreamUrlPathTemplate, out upstreamUrlPathTemplate)) + { + return new OkResponse(new UrlPath(downstreamUrlPathTemplate, upstreamUrlPathTemplate)); + } + + return new ErrorResponse(new List(){new DownstreamUrlPathTemplateDoesNotExist()}); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Router/UrlPathRouter/UrlPath.cs b/src/Ocelot.Library/Infrastructure/Router/UrlPathRouter/UrlPath.cs new file mode 100644 index 00000000..b1ea65aa --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Router/UrlPathRouter/UrlPath.cs @@ -0,0 +1,14 @@ +namespace Ocelot.Library.Infrastructure.Router.UrlPathRouter +{ + public class UrlPath + { + public UrlPath(string downstreamUrlPathTemplate, string upstreamUrlPathTemplate) + { + DownstreamUrlPathTemplate = downstreamUrlPathTemplate; + UpstreamUrlPathTemplate = upstreamUrlPathTemplate; + } + + public string DownstreamUrlPathTemplate {get;private set;} + public string UpstreamUrlPathTemplate {get;private set;} + } +} \ No newline at end of file diff --git a/test/Ocelot.AcceptanceTests/.gitignore b/test/Ocelot.AcceptanceTests/.gitignore new file mode 100644 index 00000000..0ca27f04 --- /dev/null +++ b/test/Ocelot.AcceptanceTests/.gitignore @@ -0,0 +1,234 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +build/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Microsoft Azure ApplicationInsights config file +ApplicationInsights.config + +# Windows Store app package directory +AppPackages/ +BundleArtifacts/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe + +# FAKE - F# Make +.fake/ diff --git a/test/Ocelot.AcceptanceTests/RouterTests.cs b/test/Ocelot.AcceptanceTests/RouterTests.cs new file mode 100644 index 00000000..43dc2e4d --- /dev/null +++ b/test/Ocelot.AcceptanceTests/RouterTests.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting; +using Ocelot; +using Xunit; + +namespace Ocelot.AcceptanceTests +{ + public class RouterTests + { + public RouterTests() + { + } + + [Fact] + public void should_route_request() + { + + } + } +} diff --git a/test/Ocelot.AcceptanceTests/project.json b/test/Ocelot.AcceptanceTests/project.json new file mode 100644 index 00000000..da9f68a7 --- /dev/null +++ b/test/Ocelot.AcceptanceTests/project.json @@ -0,0 +1,37 @@ +{ + "version": "1.0.0-*", + + "testRunner": "xunit", + + "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.0.0", + "type": "platform" + }, + "Microsoft.AspNetCore.Mvc": "1.0.0", + "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", + "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", + "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0", + "Microsoft.Extensions.Configuration.Json": "1.0.0", + "Microsoft.Extensions.Logging": "1.0.0", + "Microsoft.Extensions.Logging.Console": "1.0.0", + "Microsoft.Extensions.Logging.Debug": "1.0.0", + "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", + "Microsoft.AspNetCore.Http": "1.0.0", + "Ocelot.Library": "1.0.0-*", + "Ocelot": "1.0.0-*", + "xunit": "2.1.0", + "dotnet-test-xunit": "2.2.0-preview2-build1029", + "Shouldly": "2.8.0" + }, + + "frameworks": { + "netcoreapp1.0": { + "imports": [ + "dotnet5.6", + "portable-net45+win8" + ] + } + } +} diff --git a/test/Ocelot.UnitTests/RouterTests.cs b/test/Ocelot.UnitTests/UpstreamRouterTests.cs similarity index 90% rename from test/Ocelot.UnitTests/RouterTests.cs rename to test/Ocelot.UnitTests/UpstreamRouterTests.cs index e9f32823..e2060f6e 100644 --- a/test/Ocelot.UnitTests/RouterTests.cs +++ b/test/Ocelot.UnitTests/UpstreamRouterTests.cs @@ -1,5 +1,5 @@ using Ocelot.Library.Infrastructure.Responses; -using Ocelot.Library.Infrastructure.Router; +using Ocelot.Library.Infrastructure.Router.UpstreamRouter; using Shouldly; using Xunit; @@ -9,13 +9,13 @@ namespace Ocelot.UnitTests { private string _upstreamApiUrl; private string _apiKey; - private IRouterService _router; + private IUpstreamRouter _router; private Response _response; private Response _getRouteResponse; - public RouterTests() + public RouterTests() { - _router = new InMemoryRouterService(); + _router = new InMemoryUpstreamRouter(); } [Fact] @@ -34,7 +34,7 @@ namespace Ocelot.UnitTests WhenIRetrieveTheRouteByKey(); ThenTheRouteIsReturned(); } - + [Fact] public void should_return_error_response_when_key_already_used() { @@ -77,8 +77,8 @@ namespace Ocelot.UnitTests private void ThenTheRouteIsReturned() { - _getRouteResponse.Data.ApiKey.ShouldBe(_apiKey); - _getRouteResponse.Data.UpstreamRoute.ShouldBe(_upstreamApiUrl); + _getRouteResponse.Data.DownstreamUrl.ShouldBe(_apiKey); + _getRouteResponse.Data.UpstreamUrl.ShouldBe(_upstreamApiUrl); } private void GivenIHaveSetUpAnApiKeyAndUpstreamUrl(string apiKey, string upstreamUrl) diff --git a/test/Ocelot.UnitTests/UrlMapperTests.cs b/test/Ocelot.UnitTests/UrlMapperTests.cs new file mode 100644 index 00000000..b35d9933 --- /dev/null +++ b/test/Ocelot.UnitTests/UrlMapperTests.cs @@ -0,0 +1,133 @@ +using System; +using Ocelot.Library.Infrastructure.Responses; +using Ocelot.Library.Infrastructure.Router.UpstreamRouter; +using Shouldly; +using Xunit; + +namespace Ocelot.UnitTests +{ + public class UrlMapperTests + { + private UrlToUrlTemplateMatcher _urlMapper; + + public UrlMapperTests() + { + _urlMapper = new UrlToUrlTemplateMatcher(); + } + + [Fact] + public void can_match_down_stream_url_with_downstream_template_with_one_query_string_parameter() + { + var downstreamUrl = "api/product/products/?soldout=false"; + var downstreamTemplate = "api/product/products/"; + var result = _urlMapper.Match(downstreamUrl, downstreamTemplate); + result.ShouldBeTrue(); + } + + [Fact] + public void can_match_down_stream_url_with_downstream_template_with_one_query_string_parameter_and_one_template() + { + var downstreamUrl = "api/product/products/1/variants/?soldout=false"; + var downstreamTemplate = "api/product/products/{productId}/variants/"; + var result = _urlMapper.Match(downstreamUrl, downstreamTemplate); + result.ShouldBeTrue(); + } + + [Fact] + public void can_match_down_stream_url_with_downstream_template_with_one_place_holder() + { + var downstreamUrl = "api/product/products/1"; + var downstreamTemplate = "api/product/products/{productId}"; + var result = _urlMapper.Match(downstreamUrl, downstreamTemplate); + result.ShouldBeTrue(); + } + + [Fact] + public void can_match_down_stream_url_with_downstream_template_with_two_place_holders() + { + var downstreamUrl = "api/product/products/1/2"; + var downstreamTemplate = "api/product/products/{productId}/{categoryId}"; + var result = _urlMapper.Match(downstreamUrl, downstreamTemplate); + result.ShouldBeTrue(); + } + + [Fact] + public void can_match_down_stream_url_with_downstream_template_with_two_place_holders_seperated_by_something() + { + var downstreamUrl = "api/product/products/1/categories/2"; + var downstreamTemplate = "api/product/products/{productId}/categories/{categoryId}"; + var result = _urlMapper.Match(downstreamUrl, downstreamTemplate); + result.ShouldBeTrue(); + } + + [Fact] + public void can_match_down_stream_url_with_downstream_template_with_three_place_holders_seperated_by_something() + { + var downstreamUrl = "api/product/products/1/categories/2/variant/123"; + var downstreamTemplate = "api/product/products/{productId}/categories/{categoryId}/variant/{variantId}"; + var result = _urlMapper.Match(downstreamUrl, downstreamTemplate); + result.ShouldBeTrue(); + } + + [Fact] + public void can_match_down_stream_url_with_downstream_template_with_three_place_holders() + { + var downstreamUrl = "api/product/products/1/categories/2/variant/"; + var downstreamTemplate = "api/product/products/{productId}/categories/{categoryId}/variant/"; + var result = _urlMapper.Match(downstreamUrl, downstreamTemplate); + result.ShouldBeTrue(); + } + } + + public class UrlToUrlTemplateMatcher + { + public bool Match(string url, string urlTemplate) + { + url = url.ToLower(); + + urlTemplate = urlTemplate.ToLower(); + + int counterForUrl = 0; + + for (int counterForTemplate = 0; counterForTemplate < urlTemplate.Length; counterForTemplate++) + { + if (CharactersDontMatch(urlTemplate[counterForTemplate], url[counterForUrl]) && ContinueScanningUrl(counterForUrl,url.Length)) + { + if (IsPlaceholder(urlTemplate[counterForTemplate])) + { + counterForTemplate = GetNextCounterPosition(urlTemplate, counterForTemplate, '}'); + counterForUrl = GetNextCounterPosition(url, counterForUrl, '/'); + continue; + } + else + { + return false; + } + } + counterForUrl++; + } + return true; + } + + private int GetNextCounterPosition(string urlTemplate, int counterForTemplate, char delimiter) + { + var closingPlaceHolderPositionOnTemplate = urlTemplate.IndexOf(delimiter, counterForTemplate); + return closingPlaceHolderPositionOnTemplate + 1; + } + + private bool CharactersDontMatch(char characterOne, char characterTwo) + { + return characterOne != characterTwo; + } + + private bool ContinueScanningUrl(int counterForUrl, int urlLength) + { + return counterForUrl < urlLength; + } + + private bool IsPlaceholder(char character) + { + return character == '{'; + } + } +} \ No newline at end of file diff --git a/test/Ocelot.UnitTests/UrlPathRouterTests.cs b/test/Ocelot.UnitTests/UrlPathRouterTests.cs new file mode 100644 index 00000000..73cdc06e --- /dev/null +++ b/test/Ocelot.UnitTests/UrlPathRouterTests.cs @@ -0,0 +1,111 @@ +using Ocelot.Library.Infrastructure.Responses; +using Ocelot.Library.Infrastructure.Router.UrlPathRouter; +using Shouldly; +using Xunit; + +namespace Ocelot.UnitTests +{ + public class UrlPathRouterTests + { + private string _upstreamUrlPath; + private string _downstreamUrlPath; + private IUrlPathRouter _router; + private Response _response; + private Response _getResponse; + + public UrlPathRouterTests() + { + _router = new InMemoryUrlPathRouter(); + } + + [Fact] + public void can_add_url_path() + { + GivenIHaveAnUpstreamUrlPath("api/products/products/{productId}"); + GivenIWantToRouteRequestsToMyUpstreamUrlPath("api/products/{productId}"); + WhenIAddTheConfiguration(); + ThenTheResponseIsSuccesful(); + } + + [Fact] + public void can_get_url_path() + { + GivenIHaveSetUpADownstreamUrlPathAndAnUpstreamUrlPath("api2", "http://www.someapi.com/api2"); + WhenIRetrieveTheUrlPathByDownstreamUrl(); + ThenTheUrlPathIsReturned(); + } + + [Fact] + public void should_return_error_response_when_url_path_already_used() + { + GivenIHaveSetUpADownstreamUrlPathAndAnUpstreamUrlPath("api2", "http://www.someapi.com/api2"); + WhenITryToUseTheSameDownstreamUrl(); + ThenTheDownstreamUrlAlreadyBeenUsed(); + } + + [Fact] + public void should_return_error_response_if_key_doesnt_exist() + { + GivenIWantToRouteRequestsToMyUpstreamUrlPath("api"); + WhenIRetrieveTheUrlPathByDownstreamUrl(); + ThenTheKeyDoesNotExist(); + } + + private void WhenITryToUseTheSameDownstreamUrl() + { + WhenIAddTheConfiguration(); + } + + private void ThenTheDownstreamUrlAlreadyBeenUsed() + { + _response.ShouldNotBeNull(); + _response.ShouldBeOfType(); + _response.Errors[0].Message.ShouldBe("This key has already been used"); + } + + private void ThenTheKeyDoesNotExist() + { + _getResponse.ShouldNotBeNull(); + _getResponse.ShouldBeOfType>(); + _getResponse.Errors[0].Message.ShouldBe("This key does not exist"); + } + + private void WhenIRetrieveTheUrlPathByDownstreamUrl() + { + _getResponse = _router.GetRoute(_downstreamUrlPath); + } + + private void ThenTheUrlPathIsReturned() + { + _getResponse.Data.DownstreamUrlPathTemplate.ShouldBe(_downstreamUrlPath); + _getResponse.Data.UpstreamUrlPathTemplate.ShouldBe(_upstreamUrlPath); + } + + private void GivenIHaveSetUpADownstreamUrlPathAndAnUpstreamUrlPath(string downstream, string upstreamApiUrl) + { + GivenIHaveAnUpstreamUrlPath(upstreamApiUrl); + GivenIWantToRouteRequestsToMyUpstreamUrlPath(downstream); + WhenIAddTheConfiguration(); + } + + private void GivenIHaveAnUpstreamUrlPath(string upstreamApiUrl) + { + _upstreamUrlPath = upstreamApiUrl; + } + + private void GivenIWantToRouteRequestsToMyUpstreamUrlPath(string apiKey) + { + _downstreamUrlPath = apiKey; + } + + private void WhenIAddTheConfiguration() + { + _response = _router.AddRoute(_downstreamUrlPath, _upstreamUrlPath); + } + + private void ThenTheResponseIsSuccesful() + { + _response.ShouldBeOfType(); + } + } +} \ No newline at end of file From 4ca1dc8846b85df73800d39374d9c0ecc93f50ac Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Sun, 10 Jul 2016 15:51:13 +0100 Subject: [PATCH 006/183] working state --- .../IUrlPathToUrlPathTemplateMatcher.cs | 7 +++ .../UrlPathToUrlPathTemplateMatcher.cs | 54 ++++++++++++++++ src/Ocelot/Startup.cs | 1 + ...> UrlPathToUrlPathTemplateMatcherTests.cs} | 61 ++----------------- 4 files changed, 67 insertions(+), 56 deletions(-) create mode 100644 src/Ocelot.Library/Infrastructure/Router/UrlPathMatcher/IUrlPathToUrlPathTemplateMatcher.cs create mode 100644 src/Ocelot.Library/Infrastructure/Router/UrlPathMatcher/UrlPathToUrlPathTemplateMatcher.cs rename test/Ocelot.UnitTests/{UrlMapperTests.cs => UrlPathToUrlPathTemplateMatcherTests.cs} (61%) diff --git a/src/Ocelot.Library/Infrastructure/Router/UrlPathMatcher/IUrlPathToUrlPathTemplateMatcher.cs b/src/Ocelot.Library/Infrastructure/Router/UrlPathMatcher/IUrlPathToUrlPathTemplateMatcher.cs new file mode 100644 index 00000000..5fb89c15 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Router/UrlPathMatcher/IUrlPathToUrlPathTemplateMatcher.cs @@ -0,0 +1,7 @@ +namespace Ocelot.Library.Infrastructure.Router.UrlPathMatcher +{ + public interface IUrlPathToUrlPathTemplateMatcher + { + bool Match(string urlPath, string urlPathTemplate); + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Router/UrlPathMatcher/UrlPathToUrlPathTemplateMatcher.cs b/src/Ocelot.Library/Infrastructure/Router/UrlPathMatcher/UrlPathToUrlPathTemplateMatcher.cs new file mode 100644 index 00000000..fb543fb3 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Router/UrlPathMatcher/UrlPathToUrlPathTemplateMatcher.cs @@ -0,0 +1,54 @@ +namespace Ocelot.Library.Infrastructure.Router.UrlPathMatcher +{ + public class UrlPathToUrlPathTemplateMatcher : IUrlPathToUrlPathTemplateMatcher + { + public bool Match(string urlPath, string urlPathTemplate) + { + urlPath = urlPath.ToLower(); + + urlPathTemplate = urlPathTemplate.ToLower(); + + int counterForUrl = 0; + + for (int counterForTemplate = 0; counterForTemplate < urlPathTemplate.Length; counterForTemplate++) + { + if (CharactersDontMatch(urlPathTemplate[counterForTemplate], urlPath[counterForUrl]) && ContinueScanningUrl(counterForUrl,urlPath.Length)) + { + if (IsPlaceholder(urlPathTemplate[counterForTemplate])) + { + counterForTemplate = GetNextCounterPosition(urlPathTemplate, counterForTemplate, '}'); + counterForUrl = GetNextCounterPosition(urlPath, counterForUrl, '/'); + continue; + } + else + { + return false; + } + } + counterForUrl++; + } + return true; + } + + private int GetNextCounterPosition(string urlTemplate, int counterForTemplate, char delimiter) + { + var closingPlaceHolderPositionOnTemplate = urlTemplate.IndexOf(delimiter, counterForTemplate); + return closingPlaceHolderPositionOnTemplate + 1; + } + + private bool CharactersDontMatch(char characterOne, char characterTwo) + { + return characterOne != characterTwo; + } + + private bool ContinueScanningUrl(int counterForUrl, int urlLength) + { + return counterForUrl < urlLength; + } + + private bool IsPlaceholder(char character) + { + return character == '{'; + } + } +} \ No newline at end of file diff --git a/src/Ocelot/Startup.cs b/src/Ocelot/Startup.cs index 990e0cd5..8d284c04 100644 --- a/src/Ocelot/Startup.cs +++ b/src/Ocelot/Startup.cs @@ -32,6 +32,7 @@ namespace Ocelot public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(Configuration.GetSection("Logging")); + loggerFactory.AddDebug(); app.Run(async context => diff --git a/test/Ocelot.UnitTests/UrlMapperTests.cs b/test/Ocelot.UnitTests/UrlPathToUrlPathTemplateMatcherTests.cs similarity index 61% rename from test/Ocelot.UnitTests/UrlMapperTests.cs rename to test/Ocelot.UnitTests/UrlPathToUrlPathTemplateMatcherTests.cs index b35d9933..b81bed68 100644 --- a/test/Ocelot.UnitTests/UrlMapperTests.cs +++ b/test/Ocelot.UnitTests/UrlPathToUrlPathTemplateMatcherTests.cs @@ -1,18 +1,19 @@ using System; using Ocelot.Library.Infrastructure.Responses; using Ocelot.Library.Infrastructure.Router.UpstreamRouter; +using Ocelot.Library.Infrastructure.Router.UrlPathMatcher; using Shouldly; using Xunit; namespace Ocelot.UnitTests { - public class UrlMapperTests + public class UrlPathToUrlPathTemplateMatcherTests { - private UrlToUrlTemplateMatcher _urlMapper; + private IUrlPathToUrlPathTemplateMatcher _urlMapper; - public UrlMapperTests() + public UrlPathToUrlPathTemplateMatcherTests() { - _urlMapper = new UrlToUrlTemplateMatcher(); + _urlMapper = new UrlPathToUrlPathTemplateMatcher(); } [Fact] @@ -78,56 +79,4 @@ namespace Ocelot.UnitTests result.ShouldBeTrue(); } } - - public class UrlToUrlTemplateMatcher - { - public bool Match(string url, string urlTemplate) - { - url = url.ToLower(); - - urlTemplate = urlTemplate.ToLower(); - - int counterForUrl = 0; - - for (int counterForTemplate = 0; counterForTemplate < urlTemplate.Length; counterForTemplate++) - { - if (CharactersDontMatch(urlTemplate[counterForTemplate], url[counterForUrl]) && ContinueScanningUrl(counterForUrl,url.Length)) - { - if (IsPlaceholder(urlTemplate[counterForTemplate])) - { - counterForTemplate = GetNextCounterPosition(urlTemplate, counterForTemplate, '}'); - counterForUrl = GetNextCounterPosition(url, counterForUrl, '/'); - continue; - } - else - { - return false; - } - } - counterForUrl++; - } - return true; - } - - private int GetNextCounterPosition(string urlTemplate, int counterForTemplate, char delimiter) - { - var closingPlaceHolderPositionOnTemplate = urlTemplate.IndexOf(delimiter, counterForTemplate); - return closingPlaceHolderPositionOnTemplate + 1; - } - - private bool CharactersDontMatch(char characterOne, char characterTwo) - { - return characterOne != characterTwo; - } - - private bool ContinueScanningUrl(int counterForUrl, int urlLength) - { - return counterForUrl < urlLength; - } - - private bool IsPlaceholder(char character) - { - return character == '{'; - } - } } \ No newline at end of file From 5b417ad466386c92298e1f4b77d9c1942fb9afb0 Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Sun, 10 Jul 2016 15:54:03 +0100 Subject: [PATCH 007/183] plugged in proxy and still working..not seeing weird error from earlier --- src/Ocelot/Startup.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Ocelot/Startup.cs b/src/Ocelot/Startup.cs index 8d284c04..83cc57a8 100644 --- a/src/Ocelot/Startup.cs +++ b/src/Ocelot/Startup.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Ocelot.Library.Middleware; namespace Ocelot { @@ -32,9 +33,11 @@ namespace Ocelot public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(Configuration.GetSection("Logging")); - + loggerFactory.AddDebug(); + app.UseProxy(); + app.Run(async context => { await context.Response.WriteAsync("Hello from Tom"); From 711a3d6a911a9c624c3ebe586806703568436d39 Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Sun, 10 Jul 2016 17:11:12 +0100 Subject: [PATCH 008/183] added a base url finder --- .vscode/launch.json | 49 +++++++++++++++++ .vscode/tasks.json | 17 ++++++ .../BaseUrlRepository/BaseUrlMap.cs | 14 +++++ .../BaseUrlMapKeyAlreadyExists.cs | 12 +++++ .../BaseUrlMapKeyDoesNotExist.cs | 12 +++++ .../IBaseUrlMapRepository.cs | 10 ++++ .../InMemoryBaseUrlMapRepository.cs | 37 +++++++++++++ .../Router/UpstreamRouter/IUpstreamRouter.cs | 10 ---- .../UpstreamRouter/InMemoryUpstreamRouter.cs | 38 ------------- .../Router/UpstreamRouter/Route.cs | 14 ----- .../UpstreamRouter/RouteKeyAlreadyExists.cs | 12 ----- .../UpstreamRouter/RouteKeyDoesNotExist.cs | 12 ----- .../Router/UrlPathRouter/IUrlPathRouter.cs | 10 ---- .../UrlPathRouter/InMemoryUrlPathRouter.cs | 38 ------------- .../UrlFinder/IUpstreamBaseUrlFinder.cs | 9 ++++ .../UrlFinder/UpstreamBaseUrlFinder.cs | 22 ++++++++ .../IUrlPathToUrlPathTemplateMatcher.cs | 2 +- .../UrlPathToUrlPathTemplateMatcher.cs | 2 +- .../DownstreamUrlPathAlreadyExists.cs | 2 +- .../DownstreamUrlPathDoesNotExist.cs | 2 +- .../DownstreamUrlPathAlreadyExists.cs | 12 +++++ .../DownstreamUrlPathDoesNotExist.cs | 12 +++++ .../IUrlPathTemplateMapRepository.cs | 10 ++++ .../InMemoryUrlPathTemplateMapRepository.cs | 38 +++++++++++++ .../UrlPathTemplateMap.cs} | 6 +-- ...rTests.cs => BaseUrlMapRepositoryTests.cs} | 50 ++++++++--------- .../UpstreamBaseUrlFinderTests.cs | 53 +++++++++++++++++++ ...s => UrlPathTemplateMapRepositoryTests.cs} | 30 +++++------ .../UrlPathToUrlPathTemplateMatcherTests.cs | 7 +-- 29 files changed, 356 insertions(+), 186 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 .vscode/tasks.json create mode 100644 src/Ocelot.Library/Infrastructure/BaseUrlRepository/BaseUrlMap.cs create mode 100644 src/Ocelot.Library/Infrastructure/BaseUrlRepository/BaseUrlMapKeyAlreadyExists.cs create mode 100644 src/Ocelot.Library/Infrastructure/BaseUrlRepository/BaseUrlMapKeyDoesNotExist.cs create mode 100644 src/Ocelot.Library/Infrastructure/BaseUrlRepository/IBaseUrlMapRepository.cs create mode 100644 src/Ocelot.Library/Infrastructure/BaseUrlRepository/InMemoryBaseUrlMapRepository.cs delete mode 100644 src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/IUpstreamRouter.cs delete mode 100644 src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/InMemoryUpstreamRouter.cs delete mode 100644 src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/Route.cs delete mode 100644 src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/RouteKeyAlreadyExists.cs delete mode 100644 src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/RouteKeyDoesNotExist.cs delete mode 100644 src/Ocelot.Library/Infrastructure/Router/UrlPathRouter/IUrlPathRouter.cs delete mode 100644 src/Ocelot.Library/Infrastructure/Router/UrlPathRouter/InMemoryUrlPathRouter.cs create mode 100644 src/Ocelot.Library/Infrastructure/UrlFinder/IUpstreamBaseUrlFinder.cs create mode 100644 src/Ocelot.Library/Infrastructure/UrlFinder/UpstreamBaseUrlFinder.cs rename src/Ocelot.Library/Infrastructure/{Router => }/UrlPathMatcher/IUrlPathToUrlPathTemplateMatcher.cs (68%) rename src/Ocelot.Library/Infrastructure/{Router => }/UrlPathMatcher/UrlPathToUrlPathTemplateMatcher.cs (96%) rename src/Ocelot.Library/Infrastructure/{Router/UrlPathRouter => UrlPathRepository}/DownstreamUrlPathAlreadyExists.cs (80%) rename src/Ocelot.Library/Infrastructure/{Router/UrlPathRouter => UrlPathRepository}/DownstreamUrlPathDoesNotExist.cs (80%) create mode 100644 src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/DownstreamUrlPathAlreadyExists.cs create mode 100644 src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/DownstreamUrlPathDoesNotExist.cs create mode 100644 src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/IUrlPathTemplateMapRepository.cs create mode 100644 src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/InMemoryUrlPathTemplateMapRepository.cs rename src/Ocelot.Library/Infrastructure/{Router/UrlPathRouter/UrlPath.cs => UrlPathTemplateRepository/UrlPathTemplateMap.cs} (59%) rename test/Ocelot.UnitTests/{UpstreamRouterTests.cs => BaseUrlMapRepositoryTests.cs} (55%) create mode 100644 test/Ocelot.UnitTests/UpstreamBaseUrlFinderTests.cs rename test/Ocelot.UnitTests/{UrlPathRouterTests.cs => UrlPathTemplateMapRepositoryTests.cs} (73%) diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..63dc596d --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,49 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": ".NET Core Launch (console)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + "program": "${workspaceRoot}/bin/Debug//", + "args": [], + "cwd": "${workspaceRoot}", + "stopAtEntry": false, + "externalConsole": false + }, + { + "name": ".NET Core Launch (web)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + "program": "${workspaceRoot}/src/Ocelot/bin/Debug/netcoreapp1.0/Ocelot.dll", + "args": [], + "cwd": "${workspaceRoot}", + "stopAtEntry": false, + "launchBrowser": { + "enabled": true, + "args": "${auto-detect-url}", + "windows": { + "command": "cmd.exe", + "args": "/C start ${auto-detect-url}" + }, + "osx": { + "command": "open" + }, + "linux": { + "command": "xdg-open" + } + }, + "env": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + { + "name": ".NET Core Attach", + "type": "coreclr", + "request": "attach", + "processId": 0 + } + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 00000000..33256db7 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,17 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "0.1.0", + "command": "dotnet", + "isShellCommand": true, + "args": [], + "tasks": [ + { + "taskName": "build", + "args": [ ], + "isBuildCommand": true, + "showOutput": "silent", + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/BaseUrlRepository/BaseUrlMap.cs b/src/Ocelot.Library/Infrastructure/BaseUrlRepository/BaseUrlMap.cs new file mode 100644 index 00000000..564bb26e --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/BaseUrlRepository/BaseUrlMap.cs @@ -0,0 +1,14 @@ +namespace Ocelot.Library.Infrastructure.BaseUrlRepository +{ + public class BaseUrlMap + { + public BaseUrlMap(string downstreamBaseUrl, string upstreamBaseUrl) + { + DownstreamBaseUrl = downstreamBaseUrl; + UpstreamBaseUrl = upstreamBaseUrl; + } + + public string DownstreamBaseUrl {get;private set;} + public string UpstreamBaseUrl {get;private set;} + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/BaseUrlRepository/BaseUrlMapKeyAlreadyExists.cs b/src/Ocelot.Library/Infrastructure/BaseUrlRepository/BaseUrlMapKeyAlreadyExists.cs new file mode 100644 index 00000000..91b4ae4a --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/BaseUrlRepository/BaseUrlMapKeyAlreadyExists.cs @@ -0,0 +1,12 @@ +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.BaseUrlRepository +{ + public class BaseUrlMapKeyAlreadyExists : Error + { + public BaseUrlMapKeyAlreadyExists() + : base("This key has already been used") + { + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/BaseUrlRepository/BaseUrlMapKeyDoesNotExist.cs b/src/Ocelot.Library/Infrastructure/BaseUrlRepository/BaseUrlMapKeyDoesNotExist.cs new file mode 100644 index 00000000..d8367abf --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/BaseUrlRepository/BaseUrlMapKeyDoesNotExist.cs @@ -0,0 +1,12 @@ +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.BaseUrlRepository +{ + public class BaseUrlMapKeyDoesNotExist : Error + { + public BaseUrlMapKeyDoesNotExist() + : base("This key does not exist") + { + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/BaseUrlRepository/IBaseUrlMapRepository.cs b/src/Ocelot.Library/Infrastructure/BaseUrlRepository/IBaseUrlMapRepository.cs new file mode 100644 index 00000000..2e76444d --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/BaseUrlRepository/IBaseUrlMapRepository.cs @@ -0,0 +1,10 @@ +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.BaseUrlRepository +{ + public interface IBaseUrlMapRepository + { + Response AddBaseUrlMap(BaseUrlMap baseUrlMap); + Response GetBaseUrlMap(string downstreamUrl); + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/BaseUrlRepository/InMemoryBaseUrlMapRepository.cs b/src/Ocelot.Library/Infrastructure/BaseUrlRepository/InMemoryBaseUrlMapRepository.cs new file mode 100644 index 00000000..d43fd23c --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/BaseUrlRepository/InMemoryBaseUrlMapRepository.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.BaseUrlRepository +{ + public class InMemoryBaseUrlMapRepository : IBaseUrlMapRepository + { + private readonly Dictionary _routes; + public InMemoryBaseUrlMapRepository() + { + _routes = new Dictionary(); + } + public Response AddBaseUrlMap(BaseUrlMap baseUrlMap) + { + if(_routes.ContainsKey(baseUrlMap.DownstreamBaseUrl)) + { + return new ErrorResponse(new List(){new BaseUrlMapKeyAlreadyExists()}); + } + + _routes.Add(baseUrlMap.DownstreamBaseUrl, baseUrlMap.UpstreamBaseUrl); + + return new OkResponse(); + } + + public Response GetBaseUrlMap(string downstreamUrl) + { + string upstreamUrl = null; + + if(_routes.TryGetValue(downstreamUrl, out upstreamUrl)) + { + return new OkResponse(new BaseUrlMap(downstreamUrl, upstreamUrl)); + } + + return new ErrorResponse(new List(){new BaseUrlMapKeyDoesNotExist()}); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/IUpstreamRouter.cs b/src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/IUpstreamRouter.cs deleted file mode 100644 index 25323b8b..00000000 --- a/src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/IUpstreamRouter.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.Router.UpstreamRouter -{ - public interface IUpstreamRouter - { - Response AddRoute(string downstreamUrl, string upstreamUrl); - Response GetRoute(string downstreamUrl); - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/InMemoryUpstreamRouter.cs b/src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/InMemoryUpstreamRouter.cs deleted file mode 100644 index 7767dc41..00000000 --- a/src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/InMemoryUpstreamRouter.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.Collections.Generic; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.Router.UpstreamRouter -{ - public class InMemoryUpstreamRouter : IUpstreamRouter - { - private readonly Dictionary _routes; - public InMemoryUpstreamRouter() - { - _routes = new Dictionary(); - } - public Response AddRoute(string downstreamUrl, string upstreamUrl) - { - if(_routes.ContainsKey(downstreamUrl)) - { - return new ErrorResponse(new List(){new RouteKeyAlreadyExists()}); - } - - _routes.Add(downstreamUrl, upstreamUrl); - - return new OkResponse(); - } - - public Response GetRoute(string downstreamUrl) - { - string upstreamUrl = null; - - if(_routes.TryGetValue(downstreamUrl, out upstreamUrl)) - { - return new OkResponse(new Route(downstreamUrl, upstreamUrl)); - } - - return new ErrorResponse(new List(){new RouteKeyDoesNotExist()}); - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/Route.cs b/src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/Route.cs deleted file mode 100644 index 6b14d307..00000000 --- a/src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/Route.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Ocelot.Library.Infrastructure.Router.UpstreamRouter -{ - public class Route - { - public Route(string downstreamUrl, string upstreamUrl) - { - DownstreamUrl = downstreamUrl; - UpstreamUrl = upstreamUrl; - } - - public string DownstreamUrl {get;private set;} - public string UpstreamUrl {get;private set;} - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/RouteKeyAlreadyExists.cs b/src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/RouteKeyAlreadyExists.cs deleted file mode 100644 index 19a436cc..00000000 --- a/src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/RouteKeyAlreadyExists.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.Router.UpstreamRouter -{ - public class RouteKeyAlreadyExists : Error - { - public RouteKeyAlreadyExists() - : base("This key has already been used") - { - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/RouteKeyDoesNotExist.cs b/src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/RouteKeyDoesNotExist.cs deleted file mode 100644 index fe4c90ba..00000000 --- a/src/Ocelot.Library/Infrastructure/Router/UpstreamRouter/RouteKeyDoesNotExist.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.Router.UpstreamRouter -{ - public class RouteKeyDoesNotExist : Error - { - public RouteKeyDoesNotExist() - : base("This key does not exist") - { - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Router/UrlPathRouter/IUrlPathRouter.cs b/src/Ocelot.Library/Infrastructure/Router/UrlPathRouter/IUrlPathRouter.cs deleted file mode 100644 index c39be36b..00000000 --- a/src/Ocelot.Library/Infrastructure/Router/UrlPathRouter/IUrlPathRouter.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.Router.UrlPathRouter -{ - public interface IUrlPathRouter - { - Response AddRoute(string downstreamUrlPathTemplate, string upstreamUrlPathTemplate); - Response GetRoute(string downstreamUrlPathTemplate); - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Router/UrlPathRouter/InMemoryUrlPathRouter.cs b/src/Ocelot.Library/Infrastructure/Router/UrlPathRouter/InMemoryUrlPathRouter.cs deleted file mode 100644 index 73c358f2..00000000 --- a/src/Ocelot.Library/Infrastructure/Router/UrlPathRouter/InMemoryUrlPathRouter.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.Collections.Generic; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.Router.UrlPathRouter -{ - public class InMemoryUrlPathRouter : IUrlPathRouter - { - private readonly Dictionary _routes; - public InMemoryUrlPathRouter() - { - _routes = new Dictionary(); - } - public Response AddRoute(string downstreamUrlPathTemplate, string upstreamUrlPathTemplate) - { - if(_routes.ContainsKey(downstreamUrlPathTemplate)) - { - return new ErrorResponse(new List(){new DownstreamUrlPathTemplateAlreadyExists()}); - } - - _routes.Add(downstreamUrlPathTemplate, upstreamUrlPathTemplate); - - return new OkResponse(); - } - - public Response GetRoute(string downstreamUrlPathTemplate) - { - string upstreamUrlPathTemplate = null; - - if(_routes.TryGetValue(downstreamUrlPathTemplate, out upstreamUrlPathTemplate)) - { - return new OkResponse(new UrlPath(downstreamUrlPathTemplate, upstreamUrlPathTemplate)); - } - - return new ErrorResponse(new List(){new DownstreamUrlPathTemplateDoesNotExist()}); - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlFinder/IUpstreamBaseUrlFinder.cs b/src/Ocelot.Library/Infrastructure/UrlFinder/IUpstreamBaseUrlFinder.cs new file mode 100644 index 00000000..c4623939 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/UrlFinder/IUpstreamBaseUrlFinder.cs @@ -0,0 +1,9 @@ +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.UrlFinder +{ + public interface IUpstreamBaseUrlFinder + { + Response FindUpstreamBaseUrl(string downstreamBaseUrl); + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlFinder/UpstreamBaseUrlFinder.cs b/src/Ocelot.Library/Infrastructure/UrlFinder/UpstreamBaseUrlFinder.cs new file mode 100644 index 00000000..135c8fcc --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/UrlFinder/UpstreamBaseUrlFinder.cs @@ -0,0 +1,22 @@ +using System; +using Ocelot.Library.Infrastructure.BaseUrlRepository; +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.UrlFinder +{ + public class UpstreamBaseUrlFinder : IUpstreamBaseUrlFinder + { + private readonly IBaseUrlMapRepository _baseUrlMapRepository; + + public UpstreamBaseUrlFinder(IBaseUrlMapRepository baseUrlMapRepository) + { + _baseUrlMapRepository = baseUrlMapRepository; + } + public Response FindUpstreamBaseUrl(string downstreamBaseUrl) + { + var baseUrl = _baseUrlMapRepository.GetBaseUrlMap(downstreamBaseUrl); + + return new OkResponse(baseUrl.Data.UpstreamBaseUrl); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Router/UrlPathMatcher/IUrlPathToUrlPathTemplateMatcher.cs b/src/Ocelot.Library/Infrastructure/UrlPathMatcher/IUrlPathToUrlPathTemplateMatcher.cs similarity index 68% rename from src/Ocelot.Library/Infrastructure/Router/UrlPathMatcher/IUrlPathToUrlPathTemplateMatcher.cs rename to src/Ocelot.Library/Infrastructure/UrlPathMatcher/IUrlPathToUrlPathTemplateMatcher.cs index 5fb89c15..7a617e13 100644 --- a/src/Ocelot.Library/Infrastructure/Router/UrlPathMatcher/IUrlPathToUrlPathTemplateMatcher.cs +++ b/src/Ocelot.Library/Infrastructure/UrlPathMatcher/IUrlPathToUrlPathTemplateMatcher.cs @@ -1,4 +1,4 @@ -namespace Ocelot.Library.Infrastructure.Router.UrlPathMatcher +namespace Ocelot.Library.Infrastructure.UrlPathMatcher { public interface IUrlPathToUrlPathTemplateMatcher { diff --git a/src/Ocelot.Library/Infrastructure/Router/UrlPathMatcher/UrlPathToUrlPathTemplateMatcher.cs b/src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathToUrlPathTemplateMatcher.cs similarity index 96% rename from src/Ocelot.Library/Infrastructure/Router/UrlPathMatcher/UrlPathToUrlPathTemplateMatcher.cs rename to src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathToUrlPathTemplateMatcher.cs index fb543fb3..04189704 100644 --- a/src/Ocelot.Library/Infrastructure/Router/UrlPathMatcher/UrlPathToUrlPathTemplateMatcher.cs +++ b/src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathToUrlPathTemplateMatcher.cs @@ -1,4 +1,4 @@ -namespace Ocelot.Library.Infrastructure.Router.UrlPathMatcher +namespace Ocelot.Library.Infrastructure.UrlPathMatcher { public class UrlPathToUrlPathTemplateMatcher : IUrlPathToUrlPathTemplateMatcher { diff --git a/src/Ocelot.Library/Infrastructure/Router/UrlPathRouter/DownstreamUrlPathAlreadyExists.cs b/src/Ocelot.Library/Infrastructure/UrlPathRepository/DownstreamUrlPathAlreadyExists.cs similarity index 80% rename from src/Ocelot.Library/Infrastructure/Router/UrlPathRouter/DownstreamUrlPathAlreadyExists.cs rename to src/Ocelot.Library/Infrastructure/UrlPathRepository/DownstreamUrlPathAlreadyExists.cs index 3dc099a7..efb3fc9e 100644 --- a/src/Ocelot.Library/Infrastructure/Router/UrlPathRouter/DownstreamUrlPathAlreadyExists.cs +++ b/src/Ocelot.Library/Infrastructure/UrlPathRepository/DownstreamUrlPathAlreadyExists.cs @@ -1,6 +1,6 @@ using Ocelot.Library.Infrastructure.Responses; -namespace Ocelot.Library.Infrastructure.Router.UrlPathRouter +namespace Ocelot.Library.Infrastructure.UrlPathRepository { public class DownstreamUrlPathTemplateAlreadyExists : Error { diff --git a/src/Ocelot.Library/Infrastructure/Router/UrlPathRouter/DownstreamUrlPathDoesNotExist.cs b/src/Ocelot.Library/Infrastructure/UrlPathRepository/DownstreamUrlPathDoesNotExist.cs similarity index 80% rename from src/Ocelot.Library/Infrastructure/Router/UrlPathRouter/DownstreamUrlPathDoesNotExist.cs rename to src/Ocelot.Library/Infrastructure/UrlPathRepository/DownstreamUrlPathDoesNotExist.cs index 4c05e3d2..47d1f768 100644 --- a/src/Ocelot.Library/Infrastructure/Router/UrlPathRouter/DownstreamUrlPathDoesNotExist.cs +++ b/src/Ocelot.Library/Infrastructure/UrlPathRepository/DownstreamUrlPathDoesNotExist.cs @@ -1,6 +1,6 @@ using Ocelot.Library.Infrastructure.Responses; -namespace Ocelot.Library.Infrastructure.Router.UrlPathRouter +namespace Ocelot.Library.Infrastructure.UrlPathRepository { public class DownstreamUrlPathTemplateDoesNotExist : Error { diff --git a/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/DownstreamUrlPathAlreadyExists.cs b/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/DownstreamUrlPathAlreadyExists.cs new file mode 100644 index 00000000..05a552ac --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/DownstreamUrlPathAlreadyExists.cs @@ -0,0 +1,12 @@ +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.UrlPathTemplateRepository +{ + public class DownstreamUrlPathTemplateAlreadyExists : Error + { + public DownstreamUrlPathTemplateAlreadyExists() + : base("This key has already been used") + { + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/DownstreamUrlPathDoesNotExist.cs b/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/DownstreamUrlPathDoesNotExist.cs new file mode 100644 index 00000000..7d89beeb --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/DownstreamUrlPathDoesNotExist.cs @@ -0,0 +1,12 @@ +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.UrlPathTemplateRepository +{ + public class DownstreamUrlPathTemplateDoesNotExist : Error + { + public DownstreamUrlPathTemplateDoesNotExist() + : base("This key does not exist") + { + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/IUrlPathTemplateMapRepository.cs b/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/IUrlPathTemplateMapRepository.cs new file mode 100644 index 00000000..f847c7ba --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/IUrlPathTemplateMapRepository.cs @@ -0,0 +1,10 @@ +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.UrlPathTemplateRepository +{ + public interface IUrlPathTemplateMapRepository + { + Response AddUrlPathTemplateMap(UrlPathTemplateMap urlPathMap); + Response GetUrlPathTemplateMap(string downstreamUrlPathTemplate); + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/InMemoryUrlPathTemplateMapRepository.cs b/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/InMemoryUrlPathTemplateMapRepository.cs new file mode 100644 index 00000000..257f1d3f --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/InMemoryUrlPathTemplateMapRepository.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.UrlPathTemplateRepository +{ + public class InMemoryUrlPathTemplateMapRepository : IUrlPathTemplateMapRepository + { + private readonly Dictionary _routes; + public InMemoryUrlPathTemplateMapRepository() + { + _routes = new Dictionary(); + } + public Response AddUrlPathTemplateMap(UrlPathTemplateMap urlPathMap) + { + if(_routes.ContainsKey(urlPathMap.DownstreamUrlPathTemplate)) + { + return new ErrorResponse(new List(){new DownstreamUrlPathTemplateAlreadyExists()}); + } + + _routes.Add(urlPathMap.DownstreamUrlPathTemplate, urlPathMap.UpstreamUrlPathTemplate); + + return new OkResponse(); + } + + public Response GetUrlPathTemplateMap(string downstreamUrlPathTemplate) + { + string upstreamUrlPathTemplate = null; + + if(_routes.TryGetValue(downstreamUrlPathTemplate, out upstreamUrlPathTemplate)) + { + return new OkResponse(new UrlPathTemplateMap(downstreamUrlPathTemplate, upstreamUrlPathTemplate)); + } + + return new ErrorResponse(new List(){new DownstreamUrlPathTemplateDoesNotExist()}); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Router/UrlPathRouter/UrlPath.cs b/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/UrlPathTemplateMap.cs similarity index 59% rename from src/Ocelot.Library/Infrastructure/Router/UrlPathRouter/UrlPath.cs rename to src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/UrlPathTemplateMap.cs index b1ea65aa..1471813c 100644 --- a/src/Ocelot.Library/Infrastructure/Router/UrlPathRouter/UrlPath.cs +++ b/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/UrlPathTemplateMap.cs @@ -1,8 +1,8 @@ -namespace Ocelot.Library.Infrastructure.Router.UrlPathRouter +namespace Ocelot.Library.Infrastructure.UrlPathTemplateRepository { - public class UrlPath + public class UrlPathTemplateMap { - public UrlPath(string downstreamUrlPathTemplate, string upstreamUrlPathTemplate) + public UrlPathTemplateMap(string downstreamUrlPathTemplate, string upstreamUrlPathTemplate) { DownstreamUrlPathTemplate = downstreamUrlPathTemplate; UpstreamUrlPathTemplate = upstreamUrlPathTemplate; diff --git a/test/Ocelot.UnitTests/UpstreamRouterTests.cs b/test/Ocelot.UnitTests/BaseUrlMapRepositoryTests.cs similarity index 55% rename from test/Ocelot.UnitTests/UpstreamRouterTests.cs rename to test/Ocelot.UnitTests/BaseUrlMapRepositoryTests.cs index e2060f6e..721fd3ca 100644 --- a/test/Ocelot.UnitTests/UpstreamRouterTests.cs +++ b/test/Ocelot.UnitTests/BaseUrlMapRepositoryTests.cs @@ -1,28 +1,28 @@ using Ocelot.Library.Infrastructure.Responses; -using Ocelot.Library.Infrastructure.Router.UpstreamRouter; +using Ocelot.Library.Infrastructure.BaseUrlRepository; using Shouldly; using Xunit; namespace Ocelot.UnitTests { - public class RouterTests + public class BaseUrlMapRepositoryTests { - private string _upstreamApiUrl; - private string _apiKey; - private IUpstreamRouter _router; + private string _upstreamBaseUrl; + private string _downstreamBaseUrl; + private IBaseUrlMapRepository _repository; private Response _response; - private Response _getRouteResponse; - - public RouterTests() + private Response _getRouteResponse; + + public BaseUrlMapRepositoryTests() { - _router = new InMemoryUpstreamRouter(); + _repository = new InMemoryBaseUrlMapRepository(); } [Fact] public void can_add_route() { - GivenIHaveAnUpstreamApi("http://www.someapi.com/api1"); - GivenIWantToRouteRequestsToMyUpstreamApi("api"); + GivenIHaveAnUpstreamBaseUrl("www.someapi.com"); + GivenIWantToRouteRequestsFromMyDownstreamBaseUrl("api"); WhenIAddTheConfiguration(); ThenTheResponseIsSuccesful(); } @@ -30,7 +30,7 @@ namespace Ocelot.UnitTests [Fact] public void can_get_route_by_key() { - GivenIHaveSetUpAnApiKeyAndUpstreamUrl("api2", "http://www.someapi.com/api2"); + GivenIHaveSetUpAnApiKeyAndUpstreamUrl("api2", "www.someapi.com"); WhenIRetrieveTheRouteByKey(); ThenTheRouteIsReturned(); } @@ -38,7 +38,7 @@ namespace Ocelot.UnitTests [Fact] public void should_return_error_response_when_key_already_used() { - GivenIHaveSetUpAnApiKeyAndUpstreamUrl("api2", "http://www.someapi.com/api2"); + GivenIHaveSetUpAnApiKeyAndUpstreamUrl("api2", "www.someapi.com"); WhenITryToUseTheSameKey(); ThenTheKeyHasAlreadyBeenUsed(); } @@ -46,7 +46,7 @@ namespace Ocelot.UnitTests [Fact] public void should_return_error_response_if_key_doesnt_exist() { - GivenIWantToRouteRequestsToMyUpstreamApi("api"); + GivenIWantToRouteRequestsFromMyDownstreamBaseUrl("api"); WhenIRetrieveTheRouteByKey(); ThenTheKeyDoesNotExist(); } @@ -66,41 +66,41 @@ namespace Ocelot.UnitTests private void ThenTheKeyDoesNotExist() { _getRouteResponse.ShouldNotBeNull(); - _getRouteResponse.ShouldBeOfType>(); + _getRouteResponse.ShouldBeOfType>(); _getRouteResponse.Errors[0].Message.ShouldBe("This key does not exist"); } private void WhenIRetrieveTheRouteByKey() { - _getRouteResponse = _router.GetRoute(_apiKey); + _getRouteResponse = _repository.GetBaseUrlMap(_downstreamBaseUrl); } private void ThenTheRouteIsReturned() { - _getRouteResponse.Data.DownstreamUrl.ShouldBe(_apiKey); - _getRouteResponse.Data.UpstreamUrl.ShouldBe(_upstreamApiUrl); + _getRouteResponse.Data.DownstreamBaseUrl.ShouldBe(_downstreamBaseUrl); + _getRouteResponse.Data.UpstreamBaseUrl.ShouldBe(_upstreamBaseUrl); } private void GivenIHaveSetUpAnApiKeyAndUpstreamUrl(string apiKey, string upstreamUrl) { - GivenIHaveAnUpstreamApi(upstreamUrl); - GivenIWantToRouteRequestsToMyUpstreamApi(apiKey); + GivenIHaveAnUpstreamBaseUrl(upstreamUrl); + GivenIWantToRouteRequestsFromMyDownstreamBaseUrl(apiKey); WhenIAddTheConfiguration(); } - private void GivenIHaveAnUpstreamApi(string upstreamApiUrl) + private void GivenIHaveAnUpstreamBaseUrl(string upstreamApiUrl) { - _upstreamApiUrl = upstreamApiUrl; + _upstreamBaseUrl = upstreamApiUrl; } - private void GivenIWantToRouteRequestsToMyUpstreamApi(string apiKey) + private void GivenIWantToRouteRequestsFromMyDownstreamBaseUrl(string downstreamBaseUrl) { - _apiKey = apiKey; + _downstreamBaseUrl = downstreamBaseUrl; } private void WhenIAddTheConfiguration() { - _response = _router.AddRoute(_apiKey, _upstreamApiUrl); + _response = _repository.AddBaseUrlMap(new BaseUrlMap(_downstreamBaseUrl, _upstreamBaseUrl)); } private void ThenTheResponseIsSuccesful() diff --git a/test/Ocelot.UnitTests/UpstreamBaseUrlFinderTests.cs b/test/Ocelot.UnitTests/UpstreamBaseUrlFinderTests.cs new file mode 100644 index 00000000..6c794cef --- /dev/null +++ b/test/Ocelot.UnitTests/UpstreamBaseUrlFinderTests.cs @@ -0,0 +1,53 @@ +using Ocelot.Library.Infrastructure.BaseUrlRepository; +using Ocelot.Library.Infrastructure.UrlFinder; +using Ocelot.Library.Infrastructure.Responses; +using Xunit; +using Shouldly; +using System; + +namespace Ocelot.UnitTests +{ + public class UpstreamBaseUrlFinderTests + { + private IUpstreamBaseUrlFinder _upstreamBaseUrlFinder; + private IBaseUrlMapRepository _baseUrlMapRepository; + private string _downstreamBaseUrl; + private Response _result; + public UpstreamBaseUrlFinderTests() + { + _baseUrlMapRepository = new InMemoryBaseUrlMapRepository(); + _upstreamBaseUrlFinder = new UpstreamBaseUrlFinder(_baseUrlMapRepository); + } + + [Fact] + public void can_find_base_url() + { + GivenTheBaseUrlMapExists(new BaseUrlMap("api.tom.com", "api.laura.com")); + GivenTheDownstreamBaseUrlIs("api.tom.com"); + WhenIFindTheMatchingUpstreamBaseUrl(); + ThenTheFollowingIsReturned("api.laura.com"); + } + + private void GivenTheBaseUrlMapExists(BaseUrlMap baseUrlMap) + { + _baseUrlMapRepository.AddBaseUrlMap(baseUrlMap); + + } + + private void GivenTheDownstreamBaseUrlIs(string downstreamBaseUrl) + { + _downstreamBaseUrl = downstreamBaseUrl; + } + + private void WhenIFindTheMatchingUpstreamBaseUrl() + { + _result = _upstreamBaseUrlFinder.FindUpstreamBaseUrl(_downstreamBaseUrl); + + } + + private void ThenTheFollowingIsReturned(string expectedBaseUrl) + { + _result.Data.ShouldBe(expectedBaseUrl); + } + } +} \ No newline at end of file diff --git a/test/Ocelot.UnitTests/UrlPathRouterTests.cs b/test/Ocelot.UnitTests/UrlPathTemplateMapRepositoryTests.cs similarity index 73% rename from test/Ocelot.UnitTests/UrlPathRouterTests.cs rename to test/Ocelot.UnitTests/UrlPathTemplateMapRepositoryTests.cs index 73cdc06e..71ddd2c3 100644 --- a/test/Ocelot.UnitTests/UrlPathRouterTests.cs +++ b/test/Ocelot.UnitTests/UrlPathTemplateMapRepositoryTests.cs @@ -1,28 +1,28 @@ using Ocelot.Library.Infrastructure.Responses; -using Ocelot.Library.Infrastructure.Router.UrlPathRouter; +using Ocelot.Library.Infrastructure.UrlPathTemplateRepository; using Shouldly; using Xunit; namespace Ocelot.UnitTests { - public class UrlPathRouterTests + public class UrlPathTemplateMapRepositoryTests { - private string _upstreamUrlPath; + private string _upstreamUrlPath; private string _downstreamUrlPath; - private IUrlPathRouter _router; + private IUrlPathTemplateMapRepository _repository; private Response _response; - private Response _getResponse; + private Response _getResponse; - public UrlPathRouterTests() + public UrlPathTemplateMapRepositoryTests() { - _router = new InMemoryUrlPathRouter(); + _repository = new InMemoryUrlPathTemplateMapRepository(); } [Fact] public void can_add_url_path() { - GivenIHaveAnUpstreamUrlPath("api/products/products/{productId}"); - GivenIWantToRouteRequestsToMyUpstreamUrlPath("api/products/{productId}"); + GivenIHaveAnUpstreamUrlPath("/api/products/products/{productId}"); + GivenIWantToRouteRequestsToMyUpstreamUrlPath("/api/products/{productId}"); WhenIAddTheConfiguration(); ThenTheResponseIsSuccesful(); } @@ -30,7 +30,7 @@ namespace Ocelot.UnitTests [Fact] public void can_get_url_path() { - GivenIHaveSetUpADownstreamUrlPathAndAnUpstreamUrlPath("api2", "http://www.someapi.com/api2"); + GivenIHaveSetUpADownstreamUrlPathAndAnUpstreamUrlPath("/api2", "http://www.someapi.com/api2"); WhenIRetrieveTheUrlPathByDownstreamUrl(); ThenTheUrlPathIsReturned(); } @@ -38,7 +38,7 @@ namespace Ocelot.UnitTests [Fact] public void should_return_error_response_when_url_path_already_used() { - GivenIHaveSetUpADownstreamUrlPathAndAnUpstreamUrlPath("api2", "http://www.someapi.com/api2"); + GivenIHaveSetUpADownstreamUrlPathAndAnUpstreamUrlPath("/api2", "http://www.someapi.com/api2"); WhenITryToUseTheSameDownstreamUrl(); ThenTheDownstreamUrlAlreadyBeenUsed(); } @@ -46,7 +46,7 @@ namespace Ocelot.UnitTests [Fact] public void should_return_error_response_if_key_doesnt_exist() { - GivenIWantToRouteRequestsToMyUpstreamUrlPath("api"); + GivenIWantToRouteRequestsToMyUpstreamUrlPath("/api"); WhenIRetrieveTheUrlPathByDownstreamUrl(); ThenTheKeyDoesNotExist(); } @@ -66,13 +66,13 @@ namespace Ocelot.UnitTests private void ThenTheKeyDoesNotExist() { _getResponse.ShouldNotBeNull(); - _getResponse.ShouldBeOfType>(); + _getResponse.ShouldBeOfType>(); _getResponse.Errors[0].Message.ShouldBe("This key does not exist"); } private void WhenIRetrieveTheUrlPathByDownstreamUrl() { - _getResponse = _router.GetRoute(_downstreamUrlPath); + _getResponse = _repository.GetUrlPathTemplateMap(_downstreamUrlPath); } private void ThenTheUrlPathIsReturned() @@ -100,7 +100,7 @@ namespace Ocelot.UnitTests private void WhenIAddTheConfiguration() { - _response = _router.AddRoute(_downstreamUrlPath, _upstreamUrlPath); + _response = _repository.AddUrlPathTemplateMap(new UrlPathTemplateMap(_downstreamUrlPath, _upstreamUrlPath)); } private void ThenTheResponseIsSuccesful() diff --git a/test/Ocelot.UnitTests/UrlPathToUrlPathTemplateMatcherTests.cs b/test/Ocelot.UnitTests/UrlPathToUrlPathTemplateMatcherTests.cs index b81bed68..2101e637 100644 --- a/test/Ocelot.UnitTests/UrlPathToUrlPathTemplateMatcherTests.cs +++ b/test/Ocelot.UnitTests/UrlPathToUrlPathTemplateMatcherTests.cs @@ -1,10 +1,7 @@ -using System; -using Ocelot.Library.Infrastructure.Responses; -using Ocelot.Library.Infrastructure.Router.UpstreamRouter; -using Ocelot.Library.Infrastructure.Router.UrlPathMatcher; +using Ocelot.Library.Infrastructure.UrlPathMatcher; using Shouldly; using Xunit; - + namespace Ocelot.UnitTests { public class UrlPathToUrlPathTemplateMatcherTests From cea6a557e9bd3c6091bb2c37288ccdc78dd35c96 Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Sun, 10 Jul 2016 17:38:54 +0100 Subject: [PATCH 009/183] naming and plan --- .../BaseUrlRepository/BaseUrlMap.cs | 14 ------- .../BaseUrlMapKeyAlreadyExists.cs | 12 ------ .../BaseUrlMapKeyDoesNotExist.cs | 12 ------ .../IBaseUrlMapRepository.cs | 10 ----- .../InMemoryBaseUrlMapRepository.cs | 37 ------------------- .../HostUrlRepository/HostUrlMap.cs | 14 +++++++ .../HostUrlMapKeyAlreadyExists.cs | 12 ++++++ .../HostUrlMapKeyDoesNotExist.cs | 12 ++++++ .../IBaseUrlMapRepository.cs | 10 +++++ .../InMemoryBaseUrlMapRepository.cs | 37 +++++++++++++++++++ .../Infrastructure/Responses/Response.cs | 8 ++++ .../Responses/ResponseGeneric.cs | 1 + .../UrlFinder/IUpstreamBaseUrlFinder.cs | 9 ----- .../UrlFinder/IUpstreamHostUrlFinder.cs | 9 +++++ .../UrlFinder/UnableToFindUpstreamHostUrl.cs | 12 ++++++ .../UrlFinder/UpstreamBaseUrlFinder.cs | 22 ----------- .../UrlFinder/UpstreamHostUrlFinder.cs | 28 ++++++++++++++ .../DownstreamUrlPathAlreadyExists.cs | 12 ------ .../DownstreamUrlPathDoesNotExist.cs | 12 ------ .../Middleware/ProxyMiddleware.cs | 7 ++++ ...yTests.cs => HostUrlMapRepositoryTests.cs} | 20 +++++----- .../UpstreamBaseUrlFinderTests.cs | 31 +++++++++++----- 22 files changed, 182 insertions(+), 159 deletions(-) delete mode 100644 src/Ocelot.Library/Infrastructure/BaseUrlRepository/BaseUrlMap.cs delete mode 100644 src/Ocelot.Library/Infrastructure/BaseUrlRepository/BaseUrlMapKeyAlreadyExists.cs delete mode 100644 src/Ocelot.Library/Infrastructure/BaseUrlRepository/BaseUrlMapKeyDoesNotExist.cs delete mode 100644 src/Ocelot.Library/Infrastructure/BaseUrlRepository/IBaseUrlMapRepository.cs delete mode 100644 src/Ocelot.Library/Infrastructure/BaseUrlRepository/InMemoryBaseUrlMapRepository.cs create mode 100644 src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMap.cs create mode 100644 src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMapKeyAlreadyExists.cs create mode 100644 src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMapKeyDoesNotExist.cs create mode 100644 src/Ocelot.Library/Infrastructure/HostUrlRepository/IBaseUrlMapRepository.cs create mode 100644 src/Ocelot.Library/Infrastructure/HostUrlRepository/InMemoryBaseUrlMapRepository.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlFinder/IUpstreamBaseUrlFinder.cs create mode 100644 src/Ocelot.Library/Infrastructure/UrlFinder/IUpstreamHostUrlFinder.cs create mode 100644 src/Ocelot.Library/Infrastructure/UrlFinder/UnableToFindUpstreamHostUrl.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlFinder/UpstreamBaseUrlFinder.cs create mode 100644 src/Ocelot.Library/Infrastructure/UrlFinder/UpstreamHostUrlFinder.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlPathRepository/DownstreamUrlPathAlreadyExists.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlPathRepository/DownstreamUrlPathDoesNotExist.cs rename test/Ocelot.UnitTests/{BaseUrlMapRepositoryTests.cs => HostUrlMapRepositoryTests.cs} (83%) diff --git a/src/Ocelot.Library/Infrastructure/BaseUrlRepository/BaseUrlMap.cs b/src/Ocelot.Library/Infrastructure/BaseUrlRepository/BaseUrlMap.cs deleted file mode 100644 index 564bb26e..00000000 --- a/src/Ocelot.Library/Infrastructure/BaseUrlRepository/BaseUrlMap.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Ocelot.Library.Infrastructure.BaseUrlRepository -{ - public class BaseUrlMap - { - public BaseUrlMap(string downstreamBaseUrl, string upstreamBaseUrl) - { - DownstreamBaseUrl = downstreamBaseUrl; - UpstreamBaseUrl = upstreamBaseUrl; - } - - public string DownstreamBaseUrl {get;private set;} - public string UpstreamBaseUrl {get;private set;} - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/BaseUrlRepository/BaseUrlMapKeyAlreadyExists.cs b/src/Ocelot.Library/Infrastructure/BaseUrlRepository/BaseUrlMapKeyAlreadyExists.cs deleted file mode 100644 index 91b4ae4a..00000000 --- a/src/Ocelot.Library/Infrastructure/BaseUrlRepository/BaseUrlMapKeyAlreadyExists.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.BaseUrlRepository -{ - public class BaseUrlMapKeyAlreadyExists : Error - { - public BaseUrlMapKeyAlreadyExists() - : base("This key has already been used") - { - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/BaseUrlRepository/BaseUrlMapKeyDoesNotExist.cs b/src/Ocelot.Library/Infrastructure/BaseUrlRepository/BaseUrlMapKeyDoesNotExist.cs deleted file mode 100644 index d8367abf..00000000 --- a/src/Ocelot.Library/Infrastructure/BaseUrlRepository/BaseUrlMapKeyDoesNotExist.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.BaseUrlRepository -{ - public class BaseUrlMapKeyDoesNotExist : Error - { - public BaseUrlMapKeyDoesNotExist() - : base("This key does not exist") - { - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/BaseUrlRepository/IBaseUrlMapRepository.cs b/src/Ocelot.Library/Infrastructure/BaseUrlRepository/IBaseUrlMapRepository.cs deleted file mode 100644 index 2e76444d..00000000 --- a/src/Ocelot.Library/Infrastructure/BaseUrlRepository/IBaseUrlMapRepository.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.BaseUrlRepository -{ - public interface IBaseUrlMapRepository - { - Response AddBaseUrlMap(BaseUrlMap baseUrlMap); - Response GetBaseUrlMap(string downstreamUrl); - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/BaseUrlRepository/InMemoryBaseUrlMapRepository.cs b/src/Ocelot.Library/Infrastructure/BaseUrlRepository/InMemoryBaseUrlMapRepository.cs deleted file mode 100644 index d43fd23c..00000000 --- a/src/Ocelot.Library/Infrastructure/BaseUrlRepository/InMemoryBaseUrlMapRepository.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Collections.Generic; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.BaseUrlRepository -{ - public class InMemoryBaseUrlMapRepository : IBaseUrlMapRepository - { - private readonly Dictionary _routes; - public InMemoryBaseUrlMapRepository() - { - _routes = new Dictionary(); - } - public Response AddBaseUrlMap(BaseUrlMap baseUrlMap) - { - if(_routes.ContainsKey(baseUrlMap.DownstreamBaseUrl)) - { - return new ErrorResponse(new List(){new BaseUrlMapKeyAlreadyExists()}); - } - - _routes.Add(baseUrlMap.DownstreamBaseUrl, baseUrlMap.UpstreamBaseUrl); - - return new OkResponse(); - } - - public Response GetBaseUrlMap(string downstreamUrl) - { - string upstreamUrl = null; - - if(_routes.TryGetValue(downstreamUrl, out upstreamUrl)) - { - return new OkResponse(new BaseUrlMap(downstreamUrl, upstreamUrl)); - } - - return new ErrorResponse(new List(){new BaseUrlMapKeyDoesNotExist()}); - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMap.cs b/src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMap.cs new file mode 100644 index 00000000..1a13ee65 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMap.cs @@ -0,0 +1,14 @@ +namespace Ocelot.Library.Infrastructure.HostUrlRepository +{ + public class HostUrlMap + { + public HostUrlMap(string downstreamHostUrl, string upstreamHostUrl) + { + DownstreamHostUrl = downstreamHostUrl; + UpstreamHostUrl = upstreamHostUrl; + } + + public string DownstreamHostUrl {get;private set;} + public string UpstreamHostUrl {get;private set;} + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMapKeyAlreadyExists.cs b/src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMapKeyAlreadyExists.cs new file mode 100644 index 00000000..236cac79 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMapKeyAlreadyExists.cs @@ -0,0 +1,12 @@ +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.HostUrlRepository +{ + public class HostUrlMapKeyAlreadyExists : Error + { + public HostUrlMapKeyAlreadyExists() + : base("This key has already been used") + { + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMapKeyDoesNotExist.cs b/src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMapKeyDoesNotExist.cs new file mode 100644 index 00000000..913f2b67 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMapKeyDoesNotExist.cs @@ -0,0 +1,12 @@ +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.HostUrlRepository +{ + public class HostUrlMapKeyDoesNotExist : Error + { + public HostUrlMapKeyDoesNotExist() + : base("This key does not exist") + { + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/HostUrlRepository/IBaseUrlMapRepository.cs b/src/Ocelot.Library/Infrastructure/HostUrlRepository/IBaseUrlMapRepository.cs new file mode 100644 index 00000000..50a7e248 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/HostUrlRepository/IBaseUrlMapRepository.cs @@ -0,0 +1,10 @@ +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.HostUrlRepository +{ + public interface IHostUrlMapRepository + { + Response AddBaseUrlMap(HostUrlMap baseUrlMap); + Response GetBaseUrlMap(string downstreamUrl); + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/HostUrlRepository/InMemoryBaseUrlMapRepository.cs b/src/Ocelot.Library/Infrastructure/HostUrlRepository/InMemoryBaseUrlMapRepository.cs new file mode 100644 index 00000000..acb07542 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/HostUrlRepository/InMemoryBaseUrlMapRepository.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.HostUrlRepository +{ + public class InMemoryHostUrlMapRepository : IHostUrlMapRepository + { + private readonly Dictionary _routes; + public InMemoryHostUrlMapRepository() + { + _routes = new Dictionary(); + } + public Response AddBaseUrlMap(HostUrlMap baseUrlMap) + { + if(_routes.ContainsKey(baseUrlMap.DownstreamHostUrl)) + { + return new ErrorResponse(new List(){new HostUrlMapKeyAlreadyExists()}); + } + + _routes.Add(baseUrlMap.DownstreamHostUrl, baseUrlMap.UpstreamHostUrl); + + return new OkResponse(); + } + + public Response GetBaseUrlMap(string downstreamUrl) + { + string upstreamUrl = null; + + if(_routes.TryGetValue(downstreamUrl, out upstreamUrl)) + { + return new OkResponse(new HostUrlMap(downstreamUrl, upstreamUrl)); + } + + return new ErrorResponse(new List(){new HostUrlMapKeyDoesNotExist()}); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Responses/Response.cs b/src/Ocelot.Library/Infrastructure/Responses/Response.cs index 6651c0f7..ead3141c 100644 --- a/src/Ocelot.Library/Infrastructure/Responses/Response.cs +++ b/src/Ocelot.Library/Infrastructure/Responses/Response.cs @@ -15,5 +15,13 @@ namespace Ocelot.Library.Infrastructure.Responses } public List Errors { get; private set; } + + public bool IsError + { + get + { + return Errors.Count > 0; + } + } } } \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Responses/ResponseGeneric.cs b/src/Ocelot.Library/Infrastructure/Responses/ResponseGeneric.cs index 97e72e10..ed020292 100644 --- a/src/Ocelot.Library/Infrastructure/Responses/ResponseGeneric.cs +++ b/src/Ocelot.Library/Infrastructure/Responses/ResponseGeneric.cs @@ -14,5 +14,6 @@ namespace Ocelot.Library.Infrastructure.Responses } public T Data { get; private set; } + } } \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlFinder/IUpstreamBaseUrlFinder.cs b/src/Ocelot.Library/Infrastructure/UrlFinder/IUpstreamBaseUrlFinder.cs deleted file mode 100644 index c4623939..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlFinder/IUpstreamBaseUrlFinder.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.UrlFinder -{ - public interface IUpstreamBaseUrlFinder - { - Response FindUpstreamBaseUrl(string downstreamBaseUrl); - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlFinder/IUpstreamHostUrlFinder.cs b/src/Ocelot.Library/Infrastructure/UrlFinder/IUpstreamHostUrlFinder.cs new file mode 100644 index 00000000..84a78493 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/UrlFinder/IUpstreamHostUrlFinder.cs @@ -0,0 +1,9 @@ +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.UrlFinder +{ + public interface IUpstreamHostUrlFinder + { + Response FindUpstreamHostUrl(string downstreamHostUrl); + } +} diff --git a/src/Ocelot.Library/Infrastructure/UrlFinder/UnableToFindUpstreamHostUrl.cs b/src/Ocelot.Library/Infrastructure/UrlFinder/UnableToFindUpstreamHostUrl.cs new file mode 100644 index 00000000..10defcee --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/UrlFinder/UnableToFindUpstreamHostUrl.cs @@ -0,0 +1,12 @@ +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.UrlFinder +{ + public class UnableToFindUpstreamHostUrl : Error + { + public UnableToFindUpstreamHostUrl() + : base("Unable to find upstream base url") + { + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlFinder/UpstreamBaseUrlFinder.cs b/src/Ocelot.Library/Infrastructure/UrlFinder/UpstreamBaseUrlFinder.cs deleted file mode 100644 index 135c8fcc..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlFinder/UpstreamBaseUrlFinder.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using Ocelot.Library.Infrastructure.BaseUrlRepository; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.UrlFinder -{ - public class UpstreamBaseUrlFinder : IUpstreamBaseUrlFinder - { - private readonly IBaseUrlMapRepository _baseUrlMapRepository; - - public UpstreamBaseUrlFinder(IBaseUrlMapRepository baseUrlMapRepository) - { - _baseUrlMapRepository = baseUrlMapRepository; - } - public Response FindUpstreamBaseUrl(string downstreamBaseUrl) - { - var baseUrl = _baseUrlMapRepository.GetBaseUrlMap(downstreamBaseUrl); - - return new OkResponse(baseUrl.Data.UpstreamBaseUrl); - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlFinder/UpstreamHostUrlFinder.cs b/src/Ocelot.Library/Infrastructure/UrlFinder/UpstreamHostUrlFinder.cs new file mode 100644 index 00000000..555eb3d2 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/UrlFinder/UpstreamHostUrlFinder.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using Ocelot.Library.Infrastructure.HostUrlRepository; +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.UrlFinder +{ + public class UpstreamHostUrlFinder : IUpstreamHostUrlFinder + { + private readonly IHostUrlMapRepository _hostUrlMapRepository; + + public UpstreamHostUrlFinder(IHostUrlMapRepository hostUrlMapRepository) + { + _hostUrlMapRepository = hostUrlMapRepository; + } + public Response FindUpstreamHostUrl(string downstreamBaseUrl) + { + var baseUrl = _hostUrlMapRepository.GetBaseUrlMap(downstreamBaseUrl); + + if(baseUrl.IsError) + { + return new ErrorResponse(new List {new UnableToFindUpstreamHostUrl()}); + } + + return new OkResponse(baseUrl.Data.UpstreamHostUrl); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlPathRepository/DownstreamUrlPathAlreadyExists.cs b/src/Ocelot.Library/Infrastructure/UrlPathRepository/DownstreamUrlPathAlreadyExists.cs deleted file mode 100644 index efb3fc9e..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlPathRepository/DownstreamUrlPathAlreadyExists.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.UrlPathRepository -{ - public class DownstreamUrlPathTemplateAlreadyExists : Error - { - public DownstreamUrlPathTemplateAlreadyExists() - : base("This key has already been used") - { - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlPathRepository/DownstreamUrlPathDoesNotExist.cs b/src/Ocelot.Library/Infrastructure/UrlPathRepository/DownstreamUrlPathDoesNotExist.cs deleted file mode 100644 index 47d1f768..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlPathRepository/DownstreamUrlPathDoesNotExist.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.UrlPathRepository -{ - public class DownstreamUrlPathTemplateDoesNotExist : Error - { - public DownstreamUrlPathTemplateDoesNotExist() - : base("This key does not exist") - { - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs index a8698273..ddc94fcf 100644 --- a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs +++ b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs @@ -14,6 +14,13 @@ namespace Ocelot.Library.Middleware public async Task Invoke(HttpContext context) { + //get the downstream host from the request context + //get the upstream host from the host repository + //if no upstream host fail this request + //get the downstream path from the request context + //get the downstream path template from the path template finder + //todo think about variables.. + //add any query string.. await _next.Invoke(context); } } diff --git a/test/Ocelot.UnitTests/BaseUrlMapRepositoryTests.cs b/test/Ocelot.UnitTests/HostUrlMapRepositoryTests.cs similarity index 83% rename from test/Ocelot.UnitTests/BaseUrlMapRepositoryTests.cs rename to test/Ocelot.UnitTests/HostUrlMapRepositoryTests.cs index 721fd3ca..b22a6fb1 100644 --- a/test/Ocelot.UnitTests/BaseUrlMapRepositoryTests.cs +++ b/test/Ocelot.UnitTests/HostUrlMapRepositoryTests.cs @@ -1,21 +1,21 @@ using Ocelot.Library.Infrastructure.Responses; -using Ocelot.Library.Infrastructure.BaseUrlRepository; +using Ocelot.Library.Infrastructure.HostUrlRepository; using Shouldly; using Xunit; namespace Ocelot.UnitTests { - public class BaseUrlMapRepositoryTests + public class HostUrlMapRepositoryTests { private string _upstreamBaseUrl; private string _downstreamBaseUrl; - private IBaseUrlMapRepository _repository; + private IHostUrlMapRepository _repository; private Response _response; - private Response _getRouteResponse; + private Response _getRouteResponse; - public BaseUrlMapRepositoryTests() + public HostUrlMapRepositoryTests() { - _repository = new InMemoryBaseUrlMapRepository(); + _repository = new InMemoryHostUrlMapRepository(); } [Fact] @@ -66,7 +66,7 @@ namespace Ocelot.UnitTests private void ThenTheKeyDoesNotExist() { _getRouteResponse.ShouldNotBeNull(); - _getRouteResponse.ShouldBeOfType>(); + _getRouteResponse.ShouldBeOfType>(); _getRouteResponse.Errors[0].Message.ShouldBe("This key does not exist"); } @@ -77,8 +77,8 @@ namespace Ocelot.UnitTests private void ThenTheRouteIsReturned() { - _getRouteResponse.Data.DownstreamBaseUrl.ShouldBe(_downstreamBaseUrl); - _getRouteResponse.Data.UpstreamBaseUrl.ShouldBe(_upstreamBaseUrl); + _getRouteResponse.Data.DownstreamHostUrl.ShouldBe(_downstreamBaseUrl); + _getRouteResponse.Data.UpstreamHostUrl.ShouldBe(_upstreamBaseUrl); } private void GivenIHaveSetUpAnApiKeyAndUpstreamUrl(string apiKey, string upstreamUrl) @@ -100,7 +100,7 @@ namespace Ocelot.UnitTests private void WhenIAddTheConfiguration() { - _response = _repository.AddBaseUrlMap(new BaseUrlMap(_downstreamBaseUrl, _upstreamBaseUrl)); + _response = _repository.AddBaseUrlMap(new HostUrlMap(_downstreamBaseUrl, _upstreamBaseUrl)); } private void ThenTheResponseIsSuccesful() diff --git a/test/Ocelot.UnitTests/UpstreamBaseUrlFinderTests.cs b/test/Ocelot.UnitTests/UpstreamBaseUrlFinderTests.cs index 6c794cef..1cec5f18 100644 --- a/test/Ocelot.UnitTests/UpstreamBaseUrlFinderTests.cs +++ b/test/Ocelot.UnitTests/UpstreamBaseUrlFinderTests.cs @@ -1,4 +1,4 @@ -using Ocelot.Library.Infrastructure.BaseUrlRepository; +using Ocelot.Library.Infrastructure.HostUrlRepository; using Ocelot.Library.Infrastructure.UrlFinder; using Ocelot.Library.Infrastructure.Responses; using Xunit; @@ -9,28 +9,41 @@ namespace Ocelot.UnitTests { public class UpstreamBaseUrlFinderTests { - private IUpstreamBaseUrlFinder _upstreamBaseUrlFinder; - private IBaseUrlMapRepository _baseUrlMapRepository; + private IUpstreamHostUrlFinder _upstreamBaseUrlFinder; + private IHostUrlMapRepository _hostUrlMapRepository; private string _downstreamBaseUrl; private Response _result; public UpstreamBaseUrlFinderTests() { - _baseUrlMapRepository = new InMemoryBaseUrlMapRepository(); - _upstreamBaseUrlFinder = new UpstreamBaseUrlFinder(_baseUrlMapRepository); + _hostUrlMapRepository = new InMemoryHostUrlMapRepository(); + _upstreamBaseUrlFinder = new UpstreamHostUrlFinder(_hostUrlMapRepository); } [Fact] public void can_find_base_url() { - GivenTheBaseUrlMapExists(new BaseUrlMap("api.tom.com", "api.laura.com")); + GivenTheBaseUrlMapExists(new HostUrlMap("api.tom.com", "api.laura.com")); GivenTheDownstreamBaseUrlIs("api.tom.com"); WhenIFindTheMatchingUpstreamBaseUrl(); ThenTheFollowingIsReturned("api.laura.com"); } - private void GivenTheBaseUrlMapExists(BaseUrlMap baseUrlMap) + [Fact] + public void cant_find_base_url() { - _baseUrlMapRepository.AddBaseUrlMap(baseUrlMap); + GivenTheDownstreamBaseUrlIs("api.tom.com"); + WhenIFindTheMatchingUpstreamBaseUrl(); + ThenAnErrorIsReturned(); + } + + private void ThenAnErrorIsReturned() + { + _result.Errors.Count.ShouldBe(1); + } + + private void GivenTheBaseUrlMapExists(HostUrlMap baseUrlMap) + { + _hostUrlMapRepository.AddBaseUrlMap(baseUrlMap); } @@ -41,7 +54,7 @@ namespace Ocelot.UnitTests private void WhenIFindTheMatchingUpstreamBaseUrl() { - _result = _upstreamBaseUrlFinder.FindUpstreamBaseUrl(_downstreamBaseUrl); + _result = _upstreamBaseUrlFinder.FindUpstreamHostUrl(_downstreamBaseUrl); } From 1993915564362c8f54812f6288aa26c00f822dee Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Sun, 10 Jul 2016 18:49:09 +0100 Subject: [PATCH 010/183] now matches and returns templates and values@ --- .../IUrlPathToUrlPathTemplateMatcher.cs | 2 +- .../TemplateVariableNameAndValue.cs | 13 ++ .../UrlPathMatcher/UrlPathMatch.cs | 15 ++ .../UrlPathToUrlPathTemplateMatcher.cs | 43 +++++- .../UrlPathToUrlPathTemplateMatcherTests.cs | 139 ++++++++++++++---- 5 files changed, 177 insertions(+), 35 deletions(-) create mode 100644 src/Ocelot.Library/Infrastructure/UrlPathMatcher/TemplateVariableNameAndValue.cs create mode 100644 src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathMatch.cs diff --git a/src/Ocelot.Library/Infrastructure/UrlPathMatcher/IUrlPathToUrlPathTemplateMatcher.cs b/src/Ocelot.Library/Infrastructure/UrlPathMatcher/IUrlPathToUrlPathTemplateMatcher.cs index 7a617e13..a5a9e25a 100644 --- a/src/Ocelot.Library/Infrastructure/UrlPathMatcher/IUrlPathToUrlPathTemplateMatcher.cs +++ b/src/Ocelot.Library/Infrastructure/UrlPathMatcher/IUrlPathToUrlPathTemplateMatcher.cs @@ -2,6 +2,6 @@ namespace Ocelot.Library.Infrastructure.UrlPathMatcher { public interface IUrlPathToUrlPathTemplateMatcher { - bool Match(string urlPath, string urlPathTemplate); + UrlPathMatch Match(string urlPath, string urlPathTemplate); } } \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlPathMatcher/TemplateVariableNameAndValue.cs b/src/Ocelot.Library/Infrastructure/UrlPathMatcher/TemplateVariableNameAndValue.cs new file mode 100644 index 00000000..f65ab514 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/UrlPathMatcher/TemplateVariableNameAndValue.cs @@ -0,0 +1,13 @@ +namespace Ocelot.Library.Infrastructure.UrlPathMatcher +{ + public class TemplateVariableNameAndValue + { + public TemplateVariableNameAndValue(string templateVariableName, string templateVariableValue) + { + TemplateVariableName = templateVariableName; + TemplateVariableValue = templateVariableValue; + } + public string TemplateVariableName {get;private set;} + public string TemplateVariableValue {get;private set;} + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathMatch.cs b/src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathMatch.cs new file mode 100644 index 00000000..d783d683 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathMatch.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; + +namespace Ocelot.Library.Infrastructure.UrlPathMatcher +{ + public class UrlPathMatch + { + public UrlPathMatch(bool match, List templateVariableNameAndValues) + { + Match = match; + TemplateVariableNameAndValues = templateVariableNameAndValues; + } + public bool Match {get;private set;} + public List TemplateVariableNameAndValues {get;private set;} + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathToUrlPathTemplateMatcher.cs b/src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathToUrlPathTemplateMatcher.cs index 04189704..a062e2e5 100644 --- a/src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathToUrlPathTemplateMatcher.cs +++ b/src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathToUrlPathTemplateMatcher.cs @@ -1,9 +1,14 @@ +using System; +using System.Collections.Generic; + namespace Ocelot.Library.Infrastructure.UrlPathMatcher { public class UrlPathToUrlPathTemplateMatcher : IUrlPathToUrlPathTemplateMatcher { - public bool Match(string urlPath, string urlPathTemplate) + public UrlPathMatch Match(string urlPath, string urlPathTemplate) { + var templateKeysAndValues = new List(); + urlPath = urlPath.ToLower(); urlPathTemplate = urlPathTemplate.ToLower(); @@ -16,20 +21,52 @@ namespace Ocelot.Library.Infrastructure.UrlPathMatcher { if (IsPlaceholder(urlPathTemplate[counterForTemplate])) { + var variableName = GetPlaceholderVariableName(urlPathTemplate, counterForTemplate); + + var variableValue = GetPlaceholderVariableValue(urlPath, counterForUrl); + + var templateVariableNameAndValue = new TemplateVariableNameAndValue(variableName, variableValue); + + templateKeysAndValues.Add(templateVariableNameAndValue); + counterForTemplate = GetNextCounterPosition(urlPathTemplate, counterForTemplate, '}'); + counterForUrl = GetNextCounterPosition(urlPath, counterForUrl, '/'); + continue; } else { - return false; + return new UrlPathMatch(false, templateKeysAndValues); } } counterForUrl++; } - return true; + return new UrlPathMatch(true, templateKeysAndValues); } + private string GetPlaceholderVariableValue(string urlPath, int counterForUrl) + { + var positionOfNextSlash = urlPath.IndexOf('/', counterForUrl); + + if(positionOfNextSlash == -1) + { + positionOfNextSlash = urlPath.Length; + } + + var variableValue = urlPath.Substring(counterForUrl, positionOfNextSlash - counterForUrl); + + return variableValue; + } + + private string GetPlaceholderVariableName(string urlPathTemplate, int counterForTemplate) + { + var postitionOfPlaceHolderClosingBracket = urlPathTemplate.IndexOf('}', counterForTemplate) + 1; + + var variableName = urlPathTemplate.Substring(counterForTemplate, postitionOfPlaceHolderClosingBracket - counterForTemplate); + + return variableName; + } private int GetNextCounterPosition(string urlTemplate, int counterForTemplate, char delimiter) { var closingPlaceHolderPositionOnTemplate = urlTemplate.IndexOf(delimiter, counterForTemplate); diff --git a/test/Ocelot.UnitTests/UrlPathToUrlPathTemplateMatcherTests.cs b/test/Ocelot.UnitTests/UrlPathToUrlPathTemplateMatcherTests.cs index 2101e637..cfc63319 100644 --- a/test/Ocelot.UnitTests/UrlPathToUrlPathTemplateMatcherTests.cs +++ b/test/Ocelot.UnitTests/UrlPathToUrlPathTemplateMatcherTests.cs @@ -1,13 +1,17 @@ +using System.Collections.Generic; +using System.Linq; using Ocelot.Library.Infrastructure.UrlPathMatcher; using Shouldly; using Xunit; - + namespace Ocelot.UnitTests { public class UrlPathToUrlPathTemplateMatcherTests { private IUrlPathToUrlPathTemplateMatcher _urlMapper; - + private string _downstreamPath; + private string _downstreamPathTemplate; + private UrlPathMatch _result; public UrlPathToUrlPathTemplateMatcherTests() { _urlMapper = new UrlPathToUrlPathTemplateMatcher(); @@ -16,64 +20,137 @@ namespace Ocelot.UnitTests [Fact] public void can_match_down_stream_url_with_downstream_template_with_one_query_string_parameter() { - var downstreamUrl = "api/product/products/?soldout=false"; - var downstreamTemplate = "api/product/products/"; - var result = _urlMapper.Match(downstreamUrl, downstreamTemplate); - result.ShouldBeTrue(); + GivenIHaveADownstreamPath("api/product/products/?soldout=false"); + GivenIHaveAnDownstreamPathTemplate("api/product/products/"); + WhenIMatchThePaths(); + ThenTheResultIsTrue(); + ThenTheTemplatesDictionaryIs(new List()); + } - [Fact] + [Fact] public void can_match_down_stream_url_with_downstream_template_with_one_query_string_parameter_and_one_template() { - var downstreamUrl = "api/product/products/1/variants/?soldout=false"; - var downstreamTemplate = "api/product/products/{productId}/variants/"; - var result = _urlMapper.Match(downstreamUrl, downstreamTemplate); - result.ShouldBeTrue(); + var expectedTemplates = new List + { + new TemplateVariableNameAndValue("{productid}", "1") + }; + + GivenIHaveADownstreamPath("api/product/products/1/variants/?soldout=false"); + GivenIHaveAnDownstreamPathTemplate("api/product/products/{productId}/variants/"); + WhenIMatchThePaths(); + ThenTheResultIsTrue(); + ThenTheTemplatesDictionaryIs(expectedTemplates); } [Fact] public void can_match_down_stream_url_with_downstream_template_with_one_place_holder() { - var downstreamUrl = "api/product/products/1"; - var downstreamTemplate = "api/product/products/{productId}"; - var result = _urlMapper.Match(downstreamUrl, downstreamTemplate); - result.ShouldBeTrue(); + var expectedTemplates = new List + { + new TemplateVariableNameAndValue("{productid}", "1") + }; + + GivenIHaveADownstreamPath("api/product/products/1"); + GivenIHaveAnDownstreamPathTemplate("api/product/products/{productId}"); + WhenIMatchThePaths(); + ThenTheResultIsTrue(); + ThenTheTemplatesDictionaryIs(expectedTemplates); } [Fact] public void can_match_down_stream_url_with_downstream_template_with_two_place_holders() { - var downstreamUrl = "api/product/products/1/2"; - var downstreamTemplate = "api/product/products/{productId}/{categoryId}"; - var result = _urlMapper.Match(downstreamUrl, downstreamTemplate); - result.ShouldBeTrue(); + var expectedTemplates = new List + { + new TemplateVariableNameAndValue("{productid}", "1"), + new TemplateVariableNameAndValue("{categoryid}", "2") + }; + + GivenIHaveADownstreamPath("api/product/products/1/2"); + GivenIHaveAnDownstreamPathTemplate("api/product/products/{productId}/{categoryId}"); + WhenIMatchThePaths(); + ThenTheResultIsTrue(); + ThenTheTemplatesDictionaryIs(expectedTemplates); } [Fact] public void can_match_down_stream_url_with_downstream_template_with_two_place_holders_seperated_by_something() { - var downstreamUrl = "api/product/products/1/categories/2"; - var downstreamTemplate = "api/product/products/{productId}/categories/{categoryId}"; - var result = _urlMapper.Match(downstreamUrl, downstreamTemplate); - result.ShouldBeTrue(); + var expectedTemplates = new List + { + new TemplateVariableNameAndValue("{productid}", "1"), + new TemplateVariableNameAndValue("{categoryid}", "2") + }; + + GivenIHaveADownstreamPath("api/product/products/1/categories/2"); + GivenIHaveAnDownstreamPathTemplate("api/product/products/{productId}/categories/{categoryId}"); + WhenIMatchThePaths(); + ThenTheResultIsTrue(); + ThenTheTemplatesDictionaryIs(expectedTemplates); } [Fact] public void can_match_down_stream_url_with_downstream_template_with_three_place_holders_seperated_by_something() { - var downstreamUrl = "api/product/products/1/categories/2/variant/123"; - var downstreamTemplate = "api/product/products/{productId}/categories/{categoryId}/variant/{variantId}"; - var result = _urlMapper.Match(downstreamUrl, downstreamTemplate); - result.ShouldBeTrue(); + var expectedTemplates = new List + { + new TemplateVariableNameAndValue("{productid}", "1"), + new TemplateVariableNameAndValue("{categoryid}", "2"), + new TemplateVariableNameAndValue("{variantid}", "123") + }; + + GivenIHaveADownstreamPath("api/product/products/1/categories/2/variant/123"); + GivenIHaveAnDownstreamPathTemplate("api/product/products/{productId}/categories/{categoryId}/variant/{variantId}"); + WhenIMatchThePaths(); + ThenTheResultIsTrue(); + ThenTheTemplatesDictionaryIs(expectedTemplates); } [Fact] public void can_match_down_stream_url_with_downstream_template_with_three_place_holders() { - var downstreamUrl = "api/product/products/1/categories/2/variant/"; - var downstreamTemplate = "api/product/products/{productId}/categories/{categoryId}/variant/"; - var result = _urlMapper.Match(downstreamUrl, downstreamTemplate); - result.ShouldBeTrue(); + var expectedTemplates = new List + { + new TemplateVariableNameAndValue("{productid}", "1"), + new TemplateVariableNameAndValue("{categoryid}", "2") + }; + + GivenIHaveADownstreamPath("api/product/products/1/categories/2/variant/"); + GivenIHaveAnDownstreamPathTemplate("api/product/products/{productId}/categories/{categoryId}/variant/"); + WhenIMatchThePaths(); + ThenTheResultIsTrue(); + ThenTheTemplatesDictionaryIs(expectedTemplates); + } + + private void ThenTheTemplatesDictionaryIs(List expectedResults) + { + foreach (var expectedResult in expectedResults) + { + var result = _result.TemplateVariableNameAndValues + .First(t => t.TemplateVariableName == expectedResult.TemplateVariableName); + result.TemplateVariableValue.ShouldBe(expectedResult.TemplateVariableValue); + } + } + + private void GivenIHaveADownstreamPath(string downstreamPath) + { + _downstreamPath = downstreamPath; + } + + private void GivenIHaveAnDownstreamPathTemplate(string downstreamTemplate) + { + _downstreamPathTemplate = downstreamTemplate; + } + + private void WhenIMatchThePaths() + { + _result = _urlMapper.Match(_downstreamPath, _downstreamPathTemplate); + } + + private void ThenTheResultIsTrue() + { + _result.Match.ShouldBeTrue(); } } } \ No newline at end of file From ff10d07b949da6302ab2c8cd45a948e59594b78d Mon Sep 17 00:00:00 2001 From: TomPallister Date: Sat, 16 Jul 2016 15:10:19 +0100 Subject: [PATCH 011/183] Set up acceptance tests on windows --- Ocelot.sln | 7 ++++ .../Ocelot.AcceptanceTests.xproj | 22 +++++++++++++ .../Properties/AssemblyInfo.cs | 19 +++++++++++ test/Ocelot.AcceptanceTests/RouterTests.cs | 33 +++++++++++++++---- test/Ocelot.AcceptanceTests/project.json | 7 ++-- 5 files changed, 78 insertions(+), 10 deletions(-) create mode 100644 test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.xproj create mode 100644 test/Ocelot.AcceptanceTests/Properties/AssemblyInfo.cs diff --git a/Ocelot.sln b/Ocelot.sln index 848e011d..4387cd03 100644 --- a/Ocelot.sln +++ b/Ocelot.sln @@ -20,6 +20,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{5B401523-3 EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Ocelot.UnitTests", "test\Ocelot.UnitTests\Ocelot.UnitTests.xproj", "{54E84F1A-E525-4443-96EC-039CBD50C263}" EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Ocelot.AcceptanceTests", "test\Ocelot.AcceptanceTests\Ocelot.AcceptanceTests.xproj", "{F8C224FE-36BE-45F5-9B0E-666D8F4A9B52}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -38,6 +40,10 @@ Global {54E84F1A-E525-4443-96EC-039CBD50C263}.Debug|Any CPU.Build.0 = Debug|Any CPU {54E84F1A-E525-4443-96EC-039CBD50C263}.Release|Any CPU.ActiveCfg = Release|Any CPU {54E84F1A-E525-4443-96EC-039CBD50C263}.Release|Any CPU.Build.0 = Release|Any CPU + {F8C224FE-36BE-45F5-9B0E-666D8F4A9B52}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F8C224FE-36BE-45F5-9B0E-666D8F4A9B52}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F8C224FE-36BE-45F5-9B0E-666D8F4A9B52}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F8C224FE-36BE-45F5-9B0E-666D8F4A9B52}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -46,5 +52,6 @@ Global {AEC8FB40-B370-48A6-9B38-78E560041F01} = {5CFB79B7-C9DC-45A4-9A75-625D92471702} {D6DF4206-0DBA-41D8-884D-C3E08290FDBB} = {5CFB79B7-C9DC-45A4-9A75-625D92471702} {54E84F1A-E525-4443-96EC-039CBD50C263} = {5B401523-36DA-4491-B73A-7590A26E420B} + {F8C224FE-36BE-45F5-9B0E-666D8F4A9B52} = {5B401523-36DA-4491-B73A-7590A26E420B} EndGlobalSection EndGlobal diff --git a/test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.xproj b/test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.xproj new file mode 100644 index 00000000..84e2327e --- /dev/null +++ b/test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.xproj @@ -0,0 +1,22 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + f8c224fe-36be-45f5-9b0e-666d8f4a9b52 + Ocelot.AcceptanceTests + .\obj + .\bin\ + v4.5 + + + 2.0 + + + + + + \ No newline at end of file diff --git a/test/Ocelot.AcceptanceTests/Properties/AssemblyInfo.cs b/test/Ocelot.AcceptanceTests/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..2f3ceca8 --- /dev/null +++ b/test/Ocelot.AcceptanceTests/Properties/AssemblyInfo.cs @@ -0,0 +1,19 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Ocelot.AcceptanceTests")] +[assembly: AssemblyTrademark("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("f8c224fe-36be-45f5-9b0e-666d8f4a9b52")] diff --git a/test/Ocelot.AcceptanceTests/RouterTests.cs b/test/Ocelot.AcceptanceTests/RouterTests.cs index 43dc2e4d..ecc468ae 100644 --- a/test/Ocelot.AcceptanceTests/RouterTests.cs +++ b/test/Ocelot.AcceptanceTests/RouterTests.cs @@ -1,24 +1,43 @@ using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; +using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; -using Ocelot; +using Microsoft.AspNetCore.TestHost; using Xunit; namespace Ocelot.AcceptanceTests { - public class RouterTests + public class RouterTests : IDisposable { + private readonly TestServer _server; + private readonly HttpClient _client; + public RouterTests() { + // Arrange + _server = new TestServer(new WebHostBuilder() + .UseStartup()); + _client = _server.CreateClient(); } [Fact] - public void should_route_request() + public async Task ReturnHelloWorld() { - + // Act + var response = await _client.GetAsync("/"); + response.EnsureSuccessStatusCode(); + + var responseString = await response.Content.ReadAsStringAsync(); + + // Assert + Assert.Equal("Hello from Tom", + responseString); + } + + public void Dispose() + { + _client.Dispose(); + _server.Dispose(); } } } diff --git a/test/Ocelot.AcceptanceTests/project.json b/test/Ocelot.AcceptanceTests/project.json index da9f68a7..f59b9e22 100644 --- a/test/Ocelot.AcceptanceTests/project.json +++ b/test/Ocelot.AcceptanceTests/project.json @@ -1,4 +1,4 @@ -{ +{ "version": "1.0.0-*", "testRunner": "xunit", @@ -20,10 +20,11 @@ "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", "Microsoft.AspNetCore.Http": "1.0.0", "Ocelot.Library": "1.0.0-*", - "Ocelot": "1.0.0-*", "xunit": "2.1.0", "dotnet-test-xunit": "2.2.0-preview2-build1029", - "Shouldly": "2.8.0" + "Shouldly": "2.8.0", + "Ocelot": "1.0.0-*", + "Microsoft.AspNetCore.TestHost": "1.0.0" }, "frameworks": { From dbff2b9530213adf98dfa826dcad47ef8c9d5dd2 Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Thu, 21 Jul 2016 20:28:22 +0100 Subject: [PATCH 012/183] messing around with the proxy mdh the proxy middleware --- .../HostUrlRepository/HostUrlMap.cs | 6 +-- ...Repository.cs => IHostUrlMapRepository.cs} | 2 +- ...ory.cs => InMemoryHostUrlMapRepository.cs} | 10 ++-- .../UrlPathMatcher/UrlPathMatch.cs | 5 +- .../UrlPathToUrlPathTemplateMatcher.cs | 6 ++- .../IUrlPathTemplateMapRepository.cs | 2 + .../InMemoryUrlPathTemplateMapRepository.cs | 13 +++++ .../Middleware/ProxyMiddleware.cs | 53 +++++++++++++++---- src/Ocelot/Startup.cs | 10 ++-- .../Fake/FakeService.cs | 34 ++++++++++++ .../Fake/FakeStartup.cs | 40 ++++++++++++++ test/Ocelot.AcceptanceTests/RouterTests.cs | 27 +++++++--- .../HostUrlMapRepositoryTests.cs | 2 +- .../UrlPathTemplateMapRepositoryTests.cs | 20 +++++++ .../UrlPathToUrlPathTemplateMatcherTests.cs | 18 ++++++- 15 files changed, 213 insertions(+), 35 deletions(-) rename src/Ocelot.Library/Infrastructure/HostUrlRepository/{IBaseUrlMapRepository.cs => IHostUrlMapRepository.cs} (76%) rename src/Ocelot.Library/Infrastructure/HostUrlRepository/{InMemoryBaseUrlMapRepository.cs => InMemoryHostUrlMapRepository.cs} (73%) create mode 100644 test/Ocelot.AcceptanceTests/Fake/FakeService.cs create mode 100644 test/Ocelot.AcceptanceTests/Fake/FakeStartup.cs diff --git a/src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMap.cs b/src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMap.cs index 1a13ee65..a9b6ce61 100644 --- a/src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMap.cs +++ b/src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMap.cs @@ -2,13 +2,13 @@ namespace Ocelot.Library.Infrastructure.HostUrlRepository { public class HostUrlMap { - public HostUrlMap(string downstreamHostUrl, string upstreamHostUrl) + public HostUrlMap(string urlPathTemplate, string upstreamHostUrl) { - DownstreamHostUrl = downstreamHostUrl; + UrlPathTemplate = urlPathTemplate; UpstreamHostUrl = upstreamHostUrl; } - public string DownstreamHostUrl {get;private set;} + public string UrlPathTemplate {get;private set;} public string UpstreamHostUrl {get;private set;} } } \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/HostUrlRepository/IBaseUrlMapRepository.cs b/src/Ocelot.Library/Infrastructure/HostUrlRepository/IHostUrlMapRepository.cs similarity index 76% rename from src/Ocelot.Library/Infrastructure/HostUrlRepository/IBaseUrlMapRepository.cs rename to src/Ocelot.Library/Infrastructure/HostUrlRepository/IHostUrlMapRepository.cs index 50a7e248..da78044c 100644 --- a/src/Ocelot.Library/Infrastructure/HostUrlRepository/IBaseUrlMapRepository.cs +++ b/src/Ocelot.Library/Infrastructure/HostUrlRepository/IHostUrlMapRepository.cs @@ -5,6 +5,6 @@ namespace Ocelot.Library.Infrastructure.HostUrlRepository public interface IHostUrlMapRepository { Response AddBaseUrlMap(HostUrlMap baseUrlMap); - Response GetBaseUrlMap(string downstreamUrl); + Response GetBaseUrlMap(string urlPathTemplate); } } \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/HostUrlRepository/InMemoryBaseUrlMapRepository.cs b/src/Ocelot.Library/Infrastructure/HostUrlRepository/InMemoryHostUrlMapRepository.cs similarity index 73% rename from src/Ocelot.Library/Infrastructure/HostUrlRepository/InMemoryBaseUrlMapRepository.cs rename to src/Ocelot.Library/Infrastructure/HostUrlRepository/InMemoryHostUrlMapRepository.cs index acb07542..61b45ebf 100644 --- a/src/Ocelot.Library/Infrastructure/HostUrlRepository/InMemoryBaseUrlMapRepository.cs +++ b/src/Ocelot.Library/Infrastructure/HostUrlRepository/InMemoryHostUrlMapRepository.cs @@ -12,23 +12,23 @@ namespace Ocelot.Library.Infrastructure.HostUrlRepository } public Response AddBaseUrlMap(HostUrlMap baseUrlMap) { - if(_routes.ContainsKey(baseUrlMap.DownstreamHostUrl)) + if(_routes.ContainsKey(baseUrlMap.UrlPathTemplate)) { return new ErrorResponse(new List(){new HostUrlMapKeyAlreadyExists()}); } - _routes.Add(baseUrlMap.DownstreamHostUrl, baseUrlMap.UpstreamHostUrl); + _routes.Add(baseUrlMap.UrlPathTemplate, baseUrlMap.UpstreamHostUrl); return new OkResponse(); } - public Response GetBaseUrlMap(string downstreamUrl) + public Response GetBaseUrlMap(string urlPathTemplate) { string upstreamUrl = null; - if(_routes.TryGetValue(downstreamUrl, out upstreamUrl)) + if(_routes.TryGetValue(urlPathTemplate, out upstreamUrl)) { - return new OkResponse(new HostUrlMap(downstreamUrl, upstreamUrl)); + return new OkResponse(new HostUrlMap(urlPathTemplate, upstreamUrl)); } return new ErrorResponse(new List(){new HostUrlMapKeyDoesNotExist()}); diff --git a/src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathMatch.cs b/src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathMatch.cs index d783d683..e7f21430 100644 --- a/src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathMatch.cs +++ b/src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathMatch.cs @@ -4,12 +4,15 @@ namespace Ocelot.Library.Infrastructure.UrlPathMatcher { public class UrlPathMatch { - public UrlPathMatch(bool match, List templateVariableNameAndValues) + public UrlPathMatch(bool match, List templateVariableNameAndValues, string urlPathTemplate) { Match = match; TemplateVariableNameAndValues = templateVariableNameAndValues; + UrlPathTemplate = urlPathTemplate; } public bool Match {get;private set;} public List TemplateVariableNameAndValues {get;private set;} + + public string UrlPathTemplate {get;private set;} } } \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathToUrlPathTemplateMatcher.cs b/src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathToUrlPathTemplateMatcher.cs index a062e2e5..8ca2ded1 100644 --- a/src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathToUrlPathTemplateMatcher.cs +++ b/src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathToUrlPathTemplateMatcher.cs @@ -7,6 +7,8 @@ namespace Ocelot.Library.Infrastructure.UrlPathMatcher { public UrlPathMatch Match(string urlPath, string urlPathTemplate) { + var urlPathTemplateCopy = urlPathTemplate; + var templateKeysAndValues = new List(); urlPath = urlPath.ToLower(); @@ -37,12 +39,12 @@ namespace Ocelot.Library.Infrastructure.UrlPathMatcher } else { - return new UrlPathMatch(false, templateKeysAndValues); + return new UrlPathMatch(false, templateKeysAndValues, string.Empty); } } counterForUrl++; } - return new UrlPathMatch(true, templateKeysAndValues); + return new UrlPathMatch(true, templateKeysAndValues, urlPathTemplateCopy); } private string GetPlaceholderVariableValue(string urlPath, int counterForUrl) diff --git a/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/IUrlPathTemplateMapRepository.cs b/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/IUrlPathTemplateMapRepository.cs index f847c7ba..b63ecfc6 100644 --- a/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/IUrlPathTemplateMapRepository.cs +++ b/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/IUrlPathTemplateMapRepository.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using Ocelot.Library.Infrastructure.Responses; namespace Ocelot.Library.Infrastructure.UrlPathTemplateRepository @@ -6,5 +7,6 @@ namespace Ocelot.Library.Infrastructure.UrlPathTemplateRepository { Response AddUrlPathTemplateMap(UrlPathTemplateMap urlPathMap); Response GetUrlPathTemplateMap(string downstreamUrlPathTemplate); + Response> All { get; } } } \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/InMemoryUrlPathTemplateMapRepository.cs b/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/InMemoryUrlPathTemplateMapRepository.cs index 257f1d3f..b56c6b95 100644 --- a/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/InMemoryUrlPathTemplateMapRepository.cs +++ b/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/InMemoryUrlPathTemplateMapRepository.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using Ocelot.Library.Infrastructure.Responses; namespace Ocelot.Library.Infrastructure.UrlPathTemplateRepository @@ -11,6 +12,18 @@ namespace Ocelot.Library.Infrastructure.UrlPathTemplateRepository { _routes = new Dictionary(); } + + public Response> All + { + get + { + var routes = _routes + .Select(r => new UrlPathTemplateMap(r.Key, r.Value)) + .ToList(); + return new OkResponse>(routes); + } + } + public Response AddUrlPathTemplateMap(UrlPathTemplateMap urlPathMap) { if(_routes.ContainsKey(urlPathMap.DownstreamUrlPathTemplate)) diff --git a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs index ddc94fcf..6c7ad7ef 100644 --- a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs +++ b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs @@ -1,26 +1,61 @@ +using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; +using Ocelot.Library.Infrastructure.HostUrlRepository; +using Ocelot.Library.Infrastructure.UrlPathMatcher; +using Ocelot.Library.Infrastructure.UrlPathTemplateRepository; namespace Ocelot.Library.Middleware { public class ProxyMiddleware { private readonly RequestDelegate _next; - - public ProxyMiddleware(RequestDelegate next) + private readonly IUrlPathToUrlPathTemplateMatcher _urlMatcher; + private readonly IUrlPathTemplateMapRepository _urlPathRepository; + private readonly IHostUrlMapRepository _hostUrlRepository; + public ProxyMiddleware(RequestDelegate next, + IUrlPathToUrlPathTemplateMatcher urlMatcher, + IUrlPathTemplateMapRepository urlPathRepository, + IHostUrlMapRepository hostUrlRepository) { _next = next; + _urlMatcher = urlMatcher; + _urlPathRepository = urlPathRepository; + _hostUrlRepository = hostUrlRepository; } public async Task Invoke(HttpContext context) { - //get the downstream host from the request context - //get the upstream host from the host repository - //if no upstream host fail this request - //get the downstream path from the request context - //get the downstream path template from the path template finder - //todo think about variables.. - //add any query string.. + + var path = context.Request.Path.ToString(); + + var templates = _urlPathRepository.All; + + UrlPathMatch urlPathMatch = null; + string upstreamPathUrl = string.Empty; + + foreach (var template in templates.Data) + { + urlPathMatch = _urlMatcher.Match(path, template.DownstreamUrlPathTemplate); + + if (urlPathMatch.Match) + { + upstreamPathUrl = template.UpstreamUrlPathTemplate; + break; + } + } + + if (!urlPathMatch.Match) + { + throw new Exception("BOOOM TING! no match"); + } + + var upstreamHostUrl = _hostUrlRepository.GetBaseUrlMap(urlPathMatch.UrlPathTemplate); + + //now map the variables from the url path to the upstream url path + + + await _next.Invoke(context); } } diff --git a/src/Ocelot/Startup.cs b/src/Ocelot/Startup.cs index 83cc57a8..e13d551d 100644 --- a/src/Ocelot/Startup.cs +++ b/src/Ocelot/Startup.cs @@ -37,11 +37,11 @@ namespace Ocelot loggerFactory.AddDebug(); app.UseProxy(); - - app.Run(async context => - { - await context.Response.WriteAsync("Hello from Tom"); - }); + //app.Run() + // app.Run(async context => + // { + // await context.Response.WriteAsync("Hello from Tom"); + // }); } } } diff --git a/test/Ocelot.AcceptanceTests/Fake/FakeService.cs b/test/Ocelot.AcceptanceTests/Fake/FakeService.cs new file mode 100644 index 00000000..56f97ce5 --- /dev/null +++ b/test/Ocelot.AcceptanceTests/Fake/FakeService.cs @@ -0,0 +1,34 @@ +using System.IO; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting; + +namespace Ocelot.AcceptanceTests.Fake +{ + public class FakeService + { + private Task _handler; + private IWebHost _webHostBuilder; + + public void Start(string url) + { + _webHostBuilder = new WebHostBuilder() + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseUrls(url) + .UseStartup() + .Build(); + + _handler = Task.Run(() => _webHostBuilder.Run()); + } + + public void Stop() + { + if(_webHostBuilder != null) + { + _webHostBuilder.Dispose(); + _handler.Wait(); + } + } + } +} \ No newline at end of file diff --git a/test/Ocelot.AcceptanceTests/Fake/FakeStartup.cs b/test/Ocelot.AcceptanceTests/Fake/FakeStartup.cs new file mode 100644 index 00000000..35d5e644 --- /dev/null +++ b/test/Ocelot.AcceptanceTests/Fake/FakeStartup.cs @@ -0,0 +1,40 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +namespace Ocelot.AcceptanceTests.Fake +{ + public class FakeStartup + { + public FakeStartup(IHostingEnvironment env) + { + var builder = new ConfigurationBuilder() + .SetBasePath(env.ContentRootPath) + .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) + .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) + .AddEnvironmentVariables(); + Configuration = builder.Build(); + } + + public IConfigurationRoot Configuration { get; } + + // This method gets called by the runtime. Use this method to add services to the container. + public void ConfigureServices(IServiceCollection services) + { + // Add framework services. + + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) + { + app.Run(async context => + { + await context.Response.WriteAsync("Hello from Laura"); + }); + } + } +} diff --git a/test/Ocelot.AcceptanceTests/RouterTests.cs b/test/Ocelot.AcceptanceTests/RouterTests.cs index ecc468ae..0381ff41 100644 --- a/test/Ocelot.AcceptanceTests/RouterTests.cs +++ b/test/Ocelot.AcceptanceTests/RouterTests.cs @@ -4,38 +4,51 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Xunit; +using Ocelot.AcceptanceTests.Fake; +using Shouldly; namespace Ocelot.AcceptanceTests { public class RouterTests : IDisposable { + private FakeService _fakeService; private readonly TestServer _server; private readonly HttpClient _client; public RouterTests() { - // Arrange _server = new TestServer(new WebHostBuilder() .UseStartup()); _client = _server.CreateClient(); + _fakeService = new FakeService(); } [Fact] - public async Task ReturnHelloWorld() + public void hello_world() { + var response = _client.GetAsync("/").Result; + response.EnsureSuccessStatusCode(); + + var responseString = response.Content.ReadAsStringAsync().Result; + responseString.ShouldBe("Hello from Tom"); + } + + [Fact] + public async Task can_route_request() + { + _fakeService.Start("http://localhost:5001"); + // Act var response = await _client.GetAsync("/"); response.EnsureSuccessStatusCode(); var responseString = await response.Content.ReadAsStringAsync(); - - // Assert - Assert.Equal("Hello from Tom", - responseString); + responseString.ShouldBe("Hello from Laura"); } public void Dispose() - { + { + _fakeService.Stop(); _client.Dispose(); _server.Dispose(); } diff --git a/test/Ocelot.UnitTests/HostUrlMapRepositoryTests.cs b/test/Ocelot.UnitTests/HostUrlMapRepositoryTests.cs index b22a6fb1..2bcd998f 100644 --- a/test/Ocelot.UnitTests/HostUrlMapRepositoryTests.cs +++ b/test/Ocelot.UnitTests/HostUrlMapRepositoryTests.cs @@ -77,7 +77,7 @@ namespace Ocelot.UnitTests private void ThenTheRouteIsReturned() { - _getRouteResponse.Data.DownstreamHostUrl.ShouldBe(_downstreamBaseUrl); + _getRouteResponse.Data.UrlPathTemplate.ShouldBe(_downstreamBaseUrl); _getRouteResponse.Data.UpstreamHostUrl.ShouldBe(_upstreamBaseUrl); } diff --git a/test/Ocelot.UnitTests/UrlPathTemplateMapRepositoryTests.cs b/test/Ocelot.UnitTests/UrlPathTemplateMapRepositoryTests.cs index 71ddd2c3..6dd8f8ed 100644 --- a/test/Ocelot.UnitTests/UrlPathTemplateMapRepositoryTests.cs +++ b/test/Ocelot.UnitTests/UrlPathTemplateMapRepositoryTests.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using Ocelot.Library.Infrastructure.Responses; using Ocelot.Library.Infrastructure.UrlPathTemplateRepository; using Shouldly; @@ -12,6 +13,7 @@ namespace Ocelot.UnitTests private IUrlPathTemplateMapRepository _repository; private Response _response; private Response _getResponse; + private Response> _listResponse; public UrlPathTemplateMapRepositoryTests() { @@ -34,6 +36,14 @@ namespace Ocelot.UnitTests WhenIRetrieveTheUrlPathByDownstreamUrl(); ThenTheUrlPathIsReturned(); } + + [Fact] + public void can_get_all_urls() + { + GivenIHaveSetUpADownstreamUrlPathAndAnUpstreamUrlPath("/api2", "http://www.someapi.com/api2"); + WhenIRetrieveTheUrls(); + ThenTheUrlsAreReturned(); + } [Fact] public void should_return_error_response_when_url_path_already_used() @@ -75,12 +85,22 @@ namespace Ocelot.UnitTests _getResponse = _repository.GetUrlPathTemplateMap(_downstreamUrlPath); } + private void WhenIRetrieveTheUrls() + { + _listResponse = _repository.All; + } + private void ThenTheUrlPathIsReturned() { _getResponse.Data.DownstreamUrlPathTemplate.ShouldBe(_downstreamUrlPath); _getResponse.Data.UpstreamUrlPathTemplate.ShouldBe(_upstreamUrlPath); } + private void ThenTheUrlsAreReturned() + { + _listResponse.Data.Count.ShouldBeGreaterThan(0); + } + private void GivenIHaveSetUpADownstreamUrlPathAndAnUpstreamUrlPath(string downstream, string upstreamApiUrl) { GivenIHaveAnUpstreamUrlPath(upstreamApiUrl); diff --git a/test/Ocelot.UnitTests/UrlPathToUrlPathTemplateMatcherTests.cs b/test/Ocelot.UnitTests/UrlPathToUrlPathTemplateMatcherTests.cs index cfc63319..1219476a 100644 --- a/test/Ocelot.UnitTests/UrlPathToUrlPathTemplateMatcherTests.cs +++ b/test/Ocelot.UnitTests/UrlPathToUrlPathTemplateMatcherTests.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using Ocelot.Library.Infrastructure.UrlPathMatcher; @@ -25,7 +26,7 @@ namespace Ocelot.UnitTests WhenIMatchThePaths(); ThenTheResultIsTrue(); ThenTheTemplatesDictionaryIs(new List()); - + ThenTheUrlPathTemplateIs("api/product/products/"); } [Fact] @@ -41,6 +42,7 @@ namespace Ocelot.UnitTests WhenIMatchThePaths(); ThenTheResultIsTrue(); ThenTheTemplatesDictionaryIs(expectedTemplates); + ThenTheUrlPathTemplateIs("api/product/products/{productId}/variants/"); } [Fact] @@ -56,6 +58,8 @@ namespace Ocelot.UnitTests WhenIMatchThePaths(); ThenTheResultIsTrue(); ThenTheTemplatesDictionaryIs(expectedTemplates); + ThenTheUrlPathTemplateIs("api/product/products/{productId}"); + } [Fact] @@ -72,6 +76,8 @@ namespace Ocelot.UnitTests WhenIMatchThePaths(); ThenTheResultIsTrue(); ThenTheTemplatesDictionaryIs(expectedTemplates); + ThenTheUrlPathTemplateIs("api/product/products/{productId}/{categoryId}"); + } [Fact] @@ -88,6 +94,8 @@ namespace Ocelot.UnitTests WhenIMatchThePaths(); ThenTheResultIsTrue(); ThenTheTemplatesDictionaryIs(expectedTemplates); + ThenTheUrlPathTemplateIs("api/product/products/{productId}/categories/{categoryId}"); + } [Fact] @@ -105,6 +113,8 @@ namespace Ocelot.UnitTests WhenIMatchThePaths(); ThenTheResultIsTrue(); ThenTheTemplatesDictionaryIs(expectedTemplates); + ThenTheUrlPathTemplateIs("api/product/products/{productId}/categories/{categoryId}/variant/{variantId}"); + } [Fact] @@ -121,6 +131,8 @@ namespace Ocelot.UnitTests WhenIMatchThePaths(); ThenTheResultIsTrue(); ThenTheTemplatesDictionaryIs(expectedTemplates); + ThenTheUrlPathTemplateIs("api/product/products/{productId}/categories/{categoryId}/variant/"); + } private void ThenTheTemplatesDictionaryIs(List expectedResults) @@ -133,6 +145,10 @@ namespace Ocelot.UnitTests } } + private void ThenTheUrlPathTemplateIs(string expectedUrlPathTemplate) + { + _result.UrlPathTemplate.ShouldBe(expectedUrlPathTemplate); + } private void GivenIHaveADownstreamPath(string downstreamPath) { _downstreamPath = downstreamPath; From d3b9fddcfddd90c72a7e904a22a5422fa3e8f4e5 Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Thu, 21 Jul 2016 21:14:27 +0100 Subject: [PATCH 013/183] Added url replacer --- .../IUrlPathToUrlPathTemplateMatcher.cs | 2 +- .../UrlPathMatcher/UrlPathMatch.cs | 7 +- .../UrlPathToUrlPathTemplateMatcher.cs | 22 ++- ...UpstreamUrlPathTemplateVariableReplacer.cs | 10 ++ ...UpstreamUrlPathTemplateVariableReplacer.cs | 22 +++ .../Middleware/ProxyMiddleware.cs | 20 ++- ...eamUrlPathTemplateVariableReplacerTests.cs | 137 ++++++++++++++++++ .../UrlPathToUrlPathTemplateMatcherTests.cs | 68 +++++++-- 8 files changed, 250 insertions(+), 38 deletions(-) create mode 100644 src/Ocelot.Library/Infrastructure/UrlPathReplacer/IUpstreamUrlPathTemplateVariableReplacer.cs create mode 100644 src/Ocelot.Library/Infrastructure/UrlPathReplacer/UpstreamUrlPathTemplateVariableReplacer.cs create mode 100644 test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs diff --git a/src/Ocelot.Library/Infrastructure/UrlPathMatcher/IUrlPathToUrlPathTemplateMatcher.cs b/src/Ocelot.Library/Infrastructure/UrlPathMatcher/IUrlPathToUrlPathTemplateMatcher.cs index a5a9e25a..5ed4d637 100644 --- a/src/Ocelot.Library/Infrastructure/UrlPathMatcher/IUrlPathToUrlPathTemplateMatcher.cs +++ b/src/Ocelot.Library/Infrastructure/UrlPathMatcher/IUrlPathToUrlPathTemplateMatcher.cs @@ -2,6 +2,6 @@ namespace Ocelot.Library.Infrastructure.UrlPathMatcher { public interface IUrlPathToUrlPathTemplateMatcher { - UrlPathMatch Match(string urlPath, string urlPathTemplate); + UrlPathMatch Match(string downstreamUrlPath, string downStreamUrlPathTemplate); } } \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathMatch.cs b/src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathMatch.cs index e7f21430..7f474e62 100644 --- a/src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathMatch.cs +++ b/src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathMatch.cs @@ -4,15 +4,14 @@ namespace Ocelot.Library.Infrastructure.UrlPathMatcher { public class UrlPathMatch { - public UrlPathMatch(bool match, List templateVariableNameAndValues, string urlPathTemplate) + public UrlPathMatch(bool match, List templateVariableNameAndValues, string downstreamUrlPathTemplate) { Match = match; TemplateVariableNameAndValues = templateVariableNameAndValues; - UrlPathTemplate = urlPathTemplate; + DownstreamUrlPathTemplate = downstreamUrlPathTemplate; } public bool Match {get;private set;} public List TemplateVariableNameAndValues {get;private set;} - - public string UrlPathTemplate {get;private set;} + public string DownstreamUrlPathTemplate {get;private set;} } } \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathToUrlPathTemplateMatcher.cs b/src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathToUrlPathTemplateMatcher.cs index 8ca2ded1..3b2152e8 100644 --- a/src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathToUrlPathTemplateMatcher.cs +++ b/src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathToUrlPathTemplateMatcher.cs @@ -5,35 +5,31 @@ namespace Ocelot.Library.Infrastructure.UrlPathMatcher { public class UrlPathToUrlPathTemplateMatcher : IUrlPathToUrlPathTemplateMatcher { - public UrlPathMatch Match(string urlPath, string urlPathTemplate) + public UrlPathMatch Match(string downstreamUrlPath, string downstreamUrlPathTemplate) { - var urlPathTemplateCopy = urlPathTemplate; + var urlPathTemplateCopy = downstreamUrlPathTemplate; var templateKeysAndValues = new List(); - urlPath = urlPath.ToLower(); - - urlPathTemplate = urlPathTemplate.ToLower(); - int counterForUrl = 0; - for (int counterForTemplate = 0; counterForTemplate < urlPathTemplate.Length; counterForTemplate++) + for (int counterForTemplate = 0; counterForTemplate < downstreamUrlPathTemplate.Length; counterForTemplate++) { - if (CharactersDontMatch(urlPathTemplate[counterForTemplate], urlPath[counterForUrl]) && ContinueScanningUrl(counterForUrl,urlPath.Length)) + if (CharactersDontMatch(downstreamUrlPathTemplate[counterForTemplate], downstreamUrlPath[counterForUrl]) && ContinueScanningUrl(counterForUrl,downstreamUrlPath.Length)) { - if (IsPlaceholder(urlPathTemplate[counterForTemplate])) + if (IsPlaceholder(downstreamUrlPathTemplate[counterForTemplate])) { - var variableName = GetPlaceholderVariableName(urlPathTemplate, counterForTemplate); + var variableName = GetPlaceholderVariableName(downstreamUrlPathTemplate, counterForTemplate); - var variableValue = GetPlaceholderVariableValue(urlPath, counterForUrl); + var variableValue = GetPlaceholderVariableValue(downstreamUrlPath, counterForUrl); var templateVariableNameAndValue = new TemplateVariableNameAndValue(variableName, variableValue); templateKeysAndValues.Add(templateVariableNameAndValue); - counterForTemplate = GetNextCounterPosition(urlPathTemplate, counterForTemplate, '}'); + counterForTemplate = GetNextCounterPosition(downstreamUrlPathTemplate, counterForTemplate, '}'); - counterForUrl = GetNextCounterPosition(urlPath, counterForUrl, '/'); + counterForUrl = GetNextCounterPosition(downstreamUrlPath, counterForUrl, '/'); continue; } diff --git a/src/Ocelot.Library/Infrastructure/UrlPathReplacer/IUpstreamUrlPathTemplateVariableReplacer.cs b/src/Ocelot.Library/Infrastructure/UrlPathReplacer/IUpstreamUrlPathTemplateVariableReplacer.cs new file mode 100644 index 00000000..cb455185 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/UrlPathReplacer/IUpstreamUrlPathTemplateVariableReplacer.cs @@ -0,0 +1,10 @@ +using Ocelot.Library.Infrastructure.UrlPathMatcher; + +namespace Ocelot.Library.Infrastructure.UrlPathReplacer +{ + public interface IUpstreamUrlPathTemplateVariableReplacer + { + string ReplaceTemplateVariable(string upstreamPathTemplate, UrlPathMatch urlPathMatch); + + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlPathReplacer/UpstreamUrlPathTemplateVariableReplacer.cs b/src/Ocelot.Library/Infrastructure/UrlPathReplacer/UpstreamUrlPathTemplateVariableReplacer.cs new file mode 100644 index 00000000..b52ea69e --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/UrlPathReplacer/UpstreamUrlPathTemplateVariableReplacer.cs @@ -0,0 +1,22 @@ +using System; +using System.Text; +using Ocelot.Library.Infrastructure.UrlPathMatcher; + +namespace Ocelot.Library.Infrastructure.UrlPathReplacer +{ + public class UpstreamUrlPathTemplateVariableReplacer : IUpstreamUrlPathTemplateVariableReplacer + { + public string ReplaceTemplateVariable(string upstreamPathTemplate, UrlPathMatch urlPathMatch) + { + var upstreamUrl = new StringBuilder(); + upstreamUrl.Append(upstreamPathTemplate); + + foreach (var templateVarAndValue in urlPathMatch.TemplateVariableNameAndValues) + { + upstreamUrl.Replace(templateVarAndValue.TemplateVariableName, templateVarAndValue.TemplateVariableValue); + } + + return upstreamUrl.ToString(); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs index 6c7ad7ef..cb5eb149 100644 --- a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs +++ b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Ocelot.Library.Infrastructure.HostUrlRepository; using Ocelot.Library.Infrastructure.UrlPathMatcher; +using Ocelot.Library.Infrastructure.UrlPathReplacer; using Ocelot.Library.Infrastructure.UrlPathTemplateRepository; namespace Ocelot.Library.Middleware @@ -13,15 +14,18 @@ namespace Ocelot.Library.Middleware private readonly IUrlPathToUrlPathTemplateMatcher _urlMatcher; private readonly IUrlPathTemplateMapRepository _urlPathRepository; private readonly IHostUrlMapRepository _hostUrlRepository; + private readonly IUpstreamUrlPathTemplateVariableReplacer _urlReplacer; public ProxyMiddleware(RequestDelegate next, IUrlPathToUrlPathTemplateMatcher urlMatcher, IUrlPathTemplateMapRepository urlPathRepository, - IHostUrlMapRepository hostUrlRepository) + IHostUrlMapRepository hostUrlRepository, + IUpstreamUrlPathTemplateVariableReplacer urlReplacer) { _next = next; _urlMatcher = urlMatcher; _urlPathRepository = urlPathRepository; _hostUrlRepository = hostUrlRepository; + _urlReplacer = urlReplacer; } public async Task Invoke(HttpContext context) @@ -29,18 +33,18 @@ namespace Ocelot.Library.Middleware var path = context.Request.Path.ToString(); - var templates = _urlPathRepository.All; + var urlPathTemplateMaps = _urlPathRepository.All; UrlPathMatch urlPathMatch = null; - string upstreamPathUrl = string.Empty; + string upstreamPathUrlTemplate = string.Empty; - foreach (var template in templates.Data) + foreach (var template in urlPathTemplateMaps.Data) { urlPathMatch = _urlMatcher.Match(path, template.DownstreamUrlPathTemplate); if (urlPathMatch.Match) { - upstreamPathUrl = template.UpstreamUrlPathTemplate; + upstreamPathUrlTemplate = template.UpstreamUrlPathTemplate; break; } } @@ -50,11 +54,11 @@ namespace Ocelot.Library.Middleware throw new Exception("BOOOM TING! no match"); } - var upstreamHostUrl = _hostUrlRepository.GetBaseUrlMap(urlPathMatch.UrlPathTemplate); + var upstreamHostUrl = _hostUrlRepository.GetBaseUrlMap(urlPathMatch.DownstreamUrlPathTemplate); - //now map the variables from the url path to the upstream url path - + var pathUrl = _urlReplacer.ReplaceTemplateVariable(upstreamPathUrlTemplate, urlPathMatch); + //make a http request to this endpoint...maybe bring in a library await _next.Invoke(context); } diff --git a/test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs b/test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs new file mode 100644 index 00000000..31811406 --- /dev/null +++ b/test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs @@ -0,0 +1,137 @@ +using System.Collections.Generic; +using Ocelot.Library.Infrastructure.UrlPathMatcher; +using Ocelot.Library.Infrastructure.UrlPathReplacer; +using Shouldly; +using Xunit; + +namespace Ocelot.UnitTests +{ + public class UpstreamUrlPathTemplateVariableReplacerTests + { + + private string _upstreamUrlPath; + private UrlPathMatch _urlPathMatch; + private string _result; + private IUpstreamUrlPathTemplateVariableReplacer _upstreamUrlPathReplacer; + + public UpstreamUrlPathTemplateVariableReplacerTests() + { + _upstreamUrlPathReplacer = new UpstreamUrlPathTemplateVariableReplacer(); + } + [Fact] + public void can_replace_no_template_variables() + { + GivenThereIsAnUpstreamUrlPath(""); + GivenThereIsAUrlPathMatch(new UrlPathMatch(true, new List(), "")); + WhenIReplaceTheTemplateVariables(); + ThenTheUpstreamUrlPathIsReturned(""); + } + + [Fact] + public void can_replace_url_no_slash() + { + GivenThereIsAnUpstreamUrlPath("api"); + GivenThereIsAUrlPathMatch(new UrlPathMatch(true, new List(), "api")); + WhenIReplaceTheTemplateVariables(); + ThenTheUpstreamUrlPathIsReturned("api"); + } + + [Fact] + public void can_replace_url_one_slash() + { + GivenThereIsAnUpstreamUrlPath("api/"); + GivenThereIsAUrlPathMatch(new UrlPathMatch(true, new List(), "api/")); + WhenIReplaceTheTemplateVariables(); + ThenTheUpstreamUrlPathIsReturned("api/"); + } + + [Fact] + public void can_replace_url_multiple_slash() + { + GivenThereIsAnUpstreamUrlPath("api/product/products/"); + GivenThereIsAUrlPathMatch(new UrlPathMatch(true, new List(), "api/product/products/")); + WhenIReplaceTheTemplateVariables(); + ThenTheUpstreamUrlPathIsReturned("api/product/products/"); + } + + [Fact] + public void can_replace_url_one_template_variable() + { + var templateVariables = new List() + { + new TemplateVariableNameAndValue("{productId}", "1") + }; + + GivenThereIsAnUpstreamUrlPath("productservice/products/{productId}/"); + GivenThereIsAUrlPathMatch(new UrlPathMatch(true, templateVariables, "api/products/{productId}/")); + WhenIReplaceTheTemplateVariables(); + ThenTheUpstreamUrlPathIsReturned("productservice/products/1/"); + } + + [Fact] + public void can_replace_url_one_template_variable_with_path_after() + { + var templateVariables = new List() + { + new TemplateVariableNameAndValue("{productId}", "1") + }; + + GivenThereIsAnUpstreamUrlPath("productservice/products/{productId}/variants"); + GivenThereIsAUrlPathMatch(new UrlPathMatch(true, templateVariables, "api/products/{productId}/")); + WhenIReplaceTheTemplateVariables(); + ThenTheUpstreamUrlPathIsReturned("productservice/products/1/variants"); + } + + [Fact] + public void can_replace_url_two_template_variable() + { + var templateVariables = new List() + { + new TemplateVariableNameAndValue("{productId}", "1"), + new TemplateVariableNameAndValue("{variantId}", "12") + }; + + GivenThereIsAnUpstreamUrlPath("productservice/products/{productId}/variants/{variantId}"); + GivenThereIsAUrlPathMatch(new UrlPathMatch(true, templateVariables, "api/products/{productId}/{variantId}")); + WhenIReplaceTheTemplateVariables(); + ThenTheUpstreamUrlPathIsReturned("productservice/products/1/variants/12"); + } + + [Fact] + public void can_replace_url_three_template_variable() + { + var templateVariables = new List() + { + new TemplateVariableNameAndValue("{productId}", "1"), + new TemplateVariableNameAndValue("{variantId}", "12"), + new TemplateVariableNameAndValue("{categoryId}", "34") + }; + + GivenThereIsAnUpstreamUrlPath("productservice/category/{categoryId}/products/{productId}/variants/{variantId}"); + GivenThereIsAUrlPathMatch(new UrlPathMatch(true, templateVariables, "api/products/{categoryId}/{productId}/{variantId}")); + WhenIReplaceTheTemplateVariables(); + ThenTheUpstreamUrlPathIsReturned("productservice/category/34/products/1/variants/12"); + } + + private void GivenThereIsAnUpstreamUrlPath(string upstreamUrlPath) + { + _upstreamUrlPath = upstreamUrlPath; + } + + private void GivenThereIsAUrlPathMatch(UrlPathMatch urlPathMatch) + { + _urlPathMatch = urlPathMatch; + } + + private void WhenIReplaceTheTemplateVariables() + { + _result = _upstreamUrlPathReplacer.ReplaceTemplateVariable(_upstreamUrlPath, _urlPathMatch); + } + + private void ThenTheUpstreamUrlPathIsReturned(string expected) + { + _result.ShouldBe(expected); + } + + } +} diff --git a/test/Ocelot.UnitTests/UrlPathToUrlPathTemplateMatcherTests.cs b/test/Ocelot.UnitTests/UrlPathToUrlPathTemplateMatcherTests.cs index 1219476a..4cf8a87f 100644 --- a/test/Ocelot.UnitTests/UrlPathToUrlPathTemplateMatcherTests.cs +++ b/test/Ocelot.UnitTests/UrlPathToUrlPathTemplateMatcherTests.cs @@ -18,6 +18,50 @@ namespace Ocelot.UnitTests _urlMapper = new UrlPathToUrlPathTemplateMatcher(); } + [Fact] + public void can_match_down_stream_url() + { + GivenIHaveADownstreamPath(""); + GivenIHaveAnDownstreamPathTemplate(""); + WhenIMatchThePaths(); + ThenTheResultIsTrue(); + ThenTheTemplatesDictionaryIs(new List()); + ThenTheUrlPathTemplateIs(""); + } + + [Fact] + public void can_match_down_stream_url_with_no_slash() + { + GivenIHaveADownstreamPath("api"); + GivenIHaveAnDownstreamPathTemplate("api"); + WhenIMatchThePaths(); + ThenTheResultIsTrue(); + ThenTheTemplatesDictionaryIs(new List()); + ThenTheUrlPathTemplateIs("api"); + } + + [Fact] + public void can_match_down_stream_url_with_one_slash() + { + GivenIHaveADownstreamPath("api/"); + GivenIHaveAnDownstreamPathTemplate("api/"); + WhenIMatchThePaths(); + ThenTheResultIsTrue(); + ThenTheTemplatesDictionaryIs(new List()); + ThenTheUrlPathTemplateIs("api/"); + } + + [Fact] + public void can_match_down_stream_url_with_downstream_template() + { + GivenIHaveADownstreamPath("api/product/products/"); + GivenIHaveAnDownstreamPathTemplate("api/product/products/"); + WhenIMatchThePaths(); + ThenTheResultIsTrue(); + ThenTheTemplatesDictionaryIs(new List()); + ThenTheUrlPathTemplateIs("api/product/products/"); + } + [Fact] public void can_match_down_stream_url_with_downstream_template_with_one_query_string_parameter() { @@ -34,7 +78,7 @@ namespace Ocelot.UnitTests { var expectedTemplates = new List { - new TemplateVariableNameAndValue("{productid}", "1") + new TemplateVariableNameAndValue("{productId}", "1") }; GivenIHaveADownstreamPath("api/product/products/1/variants/?soldout=false"); @@ -50,7 +94,7 @@ namespace Ocelot.UnitTests { var expectedTemplates = new List { - new TemplateVariableNameAndValue("{productid}", "1") + new TemplateVariableNameAndValue("{productId}", "1") }; GivenIHaveADownstreamPath("api/product/products/1"); @@ -67,8 +111,8 @@ namespace Ocelot.UnitTests { var expectedTemplates = new List { - new TemplateVariableNameAndValue("{productid}", "1"), - new TemplateVariableNameAndValue("{categoryid}", "2") + new TemplateVariableNameAndValue("{productId}", "1"), + new TemplateVariableNameAndValue("{categoryId}", "2") }; GivenIHaveADownstreamPath("api/product/products/1/2"); @@ -85,8 +129,8 @@ namespace Ocelot.UnitTests { var expectedTemplates = new List { - new TemplateVariableNameAndValue("{productid}", "1"), - new TemplateVariableNameAndValue("{categoryid}", "2") + new TemplateVariableNameAndValue("{productId}", "1"), + new TemplateVariableNameAndValue("{categoryId}", "2") }; GivenIHaveADownstreamPath("api/product/products/1/categories/2"); @@ -103,9 +147,9 @@ namespace Ocelot.UnitTests { var expectedTemplates = new List { - new TemplateVariableNameAndValue("{productid}", "1"), - new TemplateVariableNameAndValue("{categoryid}", "2"), - new TemplateVariableNameAndValue("{variantid}", "123") + new TemplateVariableNameAndValue("{productId}", "1"), + new TemplateVariableNameAndValue("{categoryId}", "2"), + new TemplateVariableNameAndValue("{variantId}", "123") }; GivenIHaveADownstreamPath("api/product/products/1/categories/2/variant/123"); @@ -122,8 +166,8 @@ namespace Ocelot.UnitTests { var expectedTemplates = new List { - new TemplateVariableNameAndValue("{productid}", "1"), - new TemplateVariableNameAndValue("{categoryid}", "2") + new TemplateVariableNameAndValue("{productId}", "1"), + new TemplateVariableNameAndValue("{categoryId}", "2") }; GivenIHaveADownstreamPath("api/product/products/1/categories/2/variant/"); @@ -147,7 +191,7 @@ namespace Ocelot.UnitTests private void ThenTheUrlPathTemplateIs(string expectedUrlPathTemplate) { - _result.UrlPathTemplate.ShouldBe(expectedUrlPathTemplate); + _result.DownstreamUrlPathTemplate.ShouldBe(expectedUrlPathTemplate); } private void GivenIHaveADownstreamPath(string downstreamPath) { From 0421dba1e2d84b864eee0131f8d0ad3ca6d0910e Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Wed, 17 Aug 2016 19:24:23 +0100 Subject: [PATCH 014/183] Added some benchmarke benchmark stuff --- test/Ocelot.Benchmarks/.gitignore | 234 ++++++++++++++++++ ...TemplateMatcherBenchmarks-report-github.md | 20 ++ ...rlPathTemplateMatcherBenchmarks-report.csv | 3 + ...lPathTemplateMatcherBenchmarks-report.html | 20 ++ test/Ocelot.Benchmarks/Program.cs | 16 ++ ...lPathToUrlPathTemplateMatcherBenchmarks.cs | 42 ++++ test/Ocelot.Benchmarks/project.json | 28 +++ 7 files changed, 363 insertions(+) create mode 100644 test/Ocelot.Benchmarks/.gitignore create mode 100755 test/Ocelot.Benchmarks/BenchmarkDotNet.Artifacts/results/UrlPathToUrlPathTemplateMatcherBenchmarks-report-github.md create mode 100755 test/Ocelot.Benchmarks/BenchmarkDotNet.Artifacts/results/UrlPathToUrlPathTemplateMatcherBenchmarks-report.csv create mode 100755 test/Ocelot.Benchmarks/BenchmarkDotNet.Artifacts/results/UrlPathToUrlPathTemplateMatcherBenchmarks-report.html create mode 100644 test/Ocelot.Benchmarks/Program.cs create mode 100644 test/Ocelot.Benchmarks/UrlPathToUrlPathTemplateMatcherBenchmarks.cs create mode 100644 test/Ocelot.Benchmarks/project.json diff --git a/test/Ocelot.Benchmarks/.gitignore b/test/Ocelot.Benchmarks/.gitignore new file mode 100644 index 00000000..0ca27f04 --- /dev/null +++ b/test/Ocelot.Benchmarks/.gitignore @@ -0,0 +1,234 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +build/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Microsoft Azure ApplicationInsights config file +ApplicationInsights.config + +# Windows Store app package directory +AppPackages/ +BundleArtifacts/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe + +# FAKE - F# Make +.fake/ diff --git a/test/Ocelot.Benchmarks/BenchmarkDotNet.Artifacts/results/UrlPathToUrlPathTemplateMatcherBenchmarks-report-github.md b/test/Ocelot.Benchmarks/BenchmarkDotNet.Artifacts/results/UrlPathToUrlPathTemplateMatcherBenchmarks-report-github.md new file mode 100755 index 00000000..ca7d330c --- /dev/null +++ b/test/Ocelot.Benchmarks/BenchmarkDotNet.Artifacts/results/UrlPathToUrlPathTemplateMatcherBenchmarks-report-github.md @@ -0,0 +1,20 @@ +```ini + +Host Process Environment Information: +BenchmarkDotNet=v0.9.8.0 +OS=OSX +Processor=?, ProcessorCount=4 +Frequency=1000000000 ticks, Resolution=1.0000 ns, Timer=UNKNOWN +CLR=CORE, Arch=64-bit ? [RyuJIT] +GC=Concurrent Workstation +JitModules=? +dotnet cli version: 1.0.0-preview2-003121 + +Type=UrlPathToUrlPathTemplateMatcherBenchmarks Mode=Throughput Toolchain=Core +GarbageCollection=Concurrent Workstation + +``` + Method | Median | StdDev | Mean | StdError | StdDev | Op/s | Min | Q1 | Median | Q3 | Max | +----------- |------------ |---------- |------------ |---------- |---------- |----------- |------------ |------------ |------------ |------------ |------------ | + Benchmark1 | 180.4251 ns | 4.1294 ns | 180.4400 ns | 0.9234 ns | 4.1294 ns | 5542007.02 | 174.5503 ns | 177.6286 ns | 180.4251 ns | 182.5334 ns | 190.9792 ns | + Benchmark2 | 178.7267 ns | 6.1670 ns | 180.6081 ns | 1.3148 ns | 6.1670 ns | 5536849.8 | 174.0821 ns | 177.0992 ns | 178.7267 ns | 182.1962 ns | 198.1308 ns | diff --git a/test/Ocelot.Benchmarks/BenchmarkDotNet.Artifacts/results/UrlPathToUrlPathTemplateMatcherBenchmarks-report.csv b/test/Ocelot.Benchmarks/BenchmarkDotNet.Artifacts/results/UrlPathToUrlPathTemplateMatcherBenchmarks-report.csv new file mode 100755 index 00000000..2f7488c0 --- /dev/null +++ b/test/Ocelot.Benchmarks/BenchmarkDotNet.Artifacts/results/UrlPathToUrlPathTemplateMatcherBenchmarks-report.csv @@ -0,0 +1,3 @@ +Type;Method;Mode;Platform;Jit;Toolchain;Runtime;GarbageCollection;LaunchCount;WarmupCount;TargetCount;Affinity;Median;StdDev;Mean;StdError;StdDev;Op/s;Min;Q1;Median;Q3;Max +UrlPathToUrlPathTemplateMatcherBenchmarks;Benchmark1;Throughput;Host;Host;Core;Host;Concurrent Workstation;Auto;Auto;Auto;Auto;180.4251 ns;4.1294 ns;180.4400 ns;0.9234 ns;4.1294 ns;5542007.02;174.5503 ns;177.6286 ns;180.4251 ns;182.5334 ns;190.9792 ns +UrlPathToUrlPathTemplateMatcherBenchmarks;Benchmark2;Throughput;Host;Host;Core;Host;Concurrent Workstation;Auto;Auto;Auto;Auto;178.7267 ns;6.1670 ns;180.6081 ns;1.3148 ns;6.1670 ns;5536849.8;174.0821 ns;177.0992 ns;178.7267 ns;182.1962 ns;198.1308 ns diff --git a/test/Ocelot.Benchmarks/BenchmarkDotNet.Artifacts/results/UrlPathToUrlPathTemplateMatcherBenchmarks-report.html b/test/Ocelot.Benchmarks/BenchmarkDotNet.Artifacts/results/UrlPathToUrlPathTemplateMatcherBenchmarks-report.html new file mode 100755 index 00000000..229b23f1 --- /dev/null +++ b/test/Ocelot.Benchmarks/BenchmarkDotNet.Artifacts/results/UrlPathToUrlPathTemplateMatcherBenchmarks-report.html @@ -0,0 +1,20 @@ +

+Host Process Environment Information:
+BenchmarkDotNet=v0.9.8.0
+OS=OSX
+Processor=?, ProcessorCount=4
+Frequency=1000000000 ticks, Resolution=1.0000 ns, Timer=UNKNOWN
+CLR=CORE, Arch=64-bit ? [RyuJIT]
+GC=Concurrent Workstation
+JitModules=?
+dotnet cli version: 1.0.0-preview2-003121
+
+
Type=UrlPathToUrlPathTemplateMatcherBenchmarks  Mode=Throughput  Toolchain=Core  
+GarbageCollection=Concurrent Workstation  
+
+ + + + + +
MethodMedianStdDev MeanStdErrorStdDevOp/s Min Q1Median Q3 Max
Benchmark1180.4251 ns4.1294 ns180.4400 ns0.9234 ns4.1294 ns5542007.02174.5503 ns177.6286 ns180.4251 ns182.5334 ns190.9792 ns
Benchmark2178.7267 ns6.1670 ns180.6081 ns1.3148 ns6.1670 ns5536849.8174.0821 ns177.0992 ns178.7267 ns182.1962 ns198.1308 ns
diff --git a/test/Ocelot.Benchmarks/Program.cs b/test/Ocelot.Benchmarks/Program.cs new file mode 100644 index 00000000..1ff2bc92 --- /dev/null +++ b/test/Ocelot.Benchmarks/Program.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using BenchmarkDotNet.Running; + +namespace Ocelot.Benchmarks +{ + public class Program + { + public static void Main(string[] args) + { + var summary = BenchmarkRunner.Run(); + } + } +} diff --git a/test/Ocelot.Benchmarks/UrlPathToUrlPathTemplateMatcherBenchmarks.cs b/test/Ocelot.Benchmarks/UrlPathToUrlPathTemplateMatcherBenchmarks.cs new file mode 100644 index 00000000..c88cbc69 --- /dev/null +++ b/test/Ocelot.Benchmarks/UrlPathToUrlPathTemplateMatcherBenchmarks.cs @@ -0,0 +1,42 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Columns; +using BenchmarkDotNet.Configs; +using BenchmarkDotNet.Jobs; +using Ocelot.Library.Infrastructure.UrlPathMatcher; + + +namespace Ocelot.Benchmarks +{ + [Config(typeof(UrlPathToUrlPathTemplateMatcherBenchmarks))] + public class UrlPathToUrlPathTemplateMatcherBenchmarks : ManualConfig + { + private UrlPathToUrlPathTemplateMatcher _urlPathMatcher; + private string _downstreamUrlPath; + private string _downstreamUrlPathTemplate; + + public UrlPathToUrlPathTemplateMatcherBenchmarks() + { + Add(StatisticColumn.AllStatistics); + } + + [Setup] + public void SetUp() + { + _urlPathMatcher = new UrlPathToUrlPathTemplateMatcher(); + _downstreamUrlPath = "api/product/products/1/variants/?soldout=false"; + _downstreamUrlPathTemplate = "api/product/products/{productId}/variants/"; + } + + [Benchmark] + public void Benchmark1() + { + _urlPathMatcher.Match(_downstreamUrlPath, _downstreamUrlPathTemplate); + } + + [Benchmark] + public void Benchmark2() + { + _urlPathMatcher.Match(_downstreamUrlPath, _downstreamUrlPathTemplate); + } + } +} \ No newline at end of file diff --git a/test/Ocelot.Benchmarks/project.json b/test/Ocelot.Benchmarks/project.json new file mode 100644 index 00000000..da710bc9 --- /dev/null +++ b/test/Ocelot.Benchmarks/project.json @@ -0,0 +1,28 @@ +{ + "version": "1.0.0-*", + "buildOptions": { + "emitEntryPoint": true + }, + + "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.0.0", + "type": "platform" + }, + "BenchmarkDotNet": "0.9.8", + "Ocelot.Library": "1.0.0-*" + }, + + "frameworks": { + "netcoreapp1.0": { + "imports": [ + "dotnet5.6", + "portable-net45+win8" + ] + } + }, + + "tooling": { + "defaultNamespace": "Ocelot.Benchmarks" + } +} From dada014f4819f27381086ef23d212d3a1259f7e2 Mon Sep 17 00:00:00 2001 From: Tom Pallister Date: Fri, 19 Aug 2016 13:46:46 +0100 Subject: [PATCH 015/183] mucking about on lunch --- .../Middleware/ProxyMiddleware.cs | 7 ++-- src/Ocelot/Startup.cs | 16 +++++---- test/Ocelot.AcceptanceTests/RouterTests.cs | 34 +++++++++---------- 3 files changed, 31 insertions(+), 26 deletions(-) diff --git a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs index cb5eb149..a56fbd17 100644 --- a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs +++ b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs @@ -8,6 +8,8 @@ using Ocelot.Library.Infrastructure.UrlPathTemplateRepository; namespace Ocelot.Library.Middleware { + using System.Net; + public class ProxyMiddleware { private readonly RequestDelegate _next; @@ -49,9 +51,10 @@ namespace Ocelot.Library.Middleware } } - if (!urlPathMatch.Match) + if (urlPathMatch == null || !urlPathMatch.Match) { - throw new Exception("BOOOM TING! no match"); + context.Response.StatusCode = (int)HttpStatusCode.NotFound; + return; } var upstreamHostUrl = _hostUrlRepository.GetBaseUrlMap(urlPathMatch.DownstreamUrlPathTemplate); diff --git a/src/Ocelot/Startup.cs b/src/Ocelot/Startup.cs index e13d551d..d95b6f65 100644 --- a/src/Ocelot/Startup.cs +++ b/src/Ocelot/Startup.cs @@ -8,6 +8,11 @@ using Ocelot.Library.Middleware; namespace Ocelot { + using Library.Infrastructure.HostUrlRepository; + using Library.Infrastructure.UrlPathMatcher; + using Library.Infrastructure.UrlPathReplacer; + using Library.Infrastructure.UrlPathTemplateRepository; + public class Startup { public Startup(IHostingEnvironment env) @@ -26,7 +31,11 @@ namespace Ocelot public void ConfigureServices(IServiceCollection services) { // Add framework services. - + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. @@ -37,11 +46,6 @@ namespace Ocelot loggerFactory.AddDebug(); app.UseProxy(); - //app.Run() - // app.Run(async context => - // { - // await context.Response.WriteAsync("Hello from Tom"); - // }); } } } diff --git a/test/Ocelot.AcceptanceTests/RouterTests.cs b/test/Ocelot.AcceptanceTests/RouterTests.cs index 0381ff41..c3d5fafa 100644 --- a/test/Ocelot.AcceptanceTests/RouterTests.cs +++ b/test/Ocelot.AcceptanceTests/RouterTests.cs @@ -1,6 +1,5 @@ using System; using System.Net.Http; -using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Xunit; @@ -9,41 +8,40 @@ using Shouldly; namespace Ocelot.AcceptanceTests { + using System.Net; + public class RouterTests : IDisposable { - private FakeService _fakeService; + private readonly FakeService _fakeService; private readonly TestServer _server; private readonly HttpClient _client; + private HttpResponseMessage _response; public RouterTests() { _server = new TestServer(new WebHostBuilder() .UseStartup()); + _client = _server.CreateClient(); + _fakeService = new FakeService(); } [Fact] - public void hello_world() + public void should_return_response_404() { - var response = _client.GetAsync("/").Result; - response.EnsureSuccessStatusCode(); - - var responseString = response.Content.ReadAsStringAsync().Result; - responseString.ShouldBe("Hello from Tom"); + WhenIRequestTheUrl("/"); + ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound); } - [Fact] - public async Task can_route_request() - { - _fakeService.Start("http://localhost:5001"); + private void WhenIRequestTheUrl(string url) + { + _response = _client.GetAsync("/").Result; + } - // Act - var response = await _client.GetAsync("/"); - response.EnsureSuccessStatusCode(); - - var responseString = await response.Content.ReadAsStringAsync(); - responseString.ShouldBe("Hello from Laura"); + private void ThenTheStatusCodeShouldBe(HttpStatusCode expectedHttpStatusCode) + { + _response.StatusCode.ShouldBe(expectedHttpStatusCode); } public void Dispose() From c41dd950e004a9114db579ae47bf681b3dbf9030 Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Fri, 19 Aug 2016 20:20:10 +0100 Subject: [PATCH 016/183] merged develop --- .../Middleware/ProxyMiddleware.cs | 7 ++-- src/Ocelot/Startup.cs | 16 +++++---- test/Ocelot.AcceptanceTests/RouterTests.cs | 34 +++++++++---------- ...TemplateMatcherBenchmarks-report-github.md | 8 ++--- ...rlPathTemplateMatcherBenchmarks-report.csv | 4 +-- ...lPathTemplateMatcherBenchmarks-report.html | 4 +-- 6 files changed, 39 insertions(+), 34 deletions(-) diff --git a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs index cb5eb149..a56fbd17 100644 --- a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs +++ b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs @@ -8,6 +8,8 @@ using Ocelot.Library.Infrastructure.UrlPathTemplateRepository; namespace Ocelot.Library.Middleware { + using System.Net; + public class ProxyMiddleware { private readonly RequestDelegate _next; @@ -49,9 +51,10 @@ namespace Ocelot.Library.Middleware } } - if (!urlPathMatch.Match) + if (urlPathMatch == null || !urlPathMatch.Match) { - throw new Exception("BOOOM TING! no match"); + context.Response.StatusCode = (int)HttpStatusCode.NotFound; + return; } var upstreamHostUrl = _hostUrlRepository.GetBaseUrlMap(urlPathMatch.DownstreamUrlPathTemplate); diff --git a/src/Ocelot/Startup.cs b/src/Ocelot/Startup.cs index e13d551d..d95b6f65 100644 --- a/src/Ocelot/Startup.cs +++ b/src/Ocelot/Startup.cs @@ -8,6 +8,11 @@ using Ocelot.Library.Middleware; namespace Ocelot { + using Library.Infrastructure.HostUrlRepository; + using Library.Infrastructure.UrlPathMatcher; + using Library.Infrastructure.UrlPathReplacer; + using Library.Infrastructure.UrlPathTemplateRepository; + public class Startup { public Startup(IHostingEnvironment env) @@ -26,7 +31,11 @@ namespace Ocelot public void ConfigureServices(IServiceCollection services) { // Add framework services. - + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. @@ -37,11 +46,6 @@ namespace Ocelot loggerFactory.AddDebug(); app.UseProxy(); - //app.Run() - // app.Run(async context => - // { - // await context.Response.WriteAsync("Hello from Tom"); - // }); } } } diff --git a/test/Ocelot.AcceptanceTests/RouterTests.cs b/test/Ocelot.AcceptanceTests/RouterTests.cs index 0381ff41..c3d5fafa 100644 --- a/test/Ocelot.AcceptanceTests/RouterTests.cs +++ b/test/Ocelot.AcceptanceTests/RouterTests.cs @@ -1,6 +1,5 @@ using System; using System.Net.Http; -using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Xunit; @@ -9,41 +8,40 @@ using Shouldly; namespace Ocelot.AcceptanceTests { + using System.Net; + public class RouterTests : IDisposable { - private FakeService _fakeService; + private readonly FakeService _fakeService; private readonly TestServer _server; private readonly HttpClient _client; + private HttpResponseMessage _response; public RouterTests() { _server = new TestServer(new WebHostBuilder() .UseStartup()); + _client = _server.CreateClient(); + _fakeService = new FakeService(); } [Fact] - public void hello_world() + public void should_return_response_404() { - var response = _client.GetAsync("/").Result; - response.EnsureSuccessStatusCode(); - - var responseString = response.Content.ReadAsStringAsync().Result; - responseString.ShouldBe("Hello from Tom"); + WhenIRequestTheUrl("/"); + ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound); } - [Fact] - public async Task can_route_request() - { - _fakeService.Start("http://localhost:5001"); + private void WhenIRequestTheUrl(string url) + { + _response = _client.GetAsync("/").Result; + } - // Act - var response = await _client.GetAsync("/"); - response.EnsureSuccessStatusCode(); - - var responseString = await response.Content.ReadAsStringAsync(); - responseString.ShouldBe("Hello from Laura"); + private void ThenTheStatusCodeShouldBe(HttpStatusCode expectedHttpStatusCode) + { + _response.StatusCode.ShouldBe(expectedHttpStatusCode); } public void Dispose() diff --git a/test/Ocelot.Benchmarks/BenchmarkDotNet.Artifacts/results/UrlPathToUrlPathTemplateMatcherBenchmarks-report-github.md b/test/Ocelot.Benchmarks/BenchmarkDotNet.Artifacts/results/UrlPathToUrlPathTemplateMatcherBenchmarks-report-github.md index ca7d330c..500c4d6e 100755 --- a/test/Ocelot.Benchmarks/BenchmarkDotNet.Artifacts/results/UrlPathToUrlPathTemplateMatcherBenchmarks-report-github.md +++ b/test/Ocelot.Benchmarks/BenchmarkDotNet.Artifacts/results/UrlPathToUrlPathTemplateMatcherBenchmarks-report-github.md @@ -14,7 +14,7 @@ Type=UrlPathToUrlPathTemplateMatcherBenchmarks Mode=Throughput Toolchain=Core GarbageCollection=Concurrent Workstation ``` - Method | Median | StdDev | Mean | StdError | StdDev | Op/s | Min | Q1 | Median | Q3 | Max | ------------ |------------ |---------- |------------ |---------- |---------- |----------- |------------ |------------ |------------ |------------ |------------ | - Benchmark1 | 180.4251 ns | 4.1294 ns | 180.4400 ns | 0.9234 ns | 4.1294 ns | 5542007.02 | 174.5503 ns | 177.6286 ns | 180.4251 ns | 182.5334 ns | 190.9792 ns | - Benchmark2 | 178.7267 ns | 6.1670 ns | 180.6081 ns | 1.3148 ns | 6.1670 ns | 5536849.8 | 174.0821 ns | 177.0992 ns | 178.7267 ns | 182.1962 ns | 198.1308 ns | + Method | Median | StdDev | Mean | StdError | StdDev | Op/s | Min | Q1 | Median | Q3 | Max | +----------- |------------ |----------- |------------ |---------- |----------- |----------- |------------ |------------ |------------ |------------ |------------ | + Benchmark1 | 184.4215 ns | 5.1537 ns | 185.3322 ns | 1.1524 ns | 5.1537 ns | 5395716.74 | 178.2386 ns | 181.8117 ns | 184.4215 ns | 188.2762 ns | 196.7310 ns | + Benchmark2 | 186.1899 ns | 35.7006 ns | 202.4315 ns | 3.9425 ns | 35.7006 ns | 4939943.34 | 176.9750 ns | 182.9672 ns | 186.1899 ns | 205.8946 ns | 369.0701 ns | diff --git a/test/Ocelot.Benchmarks/BenchmarkDotNet.Artifacts/results/UrlPathToUrlPathTemplateMatcherBenchmarks-report.csv b/test/Ocelot.Benchmarks/BenchmarkDotNet.Artifacts/results/UrlPathToUrlPathTemplateMatcherBenchmarks-report.csv index 2f7488c0..9aaa893e 100755 --- a/test/Ocelot.Benchmarks/BenchmarkDotNet.Artifacts/results/UrlPathToUrlPathTemplateMatcherBenchmarks-report.csv +++ b/test/Ocelot.Benchmarks/BenchmarkDotNet.Artifacts/results/UrlPathToUrlPathTemplateMatcherBenchmarks-report.csv @@ -1,3 +1,3 @@ Type;Method;Mode;Platform;Jit;Toolchain;Runtime;GarbageCollection;LaunchCount;WarmupCount;TargetCount;Affinity;Median;StdDev;Mean;StdError;StdDev;Op/s;Min;Q1;Median;Q3;Max -UrlPathToUrlPathTemplateMatcherBenchmarks;Benchmark1;Throughput;Host;Host;Core;Host;Concurrent Workstation;Auto;Auto;Auto;Auto;180.4251 ns;4.1294 ns;180.4400 ns;0.9234 ns;4.1294 ns;5542007.02;174.5503 ns;177.6286 ns;180.4251 ns;182.5334 ns;190.9792 ns -UrlPathToUrlPathTemplateMatcherBenchmarks;Benchmark2;Throughput;Host;Host;Core;Host;Concurrent Workstation;Auto;Auto;Auto;Auto;178.7267 ns;6.1670 ns;180.6081 ns;1.3148 ns;6.1670 ns;5536849.8;174.0821 ns;177.0992 ns;178.7267 ns;182.1962 ns;198.1308 ns +UrlPathToUrlPathTemplateMatcherBenchmarks;Benchmark1;Throughput;Host;Host;Core;Host;Concurrent Workstation;Auto;Auto;Auto;Auto;184.4215 ns;5.1537 ns;185.3322 ns;1.1524 ns;5.1537 ns;5395716.74;178.2386 ns;181.8117 ns;184.4215 ns;188.2762 ns;196.7310 ns +UrlPathToUrlPathTemplateMatcherBenchmarks;Benchmark2;Throughput;Host;Host;Core;Host;Concurrent Workstation;Auto;Auto;Auto;Auto;186.1899 ns;35.7006 ns;202.4315 ns;3.9425 ns;35.7006 ns;4939943.34;176.9750 ns;182.9672 ns;186.1899 ns;205.8946 ns;369.0701 ns diff --git a/test/Ocelot.Benchmarks/BenchmarkDotNet.Artifacts/results/UrlPathToUrlPathTemplateMatcherBenchmarks-report.html b/test/Ocelot.Benchmarks/BenchmarkDotNet.Artifacts/results/UrlPathToUrlPathTemplateMatcherBenchmarks-report.html index 229b23f1..6631b3b4 100755 --- a/test/Ocelot.Benchmarks/BenchmarkDotNet.Artifacts/results/UrlPathToUrlPathTemplateMatcherBenchmarks-report.html +++ b/test/Ocelot.Benchmarks/BenchmarkDotNet.Artifacts/results/UrlPathToUrlPathTemplateMatcherBenchmarks-report.html @@ -15,6 +15,6 @@ GarbageCollection=Concurrent Workstation - - + +
MethodMedianStdDev MeanStdErrorStdDevOp/s Min Q1Median Q3 Max
Benchmark1180.4251 ns4.1294 ns180.4400 ns0.9234 ns4.1294 ns5542007.02174.5503 ns177.6286 ns180.4251 ns182.5334 ns190.9792 ns
Benchmark2178.7267 ns6.1670 ns180.6081 ns1.3148 ns6.1670 ns5536849.8174.0821 ns177.0992 ns178.7267 ns182.1962 ns198.1308 ns
Benchmark1184.4215 ns5.1537 ns185.3322 ns1.1524 ns5.1537 ns5395716.74178.2386 ns181.8117 ns184.4215 ns188.2762 ns196.7310 ns
Benchmark2186.1899 ns35.7006 ns202.4315 ns3.9425 ns35.7006 ns4939943.34176.9750 ns182.9672 ns186.1899 ns205.8946 ns369.0701 ns
From 6ac9954770e6a65290d38143207d3dbf1e3d9b15 Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Fri, 19 Aug 2016 21:46:14 +0100 Subject: [PATCH 017/183] remove results --- ...TemplateMatcherBenchmarks-report-github.md | 20 ------------------- ...rlPathTemplateMatcherBenchmarks-report.csv | 3 --- ...lPathTemplateMatcherBenchmarks-report.html | 20 ------------------- 3 files changed, 43 deletions(-) delete mode 100755 test/Ocelot.Benchmarks/BenchmarkDotNet.Artifacts/results/UrlPathToUrlPathTemplateMatcherBenchmarks-report-github.md delete mode 100755 test/Ocelot.Benchmarks/BenchmarkDotNet.Artifacts/results/UrlPathToUrlPathTemplateMatcherBenchmarks-report.csv delete mode 100755 test/Ocelot.Benchmarks/BenchmarkDotNet.Artifacts/results/UrlPathToUrlPathTemplateMatcherBenchmarks-report.html diff --git a/test/Ocelot.Benchmarks/BenchmarkDotNet.Artifacts/results/UrlPathToUrlPathTemplateMatcherBenchmarks-report-github.md b/test/Ocelot.Benchmarks/BenchmarkDotNet.Artifacts/results/UrlPathToUrlPathTemplateMatcherBenchmarks-report-github.md deleted file mode 100755 index 500c4d6e..00000000 --- a/test/Ocelot.Benchmarks/BenchmarkDotNet.Artifacts/results/UrlPathToUrlPathTemplateMatcherBenchmarks-report-github.md +++ /dev/null @@ -1,20 +0,0 @@ -```ini - -Host Process Environment Information: -BenchmarkDotNet=v0.9.8.0 -OS=OSX -Processor=?, ProcessorCount=4 -Frequency=1000000000 ticks, Resolution=1.0000 ns, Timer=UNKNOWN -CLR=CORE, Arch=64-bit ? [RyuJIT] -GC=Concurrent Workstation -JitModules=? -dotnet cli version: 1.0.0-preview2-003121 - -Type=UrlPathToUrlPathTemplateMatcherBenchmarks Mode=Throughput Toolchain=Core -GarbageCollection=Concurrent Workstation - -``` - Method | Median | StdDev | Mean | StdError | StdDev | Op/s | Min | Q1 | Median | Q3 | Max | ------------ |------------ |----------- |------------ |---------- |----------- |----------- |------------ |------------ |------------ |------------ |------------ | - Benchmark1 | 184.4215 ns | 5.1537 ns | 185.3322 ns | 1.1524 ns | 5.1537 ns | 5395716.74 | 178.2386 ns | 181.8117 ns | 184.4215 ns | 188.2762 ns | 196.7310 ns | - Benchmark2 | 186.1899 ns | 35.7006 ns | 202.4315 ns | 3.9425 ns | 35.7006 ns | 4939943.34 | 176.9750 ns | 182.9672 ns | 186.1899 ns | 205.8946 ns | 369.0701 ns | diff --git a/test/Ocelot.Benchmarks/BenchmarkDotNet.Artifacts/results/UrlPathToUrlPathTemplateMatcherBenchmarks-report.csv b/test/Ocelot.Benchmarks/BenchmarkDotNet.Artifacts/results/UrlPathToUrlPathTemplateMatcherBenchmarks-report.csv deleted file mode 100755 index 9aaa893e..00000000 --- a/test/Ocelot.Benchmarks/BenchmarkDotNet.Artifacts/results/UrlPathToUrlPathTemplateMatcherBenchmarks-report.csv +++ /dev/null @@ -1,3 +0,0 @@ -Type;Method;Mode;Platform;Jit;Toolchain;Runtime;GarbageCollection;LaunchCount;WarmupCount;TargetCount;Affinity;Median;StdDev;Mean;StdError;StdDev;Op/s;Min;Q1;Median;Q3;Max -UrlPathToUrlPathTemplateMatcherBenchmarks;Benchmark1;Throughput;Host;Host;Core;Host;Concurrent Workstation;Auto;Auto;Auto;Auto;184.4215 ns;5.1537 ns;185.3322 ns;1.1524 ns;5.1537 ns;5395716.74;178.2386 ns;181.8117 ns;184.4215 ns;188.2762 ns;196.7310 ns -UrlPathToUrlPathTemplateMatcherBenchmarks;Benchmark2;Throughput;Host;Host;Core;Host;Concurrent Workstation;Auto;Auto;Auto;Auto;186.1899 ns;35.7006 ns;202.4315 ns;3.9425 ns;35.7006 ns;4939943.34;176.9750 ns;182.9672 ns;186.1899 ns;205.8946 ns;369.0701 ns diff --git a/test/Ocelot.Benchmarks/BenchmarkDotNet.Artifacts/results/UrlPathToUrlPathTemplateMatcherBenchmarks-report.html b/test/Ocelot.Benchmarks/BenchmarkDotNet.Artifacts/results/UrlPathToUrlPathTemplateMatcherBenchmarks-report.html deleted file mode 100755 index 6631b3b4..00000000 --- a/test/Ocelot.Benchmarks/BenchmarkDotNet.Artifacts/results/UrlPathToUrlPathTemplateMatcherBenchmarks-report.html +++ /dev/null @@ -1,20 +0,0 @@ -

-Host Process Environment Information:
-BenchmarkDotNet=v0.9.8.0
-OS=OSX
-Processor=?, ProcessorCount=4
-Frequency=1000000000 ticks, Resolution=1.0000 ns, Timer=UNKNOWN
-CLR=CORE, Arch=64-bit ? [RyuJIT]
-GC=Concurrent Workstation
-JitModules=?
-dotnet cli version: 1.0.0-preview2-003121
-
-
Type=UrlPathToUrlPathTemplateMatcherBenchmarks  Mode=Throughput  Toolchain=Core  
-GarbageCollection=Concurrent Workstation  
-
- - - - - -
MethodMedianStdDev MeanStdErrorStdDevOp/s Min Q1Median Q3 Max
Benchmark1184.4215 ns5.1537 ns185.3322 ns1.1524 ns5.1537 ns5395716.74178.2386 ns181.8117 ns184.4215 ns188.2762 ns196.7310 ns
Benchmark2186.1899 ns35.7006 ns202.4315 ns3.9425 ns35.7006 ns4939943.34176.9750 ns182.9672 ns186.1899 ns205.8946 ns369.0701 ns
From b2c1e627bbf2b664bd14abc55b203fac62e9a98a Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Fri, 19 Aug 2016 21:46:48 +0100 Subject: [PATCH 018/183] ignore resuts --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 0ca27f04..7639ba0d 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ build/ bld/ [Bb]in/ [Oo]bj/ +results/ # Visual Studio 2015 cache/options directory .vs/ From 61706274b0944aa7630279c019d4e78169a158cd Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Fri, 19 Aug 2016 22:02:13 +0100 Subject: [PATCH 019/183] very simple build scripts --- build.sh | 16 ++++++++++++++++ run-benchmarks.sh | 14 ++++++++++++++ run-tests.sh | 12 ++++++++++++ 3 files changed, 42 insertions(+) create mode 100755 build.sh create mode 100755 run-benchmarks.sh create mode 100755 run-tests.sh diff --git a/build.sh b/build.sh new file mode 100755 index 00000000..ae56ff00 --- /dev/null +++ b/build.sh @@ -0,0 +1,16 @@ + #!/bin/bash +echo ------------------------- + +echo Running Ocelot.UnitTests + +dotnet test test/Ocelot.UnitTests/ + +echo Running Ocelot.AcceptanceTests + +dotnet test test/Ocelot.AcceptanceTests/ + +echo Building Ocelot + +dotnet publish src/Ocelot + + diff --git a/run-benchmarks.sh b/run-benchmarks.sh new file mode 100755 index 00000000..6ca94700 --- /dev/null +++ b/run-benchmarks.sh @@ -0,0 +1,14 @@ + #!/bin/bash +echo ------------------------- + +echo Running Ocelot.Benchmarks + +cd test/Ocelot.Benchmarks + +dotnet run + +cd ../../ + + + + diff --git a/run-tests.sh b/run-tests.sh new file mode 100755 index 00000000..90b53058 --- /dev/null +++ b/run-tests.sh @@ -0,0 +1,12 @@ + #!/bin/bash +echo ------------------------- + +echo Running Ocelot.UnitTests + +dotnet test test/Ocelot.UnitTests/ + +echo Running Ocelot.AcceptanceTests + +dotnet test test/Ocelot.AcceptanceTests/ + + From 6d46829ce2214e15fa1c957acbc2934dc84ece4b Mon Sep 17 00:00:00 2001 From: Tom Pallister Date: Wed, 24 Aug 2016 17:51:55 +0100 Subject: [PATCH 020/183] Started adding BDDfy... --- test/Ocelot.AcceptanceTests/RouterTests.cs | 6 ++-- test/Ocelot.AcceptanceTests/project.json | 5 +-- .../HostUrlMapRepositoryTests.cs | 32 +++++++++++-------- test/Ocelot.UnitTests/project.json | 5 +-- 4 files changed, 29 insertions(+), 19 deletions(-) diff --git a/test/Ocelot.AcceptanceTests/RouterTests.cs b/test/Ocelot.AcceptanceTests/RouterTests.cs index c3d5fafa..2d4d2c4e 100644 --- a/test/Ocelot.AcceptanceTests/RouterTests.cs +++ b/test/Ocelot.AcceptanceTests/RouterTests.cs @@ -9,6 +9,7 @@ using Shouldly; namespace Ocelot.AcceptanceTests { using System.Net; + using TestStack.BDDfy; public class RouterTests : IDisposable { @@ -30,8 +31,9 @@ namespace Ocelot.AcceptanceTests [Fact] public void should_return_response_404() { - WhenIRequestTheUrl("/"); - ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound); + this.When(x => x.WhenIRequestTheUrl("/")) + .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound)) + .BDDfy(); } private void WhenIRequestTheUrl(string url) diff --git a/test/Ocelot.AcceptanceTests/project.json b/test/Ocelot.AcceptanceTests/project.json index f59b9e22..c350a62b 100644 --- a/test/Ocelot.AcceptanceTests/project.json +++ b/test/Ocelot.AcceptanceTests/project.json @@ -1,4 +1,4 @@ -{ +{ "version": "1.0.0-*", "testRunner": "xunit", @@ -24,7 +24,8 @@ "dotnet-test-xunit": "2.2.0-preview2-build1029", "Shouldly": "2.8.0", "Ocelot": "1.0.0-*", - "Microsoft.AspNetCore.TestHost": "1.0.0" + "Microsoft.AspNetCore.TestHost": "1.0.0", + "TestStack.BDDfy": "4.3.1" }, "frameworks": { diff --git a/test/Ocelot.UnitTests/HostUrlMapRepositoryTests.cs b/test/Ocelot.UnitTests/HostUrlMapRepositoryTests.cs index 2bcd998f..eb42e999 100644 --- a/test/Ocelot.UnitTests/HostUrlMapRepositoryTests.cs +++ b/test/Ocelot.UnitTests/HostUrlMapRepositoryTests.cs @@ -5,6 +5,8 @@ using Xunit; namespace Ocelot.UnitTests { + using TestStack.BDDfy; + public class HostUrlMapRepositoryTests { private string _upstreamBaseUrl; @@ -21,34 +23,38 @@ namespace Ocelot.UnitTests [Fact] public void can_add_route() { - GivenIHaveAnUpstreamBaseUrl("www.someapi.com"); - GivenIWantToRouteRequestsFromMyDownstreamBaseUrl("api"); - WhenIAddTheConfiguration(); - ThenTheResponseIsSuccesful(); + this.Given(x => x.GivenIHaveAnUpstreamBaseUrl("www.someapi.com")) + .And(x => x.GivenIWantToRouteRequestsFromMyDownstreamBaseUrl("api")) + .When(x => x.WhenIAddTheConfiguration()) + .Then(x => x.ThenTheResponseIsSuccesful()) + .BDDfy(); } [Fact] public void can_get_route_by_key() { - GivenIHaveSetUpAnApiKeyAndUpstreamUrl("api2", "www.someapi.com"); - WhenIRetrieveTheRouteByKey(); - ThenTheRouteIsReturned(); + this.Given(x => x.GivenIHaveSetUpAnApiKeyAndUpstreamUrl("api2", "www.someapi.com")) + .When(x => x.WhenIRetrieveTheRouteByKey()) + .Then(x => x.ThenTheRouteIsReturned()) + .BDDfy(); } [Fact] public void should_return_error_response_when_key_already_used() { - GivenIHaveSetUpAnApiKeyAndUpstreamUrl("api2", "www.someapi.com"); - WhenITryToUseTheSameKey(); - ThenTheKeyHasAlreadyBeenUsed(); + this.Given(x => x.GivenIHaveSetUpAnApiKeyAndUpstreamUrl("api2", "www.someapi.com")) + .When(x => x.WhenITryToUseTheSameKey()) + .Then(x => x.ThenTheKeyHasAlreadyBeenUsed()) + .BDDfy(); } [Fact] public void should_return_error_response_if_key_doesnt_exist() { - GivenIWantToRouteRequestsFromMyDownstreamBaseUrl("api"); - WhenIRetrieveTheRouteByKey(); - ThenTheKeyDoesNotExist(); + this.Given(x => x.GivenIWantToRouteRequestsFromMyDownstreamBaseUrl("api")) + .When(x => x.WhenIRetrieveTheRouteByKey()) + .Then(x => x.ThenTheKeyDoesNotExist()) + .BDDfy(); } private void WhenITryToUseTheSameKey() diff --git a/test/Ocelot.UnitTests/project.json b/test/Ocelot.UnitTests/project.json index 926c8e73..f415f589 100644 --- a/test/Ocelot.UnitTests/project.json +++ b/test/Ocelot.UnitTests/project.json @@ -1,4 +1,4 @@ -{ +{ "version": "1.0.0-*", "testRunner": "xunit", @@ -22,7 +22,8 @@ "Ocelot.Library": "1.0.0-*", "xunit": "2.1.0", "dotnet-test-xunit": "2.2.0-preview2-build1029", - "Shouldly": "2.8.0" + "Shouldly": "2.8.0", + "TestStack.BDDfy": "4.3.1" }, "frameworks": { From 26ee5e6257dab06678bdcd3deb06204776548a62 Mon Sep 17 00:00:00 2001 From: Tom Pallister Date: Thu, 25 Aug 2016 16:18:08 +0100 Subject: [PATCH 021/183] all tests bddfy --- .../HostUrlMapRepositoryTests.cs | 2 +- .../UpstreamBaseUrlFinderTests.cs | 22 +-- ...eamUrlPathTemplateVariableReplacerTests.cs | 78 +++++---- .../UrlPathTemplateMapRepositoryTests.cs | 39 +++-- .../UrlPathToUrlPathTemplateMatcherTests.cs | 155 +++++++++--------- 5 files changed, 161 insertions(+), 135 deletions(-) diff --git a/test/Ocelot.UnitTests/HostUrlMapRepositoryTests.cs b/test/Ocelot.UnitTests/HostUrlMapRepositoryTests.cs index eb42e999..045dfab1 100644 --- a/test/Ocelot.UnitTests/HostUrlMapRepositoryTests.cs +++ b/test/Ocelot.UnitTests/HostUrlMapRepositoryTests.cs @@ -11,7 +11,7 @@ namespace Ocelot.UnitTests { private string _upstreamBaseUrl; private string _downstreamBaseUrl; - private IHostUrlMapRepository _repository; + private readonly IHostUrlMapRepository _repository; private Response _response; private Response _getRouteResponse; diff --git a/test/Ocelot.UnitTests/UpstreamBaseUrlFinderTests.cs b/test/Ocelot.UnitTests/UpstreamBaseUrlFinderTests.cs index 1cec5f18..6a36b312 100644 --- a/test/Ocelot.UnitTests/UpstreamBaseUrlFinderTests.cs +++ b/test/Ocelot.UnitTests/UpstreamBaseUrlFinderTests.cs @@ -3,14 +3,14 @@ using Ocelot.Library.Infrastructure.UrlFinder; using Ocelot.Library.Infrastructure.Responses; using Xunit; using Shouldly; -using System; +using TestStack.BDDfy; namespace Ocelot.UnitTests { public class UpstreamBaseUrlFinderTests { - private IUpstreamHostUrlFinder _upstreamBaseUrlFinder; - private IHostUrlMapRepository _hostUrlMapRepository; + private readonly IUpstreamHostUrlFinder _upstreamBaseUrlFinder; + private readonly IHostUrlMapRepository _hostUrlMapRepository; private string _downstreamBaseUrl; private Response _result; public UpstreamBaseUrlFinderTests() @@ -22,18 +22,20 @@ namespace Ocelot.UnitTests [Fact] public void can_find_base_url() { - GivenTheBaseUrlMapExists(new HostUrlMap("api.tom.com", "api.laura.com")); - GivenTheDownstreamBaseUrlIs("api.tom.com"); - WhenIFindTheMatchingUpstreamBaseUrl(); - ThenTheFollowingIsReturned("api.laura.com"); + this.Given(x => x.GivenTheBaseUrlMapExists(new HostUrlMap("api.tom.com", "api.laura.com"))) + .And(x => x.GivenTheDownstreamBaseUrlIs("api.tom.com")) + .When(x => x.WhenIFindTheMatchingUpstreamBaseUrl()) + .Then(x => x.ThenTheFollowingIsReturned("api.laura.com")) + .BDDfy(); } [Fact] public void cant_find_base_url() { - GivenTheDownstreamBaseUrlIs("api.tom.com"); - WhenIFindTheMatchingUpstreamBaseUrl(); - ThenAnErrorIsReturned(); + this.Given(x => x.GivenTheDownstreamBaseUrlIs("api.tom.com")) + .When(x => x.WhenIFindTheMatchingUpstreamBaseUrl()) + .Then(x => x.ThenAnErrorIsReturned()) + .BDDfy(); } private void ThenAnErrorIsReturned() diff --git a/test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs b/test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs index 31811406..fd4deacf 100644 --- a/test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs +++ b/test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs @@ -6,52 +6,58 @@ using Xunit; namespace Ocelot.UnitTests { + using TestStack.BDDfy; + public class UpstreamUrlPathTemplateVariableReplacerTests { - private string _upstreamUrlPath; private UrlPathMatch _urlPathMatch; private string _result; - private IUpstreamUrlPathTemplateVariableReplacer _upstreamUrlPathReplacer; + private readonly IUpstreamUrlPathTemplateVariableReplacer _upstreamUrlPathReplacer; public UpstreamUrlPathTemplateVariableReplacerTests() { _upstreamUrlPathReplacer = new UpstreamUrlPathTemplateVariableReplacer(); } + [Fact] public void can_replace_no_template_variables() { - GivenThereIsAnUpstreamUrlPath(""); - GivenThereIsAUrlPathMatch(new UrlPathMatch(true, new List(), "")); - WhenIReplaceTheTemplateVariables(); - ThenTheUpstreamUrlPathIsReturned(""); + this.Given(x => x.GivenThereIsAnUpstreamUrlPath("")) + .And(x => x.GivenThereIsAUrlPathMatch(new UrlPathMatch(true, new List(), ""))) + .When(x => x.WhenIReplaceTheTemplateVariables()) + .Then(x => x.ThenTheUpstreamUrlPathIsReturned("")) + .BDDfy(); } [Fact] public void can_replace_url_no_slash() { - GivenThereIsAnUpstreamUrlPath("api"); - GivenThereIsAUrlPathMatch(new UrlPathMatch(true, new List(), "api")); - WhenIReplaceTheTemplateVariables(); - ThenTheUpstreamUrlPathIsReturned("api"); + this.Given(x => x.GivenThereIsAnUpstreamUrlPath("api")) + .And(x => x.GivenThereIsAUrlPathMatch(new UrlPathMatch(true, new List(), "api"))) + .When(x => x.WhenIReplaceTheTemplateVariables()) + .Then(x => x.ThenTheUpstreamUrlPathIsReturned("api")) + .BDDfy(); } [Fact] public void can_replace_url_one_slash() { - GivenThereIsAnUpstreamUrlPath("api/"); - GivenThereIsAUrlPathMatch(new UrlPathMatch(true, new List(), "api/")); - WhenIReplaceTheTemplateVariables(); - ThenTheUpstreamUrlPathIsReturned("api/"); + this.Given(x => x.GivenThereIsAnUpstreamUrlPath("api/")) + .And(x => x.GivenThereIsAUrlPathMatch(new UrlPathMatch(true, new List(), "api/"))) + .When(x => x.WhenIReplaceTheTemplateVariables()) + .Then(x => x.ThenTheUpstreamUrlPathIsReturned("api/")) + .BDDfy(); } [Fact] public void can_replace_url_multiple_slash() { - GivenThereIsAnUpstreamUrlPath("api/product/products/"); - GivenThereIsAUrlPathMatch(new UrlPathMatch(true, new List(), "api/product/products/")); - WhenIReplaceTheTemplateVariables(); - ThenTheUpstreamUrlPathIsReturned("api/product/products/"); + this.Given(x => x.GivenThereIsAnUpstreamUrlPath("api/product/products/")) + .And(x => x.GivenThereIsAUrlPathMatch(new UrlPathMatch(true, new List(), "api/product/products/"))) + .When(x => x.WhenIReplaceTheTemplateVariables()) + .Then(x => x.ThenTheUpstreamUrlPathIsReturned("api/product/products/")) + .BDDfy(); } [Fact] @@ -62,10 +68,11 @@ namespace Ocelot.UnitTests new TemplateVariableNameAndValue("{productId}", "1") }; - GivenThereIsAnUpstreamUrlPath("productservice/products/{productId}/"); - GivenThereIsAUrlPathMatch(new UrlPathMatch(true, templateVariables, "api/products/{productId}/")); - WhenIReplaceTheTemplateVariables(); - ThenTheUpstreamUrlPathIsReturned("productservice/products/1/"); + this.Given(x => x.GivenThereIsAnUpstreamUrlPath("productservice/products/{productId}/")) + .And(x => x.GivenThereIsAUrlPathMatch(new UrlPathMatch(true, templateVariables, "api/products/{productId}/"))) + .When(x => x.WhenIReplaceTheTemplateVariables()) + .Then(x => x.ThenTheUpstreamUrlPathIsReturned("productservice/products/1/")) + .BDDfy(); } [Fact] @@ -76,10 +83,11 @@ namespace Ocelot.UnitTests new TemplateVariableNameAndValue("{productId}", "1") }; - GivenThereIsAnUpstreamUrlPath("productservice/products/{productId}/variants"); - GivenThereIsAUrlPathMatch(new UrlPathMatch(true, templateVariables, "api/products/{productId}/")); - WhenIReplaceTheTemplateVariables(); - ThenTheUpstreamUrlPathIsReturned("productservice/products/1/variants"); + this.Given(x => x.GivenThereIsAnUpstreamUrlPath("productservice/products/{productId}/variants")) + .And(x => x.GivenThereIsAUrlPathMatch(new UrlPathMatch(true, templateVariables, "api/products/{productId}/"))) + .When(x => x.WhenIReplaceTheTemplateVariables()) + .Then(x => x.ThenTheUpstreamUrlPathIsReturned("productservice/products/1/variants")) + .BDDfy(); } [Fact] @@ -91,10 +99,11 @@ namespace Ocelot.UnitTests new TemplateVariableNameAndValue("{variantId}", "12") }; - GivenThereIsAnUpstreamUrlPath("productservice/products/{productId}/variants/{variantId}"); - GivenThereIsAUrlPathMatch(new UrlPathMatch(true, templateVariables, "api/products/{productId}/{variantId}")); - WhenIReplaceTheTemplateVariables(); - ThenTheUpstreamUrlPathIsReturned("productservice/products/1/variants/12"); + this.Given(x => x.GivenThereIsAnUpstreamUrlPath("productservice/products/{productId}/variants/{variantId}")) + .And(x => x.GivenThereIsAUrlPathMatch(new UrlPathMatch(true, templateVariables, "api/products/{productId}/{variantId}"))) + .When(x => x.WhenIReplaceTheTemplateVariables()) + .Then(x => x.ThenTheUpstreamUrlPathIsReturned("productservice/products/1/variants/12")) + .BDDfy(); } [Fact] @@ -107,10 +116,11 @@ namespace Ocelot.UnitTests new TemplateVariableNameAndValue("{categoryId}", "34") }; - GivenThereIsAnUpstreamUrlPath("productservice/category/{categoryId}/products/{productId}/variants/{variantId}"); - GivenThereIsAUrlPathMatch(new UrlPathMatch(true, templateVariables, "api/products/{categoryId}/{productId}/{variantId}")); - WhenIReplaceTheTemplateVariables(); - ThenTheUpstreamUrlPathIsReturned("productservice/category/34/products/1/variants/12"); + this.Given(x => x.GivenThereIsAnUpstreamUrlPath("productservice/category/{categoryId}/products/{productId}/variants/{variantId}")) + .And(x => x.GivenThereIsAUrlPathMatch(new UrlPathMatch(true, templateVariables, "api/products/{categoryId}/{productId}/{variantId}"))) + .When(x => x.WhenIReplaceTheTemplateVariables()) + .Then(x => x.ThenTheUpstreamUrlPathIsReturned("productservice/category/34/products/1/variants/12")) + .BDDfy(); } private void GivenThereIsAnUpstreamUrlPath(string upstreamUrlPath) diff --git a/test/Ocelot.UnitTests/UrlPathTemplateMapRepositoryTests.cs b/test/Ocelot.UnitTests/UrlPathTemplateMapRepositoryTests.cs index 6dd8f8ed..98de6ba9 100644 --- a/test/Ocelot.UnitTests/UrlPathTemplateMapRepositoryTests.cs +++ b/test/Ocelot.UnitTests/UrlPathTemplateMapRepositoryTests.cs @@ -6,6 +6,8 @@ using Xunit; namespace Ocelot.UnitTests { + using TestStack.BDDfy; + public class UrlPathTemplateMapRepositoryTests { private string _upstreamUrlPath; @@ -23,42 +25,47 @@ namespace Ocelot.UnitTests [Fact] public void can_add_url_path() { - GivenIHaveAnUpstreamUrlPath("/api/products/products/{productId}"); - GivenIWantToRouteRequestsToMyUpstreamUrlPath("/api/products/{productId}"); - WhenIAddTheConfiguration(); - ThenTheResponseIsSuccesful(); + this.Given(x => x.GivenIHaveAnUpstreamUrlPath("/api/products/products/{productId}")) + .And(x => x.GivenIWantToRouteRequestsToMyUpstreamUrlPath("/api/products/{productId}")) + .When(x => x.WhenIAddTheConfiguration()) + .Then(x => x.ThenTheResponseIsSuccesful()) + .BDDfy(); } [Fact] public void can_get_url_path() { - GivenIHaveSetUpADownstreamUrlPathAndAnUpstreamUrlPath("/api2", "http://www.someapi.com/api2"); - WhenIRetrieveTheUrlPathByDownstreamUrl(); - ThenTheUrlPathIsReturned(); + this.Given(x => x.GivenIHaveSetUpADownstreamUrlPathAndAnUpstreamUrlPath("/api2", "http://www.someapi.com/api2")) + .When(x => x.WhenIRetrieveTheUrlPathByDownstreamUrl()) + .Then(x => x.ThenTheUrlPathIsReturned()) + .BDDfy(); } [Fact] public void can_get_all_urls() { - GivenIHaveSetUpADownstreamUrlPathAndAnUpstreamUrlPath("/api2", "http://www.someapi.com/api2"); - WhenIRetrieveTheUrls(); - ThenTheUrlsAreReturned(); + this.Given(x => x.GivenIHaveSetUpADownstreamUrlPathAndAnUpstreamUrlPath("/api2", "http://www.someapi.com/api2")) + .When(x => x.WhenIRetrieveTheUrls()) + .Then(x => x.ThenTheUrlsAreReturned()) + .BDDfy(); } [Fact] public void should_return_error_response_when_url_path_already_used() { - GivenIHaveSetUpADownstreamUrlPathAndAnUpstreamUrlPath("/api2", "http://www.someapi.com/api2"); - WhenITryToUseTheSameDownstreamUrl(); - ThenTheDownstreamUrlAlreadyBeenUsed(); + this.Given(x => x.GivenIHaveSetUpADownstreamUrlPathAndAnUpstreamUrlPath("/api2", "http://www.someapi.com/api2")) + .When(x => x.WhenITryToUseTheSameDownstreamUrl()) + .Then(x => x.ThenTheDownstreamUrlAlreadyBeenUsed()) + .BDDfy(); } [Fact] public void should_return_error_response_if_key_doesnt_exist() { - GivenIWantToRouteRequestsToMyUpstreamUrlPath("/api"); - WhenIRetrieveTheUrlPathByDownstreamUrl(); - ThenTheKeyDoesNotExist(); + this.Given(x => x.GivenIWantToRouteRequestsToMyUpstreamUrlPath("/api")) + .When(x => x.WhenIRetrieveTheUrlPathByDownstreamUrl()) + .Then(x => x.ThenTheKeyDoesNotExist()) + .BDDfy(); } private void WhenITryToUseTheSameDownstreamUrl() diff --git a/test/Ocelot.UnitTests/UrlPathToUrlPathTemplateMatcherTests.cs b/test/Ocelot.UnitTests/UrlPathToUrlPathTemplateMatcherTests.cs index 4cf8a87f..0a3b105d 100644 --- a/test/Ocelot.UnitTests/UrlPathToUrlPathTemplateMatcherTests.cs +++ b/test/Ocelot.UnitTests/UrlPathToUrlPathTemplateMatcherTests.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using System.Linq; using Ocelot.Library.Infrastructure.UrlPathMatcher; @@ -7,9 +6,11 @@ using Xunit; namespace Ocelot.UnitTests { + using TestStack.BDDfy; + public class UrlPathToUrlPathTemplateMatcherTests { - private IUrlPathToUrlPathTemplateMatcher _urlMapper; + private readonly IUrlPathToUrlPathTemplateMatcher _urlMapper; private string _downstreamPath; private string _downstreamPathTemplate; private UrlPathMatch _result; @@ -21,56 +22,61 @@ namespace Ocelot.UnitTests [Fact] public void can_match_down_stream_url() { - GivenIHaveADownstreamPath(""); - GivenIHaveAnDownstreamPathTemplate(""); - WhenIMatchThePaths(); - ThenTheResultIsTrue(); - ThenTheTemplatesDictionaryIs(new List()); - ThenTheUrlPathTemplateIs(""); + this.Given(x => x.GivenIHaveADownstreamPath("")) + .And(x => x.GivenIHaveAnDownstreamPathTemplate("")) + .When(x => x.WhenIMatchThePaths()) + .And(x => x.ThenTheResultIsTrue()) + .And(x => x.ThenTheTemplatesDictionaryIs(new List())) + .And(x => x.ThenTheUrlPathTemplateIs("")) + .BDDfy(); } [Fact] public void can_match_down_stream_url_with_no_slash() { - GivenIHaveADownstreamPath("api"); - GivenIHaveAnDownstreamPathTemplate("api"); - WhenIMatchThePaths(); - ThenTheResultIsTrue(); - ThenTheTemplatesDictionaryIs(new List()); - ThenTheUrlPathTemplateIs("api"); + this.Given(x => x.GivenIHaveADownstreamPath("api")) + .Given(x => x.GivenIHaveAnDownstreamPathTemplate("api")) + .When(x => x.WhenIMatchThePaths()) + .Then(x => x.ThenTheResultIsTrue()) + .And(x => x.ThenTheTemplatesDictionaryIs(new List())) + .And(x => x.ThenTheUrlPathTemplateIs("api")) + .BDDfy(); } [Fact] public void can_match_down_stream_url_with_one_slash() { - GivenIHaveADownstreamPath("api/"); - GivenIHaveAnDownstreamPathTemplate("api/"); - WhenIMatchThePaths(); - ThenTheResultIsTrue(); - ThenTheTemplatesDictionaryIs(new List()); - ThenTheUrlPathTemplateIs("api/"); + this.Given(x => x.GivenIHaveADownstreamPath("api/")) + .Given(x => x.GivenIHaveAnDownstreamPathTemplate("api/")) + .When(x => x.WhenIMatchThePaths()) + .Then(x => x.ThenTheResultIsTrue()) + .And(x => x.ThenTheTemplatesDictionaryIs(new List())) + .And(x => x.ThenTheUrlPathTemplateIs("api/")) + .BDDfy(); } [Fact] public void can_match_down_stream_url_with_downstream_template() { - GivenIHaveADownstreamPath("api/product/products/"); - GivenIHaveAnDownstreamPathTemplate("api/product/products/"); - WhenIMatchThePaths(); - ThenTheResultIsTrue(); - ThenTheTemplatesDictionaryIs(new List()); - ThenTheUrlPathTemplateIs("api/product/products/"); + this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/")) + .Given(x => x.GivenIHaveAnDownstreamPathTemplate("api/product/products/")) + .When(x => x.WhenIMatchThePaths()) + .Then(x => x.ThenTheResultIsTrue()) + .And(x => x.ThenTheTemplatesDictionaryIs(new List())) + .And(x => x.ThenTheUrlPathTemplateIs("api/product/products/")) + .BDDfy(); } [Fact] public void can_match_down_stream_url_with_downstream_template_with_one_query_string_parameter() { - GivenIHaveADownstreamPath("api/product/products/?soldout=false"); - GivenIHaveAnDownstreamPathTemplate("api/product/products/"); - WhenIMatchThePaths(); - ThenTheResultIsTrue(); - ThenTheTemplatesDictionaryIs(new List()); - ThenTheUrlPathTemplateIs("api/product/products/"); + this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/?soldout=false")) + .Given(x => x.GivenIHaveAnDownstreamPathTemplate("api/product/products/")) + .When(x => x.WhenIMatchThePaths()) + .Then(x => x.ThenTheResultIsTrue()) + .And(x => x.ThenTheTemplatesDictionaryIs(new List())) + .And(x => x.ThenTheUrlPathTemplateIs("api/product/products/")) + .BDDfy(); } [Fact] @@ -80,13 +86,14 @@ namespace Ocelot.UnitTests { new TemplateVariableNameAndValue("{productId}", "1") }; - - GivenIHaveADownstreamPath("api/product/products/1/variants/?soldout=false"); - GivenIHaveAnDownstreamPathTemplate("api/product/products/{productId}/variants/"); - WhenIMatchThePaths(); - ThenTheResultIsTrue(); - ThenTheTemplatesDictionaryIs(expectedTemplates); - ThenTheUrlPathTemplateIs("api/product/products/{productId}/variants/"); + + this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/1/variants/?soldout=false")) + .Given(x => x.GivenIHaveAnDownstreamPathTemplate("api/product/products/{productId}/variants/")) + .When(x => x.WhenIMatchThePaths()) + .Then(x => x.ThenTheResultIsTrue()) + .And(x => x.ThenTheTemplatesDictionaryIs(expectedTemplates)) + .And(x => x.ThenTheUrlPathTemplateIs("api/product/products/{productId}/variants/")) + .BDDfy(); } [Fact] @@ -97,13 +104,13 @@ namespace Ocelot.UnitTests new TemplateVariableNameAndValue("{productId}", "1") }; - GivenIHaveADownstreamPath("api/product/products/1"); - GivenIHaveAnDownstreamPathTemplate("api/product/products/{productId}"); - WhenIMatchThePaths(); - ThenTheResultIsTrue(); - ThenTheTemplatesDictionaryIs(expectedTemplates); - ThenTheUrlPathTemplateIs("api/product/products/{productId}"); - + this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/1")) + .Given(x => x.GivenIHaveAnDownstreamPathTemplate("api/product/products/{productId}")) + .When(x => x.WhenIMatchThePaths()) + .Then(x => x.ThenTheResultIsTrue()) + .And(x => x.ThenTheTemplatesDictionaryIs(expectedTemplates)) + .And(x => x.ThenTheUrlPathTemplateIs("api/product/products/{productId}")) + .BDDfy(); } [Fact] @@ -114,14 +121,14 @@ namespace Ocelot.UnitTests new TemplateVariableNameAndValue("{productId}", "1"), new TemplateVariableNameAndValue("{categoryId}", "2") }; - - GivenIHaveADownstreamPath("api/product/products/1/2"); - GivenIHaveAnDownstreamPathTemplate("api/product/products/{productId}/{categoryId}"); - WhenIMatchThePaths(); - ThenTheResultIsTrue(); - ThenTheTemplatesDictionaryIs(expectedTemplates); - ThenTheUrlPathTemplateIs("api/product/products/{productId}/{categoryId}"); + this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/1/2")) + .Given(x => x.GivenIHaveAnDownstreamPathTemplate("api/product/products/{productId}/{categoryId}")) + .When(x => x.WhenIMatchThePaths()) + .Then(x => x.ThenTheResultIsTrue()) + .And(x => x.ThenTheTemplatesDictionaryIs(expectedTemplates)) + .And(x => x.ThenTheUrlPathTemplateIs("api/product/products/{productId}/{categoryId}")) + .BDDfy(); } [Fact] @@ -132,14 +139,14 @@ namespace Ocelot.UnitTests new TemplateVariableNameAndValue("{productId}", "1"), new TemplateVariableNameAndValue("{categoryId}", "2") }; - - GivenIHaveADownstreamPath("api/product/products/1/categories/2"); - GivenIHaveAnDownstreamPathTemplate("api/product/products/{productId}/categories/{categoryId}"); - WhenIMatchThePaths(); - ThenTheResultIsTrue(); - ThenTheTemplatesDictionaryIs(expectedTemplates); - ThenTheUrlPathTemplateIs("api/product/products/{productId}/categories/{categoryId}"); + this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/1/categories/2")) + .And(x => x.GivenIHaveAnDownstreamPathTemplate("api/product/products/{productId}/categories/{categoryId}")) + .When(x => x.WhenIMatchThePaths()) + .Then(x => x.ThenTheResultIsTrue()) + .And(x => x.ThenTheTemplatesDictionaryIs(expectedTemplates)) + .And(x => x.ThenTheUrlPathTemplateIs("api/product/products/{productId}/categories/{categoryId}")) + .BDDfy(); } [Fact] @@ -151,14 +158,14 @@ namespace Ocelot.UnitTests new TemplateVariableNameAndValue("{categoryId}", "2"), new TemplateVariableNameAndValue("{variantId}", "123") }; - - GivenIHaveADownstreamPath("api/product/products/1/categories/2/variant/123"); - GivenIHaveAnDownstreamPathTemplate("api/product/products/{productId}/categories/{categoryId}/variant/{variantId}"); - WhenIMatchThePaths(); - ThenTheResultIsTrue(); - ThenTheTemplatesDictionaryIs(expectedTemplates); - ThenTheUrlPathTemplateIs("api/product/products/{productId}/categories/{categoryId}/variant/{variantId}"); + this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/1/categories/2/variant/123")) + .And(x => x.GivenIHaveAnDownstreamPathTemplate("api/product/products/{productId}/categories/{categoryId}/variant/{variantId}")) + .When(x => x.WhenIMatchThePaths()) + .Then(x => x.ThenTheResultIsTrue()) + .And(x => x.ThenTheTemplatesDictionaryIs(expectedTemplates)) + .And(x => x.ThenTheUrlPathTemplateIs("api/product/products/{productId}/categories/{categoryId}/variant/{variantId}")) + .BDDfy(); } [Fact] @@ -169,14 +176,14 @@ namespace Ocelot.UnitTests new TemplateVariableNameAndValue("{productId}", "1"), new TemplateVariableNameAndValue("{categoryId}", "2") }; - - GivenIHaveADownstreamPath("api/product/products/1/categories/2/variant/"); - GivenIHaveAnDownstreamPathTemplate("api/product/products/{productId}/categories/{categoryId}/variant/"); - WhenIMatchThePaths(); - ThenTheResultIsTrue(); - ThenTheTemplatesDictionaryIs(expectedTemplates); - ThenTheUrlPathTemplateIs("api/product/products/{productId}/categories/{categoryId}/variant/"); + this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/1/categories/2/variant/")) + .And(x => x.GivenIHaveAnDownstreamPathTemplate("api/product/products/{productId}/categories/{categoryId}/variant/")) + .When(x => x.WhenIMatchThePaths()) + .Then(x => x.ThenTheResultIsTrue()) + .And(x => x.ThenTheTemplatesDictionaryIs(expectedTemplates)) + .And(x => x.ThenTheUrlPathTemplateIs("api/product/products/{productId}/categories/{categoryId}/variant/")) + .BDDfy(); } private void ThenTheTemplatesDictionaryIs(List expectedResults) From c4e0bae4ce93ef126c09f6d03f9b37b1ca3d24cb Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Sat, 27 Aug 2016 14:13:45 +0100 Subject: [PATCH 022/183] simplifying stuff after i realised i added loads of crap i dont need --- .../HostUrlRepository/HostUrlMap.cs | 14 --- .../HostUrlMapKeyAlreadyExists.cs | 12 -- .../HostUrlMapKeyDoesNotExist.cs | 12 -- .../IHostUrlMapRepository.cs | 10 -- .../InMemoryHostUrlMapRepository.cs | 37 ------ .../UrlFinder/IUpstreamHostUrlFinder.cs | 9 -- .../UrlFinder/UnableToFindUpstreamHostUrl.cs | 12 -- .../UrlFinder/UpstreamHostUrlFinder.cs | 28 ----- .../IUrlPathToUrlTemplateMatcher.cs | 7 ++ .../TemplateVariableNameAndValue.cs | 2 +- .../Infrastructure/UrlMatcher/UrlMatch.cs | 17 +++ .../UrlPathToUrlTemplateMatcher.cs} | 22 ++-- .../IUrlPathToUrlPathTemplateMatcher.cs | 7 -- .../UrlPathMatcher/UrlPathMatch.cs | 17 --- ...UpstreamUrlPathTemplateVariableReplacer.cs | 10 -- ...UpstreamUrlPathTemplateVariableReplacer.cs | 22 ---- .../DownstreamUrlPathAlreadyExists.cs | 12 -- .../DownstreamUrlPathDoesNotExist.cs | 12 -- .../IUrlPathTemplateMapRepository.cs | 12 -- .../InMemoryUrlPathTemplateMapRepository.cs | 51 -------- .../UrlPathTemplateMap.cs | 14 --- .../DownstreamUrlTemplateVariableReplacer.cs | 22 ++++ ...wnstreamUrlPathTemplateVariableReplacer.cs | 9 ++ .../DownstreamUrlAlreadyExists.cs | 12 ++ .../DownstreamUrlDoesNotExist.cs | 12 ++ .../IUrlTemplateMapRepository.cs | 11 ++ .../InMemoryUrlTemplateMapRepository.cs | 39 ++++++ .../UrlTemplateRepository/UrlTemplateMap.cs | 14 +++ .../Middleware/ProxyMiddleware.cs | 51 ++++---- src/Ocelot/Startup.cs | 15 +-- .../{RouterTests.cs => OcelotTests.cs} | 18 ++- .../HostUrlMapRepositoryTests.cs | 117 ------------------ .../UpstreamBaseUrlFinderTests.cs | 68 ---------- ...eamUrlPathTemplateVariableReplacerTests.cs | 72 +++++------ .../UrlPathTemplateMapRepositoryTests.cs | 75 +++-------- ...cs => UrlPathToUrlTemplateMatcherTests.cs} | 96 +++++++------- 36 files changed, 302 insertions(+), 668 deletions(-) delete mode 100644 src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMap.cs delete mode 100644 src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMapKeyAlreadyExists.cs delete mode 100644 src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMapKeyDoesNotExist.cs delete mode 100644 src/Ocelot.Library/Infrastructure/HostUrlRepository/IHostUrlMapRepository.cs delete mode 100644 src/Ocelot.Library/Infrastructure/HostUrlRepository/InMemoryHostUrlMapRepository.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlFinder/IUpstreamHostUrlFinder.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlFinder/UnableToFindUpstreamHostUrl.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlFinder/UpstreamHostUrlFinder.cs create mode 100644 src/Ocelot.Library/Infrastructure/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs rename src/Ocelot.Library/Infrastructure/{UrlPathMatcher => UrlMatcher}/TemplateVariableNameAndValue.cs (88%) create mode 100644 src/Ocelot.Library/Infrastructure/UrlMatcher/UrlMatch.cs rename src/Ocelot.Library/Infrastructure/{UrlPathMatcher/UrlPathToUrlPathTemplateMatcher.cs => UrlMatcher/UrlPathToUrlTemplateMatcher.cs} (74%) delete mode 100644 src/Ocelot.Library/Infrastructure/UrlPathMatcher/IUrlPathToUrlPathTemplateMatcher.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathMatch.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlPathReplacer/IUpstreamUrlPathTemplateVariableReplacer.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlPathReplacer/UpstreamUrlPathTemplateVariableReplacer.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/DownstreamUrlPathAlreadyExists.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/DownstreamUrlPathDoesNotExist.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/IUrlPathTemplateMapRepository.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/InMemoryUrlPathTemplateMapRepository.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/UrlPathTemplateMap.cs create mode 100644 src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs create mode 100644 src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs create mode 100644 src/Ocelot.Library/Infrastructure/UrlTemplateRepository/DownstreamUrlAlreadyExists.cs create mode 100644 src/Ocelot.Library/Infrastructure/UrlTemplateRepository/DownstreamUrlDoesNotExist.cs create mode 100644 src/Ocelot.Library/Infrastructure/UrlTemplateRepository/IUrlTemplateMapRepository.cs create mode 100644 src/Ocelot.Library/Infrastructure/UrlTemplateRepository/InMemoryUrlTemplateMapRepository.cs create mode 100644 src/Ocelot.Library/Infrastructure/UrlTemplateRepository/UrlTemplateMap.cs rename test/Ocelot.AcceptanceTests/{RouterTests.cs => OcelotTests.cs} (70%) delete mode 100644 test/Ocelot.UnitTests/HostUrlMapRepositoryTests.cs delete mode 100644 test/Ocelot.UnitTests/UpstreamBaseUrlFinderTests.cs rename test/Ocelot.UnitTests/{UrlPathToUrlPathTemplateMatcherTests.cs => UrlPathToUrlTemplateMatcherTests.cs} (63%) diff --git a/src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMap.cs b/src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMap.cs deleted file mode 100644 index a9b6ce61..00000000 --- a/src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMap.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Ocelot.Library.Infrastructure.HostUrlRepository -{ - public class HostUrlMap - { - public HostUrlMap(string urlPathTemplate, string upstreamHostUrl) - { - UrlPathTemplate = urlPathTemplate; - UpstreamHostUrl = upstreamHostUrl; - } - - public string UrlPathTemplate {get;private set;} - public string UpstreamHostUrl {get;private set;} - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMapKeyAlreadyExists.cs b/src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMapKeyAlreadyExists.cs deleted file mode 100644 index 236cac79..00000000 --- a/src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMapKeyAlreadyExists.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.HostUrlRepository -{ - public class HostUrlMapKeyAlreadyExists : Error - { - public HostUrlMapKeyAlreadyExists() - : base("This key has already been used") - { - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMapKeyDoesNotExist.cs b/src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMapKeyDoesNotExist.cs deleted file mode 100644 index 913f2b67..00000000 --- a/src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMapKeyDoesNotExist.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.HostUrlRepository -{ - public class HostUrlMapKeyDoesNotExist : Error - { - public HostUrlMapKeyDoesNotExist() - : base("This key does not exist") - { - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/HostUrlRepository/IHostUrlMapRepository.cs b/src/Ocelot.Library/Infrastructure/HostUrlRepository/IHostUrlMapRepository.cs deleted file mode 100644 index da78044c..00000000 --- a/src/Ocelot.Library/Infrastructure/HostUrlRepository/IHostUrlMapRepository.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.HostUrlRepository -{ - public interface IHostUrlMapRepository - { - Response AddBaseUrlMap(HostUrlMap baseUrlMap); - Response GetBaseUrlMap(string urlPathTemplate); - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/HostUrlRepository/InMemoryHostUrlMapRepository.cs b/src/Ocelot.Library/Infrastructure/HostUrlRepository/InMemoryHostUrlMapRepository.cs deleted file mode 100644 index 61b45ebf..00000000 --- a/src/Ocelot.Library/Infrastructure/HostUrlRepository/InMemoryHostUrlMapRepository.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Collections.Generic; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.HostUrlRepository -{ - public class InMemoryHostUrlMapRepository : IHostUrlMapRepository - { - private readonly Dictionary _routes; - public InMemoryHostUrlMapRepository() - { - _routes = new Dictionary(); - } - public Response AddBaseUrlMap(HostUrlMap baseUrlMap) - { - if(_routes.ContainsKey(baseUrlMap.UrlPathTemplate)) - { - return new ErrorResponse(new List(){new HostUrlMapKeyAlreadyExists()}); - } - - _routes.Add(baseUrlMap.UrlPathTemplate, baseUrlMap.UpstreamHostUrl); - - return new OkResponse(); - } - - public Response GetBaseUrlMap(string urlPathTemplate) - { - string upstreamUrl = null; - - if(_routes.TryGetValue(urlPathTemplate, out upstreamUrl)) - { - return new OkResponse(new HostUrlMap(urlPathTemplate, upstreamUrl)); - } - - return new ErrorResponse(new List(){new HostUrlMapKeyDoesNotExist()}); - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlFinder/IUpstreamHostUrlFinder.cs b/src/Ocelot.Library/Infrastructure/UrlFinder/IUpstreamHostUrlFinder.cs deleted file mode 100644 index 84a78493..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlFinder/IUpstreamHostUrlFinder.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.UrlFinder -{ - public interface IUpstreamHostUrlFinder - { - Response FindUpstreamHostUrl(string downstreamHostUrl); - } -} diff --git a/src/Ocelot.Library/Infrastructure/UrlFinder/UnableToFindUpstreamHostUrl.cs b/src/Ocelot.Library/Infrastructure/UrlFinder/UnableToFindUpstreamHostUrl.cs deleted file mode 100644 index 10defcee..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlFinder/UnableToFindUpstreamHostUrl.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.UrlFinder -{ - public class UnableToFindUpstreamHostUrl : Error - { - public UnableToFindUpstreamHostUrl() - : base("Unable to find upstream base url") - { - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlFinder/UpstreamHostUrlFinder.cs b/src/Ocelot.Library/Infrastructure/UrlFinder/UpstreamHostUrlFinder.cs deleted file mode 100644 index 555eb3d2..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlFinder/UpstreamHostUrlFinder.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Collections.Generic; -using Ocelot.Library.Infrastructure.HostUrlRepository; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.UrlFinder -{ - public class UpstreamHostUrlFinder : IUpstreamHostUrlFinder - { - private readonly IHostUrlMapRepository _hostUrlMapRepository; - - public UpstreamHostUrlFinder(IHostUrlMapRepository hostUrlMapRepository) - { - _hostUrlMapRepository = hostUrlMapRepository; - } - public Response FindUpstreamHostUrl(string downstreamBaseUrl) - { - var baseUrl = _hostUrlMapRepository.GetBaseUrlMap(downstreamBaseUrl); - - if(baseUrl.IsError) - { - return new ErrorResponse(new List {new UnableToFindUpstreamHostUrl()}); - } - - return new OkResponse(baseUrl.Data.UpstreamHostUrl); - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs b/src/Ocelot.Library/Infrastructure/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs new file mode 100644 index 00000000..6f96a28c --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs @@ -0,0 +1,7 @@ +namespace Ocelot.Library.Infrastructure.UrlMatcher +{ + public interface IUrlPathToUrlTemplateMatcher + { + UrlMatch Match(string downstreamUrlPath, string downstreamUrlTemplate); + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlPathMatcher/TemplateVariableNameAndValue.cs b/src/Ocelot.Library/Infrastructure/UrlMatcher/TemplateVariableNameAndValue.cs similarity index 88% rename from src/Ocelot.Library/Infrastructure/UrlPathMatcher/TemplateVariableNameAndValue.cs rename to src/Ocelot.Library/Infrastructure/UrlMatcher/TemplateVariableNameAndValue.cs index f65ab514..07935d08 100644 --- a/src/Ocelot.Library/Infrastructure/UrlPathMatcher/TemplateVariableNameAndValue.cs +++ b/src/Ocelot.Library/Infrastructure/UrlMatcher/TemplateVariableNameAndValue.cs @@ -1,4 +1,4 @@ -namespace Ocelot.Library.Infrastructure.UrlPathMatcher +namespace Ocelot.Library.Infrastructure.UrlMatcher { public class TemplateVariableNameAndValue { diff --git a/src/Ocelot.Library/Infrastructure/UrlMatcher/UrlMatch.cs b/src/Ocelot.Library/Infrastructure/UrlMatcher/UrlMatch.cs new file mode 100644 index 00000000..0eb4cb47 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/UrlMatcher/UrlMatch.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; + +namespace Ocelot.Library.Infrastructure.UrlMatcher +{ + public class UrlMatch + { + public UrlMatch(bool match, List templateVariableNameAndValues, string downstreamUrlTemplate) + { + Match = match; + TemplateVariableNameAndValues = templateVariableNameAndValues; + DownstreamUrlTemplate = downstreamUrlTemplate; + } + public bool Match {get;private set;} + public List TemplateVariableNameAndValues {get;private set;} + public string DownstreamUrlTemplate {get;private set;} + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathToUrlPathTemplateMatcher.cs b/src/Ocelot.Library/Infrastructure/UrlMatcher/UrlPathToUrlTemplateMatcher.cs similarity index 74% rename from src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathToUrlPathTemplateMatcher.cs rename to src/Ocelot.Library/Infrastructure/UrlMatcher/UrlPathToUrlTemplateMatcher.cs index 3b2152e8..fc34153e 100644 --- a/src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathToUrlPathTemplateMatcher.cs +++ b/src/Ocelot.Library/Infrastructure/UrlMatcher/UrlPathToUrlTemplateMatcher.cs @@ -1,25 +1,25 @@ using System; using System.Collections.Generic; -namespace Ocelot.Library.Infrastructure.UrlPathMatcher +namespace Ocelot.Library.Infrastructure.UrlMatcher { - public class UrlPathToUrlPathTemplateMatcher : IUrlPathToUrlPathTemplateMatcher + public class UrlPathToUrlTemplateMatcher : IUrlPathToUrlTemplateMatcher { - public UrlPathMatch Match(string downstreamUrlPath, string downstreamUrlPathTemplate) + public UrlMatch Match(string downstreamUrlPath, string downstreamUrlTemplate) { - var urlPathTemplateCopy = downstreamUrlPathTemplate; + var urlPathTemplateCopy = downstreamUrlTemplate; var templateKeysAndValues = new List(); int counterForUrl = 0; - for (int counterForTemplate = 0; counterForTemplate < downstreamUrlPathTemplate.Length; counterForTemplate++) + for (int counterForTemplate = 0; counterForTemplate < downstreamUrlTemplate.Length; counterForTemplate++) { - if (CharactersDontMatch(downstreamUrlPathTemplate[counterForTemplate], downstreamUrlPath[counterForUrl]) && ContinueScanningUrl(counterForUrl,downstreamUrlPath.Length)) + if (CharactersDontMatch(downstreamUrlTemplate[counterForTemplate], downstreamUrlPath[counterForUrl]) && ContinueScanningUrl(counterForUrl,downstreamUrlPath.Length)) { - if (IsPlaceholder(downstreamUrlPathTemplate[counterForTemplate])) + if (IsPlaceholder(downstreamUrlTemplate[counterForTemplate])) { - var variableName = GetPlaceholderVariableName(downstreamUrlPathTemplate, counterForTemplate); + var variableName = GetPlaceholderVariableName(downstreamUrlTemplate, counterForTemplate); var variableValue = GetPlaceholderVariableValue(downstreamUrlPath, counterForUrl); @@ -27,7 +27,7 @@ namespace Ocelot.Library.Infrastructure.UrlPathMatcher templateKeysAndValues.Add(templateVariableNameAndValue); - counterForTemplate = GetNextCounterPosition(downstreamUrlPathTemplate, counterForTemplate, '}'); + counterForTemplate = GetNextCounterPosition(downstreamUrlTemplate, counterForTemplate, '}'); counterForUrl = GetNextCounterPosition(downstreamUrlPath, counterForUrl, '/'); @@ -35,12 +35,12 @@ namespace Ocelot.Library.Infrastructure.UrlPathMatcher } else { - return new UrlPathMatch(false, templateKeysAndValues, string.Empty); + return new UrlMatch(false, templateKeysAndValues, string.Empty); } } counterForUrl++; } - return new UrlPathMatch(true, templateKeysAndValues, urlPathTemplateCopy); + return new UrlMatch(true, templateKeysAndValues, urlPathTemplateCopy); } private string GetPlaceholderVariableValue(string urlPath, int counterForUrl) diff --git a/src/Ocelot.Library/Infrastructure/UrlPathMatcher/IUrlPathToUrlPathTemplateMatcher.cs b/src/Ocelot.Library/Infrastructure/UrlPathMatcher/IUrlPathToUrlPathTemplateMatcher.cs deleted file mode 100644 index 5ed4d637..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlPathMatcher/IUrlPathToUrlPathTemplateMatcher.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Ocelot.Library.Infrastructure.UrlPathMatcher -{ - public interface IUrlPathToUrlPathTemplateMatcher - { - UrlPathMatch Match(string downstreamUrlPath, string downStreamUrlPathTemplate); - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathMatch.cs b/src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathMatch.cs deleted file mode 100644 index 7f474e62..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathMatch.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Collections.Generic; - -namespace Ocelot.Library.Infrastructure.UrlPathMatcher -{ - public class UrlPathMatch - { - public UrlPathMatch(bool match, List templateVariableNameAndValues, string downstreamUrlPathTemplate) - { - Match = match; - TemplateVariableNameAndValues = templateVariableNameAndValues; - DownstreamUrlPathTemplate = downstreamUrlPathTemplate; - } - public bool Match {get;private set;} - public List TemplateVariableNameAndValues {get;private set;} - public string DownstreamUrlPathTemplate {get;private set;} - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlPathReplacer/IUpstreamUrlPathTemplateVariableReplacer.cs b/src/Ocelot.Library/Infrastructure/UrlPathReplacer/IUpstreamUrlPathTemplateVariableReplacer.cs deleted file mode 100644 index cb455185..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlPathReplacer/IUpstreamUrlPathTemplateVariableReplacer.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Ocelot.Library.Infrastructure.UrlPathMatcher; - -namespace Ocelot.Library.Infrastructure.UrlPathReplacer -{ - public interface IUpstreamUrlPathTemplateVariableReplacer - { - string ReplaceTemplateVariable(string upstreamPathTemplate, UrlPathMatch urlPathMatch); - - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlPathReplacer/UpstreamUrlPathTemplateVariableReplacer.cs b/src/Ocelot.Library/Infrastructure/UrlPathReplacer/UpstreamUrlPathTemplateVariableReplacer.cs deleted file mode 100644 index b52ea69e..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlPathReplacer/UpstreamUrlPathTemplateVariableReplacer.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using System.Text; -using Ocelot.Library.Infrastructure.UrlPathMatcher; - -namespace Ocelot.Library.Infrastructure.UrlPathReplacer -{ - public class UpstreamUrlPathTemplateVariableReplacer : IUpstreamUrlPathTemplateVariableReplacer - { - public string ReplaceTemplateVariable(string upstreamPathTemplate, UrlPathMatch urlPathMatch) - { - var upstreamUrl = new StringBuilder(); - upstreamUrl.Append(upstreamPathTemplate); - - foreach (var templateVarAndValue in urlPathMatch.TemplateVariableNameAndValues) - { - upstreamUrl.Replace(templateVarAndValue.TemplateVariableName, templateVarAndValue.TemplateVariableValue); - } - - return upstreamUrl.ToString(); - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/DownstreamUrlPathAlreadyExists.cs b/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/DownstreamUrlPathAlreadyExists.cs deleted file mode 100644 index 05a552ac..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/DownstreamUrlPathAlreadyExists.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.UrlPathTemplateRepository -{ - public class DownstreamUrlPathTemplateAlreadyExists : Error - { - public DownstreamUrlPathTemplateAlreadyExists() - : base("This key has already been used") - { - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/DownstreamUrlPathDoesNotExist.cs b/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/DownstreamUrlPathDoesNotExist.cs deleted file mode 100644 index 7d89beeb..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/DownstreamUrlPathDoesNotExist.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.UrlPathTemplateRepository -{ - public class DownstreamUrlPathTemplateDoesNotExist : Error - { - public DownstreamUrlPathTemplateDoesNotExist() - : base("This key does not exist") - { - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/IUrlPathTemplateMapRepository.cs b/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/IUrlPathTemplateMapRepository.cs deleted file mode 100644 index b63ecfc6..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/IUrlPathTemplateMapRepository.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Collections.Generic; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.UrlPathTemplateRepository -{ - public interface IUrlPathTemplateMapRepository - { - Response AddUrlPathTemplateMap(UrlPathTemplateMap urlPathMap); - Response GetUrlPathTemplateMap(string downstreamUrlPathTemplate); - Response> All { get; } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/InMemoryUrlPathTemplateMapRepository.cs b/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/InMemoryUrlPathTemplateMapRepository.cs deleted file mode 100644 index b56c6b95..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/InMemoryUrlPathTemplateMapRepository.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.UrlPathTemplateRepository -{ - public class InMemoryUrlPathTemplateMapRepository : IUrlPathTemplateMapRepository - { - private readonly Dictionary _routes; - public InMemoryUrlPathTemplateMapRepository() - { - _routes = new Dictionary(); - } - - public Response> All - { - get - { - var routes = _routes - .Select(r => new UrlPathTemplateMap(r.Key, r.Value)) - .ToList(); - return new OkResponse>(routes); - } - } - - public Response AddUrlPathTemplateMap(UrlPathTemplateMap urlPathMap) - { - if(_routes.ContainsKey(urlPathMap.DownstreamUrlPathTemplate)) - { - return new ErrorResponse(new List(){new DownstreamUrlPathTemplateAlreadyExists()}); - } - - _routes.Add(urlPathMap.DownstreamUrlPathTemplate, urlPathMap.UpstreamUrlPathTemplate); - - return new OkResponse(); - } - - public Response GetUrlPathTemplateMap(string downstreamUrlPathTemplate) - { - string upstreamUrlPathTemplate = null; - - if(_routes.TryGetValue(downstreamUrlPathTemplate, out upstreamUrlPathTemplate)) - { - return new OkResponse(new UrlPathTemplateMap(downstreamUrlPathTemplate, upstreamUrlPathTemplate)); - } - - return new ErrorResponse(new List(){new DownstreamUrlPathTemplateDoesNotExist()}); - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/UrlPathTemplateMap.cs b/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/UrlPathTemplateMap.cs deleted file mode 100644 index 1471813c..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/UrlPathTemplateMap.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Ocelot.Library.Infrastructure.UrlPathTemplateRepository -{ - public class UrlPathTemplateMap - { - public UrlPathTemplateMap(string downstreamUrlPathTemplate, string upstreamUrlPathTemplate) - { - DownstreamUrlPathTemplate = downstreamUrlPathTemplate; - UpstreamUrlPathTemplate = upstreamUrlPathTemplate; - } - - public string DownstreamUrlPathTemplate {get;private set;} - public string UpstreamUrlPathTemplate {get;private set;} - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs new file mode 100644 index 00000000..14e99be9 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs @@ -0,0 +1,22 @@ +using System.Text; +using Ocelot.Library.Infrastructure.UrlMatcher; + +namespace Ocelot.Library.Infrastructure.UrlTemplateReplacer +{ + public class DownstreamUrlTemplateVariableReplacer : IDownstreamUrlTemplateVariableReplacer + { + public string ReplaceTemplateVariable(string downstreamPathTemplate, UrlMatch urlMatch) + { + var upstreamUrl = new StringBuilder(); + + upstreamUrl.Append(downstreamPathTemplate); + + foreach (var templateVarAndValue in urlMatch.TemplateVariableNameAndValues) + { + upstreamUrl.Replace(templateVarAndValue.TemplateVariableName, templateVarAndValue.TemplateVariableValue); + } + + return upstreamUrl.ToString(); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs new file mode 100644 index 00000000..53b532f4 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs @@ -0,0 +1,9 @@ +using Ocelot.Library.Infrastructure.UrlMatcher; + +namespace Ocelot.Library.Infrastructure.UrlTemplateReplacer +{ + public interface IDownstreamUrlTemplateVariableReplacer + { + string ReplaceTemplateVariable(string downstreamPathTemplate, UrlMatch urlMatch); + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/DownstreamUrlAlreadyExists.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/DownstreamUrlAlreadyExists.cs new file mode 100644 index 00000000..cf471ba3 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/DownstreamUrlAlreadyExists.cs @@ -0,0 +1,12 @@ +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.UrlTemplateRepository +{ + public class DownstreamUrlTemplateAlreadyExists : Error + { + public DownstreamUrlTemplateAlreadyExists() + : base("This key has already been used") + { + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/DownstreamUrlDoesNotExist.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/DownstreamUrlDoesNotExist.cs new file mode 100644 index 00000000..ba960046 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/DownstreamUrlDoesNotExist.cs @@ -0,0 +1,12 @@ +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.UrlTemplateRepository +{ + public class DownstreamUrlTemplateDoesNotExist : Error + { + public DownstreamUrlTemplateDoesNotExist() + : base("This key does not exist") + { + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/IUrlTemplateMapRepository.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/IUrlTemplateMapRepository.cs new file mode 100644 index 00000000..d4be69ae --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/IUrlTemplateMapRepository.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.UrlTemplateRepository +{ + public interface IUrlTemplateMapRepository + { + Response AddUrlTemplateMap(UrlTemplateMap urlPathMap); + Response> All { get; } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/InMemoryUrlTemplateMapRepository.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/InMemoryUrlTemplateMapRepository.cs new file mode 100644 index 00000000..0129b4d6 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/InMemoryUrlTemplateMapRepository.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.UrlTemplateRepository +{ + public class InMemoryUrlTemplateMapRepository : IUrlTemplateMapRepository + { + private readonly Dictionary _urlTemplates; + public InMemoryUrlTemplateMapRepository() + { + _urlTemplates = new Dictionary(); + } + + public Response> All + { + get + { + var routes = _urlTemplates + .Select(r => new UrlTemplateMap(r.Key, r.Value)) + .ToList(); + return new OkResponse>(routes); + } + } + + public Response AddUrlTemplateMap(UrlTemplateMap urlMap) + { + if(_urlTemplates.ContainsKey(urlMap.DownstreamUrlTemplate)) + { + return new ErrorResponse(new List(){new DownstreamUrlTemplateAlreadyExists()}); + } + + _urlTemplates.Add(urlMap.DownstreamUrlTemplate, urlMap.UpstreamUrlPathTemplate); + + return new OkResponse(); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/UrlTemplateMap.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/UrlTemplateMap.cs new file mode 100644 index 00000000..198917a9 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/UrlTemplateMap.cs @@ -0,0 +1,14 @@ +namespace Ocelot.Library.Infrastructure.UrlTemplateRepository +{ + public class UrlTemplateMap + { + public UrlTemplateMap(string downstreamUrlTemplate, string upstreamUrlPathTemplate) + { + DownstreamUrlTemplate = downstreamUrlTemplate; + UpstreamUrlPathTemplate = upstreamUrlPathTemplate; + } + + public string DownstreamUrlTemplate {get;private set;} + public string UpstreamUrlPathTemplate {get;private set;} + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs index a56fbd17..077bfae9 100644 --- a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs +++ b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs @@ -1,10 +1,8 @@ -using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; -using Ocelot.Library.Infrastructure.HostUrlRepository; -using Ocelot.Library.Infrastructure.UrlPathMatcher; -using Ocelot.Library.Infrastructure.UrlPathReplacer; -using Ocelot.Library.Infrastructure.UrlPathTemplateRepository; +using Ocelot.Library.Infrastructure.UrlMatcher; +using Ocelot.Library.Infrastructure.UrlTemplateRepository; +using Ocelot.Library.Infrastructure.UrlTemplateReplacer; namespace Ocelot.Library.Middleware { @@ -13,53 +11,48 @@ namespace Ocelot.Library.Middleware public class ProxyMiddleware { private readonly RequestDelegate _next; - private readonly IUrlPathToUrlPathTemplateMatcher _urlMatcher; - private readonly IUrlPathTemplateMapRepository _urlPathRepository; - private readonly IHostUrlMapRepository _hostUrlRepository; - private readonly IUpstreamUrlPathTemplateVariableReplacer _urlReplacer; + private readonly IUrlPathToUrlTemplateMatcher _urlMatcher; + private readonly IUrlTemplateMapRepository _urlTemplateMapRepository; + private readonly IDownstreamUrlTemplateVariableReplacer _urlReplacer; public ProxyMiddleware(RequestDelegate next, - IUrlPathToUrlPathTemplateMatcher urlMatcher, - IUrlPathTemplateMapRepository urlPathRepository, - IHostUrlMapRepository hostUrlRepository, - IUpstreamUrlPathTemplateVariableReplacer urlReplacer) + IUrlPathToUrlTemplateMatcher urlMatcher, + IUrlTemplateMapRepository urlPathRepository, + IDownstreamUrlTemplateVariableReplacer urlReplacer) { _next = next; _urlMatcher = urlMatcher; - _urlPathRepository = urlPathRepository; - _hostUrlRepository = hostUrlRepository; + _urlTemplateMapRepository = urlPathRepository; _urlReplacer = urlReplacer; } public async Task Invoke(HttpContext context) - { - - var path = context.Request.Path.ToString(); + { + var downstreamUrlPath = context.Request.Path.ToString(); - var urlPathTemplateMaps = _urlPathRepository.All; + var upstreamUrlTemplates = _urlTemplateMapRepository.All; - UrlPathMatch urlPathMatch = null; - string upstreamPathUrlTemplate = string.Empty; + UrlMatch urlMatch = null; - foreach (var template in urlPathTemplateMaps.Data) + string downstreamUrlTemplate = string.Empty; + + foreach (var template in upstreamUrlTemplates.Data) { - urlPathMatch = _urlMatcher.Match(path, template.DownstreamUrlPathTemplate); + urlMatch = _urlMatcher.Match(downstreamUrlPath, template.DownstreamUrlTemplate); - if (urlPathMatch.Match) + if (urlMatch.Match) { - upstreamPathUrlTemplate = template.UpstreamUrlPathTemplate; + downstreamUrlTemplate = template.DownstreamUrlTemplate; break; } } - if (urlPathMatch == null || !urlPathMatch.Match) + if (urlMatch == null || !urlMatch.Match) { context.Response.StatusCode = (int)HttpStatusCode.NotFound; return; } - var upstreamHostUrl = _hostUrlRepository.GetBaseUrlMap(urlPathMatch.DownstreamUrlPathTemplate); - - var pathUrl = _urlReplacer.ReplaceTemplateVariable(upstreamPathUrlTemplate, urlPathMatch); + var downstreamUrl = _urlReplacer.ReplaceTemplateVariable(downstreamUrlTemplate, urlMatch); //make a http request to this endpoint...maybe bring in a library diff --git a/src/Ocelot/Startup.cs b/src/Ocelot/Startup.cs index d95b6f65..c585c1a5 100644 --- a/src/Ocelot/Startup.cs +++ b/src/Ocelot/Startup.cs @@ -8,10 +8,9 @@ using Ocelot.Library.Middleware; namespace Ocelot { - using Library.Infrastructure.HostUrlRepository; - using Library.Infrastructure.UrlPathMatcher; - using Library.Infrastructure.UrlPathReplacer; - using Library.Infrastructure.UrlPathTemplateRepository; + using Library.Infrastructure.UrlMatcher; + using Library.Infrastructure.UrlTemplateReplacer; + using Library.Infrastructure.UrlTemplateRepository; public class Startup { @@ -31,11 +30,9 @@ namespace Ocelot public void ConfigureServices(IServiceCollection services) { // Add framework services. - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. diff --git a/test/Ocelot.AcceptanceTests/RouterTests.cs b/test/Ocelot.AcceptanceTests/OcelotTests.cs similarity index 70% rename from test/Ocelot.AcceptanceTests/RouterTests.cs rename to test/Ocelot.AcceptanceTests/OcelotTests.cs index 2d4d2c4e..6f767a64 100644 --- a/test/Ocelot.AcceptanceTests/RouterTests.cs +++ b/test/Ocelot.AcceptanceTests/OcelotTests.cs @@ -11,14 +11,14 @@ namespace Ocelot.AcceptanceTests using System.Net; using TestStack.BDDfy; - public class RouterTests : IDisposable + public class OcelotTests : IDisposable { private readonly FakeService _fakeService; private readonly TestServer _server; private readonly HttpClient _client; private HttpResponseMessage _response; - public RouterTests() + public OcelotTests() { _server = new TestServer(new WebHostBuilder() .UseStartup()); @@ -36,6 +36,15 @@ namespace Ocelot.AcceptanceTests .BDDfy(); } + [Fact] + public void should_return_response_200() + { + this.When(x => x.WhenIRequestTheUrl("/")) + .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + .And(x => x.ThenTheResponseBodyShouldBe("Hello from Laura")) + .BDDfy(); + } + private void WhenIRequestTheUrl(string url) { _response = _client.GetAsync("/").Result; @@ -46,6 +55,11 @@ namespace Ocelot.AcceptanceTests _response.StatusCode.ShouldBe(expectedHttpStatusCode); } + private void ThenTheResponseBodyShouldBe(string expectedBody) + { + _response.Content.ReadAsStringAsync().Result.ShouldBe(expectedBody); + } + public void Dispose() { _fakeService.Stop(); diff --git a/test/Ocelot.UnitTests/HostUrlMapRepositoryTests.cs b/test/Ocelot.UnitTests/HostUrlMapRepositoryTests.cs deleted file mode 100644 index 045dfab1..00000000 --- a/test/Ocelot.UnitTests/HostUrlMapRepositoryTests.cs +++ /dev/null @@ -1,117 +0,0 @@ -using Ocelot.Library.Infrastructure.Responses; -using Ocelot.Library.Infrastructure.HostUrlRepository; -using Shouldly; -using Xunit; - -namespace Ocelot.UnitTests -{ - using TestStack.BDDfy; - - public class HostUrlMapRepositoryTests - { - private string _upstreamBaseUrl; - private string _downstreamBaseUrl; - private readonly IHostUrlMapRepository _repository; - private Response _response; - private Response _getRouteResponse; - - public HostUrlMapRepositoryTests() - { - _repository = new InMemoryHostUrlMapRepository(); - } - - [Fact] - public void can_add_route() - { - this.Given(x => x.GivenIHaveAnUpstreamBaseUrl("www.someapi.com")) - .And(x => x.GivenIWantToRouteRequestsFromMyDownstreamBaseUrl("api")) - .When(x => x.WhenIAddTheConfiguration()) - .Then(x => x.ThenTheResponseIsSuccesful()) - .BDDfy(); - } - - [Fact] - public void can_get_route_by_key() - { - this.Given(x => x.GivenIHaveSetUpAnApiKeyAndUpstreamUrl("api2", "www.someapi.com")) - .When(x => x.WhenIRetrieveTheRouteByKey()) - .Then(x => x.ThenTheRouteIsReturned()) - .BDDfy(); - } - - [Fact] - public void should_return_error_response_when_key_already_used() - { - this.Given(x => x.GivenIHaveSetUpAnApiKeyAndUpstreamUrl("api2", "www.someapi.com")) - .When(x => x.WhenITryToUseTheSameKey()) - .Then(x => x.ThenTheKeyHasAlreadyBeenUsed()) - .BDDfy(); - } - - [Fact] - public void should_return_error_response_if_key_doesnt_exist() - { - this.Given(x => x.GivenIWantToRouteRequestsFromMyDownstreamBaseUrl("api")) - .When(x => x.WhenIRetrieveTheRouteByKey()) - .Then(x => x.ThenTheKeyDoesNotExist()) - .BDDfy(); - } - - private void WhenITryToUseTheSameKey() - { - WhenIAddTheConfiguration(); - } - - private void ThenTheKeyHasAlreadyBeenUsed() - { - _response.ShouldNotBeNull(); - _response.ShouldBeOfType(); - _response.Errors[0].Message.ShouldBe("This key has already been used"); - } - - private void ThenTheKeyDoesNotExist() - { - _getRouteResponse.ShouldNotBeNull(); - _getRouteResponse.ShouldBeOfType>(); - _getRouteResponse.Errors[0].Message.ShouldBe("This key does not exist"); - } - - private void WhenIRetrieveTheRouteByKey() - { - _getRouteResponse = _repository.GetBaseUrlMap(_downstreamBaseUrl); - } - - private void ThenTheRouteIsReturned() - { - _getRouteResponse.Data.UrlPathTemplate.ShouldBe(_downstreamBaseUrl); - _getRouteResponse.Data.UpstreamHostUrl.ShouldBe(_upstreamBaseUrl); - } - - private void GivenIHaveSetUpAnApiKeyAndUpstreamUrl(string apiKey, string upstreamUrl) - { - GivenIHaveAnUpstreamBaseUrl(upstreamUrl); - GivenIWantToRouteRequestsFromMyDownstreamBaseUrl(apiKey); - WhenIAddTheConfiguration(); - } - - private void GivenIHaveAnUpstreamBaseUrl(string upstreamApiUrl) - { - _upstreamBaseUrl = upstreamApiUrl; - } - - private void GivenIWantToRouteRequestsFromMyDownstreamBaseUrl(string downstreamBaseUrl) - { - _downstreamBaseUrl = downstreamBaseUrl; - } - - private void WhenIAddTheConfiguration() - { - _response = _repository.AddBaseUrlMap(new HostUrlMap(_downstreamBaseUrl, _upstreamBaseUrl)); - } - - private void ThenTheResponseIsSuccesful() - { - _response.ShouldBeOfType(); - } - } -} \ No newline at end of file diff --git a/test/Ocelot.UnitTests/UpstreamBaseUrlFinderTests.cs b/test/Ocelot.UnitTests/UpstreamBaseUrlFinderTests.cs deleted file mode 100644 index 6a36b312..00000000 --- a/test/Ocelot.UnitTests/UpstreamBaseUrlFinderTests.cs +++ /dev/null @@ -1,68 +0,0 @@ -using Ocelot.Library.Infrastructure.HostUrlRepository; -using Ocelot.Library.Infrastructure.UrlFinder; -using Ocelot.Library.Infrastructure.Responses; -using Xunit; -using Shouldly; -using TestStack.BDDfy; - -namespace Ocelot.UnitTests -{ - public class UpstreamBaseUrlFinderTests - { - private readonly IUpstreamHostUrlFinder _upstreamBaseUrlFinder; - private readonly IHostUrlMapRepository _hostUrlMapRepository; - private string _downstreamBaseUrl; - private Response _result; - public UpstreamBaseUrlFinderTests() - { - _hostUrlMapRepository = new InMemoryHostUrlMapRepository(); - _upstreamBaseUrlFinder = new UpstreamHostUrlFinder(_hostUrlMapRepository); - } - - [Fact] - public void can_find_base_url() - { - this.Given(x => x.GivenTheBaseUrlMapExists(new HostUrlMap("api.tom.com", "api.laura.com"))) - .And(x => x.GivenTheDownstreamBaseUrlIs("api.tom.com")) - .When(x => x.WhenIFindTheMatchingUpstreamBaseUrl()) - .Then(x => x.ThenTheFollowingIsReturned("api.laura.com")) - .BDDfy(); - } - - [Fact] - public void cant_find_base_url() - { - this.Given(x => x.GivenTheDownstreamBaseUrlIs("api.tom.com")) - .When(x => x.WhenIFindTheMatchingUpstreamBaseUrl()) - .Then(x => x.ThenAnErrorIsReturned()) - .BDDfy(); - } - - private void ThenAnErrorIsReturned() - { - _result.Errors.Count.ShouldBe(1); - } - - private void GivenTheBaseUrlMapExists(HostUrlMap baseUrlMap) - { - _hostUrlMapRepository.AddBaseUrlMap(baseUrlMap); - - } - - private void GivenTheDownstreamBaseUrlIs(string downstreamBaseUrl) - { - _downstreamBaseUrl = downstreamBaseUrl; - } - - private void WhenIFindTheMatchingUpstreamBaseUrl() - { - _result = _upstreamBaseUrlFinder.FindUpstreamHostUrl(_downstreamBaseUrl); - - } - - private void ThenTheFollowingIsReturned(string expectedBaseUrl) - { - _result.Data.ShouldBe(expectedBaseUrl); - } - } -} \ No newline at end of file diff --git a/test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs b/test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs index fd4deacf..aef6e6c6 100644 --- a/test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs +++ b/test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -using Ocelot.Library.Infrastructure.UrlPathMatcher; -using Ocelot.Library.Infrastructure.UrlPathReplacer; +using Ocelot.Library.Infrastructure.UrlMatcher; +using Ocelot.Library.Infrastructure.UrlTemplateReplacer; using Shouldly; using Xunit; @@ -10,53 +10,53 @@ namespace Ocelot.UnitTests public class UpstreamUrlPathTemplateVariableReplacerTests { - private string _upstreamUrlPath; - private UrlPathMatch _urlPathMatch; + private string _downstreamUrlTemplate; + private UrlMatch _urlMatch; private string _result; - private readonly IUpstreamUrlPathTemplateVariableReplacer _upstreamUrlPathReplacer; + private readonly IDownstreamUrlTemplateVariableReplacer _downstreamUrlPathReplacer; public UpstreamUrlPathTemplateVariableReplacerTests() { - _upstreamUrlPathReplacer = new UpstreamUrlPathTemplateVariableReplacer(); + _downstreamUrlPathReplacer = new DownstreamUrlTemplateVariableReplacer(); } [Fact] public void can_replace_no_template_variables() { - this.Given(x => x.GivenThereIsAnUpstreamUrlPath("")) - .And(x => x.GivenThereIsAUrlPathMatch(new UrlPathMatch(true, new List(), ""))) + this.Given(x => x.GivenThereIsADownstreamUrl("")) + .And(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, new List(), ""))) .When(x => x.WhenIReplaceTheTemplateVariables()) - .Then(x => x.ThenTheUpstreamUrlPathIsReturned("")) + .Then(x => x.ThenTheDownstreamUrlPathIsReturned("")) .BDDfy(); } [Fact] public void can_replace_url_no_slash() { - this.Given(x => x.GivenThereIsAnUpstreamUrlPath("api")) - .And(x => x.GivenThereIsAUrlPathMatch(new UrlPathMatch(true, new List(), "api"))) + this.Given(x => x.GivenThereIsADownstreamUrl("api")) + .And(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, new List(), "api"))) .When(x => x.WhenIReplaceTheTemplateVariables()) - .Then(x => x.ThenTheUpstreamUrlPathIsReturned("api")) + .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api")) .BDDfy(); } [Fact] public void can_replace_url_one_slash() { - this.Given(x => x.GivenThereIsAnUpstreamUrlPath("api/")) - .And(x => x.GivenThereIsAUrlPathMatch(new UrlPathMatch(true, new List(), "api/"))) + this.Given(x => x.GivenThereIsADownstreamUrl("api/")) + .And(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, new List(), "api/"))) .When(x => x.WhenIReplaceTheTemplateVariables()) - .Then(x => x.ThenTheUpstreamUrlPathIsReturned("api/")) + .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api/")) .BDDfy(); } [Fact] public void can_replace_url_multiple_slash() { - this.Given(x => x.GivenThereIsAnUpstreamUrlPath("api/product/products/")) - .And(x => x.GivenThereIsAUrlPathMatch(new UrlPathMatch(true, new List(), "api/product/products/"))) + this.Given(x => x.GivenThereIsADownstreamUrl("api/product/products/")) + .And(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, new List(), "api/product/products/"))) .When(x => x.WhenIReplaceTheTemplateVariables()) - .Then(x => x.ThenTheUpstreamUrlPathIsReturned("api/product/products/")) + .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api/product/products/")) .BDDfy(); } @@ -68,10 +68,10 @@ namespace Ocelot.UnitTests new TemplateVariableNameAndValue("{productId}", "1") }; - this.Given(x => x.GivenThereIsAnUpstreamUrlPath("productservice/products/{productId}/")) - .And(x => x.GivenThereIsAUrlPathMatch(new UrlPathMatch(true, templateVariables, "api/products/{productId}/"))) + this.Given(x => x.GivenThereIsADownstreamUrl("productservice/products/{productId}/")) + .And(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, templateVariables, "api/products/{productId}/"))) .When(x => x.WhenIReplaceTheTemplateVariables()) - .Then(x => x.ThenTheUpstreamUrlPathIsReturned("productservice/products/1/")) + .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/")) .BDDfy(); } @@ -83,10 +83,10 @@ namespace Ocelot.UnitTests new TemplateVariableNameAndValue("{productId}", "1") }; - this.Given(x => x.GivenThereIsAnUpstreamUrlPath("productservice/products/{productId}/variants")) - .And(x => x.GivenThereIsAUrlPathMatch(new UrlPathMatch(true, templateVariables, "api/products/{productId}/"))) + this.Given(x => x.GivenThereIsADownstreamUrl("productservice/products/{productId}/variants")) + .And(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, templateVariables, "api/products/{productId}/"))) .When(x => x.WhenIReplaceTheTemplateVariables()) - .Then(x => x.ThenTheUpstreamUrlPathIsReturned("productservice/products/1/variants")) + .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/variants")) .BDDfy(); } @@ -99,10 +99,10 @@ namespace Ocelot.UnitTests new TemplateVariableNameAndValue("{variantId}", "12") }; - this.Given(x => x.GivenThereIsAnUpstreamUrlPath("productservice/products/{productId}/variants/{variantId}")) - .And(x => x.GivenThereIsAUrlPathMatch(new UrlPathMatch(true, templateVariables, "api/products/{productId}/{variantId}"))) + this.Given(x => x.GivenThereIsADownstreamUrl("productservice/products/{productId}/variants/{variantId}")) + .And(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, templateVariables, "api/products/{productId}/{variantId}"))) .When(x => x.WhenIReplaceTheTemplateVariables()) - .Then(x => x.ThenTheUpstreamUrlPathIsReturned("productservice/products/1/variants/12")) + .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/variants/12")) .BDDfy(); } @@ -116,29 +116,29 @@ namespace Ocelot.UnitTests new TemplateVariableNameAndValue("{categoryId}", "34") }; - this.Given(x => x.GivenThereIsAnUpstreamUrlPath("productservice/category/{categoryId}/products/{productId}/variants/{variantId}")) - .And(x => x.GivenThereIsAUrlPathMatch(new UrlPathMatch(true, templateVariables, "api/products/{categoryId}/{productId}/{variantId}"))) + this.Given(x => x.GivenThereIsADownstreamUrl("productservice/category/{categoryId}/products/{productId}/variants/{variantId}")) + .And(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, templateVariables, "api/products/{categoryId}/{productId}/{variantId}"))) .When(x => x.WhenIReplaceTheTemplateVariables()) - .Then(x => x.ThenTheUpstreamUrlPathIsReturned("productservice/category/34/products/1/variants/12")) + .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/category/34/products/1/variants/12")) .BDDfy(); } - private void GivenThereIsAnUpstreamUrlPath(string upstreamUrlPath) + private void GivenThereIsADownstreamUrl(string downstreamUrlTemplate) { - _upstreamUrlPath = upstreamUrlPath; + _downstreamUrlTemplate = downstreamUrlTemplate; } - private void GivenThereIsAUrlPathMatch(UrlPathMatch urlPathMatch) + private void GivenThereIsAUrlMatch(UrlMatch urlMatch) { - _urlPathMatch = urlPathMatch; + _urlMatch = urlMatch; } private void WhenIReplaceTheTemplateVariables() { - _result = _upstreamUrlPathReplacer.ReplaceTemplateVariable(_upstreamUrlPath, _urlPathMatch); + _result = _downstreamUrlPathReplacer.ReplaceTemplateVariable(_downstreamUrlTemplate, _urlMatch); } - private void ThenTheUpstreamUrlPathIsReturned(string expected) + private void ThenTheDownstreamUrlPathIsReturned(string expected) { _result.ShouldBe(expected); } diff --git a/test/Ocelot.UnitTests/UrlPathTemplateMapRepositoryTests.cs b/test/Ocelot.UnitTests/UrlPathTemplateMapRepositoryTests.cs index 98de6ba9..19811718 100644 --- a/test/Ocelot.UnitTests/UrlPathTemplateMapRepositoryTests.cs +++ b/test/Ocelot.UnitTests/UrlPathTemplateMapRepositoryTests.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using Ocelot.Library.Infrastructure.Responses; -using Ocelot.Library.Infrastructure.UrlPathTemplateRepository; +using Ocelot.Library.Infrastructure.UrlTemplateRepository; using Shouldly; using Xunit; @@ -10,41 +10,31 @@ namespace Ocelot.UnitTests public class UrlPathTemplateMapRepositoryTests { - private string _upstreamUrlPath; - private string _downstreamUrlPath; - private IUrlPathTemplateMapRepository _repository; + private string _upstreamUrlPathTemplate; + private string _downstreamUrlTemplate; + private IUrlTemplateMapRepository _repository; private Response _response; - private Response _getResponse; - private Response> _listResponse; + private Response> _listResponse; public UrlPathTemplateMapRepositoryTests() { - _repository = new InMemoryUrlPathTemplateMapRepository(); + _repository = new InMemoryUrlTemplateMapRepository(); } [Fact] public void can_add_url_path() { - this.Given(x => x.GivenIHaveAnUpstreamUrlPath("/api/products/products/{productId}")) - .And(x => x.GivenIWantToRouteRequestsToMyUpstreamUrlPath("/api/products/{productId}")) + this.Given(x => x.GivenIHaveAnUpstreamUrlPathTemplate("/api/products/products/{productId}")) + .And(x => x.GivenADownstreamUrlTemplate("/api/products/{productId}")) .When(x => x.WhenIAddTheConfiguration()) .Then(x => x.ThenTheResponseIsSuccesful()) .BDDfy(); } - [Fact] - public void can_get_url_path() - { - this.Given(x => x.GivenIHaveSetUpADownstreamUrlPathAndAnUpstreamUrlPath("/api2", "http://www.someapi.com/api2")) - .When(x => x.WhenIRetrieveTheUrlPathByDownstreamUrl()) - .Then(x => x.ThenTheUrlPathIsReturned()) - .BDDfy(); - } - [Fact] public void can_get_all_urls() { - this.Given(x => x.GivenIHaveSetUpADownstreamUrlPathAndAnUpstreamUrlPath("/api2", "http://www.someapi.com/api2")) + this.Given(x => x.GivenIHaveSetUpADownstreamUrlTemplateAndAnUpstreamUrlPathTemplate("/api2", "http://www.someapi.com/api2")) .When(x => x.WhenIRetrieveTheUrls()) .Then(x => x.ThenTheUrlsAreReturned()) .BDDfy(); @@ -53,21 +43,12 @@ namespace Ocelot.UnitTests [Fact] public void should_return_error_response_when_url_path_already_used() { - this.Given(x => x.GivenIHaveSetUpADownstreamUrlPathAndAnUpstreamUrlPath("/api2", "http://www.someapi.com/api2")) + this.Given(x => x.GivenIHaveSetUpADownstreamUrlTemplateAndAnUpstreamUrlPathTemplate("/api2", "http://www.someapi.com/api2")) .When(x => x.WhenITryToUseTheSameDownstreamUrl()) .Then(x => x.ThenTheDownstreamUrlAlreadyBeenUsed()) .BDDfy(); } - [Fact] - public void should_return_error_response_if_key_doesnt_exist() - { - this.Given(x => x.GivenIWantToRouteRequestsToMyUpstreamUrlPath("/api")) - .When(x => x.WhenIRetrieveTheUrlPathByDownstreamUrl()) - .Then(x => x.ThenTheKeyDoesNotExist()) - .BDDfy(); - } - private void WhenITryToUseTheSameDownstreamUrl() { WhenIAddTheConfiguration(); @@ -80,54 +61,36 @@ namespace Ocelot.UnitTests _response.Errors[0].Message.ShouldBe("This key has already been used"); } - private void ThenTheKeyDoesNotExist() - { - _getResponse.ShouldNotBeNull(); - _getResponse.ShouldBeOfType>(); - _getResponse.Errors[0].Message.ShouldBe("This key does not exist"); - } - - private void WhenIRetrieveTheUrlPathByDownstreamUrl() - { - _getResponse = _repository.GetUrlPathTemplateMap(_downstreamUrlPath); - } - - private void WhenIRetrieveTheUrls() + private void WhenIRetrieveTheUrls() { _listResponse = _repository.All; } - private void ThenTheUrlPathIsReturned() - { - _getResponse.Data.DownstreamUrlPathTemplate.ShouldBe(_downstreamUrlPath); - _getResponse.Data.UpstreamUrlPathTemplate.ShouldBe(_upstreamUrlPath); - } - private void ThenTheUrlsAreReturned() { _listResponse.Data.Count.ShouldBeGreaterThan(0); } - private void GivenIHaveSetUpADownstreamUrlPathAndAnUpstreamUrlPath(string downstream, string upstreamApiUrl) + private void GivenIHaveSetUpADownstreamUrlTemplateAndAnUpstreamUrlPathTemplate(string downstreamUrlTemplate, string upstreamUrlPathTemplate) { - GivenIHaveAnUpstreamUrlPath(upstreamApiUrl); - GivenIWantToRouteRequestsToMyUpstreamUrlPath(downstream); + GivenIHaveAnUpstreamUrlPathTemplate(upstreamUrlPathTemplate); + GivenADownstreamUrlTemplate(downstreamUrlTemplate); WhenIAddTheConfiguration(); } - private void GivenIHaveAnUpstreamUrlPath(string upstreamApiUrl) + private void GivenIHaveAnUpstreamUrlPathTemplate(string upstreamUrlPathTemplate) { - _upstreamUrlPath = upstreamApiUrl; + _upstreamUrlPathTemplate = upstreamUrlPathTemplate; } - private void GivenIWantToRouteRequestsToMyUpstreamUrlPath(string apiKey) + private void GivenADownstreamUrlTemplate(string downstreamUrlTemplate) { - _downstreamUrlPath = apiKey; + _downstreamUrlTemplate = downstreamUrlTemplate; } private void WhenIAddTheConfiguration() { - _response = _repository.AddUrlPathTemplateMap(new UrlPathTemplateMap(_downstreamUrlPath, _upstreamUrlPath)); + _response = _repository.AddUrlTemplateMap(new UrlTemplateMap(_downstreamUrlTemplate, _upstreamUrlPathTemplate)); } private void ThenTheResponseIsSuccesful() diff --git a/test/Ocelot.UnitTests/UrlPathToUrlPathTemplateMatcherTests.cs b/test/Ocelot.UnitTests/UrlPathToUrlTemplateMatcherTests.cs similarity index 63% rename from test/Ocelot.UnitTests/UrlPathToUrlPathTemplateMatcherTests.cs rename to test/Ocelot.UnitTests/UrlPathToUrlTemplateMatcherTests.cs index 0a3b105d..eb3ff139 100644 --- a/test/Ocelot.UnitTests/UrlPathToUrlPathTemplateMatcherTests.cs +++ b/test/Ocelot.UnitTests/UrlPathToUrlTemplateMatcherTests.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using System.Linq; -using Ocelot.Library.Infrastructure.UrlPathMatcher; +using Ocelot.Library.Infrastructure.UrlMatcher; using Shouldly; using Xunit; @@ -8,26 +8,26 @@ namespace Ocelot.UnitTests { using TestStack.BDDfy; - public class UrlPathToUrlPathTemplateMatcherTests + public class UrlPathToUrlTemplateMatcherTests { - private readonly IUrlPathToUrlPathTemplateMatcher _urlMapper; - private string _downstreamPath; + private readonly IUrlPathToUrlTemplateMatcher _urlMatcher; + private string _downstreamUrlPath; private string _downstreamPathTemplate; - private UrlPathMatch _result; - public UrlPathToUrlPathTemplateMatcherTests() + private UrlMatch _result; + public UrlPathToUrlTemplateMatcherTests() { - _urlMapper = new UrlPathToUrlPathTemplateMatcher(); + _urlMatcher = new UrlPathToUrlTemplateMatcher(); } [Fact] public void can_match_down_stream_url() { this.Given(x => x.GivenIHaveADownstreamPath("")) - .And(x => x.GivenIHaveAnDownstreamPathTemplate("")) + .And(x => x.GivenIHaveAnDownstreamUrlTemplate("")) .When(x => x.WhenIMatchThePaths()) .And(x => x.ThenTheResultIsTrue()) - .And(x => x.ThenTheTemplatesDictionaryIs(new List())) - .And(x => x.ThenTheUrlPathTemplateIs("")) + .And(x => x.ThenTheTemplatesVariablesAre(new List())) + .And(x => x.ThenTheDownstreamUrlTemplateIs("")) .BDDfy(); } @@ -35,23 +35,23 @@ namespace Ocelot.UnitTests public void can_match_down_stream_url_with_no_slash() { this.Given(x => x.GivenIHaveADownstreamPath("api")) - .Given(x => x.GivenIHaveAnDownstreamPathTemplate("api")) + .Given(x => x.GivenIHaveAnDownstreamUrlTemplate("api")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsTrue()) - .And(x => x.ThenTheTemplatesDictionaryIs(new List())) - .And(x => x.ThenTheUrlPathTemplateIs("api")) + .And(x => x.ThenTheTemplatesVariablesAre(new List())) + .And(x => x.ThenTheDownstreamUrlTemplateIs("api")) .BDDfy(); } - [Fact] + [Fact] public void can_match_down_stream_url_with_one_slash() { this.Given(x => x.GivenIHaveADownstreamPath("api/")) - .Given(x => x.GivenIHaveAnDownstreamPathTemplate("api/")) + .Given(x => x.GivenIHaveAnDownstreamUrlTemplate("api/")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsTrue()) - .And(x => x.ThenTheTemplatesDictionaryIs(new List())) - .And(x => x.ThenTheUrlPathTemplateIs("api/")) + .And(x => x.ThenTheTemplatesVariablesAre(new List())) + .And(x => x.ThenTheDownstreamUrlTemplateIs("api/")) .BDDfy(); } @@ -59,11 +59,11 @@ namespace Ocelot.UnitTests public void can_match_down_stream_url_with_downstream_template() { this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/")) - .Given(x => x.GivenIHaveAnDownstreamPathTemplate("api/product/products/")) + .Given(x => x.GivenIHaveAnDownstreamUrlTemplate("api/product/products/")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsTrue()) - .And(x => x.ThenTheTemplatesDictionaryIs(new List())) - .And(x => x.ThenTheUrlPathTemplateIs("api/product/products/")) + .And(x => x.ThenTheTemplatesVariablesAre(new List())) + .And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/")) .BDDfy(); } @@ -71,11 +71,11 @@ namespace Ocelot.UnitTests public void can_match_down_stream_url_with_downstream_template_with_one_query_string_parameter() { this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/?soldout=false")) - .Given(x => x.GivenIHaveAnDownstreamPathTemplate("api/product/products/")) + .Given(x => x.GivenIHaveAnDownstreamUrlTemplate("api/product/products/")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsTrue()) - .And(x => x.ThenTheTemplatesDictionaryIs(new List())) - .And(x => x.ThenTheUrlPathTemplateIs("api/product/products/")) + .And(x => x.ThenTheTemplatesVariablesAre(new List())) + .And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/")) .BDDfy(); } @@ -88,11 +88,11 @@ namespace Ocelot.UnitTests }; this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/1/variants/?soldout=false")) - .Given(x => x.GivenIHaveAnDownstreamPathTemplate("api/product/products/{productId}/variants/")) + .Given(x => x.GivenIHaveAnDownstreamUrlTemplate("api/product/products/{productId}/variants/")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsTrue()) - .And(x => x.ThenTheTemplatesDictionaryIs(expectedTemplates)) - .And(x => x.ThenTheUrlPathTemplateIs("api/product/products/{productId}/variants/")) + .And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates)) + .And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/{productId}/variants/")) .BDDfy(); } @@ -105,11 +105,11 @@ namespace Ocelot.UnitTests }; this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/1")) - .Given(x => x.GivenIHaveAnDownstreamPathTemplate("api/product/products/{productId}")) + .Given(x => x.GivenIHaveAnDownstreamUrlTemplate("api/product/products/{productId}")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsTrue()) - .And(x => x.ThenTheTemplatesDictionaryIs(expectedTemplates)) - .And(x => x.ThenTheUrlPathTemplateIs("api/product/products/{productId}")) + .And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates)) + .And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/{productId}")) .BDDfy(); } @@ -123,11 +123,11 @@ namespace Ocelot.UnitTests }; this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/1/2")) - .Given(x => x.GivenIHaveAnDownstreamPathTemplate("api/product/products/{productId}/{categoryId}")) + .Given(x => x.GivenIHaveAnDownstreamUrlTemplate("api/product/products/{productId}/{categoryId}")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsTrue()) - .And(x => x.ThenTheTemplatesDictionaryIs(expectedTemplates)) - .And(x => x.ThenTheUrlPathTemplateIs("api/product/products/{productId}/{categoryId}")) + .And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates)) + .And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/{productId}/{categoryId}")) .BDDfy(); } @@ -141,11 +141,11 @@ namespace Ocelot.UnitTests }; this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/1/categories/2")) - .And(x => x.GivenIHaveAnDownstreamPathTemplate("api/product/products/{productId}/categories/{categoryId}")) + .And(x => x.GivenIHaveAnDownstreamUrlTemplate("api/product/products/{productId}/categories/{categoryId}")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsTrue()) - .And(x => x.ThenTheTemplatesDictionaryIs(expectedTemplates)) - .And(x => x.ThenTheUrlPathTemplateIs("api/product/products/{productId}/categories/{categoryId}")) + .And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates)) + .And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/{productId}/categories/{categoryId}")) .BDDfy(); } @@ -160,11 +160,11 @@ namespace Ocelot.UnitTests }; this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/1/categories/2/variant/123")) - .And(x => x.GivenIHaveAnDownstreamPathTemplate("api/product/products/{productId}/categories/{categoryId}/variant/{variantId}")) + .And(x => x.GivenIHaveAnDownstreamUrlTemplate("api/product/products/{productId}/categories/{categoryId}/variant/{variantId}")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsTrue()) - .And(x => x.ThenTheTemplatesDictionaryIs(expectedTemplates)) - .And(x => x.ThenTheUrlPathTemplateIs("api/product/products/{productId}/categories/{categoryId}/variant/{variantId}")) + .And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates)) + .And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/{productId}/categories/{categoryId}/variant/{variantId}")) .BDDfy(); } @@ -178,15 +178,15 @@ namespace Ocelot.UnitTests }; this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/1/categories/2/variant/")) - .And(x => x.GivenIHaveAnDownstreamPathTemplate("api/product/products/{productId}/categories/{categoryId}/variant/")) + .And(x => x.GivenIHaveAnDownstreamUrlTemplate("api/product/products/{productId}/categories/{categoryId}/variant/")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsTrue()) - .And(x => x.ThenTheTemplatesDictionaryIs(expectedTemplates)) - .And(x => x.ThenTheUrlPathTemplateIs("api/product/products/{productId}/categories/{categoryId}/variant/")) + .And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates)) + .And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/{productId}/categories/{categoryId}/variant/")) .BDDfy(); } - private void ThenTheTemplatesDictionaryIs(List expectedResults) + private void ThenTheTemplatesVariablesAre(List expectedResults) { foreach (var expectedResult in expectedResults) { @@ -196,23 +196,23 @@ namespace Ocelot.UnitTests } } - private void ThenTheUrlPathTemplateIs(string expectedUrlPathTemplate) + private void ThenTheDownstreamUrlTemplateIs(string expectedDownstreamUrlTemplate) { - _result.DownstreamUrlPathTemplate.ShouldBe(expectedUrlPathTemplate); + _result.DownstreamUrlTemplate.ShouldBe(expectedDownstreamUrlTemplate); } private void GivenIHaveADownstreamPath(string downstreamPath) { - _downstreamPath = downstreamPath; + _downstreamUrlPath = downstreamPath; } - private void GivenIHaveAnDownstreamPathTemplate(string downstreamTemplate) + private void GivenIHaveAnDownstreamUrlTemplate(string downstreamUrlTemplate) { - _downstreamPathTemplate = downstreamTemplate; + _downstreamPathTemplate = downstreamUrlTemplate; } private void WhenIMatchThePaths() { - _result = _urlMapper.Match(_downstreamPath, _downstreamPathTemplate); + _result = _urlMatcher.Match(_downstreamUrlPath, _downstreamPathTemplate); } private void ThenTheResultIsTrue() From e7a41fbc4d7daf70aff2f22f1f2d81ea6d7e31b6 Mon Sep 17 00:00:00 2001 From: Tom Pallister Date: Wed, 31 Aug 2016 20:46:46 +0100 Subject: [PATCH 023/183] hacking yaml config --- .../Configuration/Configuration.cs | 18 +++ .../Configuration/ConfigurationReader.cs | 22 ++++ .../Configuration/IConfigurationReader.cs | 7 + .../Infrastructure/Configuration/Route.cs | 18 +++ .../YamlConfigurationExtensions.cs | 42 ++++++ .../YamlConfigurationFileParser.cs | 121 ++++++++++++++++++ .../YamlConfigurationProvider.cs | 22 ++++ .../Configuration/YamlConfigurationSource.cs | 13 ++ .../Middleware/ProxyMiddleware.cs | 8 +- src/Ocelot.Library/project.json | 33 ++--- src/Ocelot/Startup.cs | 6 + .../ConfigurationReaderTests.cs | 54 ++++++++ test/Ocelot.AcceptanceTests/OcelotTests.cs | 2 +- .../Ocelot.AcceptanceTests/configuration.yaml | 3 + test/Ocelot.AcceptanceTests/project.json | 79 +++++++----- test/Ocelot.UnitTests/project.json | 43 ++++--- 16 files changed, 417 insertions(+), 74 deletions(-) create mode 100644 src/Ocelot.Library/Infrastructure/Configuration/Configuration.cs create mode 100644 src/Ocelot.Library/Infrastructure/Configuration/ConfigurationReader.cs create mode 100644 src/Ocelot.Library/Infrastructure/Configuration/IConfigurationReader.cs create mode 100644 src/Ocelot.Library/Infrastructure/Configuration/Route.cs create mode 100644 src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationExtensions.cs create mode 100644 src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationFileParser.cs create mode 100644 src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationProvider.cs create mode 100644 src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationSource.cs create mode 100644 test/Ocelot.AcceptanceTests/ConfigurationReaderTests.cs create mode 100644 test/Ocelot.AcceptanceTests/configuration.yaml diff --git a/src/Ocelot.Library/Infrastructure/Configuration/Configuration.cs b/src/Ocelot.Library/Infrastructure/Configuration/Configuration.cs new file mode 100644 index 00000000..f70712ed --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Configuration/Configuration.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; + +namespace Ocelot.Library.Infrastructure.Configuration +{ + public class Configuration + { + public Configuration() + { + Routes = new List(); + } + public Configuration(List routes) + { + Routes = routes; + } + + public List Routes { get; private set; } + } +} diff --git a/src/Ocelot.Library/Infrastructure/Configuration/ConfigurationReader.cs b/src/Ocelot.Library/Infrastructure/Configuration/ConfigurationReader.cs new file mode 100644 index 00000000..139cff46 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Configuration/ConfigurationReader.cs @@ -0,0 +1,22 @@ +namespace Ocelot.Library.Infrastructure.Configuration +{ + using System.IO; + using YamlDotNet.Serialization; + using YamlDotNet.Serialization.NamingConventions; + + public class ConfigurationReader : IConfigurationReader + { + public Configuration Read(string configurationFilePath) + { + var contents = File.ReadAllText(configurationFilePath); + + var input = new StringReader(contents); + + var deserializer = new Deserializer(namingConvention: new CamelCaseNamingConvention()); + + var configuration = deserializer.Deserialize(input); + + return configuration;; + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Configuration/IConfigurationReader.cs b/src/Ocelot.Library/Infrastructure/Configuration/IConfigurationReader.cs new file mode 100644 index 00000000..d53b0526 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Configuration/IConfigurationReader.cs @@ -0,0 +1,7 @@ +namespace Ocelot.Library.Infrastructure.Configuration +{ + public interface IConfigurationReader + { + Configuration Read(string configurationFilePath); + } +} diff --git a/src/Ocelot.Library/Infrastructure/Configuration/Route.cs b/src/Ocelot.Library/Infrastructure/Configuration/Route.cs new file mode 100644 index 00000000..aa551658 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Configuration/Route.cs @@ -0,0 +1,18 @@ +namespace Ocelot.Library.Infrastructure.Configuration +{ + public class Route + { + public Route() + { + + } + public Route(string downstream, string upstream) + { + Downstream = downstream; + Upstream = upstream; + } + + public string Downstream { get; private set; } + public string Upstream { get; private set; } + } +} diff --git a/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationExtensions.cs b/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationExtensions.cs new file mode 100644 index 00000000..802016c8 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationExtensions.cs @@ -0,0 +1,42 @@ +using System.IO; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.FileProviders; + +namespace Ocelot.Library.Infrastructure.Configuration +{ + public static class YamlConfigurationExtensions + { + public static IConfigurationBuilder AddYamlFile(this IConfigurationBuilder builder, string path) + { + return AddYamlFile(builder, provider: null, path: path, optional: false, reloadOnChange: false); + } + + public static IConfigurationBuilder AddYamlFile(this IConfigurationBuilder builder, string path, bool optional) + { + return AddYamlFile(builder, provider: null, path: path, optional: optional, reloadOnChange: false); + } + + public static IConfigurationBuilder AddYamlFile(this IConfigurationBuilder builder, string path, bool optional, bool reloadOnChange) + { + return AddYamlFile(builder, provider: null, path: path, optional: optional, reloadOnChange: reloadOnChange); + } + + public static IConfigurationBuilder AddYamlFile(this IConfigurationBuilder builder, IFileProvider provider, string path, bool optional, bool reloadOnChange) + { + if (provider == null && Path.IsPathRooted(path)) + { + provider = new PhysicalFileProvider(Path.GetDirectoryName(path)); + path = Path.GetFileName(path); + } + var source = new YamlConfigurationSource + { + FileProvider = provider, + Path = path, + Optional = optional, + ReloadOnChange = reloadOnChange + }; + builder.Add(source); + return builder; + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationFileParser.cs b/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationFileParser.cs new file mode 100644 index 00000000..5e6d7c34 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationFileParser.cs @@ -0,0 +1,121 @@ +namespace Ocelot.Library.Infrastructure.Configuration +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Linq; + using Microsoft.Extensions.Configuration; + using YamlDotNet.RepresentationModel; + + internal class YamlConfigurationFileParser + { + private readonly IDictionary _data = new SortedDictionary(StringComparer.OrdinalIgnoreCase); + private readonly Stack _context = new Stack(); + private string _currentPath; + + public IDictionary Parse(Stream input) + { + _data.Clear(); + _context.Clear(); + + // https://dotnetfiddle.net/rrR2Bb + var yaml = new YamlStream(); + yaml.Load(new StreamReader(input)); + + if (yaml.Documents.Any()) + { + var mapping = (YamlMappingNode)yaml.Documents[0].RootNode; + + // The document node is a mapping node + VisitYamlMappingNode(mapping); + } + + return _data; + } + + private void VisitYamlNodePair(KeyValuePair yamlNodePair) + { + var context = ((YamlScalarNode)yamlNodePair.Key).Value; + VisitYamlNode(context, yamlNodePair.Value); + } + + private void VisitYamlNode(string context, YamlNode node) + { + if (node is YamlScalarNode) + { + VisitYamlScalarNode(context, (YamlScalarNode)node); + } + if (node is YamlMappingNode) + { + VisitYamlMappingNode(context, (YamlMappingNode)node); + } + if (node is YamlSequenceNode) + { + VisitYamlSequenceNode(context, (YamlSequenceNode)node); + } + } + + private void VisitYamlScalarNode(string context, YamlScalarNode yamlValue) + { + //a node with a single 1-1 mapping + EnterContext(context); + var currentKey = _currentPath; + + if (_data.ContainsKey(currentKey)) + { + throw new FormatException("Key is duplicate ${currentKey}"); + } + + _data[currentKey] = yamlValue.Value; + ExitContext(); + } + + private void VisitYamlMappingNode(YamlMappingNode node) + { + foreach (var yamlNodePair in node.Children) + { + VisitYamlNodePair(yamlNodePair); + } + } + + private void VisitYamlMappingNode(string context, YamlMappingNode yamlValue) + { + //a node with an associated sub-document + EnterContext(context); + + VisitYamlMappingNode(yamlValue); + + ExitContext(); + } + + private void VisitYamlSequenceNode(string context, YamlSequenceNode yamlValue) + { + //a node with an associated list + EnterContext(context); + + VisitYamlSequenceNode(yamlValue); + + ExitContext(); + } + + private void VisitYamlSequenceNode(YamlSequenceNode node) + { + for (int i = 0; i < node.Children.Count; i++) + { + VisitYamlNode(i.ToString(), node.Children[i]); + } + } + + private void EnterContext(string context) + { + _context.Push(context); + _currentPath = ConfigurationPath.Combine(_context.Reverse()); + } + + private void ExitContext() + { + _context.Pop(); + _currentPath = ConfigurationPath.Combine(_context.Reverse()); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationProvider.cs b/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationProvider.cs new file mode 100644 index 00000000..fc81e102 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationProvider.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Ocelot.Library.Infrastructure.Configuration +{ + using System.IO; + using Microsoft.Extensions.Configuration; + + public class YamlConfigurationProvider : FileConfigurationProvider + { + public YamlConfigurationProvider(YamlConfigurationSource source) : base(source) { } + + public override void Load(Stream stream) + { + var parser = new YamlConfigurationFileParser(); + + Data = parser.Parse(stream); + } + } +} diff --git a/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationSource.cs b/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationSource.cs new file mode 100644 index 00000000..d1684517 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationSource.cs @@ -0,0 +1,13 @@ +namespace Ocelot.Library.Infrastructure.Configuration +{ + using Microsoft.Extensions.Configuration; + + public class YamlConfigurationSource : FileConfigurationSource + { + public override IConfigurationProvider Build(IConfigurationBuilder builder) + { + FileProvider = FileProvider ?? builder.GetFileProvider(); + return new YamlConfigurationProvider(this); + } + } +} diff --git a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs index 077bfae9..0acf6c25 100644 --- a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs +++ b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs @@ -7,6 +7,8 @@ using Ocelot.Library.Infrastructure.UrlTemplateReplacer; namespace Ocelot.Library.Middleware { using System.Net; + using Infrastructure.Configuration; + using Microsoft.Extensions.Options; public class ProxyMiddleware { @@ -14,19 +16,23 @@ namespace Ocelot.Library.Middleware private readonly IUrlPathToUrlTemplateMatcher _urlMatcher; private readonly IUrlTemplateMapRepository _urlTemplateMapRepository; private readonly IDownstreamUrlTemplateVariableReplacer _urlReplacer; + private readonly IOptions _optionsAccessor; + public ProxyMiddleware(RequestDelegate next, IUrlPathToUrlTemplateMatcher urlMatcher, IUrlTemplateMapRepository urlPathRepository, - IDownstreamUrlTemplateVariableReplacer urlReplacer) + IDownstreamUrlTemplateVariableReplacer urlReplacer, IOptions optionsAccessor) { _next = next; _urlMatcher = urlMatcher; _urlTemplateMapRepository = urlPathRepository; _urlReplacer = urlReplacer; + _optionsAccessor = optionsAccessor; } public async Task Invoke(HttpContext context) { + var downstreamUrlPath = context.Request.Path.ToString(); var upstreamUrlTemplates = _urlTemplateMapRepository.All; diff --git a/src/Ocelot.Library/project.json b/src/Ocelot.Library/project.json index ca884c95..7037f0a7 100644 --- a/src/Ocelot.Library/project.json +++ b/src/Ocelot.Library/project.json @@ -1,23 +1,24 @@ { "version": "1.0.0-*", - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.0.0", - "type": "platform" - }, - "Microsoft.AspNetCore.Mvc": "1.0.0", - "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", - "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", - "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", - "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0", - "Microsoft.Extensions.Configuration.Json": "1.0.0", - "Microsoft.Extensions.Logging": "1.0.0", - "Microsoft.Extensions.Logging.Console": "1.0.0", - "Microsoft.Extensions.Logging.Debug": "1.0.0", - "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", - "Microsoft.AspNetCore.Http": "1.0.0" + "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.0.0", + "type": "platform" }, + "Microsoft.AspNetCore.Mvc": "1.0.0", + "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", + "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", + "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0", + "Microsoft.Extensions.Configuration.Json": "1.0.0", + "Microsoft.Extensions.Logging": "1.0.0", + "Microsoft.Extensions.Logging.Console": "1.0.0", + "Microsoft.Extensions.Logging.Debug": "1.0.0", + "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", + "Microsoft.AspNetCore.Http": "1.0.0", + "YamlDotNet": "3.9.0" + }, "frameworks": { "netcoreapp1.0": { diff --git a/src/Ocelot/Startup.cs b/src/Ocelot/Startup.cs index c585c1a5..779a0e74 100644 --- a/src/Ocelot/Startup.cs +++ b/src/Ocelot/Startup.cs @@ -8,6 +8,7 @@ using Ocelot.Library.Middleware; namespace Ocelot { + using Library.Infrastructure.Configuration; using Library.Infrastructure.UrlMatcher; using Library.Infrastructure.UrlTemplateReplacer; using Library.Infrastructure.UrlTemplateRepository; @@ -20,6 +21,7 @@ namespace Ocelot .SetBasePath(env.ContentRootPath) .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) + .AddYamlFile("configuration.yaml") .AddEnvironmentVariables(); Configuration = builder.Build(); } @@ -29,6 +31,10 @@ namespace Ocelot // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { + services.AddOptions(); + + services.Configure(Configuration); + // Add framework services. services.AddSingleton(); services.AddSingleton(); diff --git a/test/Ocelot.AcceptanceTests/ConfigurationReaderTests.cs b/test/Ocelot.AcceptanceTests/ConfigurationReaderTests.cs new file mode 100644 index 00000000..14878829 --- /dev/null +++ b/test/Ocelot.AcceptanceTests/ConfigurationReaderTests.cs @@ -0,0 +1,54 @@ +namespace Ocelot.AcceptanceTests +{ + using System.Collections.Generic; + using Library.Infrastructure.Configuration; + using Shouldly; + using TestStack.BDDfy; + using Xunit; + + public class ConfigurationReaderTests + { + private readonly IConfigurationReader _configurationReader; + private string _configPath; + private Configuration _result; + + public ConfigurationReaderTests() + { + _configurationReader = new ConfigurationReader(); + } + + [Fact] + public void can_read_configuration() + { + const string path = "./ConfigurationReaderTests.can_read_configuration.yaml"; + + var expected = + new Configuration(new List + { + new Route("productservice/category/{categoryId}/products/{productId}/variants/{variantId}", + "https://www.moonpig.com/api/products/{categoryId}/{productId}/{variantId}") + }); + + this.Given(x => x.GivenAConfigPathOf(path)) + .When(x => x.WhenICallTheConfigurationReader()) + .Then(x => x.ThenTheFollowingConfigurationIsReturned(expected)) + .BDDfy(); + } + + private void GivenAConfigPathOf(string configPath) + { + _configPath = configPath; + } + + private void WhenICallTheConfigurationReader() + { + _result = _configurationReader.Read(_configPath); + } + + private void ThenTheFollowingConfigurationIsReturned(Configuration expected) + { + _result.Routes[0].Downstream.ShouldBe(expected.Routes[0].Downstream); + _result.Routes[0].Upstream.ShouldBe(expected.Routes[0].Upstream); + } + } +} diff --git a/test/Ocelot.AcceptanceTests/OcelotTests.cs b/test/Ocelot.AcceptanceTests/OcelotTests.cs index 6f767a64..08a2734c 100644 --- a/test/Ocelot.AcceptanceTests/OcelotTests.cs +++ b/test/Ocelot.AcceptanceTests/OcelotTests.cs @@ -36,7 +36,7 @@ namespace Ocelot.AcceptanceTests .BDDfy(); } - [Fact] + [Fact] public void should_return_response_200() { this.When(x => x.WhenIRequestTheUrl("/")) diff --git a/test/Ocelot.AcceptanceTests/configuration.yaml b/test/Ocelot.AcceptanceTests/configuration.yaml new file mode 100644 index 00000000..98c05a41 --- /dev/null +++ b/test/Ocelot.AcceptanceTests/configuration.yaml @@ -0,0 +1,3 @@ +routes: + - downstream: "productservice/category/{categoryId}/products/{productId}/variants/{variantId}" + upstream: "https://www.moonpig.com/api/products/{categoryId}/{productId}/{variantId}" diff --git a/test/Ocelot.AcceptanceTests/project.json b/test/Ocelot.AcceptanceTests/project.json index c350a62b..c672997c 100644 --- a/test/Ocelot.AcceptanceTests/project.json +++ b/test/Ocelot.AcceptanceTests/project.json @@ -1,39 +1,48 @@ { - "version": "1.0.0-*", + "version": "1.0.0-*", - "testRunner": "xunit", - - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.0.0", - "type": "platform" - }, - "Microsoft.AspNetCore.Mvc": "1.0.0", - "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", - "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", - "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", - "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0", - "Microsoft.Extensions.Configuration.Json": "1.0.0", - "Microsoft.Extensions.Logging": "1.0.0", - "Microsoft.Extensions.Logging.Console": "1.0.0", - "Microsoft.Extensions.Logging.Debug": "1.0.0", - "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", - "Microsoft.AspNetCore.Http": "1.0.0", - "Ocelot.Library": "1.0.0-*", - "xunit": "2.1.0", - "dotnet-test-xunit": "2.2.0-preview2-build1029", - "Shouldly": "2.8.0", - "Ocelot": "1.0.0-*", - "Microsoft.AspNetCore.TestHost": "1.0.0", - "TestStack.BDDfy": "4.3.1" - }, - - "frameworks": { - "netcoreapp1.0": { - "imports": [ - "dotnet5.6", - "portable-net45+win8" - ] - } + "buildOptions": { + "copyToOutput": { + "include": [ + "configuration.yaml" + ] } + }, + + "testRunner": "xunit", + + "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.0.0", + "type": "platform" + }, + "Microsoft.AspNetCore.Mvc": "1.0.0", + "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", + "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", + "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0", + "Microsoft.Extensions.Configuration.Json": "1.0.0", + "Microsoft.Extensions.Logging": "1.0.0", + "Microsoft.Extensions.Logging.Console": "1.0.0", + "Microsoft.Extensions.Logging.Debug": "1.0.0", + "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", + "Microsoft.AspNetCore.Http": "1.0.0", + "Ocelot.Library": "1.0.0-*", + "xunit": "2.1.0", + "dotnet-test-xunit": "2.2.0-preview2-build1029", + "Shouldly": "2.8.0", + "Ocelot": "1.0.0-*", + "Microsoft.AspNetCore.TestHost": "1.0.0", + "TestStack.BDDfy": "4.3.1", + "YamlDotNet": "3.9.0" + }, + + "frameworks": { + "netcoreapp1.0": { + "imports": [ + "dotnet5.6", + "portable-net45+win8" + ] + } + } } diff --git a/test/Ocelot.UnitTests/project.json b/test/Ocelot.UnitTests/project.json index f415f589..f8c0cf9d 100644 --- a/test/Ocelot.UnitTests/project.json +++ b/test/Ocelot.UnitTests/project.json @@ -3,28 +3,29 @@ "testRunner": "xunit", - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.0.0", - "type": "platform" - }, - "Microsoft.AspNetCore.Mvc": "1.0.0", - "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", - "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", - "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", - "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0", - "Microsoft.Extensions.Configuration.Json": "1.0.0", - "Microsoft.Extensions.Logging": "1.0.0", - "Microsoft.Extensions.Logging.Console": "1.0.0", - "Microsoft.Extensions.Logging.Debug": "1.0.0", - "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", - "Microsoft.AspNetCore.Http": "1.0.0", - "Ocelot.Library": "1.0.0-*", - "xunit": "2.1.0", - "dotnet-test-xunit": "2.2.0-preview2-build1029", - "Shouldly": "2.8.0", - "TestStack.BDDfy": "4.3.1" + "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.0.0", + "type": "platform" }, + "Microsoft.AspNetCore.Mvc": "1.0.0", + "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", + "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", + "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0", + "Microsoft.Extensions.Configuration.Json": "1.0.0", + "Microsoft.Extensions.Logging": "1.0.0", + "Microsoft.Extensions.Logging.Console": "1.0.0", + "Microsoft.Extensions.Logging.Debug": "1.0.0", + "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", + "Microsoft.AspNetCore.Http": "1.0.0", + "Ocelot.Library": "1.0.0-*", + "xunit": "2.1.0", + "dotnet-test-xunit": "2.2.0-preview2-build1029", + "Shouldly": "2.8.0", + "TestStack.BDDfy": "4.3.1", + "YamlDotNet": "3.9.0" + }, "frameworks": { "netcoreapp1.0": { From 15d7cafa1c820cf7c394997e93d3caf0f7a68d7a Mon Sep 17 00:00:00 2001 From: Tom Pallister Date: Thu, 1 Sep 2016 09:05:04 +0100 Subject: [PATCH 024/183] Brought in YAML lib for configuration and added failing acceptance test --- .../Configuration/Configuration.cs | 6 +- .../Configuration/ConfigurationReader.cs | 22 ---- .../Configuration/IConfigurationReader.cs | 7 - .../Infrastructure/Configuration/Route.cs | 14 +- .../YamlConfigurationExtensions.cs | 42 ------ .../YamlConfigurationFileParser.cs | 121 ------------------ .../YamlConfigurationProvider.cs | 22 ---- .../Configuration/YamlConfigurationSource.cs | 13 -- src/Ocelot/Startup.cs | 1 - src/Ocelot/project.json | 3 +- .../ConfigurationReaderTests.cs | 54 -------- test/Ocelot.AcceptanceTests/OcelotTests.cs | 79 +++++++++--- .../Ocelot.AcceptanceTests/configuration.yaml | 6 +- 13 files changed, 69 insertions(+), 321 deletions(-) delete mode 100644 src/Ocelot.Library/Infrastructure/Configuration/ConfigurationReader.cs delete mode 100644 src/Ocelot.Library/Infrastructure/Configuration/IConfigurationReader.cs delete mode 100644 src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationExtensions.cs delete mode 100644 src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationFileParser.cs delete mode 100644 src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationProvider.cs delete mode 100644 src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationSource.cs delete mode 100644 test/Ocelot.AcceptanceTests/ConfigurationReaderTests.cs diff --git a/src/Ocelot.Library/Infrastructure/Configuration/Configuration.cs b/src/Ocelot.Library/Infrastructure/Configuration/Configuration.cs index f70712ed..1a118086 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/Configuration.cs +++ b/src/Ocelot.Library/Infrastructure/Configuration/Configuration.cs @@ -8,11 +8,7 @@ namespace Ocelot.Library.Infrastructure.Configuration { Routes = new List(); } - public Configuration(List routes) - { - Routes = routes; - } - public List Routes { get; private set; } + public List Routes { get; set; } } } diff --git a/src/Ocelot.Library/Infrastructure/Configuration/ConfigurationReader.cs b/src/Ocelot.Library/Infrastructure/Configuration/ConfigurationReader.cs deleted file mode 100644 index 139cff46..00000000 --- a/src/Ocelot.Library/Infrastructure/Configuration/ConfigurationReader.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace Ocelot.Library.Infrastructure.Configuration -{ - using System.IO; - using YamlDotNet.Serialization; - using YamlDotNet.Serialization.NamingConventions; - - public class ConfigurationReader : IConfigurationReader - { - public Configuration Read(string configurationFilePath) - { - var contents = File.ReadAllText(configurationFilePath); - - var input = new StringReader(contents); - - var deserializer = new Deserializer(namingConvention: new CamelCaseNamingConvention()); - - var configuration = deserializer.Deserialize(input); - - return configuration;; - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Configuration/IConfigurationReader.cs b/src/Ocelot.Library/Infrastructure/Configuration/IConfigurationReader.cs deleted file mode 100644 index d53b0526..00000000 --- a/src/Ocelot.Library/Infrastructure/Configuration/IConfigurationReader.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Ocelot.Library.Infrastructure.Configuration -{ - public interface IConfigurationReader - { - Configuration Read(string configurationFilePath); - } -} diff --git a/src/Ocelot.Library/Infrastructure/Configuration/Route.cs b/src/Ocelot.Library/Infrastructure/Configuration/Route.cs index aa551658..a30d3bbf 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/Route.cs +++ b/src/Ocelot.Library/Infrastructure/Configuration/Route.cs @@ -2,17 +2,7 @@ { public class Route { - public Route() - { - - } - public Route(string downstream, string upstream) - { - Downstream = downstream; - Upstream = upstream; - } - - public string Downstream { get; private set; } - public string Upstream { get; private set; } + public string Downstream { get; set; } + public string Upstream { get; set; } } } diff --git a/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationExtensions.cs b/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationExtensions.cs deleted file mode 100644 index 802016c8..00000000 --- a/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationExtensions.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System.IO; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.FileProviders; - -namespace Ocelot.Library.Infrastructure.Configuration -{ - public static class YamlConfigurationExtensions - { - public static IConfigurationBuilder AddYamlFile(this IConfigurationBuilder builder, string path) - { - return AddYamlFile(builder, provider: null, path: path, optional: false, reloadOnChange: false); - } - - public static IConfigurationBuilder AddYamlFile(this IConfigurationBuilder builder, string path, bool optional) - { - return AddYamlFile(builder, provider: null, path: path, optional: optional, reloadOnChange: false); - } - - public static IConfigurationBuilder AddYamlFile(this IConfigurationBuilder builder, string path, bool optional, bool reloadOnChange) - { - return AddYamlFile(builder, provider: null, path: path, optional: optional, reloadOnChange: reloadOnChange); - } - - public static IConfigurationBuilder AddYamlFile(this IConfigurationBuilder builder, IFileProvider provider, string path, bool optional, bool reloadOnChange) - { - if (provider == null && Path.IsPathRooted(path)) - { - provider = new PhysicalFileProvider(Path.GetDirectoryName(path)); - path = Path.GetFileName(path); - } - var source = new YamlConfigurationSource - { - FileProvider = provider, - Path = path, - Optional = optional, - ReloadOnChange = reloadOnChange - }; - builder.Add(source); - return builder; - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationFileParser.cs b/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationFileParser.cs deleted file mode 100644 index 5e6d7c34..00000000 --- a/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationFileParser.cs +++ /dev/null @@ -1,121 +0,0 @@ -namespace Ocelot.Library.Infrastructure.Configuration -{ - using System; - using System.Collections.Generic; - using System.IO; - using System.Linq; - using Microsoft.Extensions.Configuration; - using YamlDotNet.RepresentationModel; - - internal class YamlConfigurationFileParser - { - private readonly IDictionary _data = new SortedDictionary(StringComparer.OrdinalIgnoreCase); - private readonly Stack _context = new Stack(); - private string _currentPath; - - public IDictionary Parse(Stream input) - { - _data.Clear(); - _context.Clear(); - - // https://dotnetfiddle.net/rrR2Bb - var yaml = new YamlStream(); - yaml.Load(new StreamReader(input)); - - if (yaml.Documents.Any()) - { - var mapping = (YamlMappingNode)yaml.Documents[0].RootNode; - - // The document node is a mapping node - VisitYamlMappingNode(mapping); - } - - return _data; - } - - private void VisitYamlNodePair(KeyValuePair yamlNodePair) - { - var context = ((YamlScalarNode)yamlNodePair.Key).Value; - VisitYamlNode(context, yamlNodePair.Value); - } - - private void VisitYamlNode(string context, YamlNode node) - { - if (node is YamlScalarNode) - { - VisitYamlScalarNode(context, (YamlScalarNode)node); - } - if (node is YamlMappingNode) - { - VisitYamlMappingNode(context, (YamlMappingNode)node); - } - if (node is YamlSequenceNode) - { - VisitYamlSequenceNode(context, (YamlSequenceNode)node); - } - } - - private void VisitYamlScalarNode(string context, YamlScalarNode yamlValue) - { - //a node with a single 1-1 mapping - EnterContext(context); - var currentKey = _currentPath; - - if (_data.ContainsKey(currentKey)) - { - throw new FormatException("Key is duplicate ${currentKey}"); - } - - _data[currentKey] = yamlValue.Value; - ExitContext(); - } - - private void VisitYamlMappingNode(YamlMappingNode node) - { - foreach (var yamlNodePair in node.Children) - { - VisitYamlNodePair(yamlNodePair); - } - } - - private void VisitYamlMappingNode(string context, YamlMappingNode yamlValue) - { - //a node with an associated sub-document - EnterContext(context); - - VisitYamlMappingNode(yamlValue); - - ExitContext(); - } - - private void VisitYamlSequenceNode(string context, YamlSequenceNode yamlValue) - { - //a node with an associated list - EnterContext(context); - - VisitYamlSequenceNode(yamlValue); - - ExitContext(); - } - - private void VisitYamlSequenceNode(YamlSequenceNode node) - { - for (int i = 0; i < node.Children.Count; i++) - { - VisitYamlNode(i.ToString(), node.Children[i]); - } - } - - private void EnterContext(string context) - { - _context.Push(context); - _currentPath = ConfigurationPath.Combine(_context.Reverse()); - } - - private void ExitContext() - { - _context.Pop(); - _currentPath = ConfigurationPath.Combine(_context.Reverse()); - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationProvider.cs b/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationProvider.cs deleted file mode 100644 index fc81e102..00000000 --- a/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationProvider.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Ocelot.Library.Infrastructure.Configuration -{ - using System.IO; - using Microsoft.Extensions.Configuration; - - public class YamlConfigurationProvider : FileConfigurationProvider - { - public YamlConfigurationProvider(YamlConfigurationSource source) : base(source) { } - - public override void Load(Stream stream) - { - var parser = new YamlConfigurationFileParser(); - - Data = parser.Parse(stream); - } - } -} diff --git a/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationSource.cs b/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationSource.cs deleted file mode 100644 index d1684517..00000000 --- a/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationSource.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Ocelot.Library.Infrastructure.Configuration -{ - using Microsoft.Extensions.Configuration; - - public class YamlConfigurationSource : FileConfigurationSource - { - public override IConfigurationProvider Build(IConfigurationBuilder builder) - { - FileProvider = FileProvider ?? builder.GetFileProvider(); - return new YamlConfigurationProvider(this); - } - } -} diff --git a/src/Ocelot/Startup.cs b/src/Ocelot/Startup.cs index 779a0e74..93346a40 100644 --- a/src/Ocelot/Startup.cs +++ b/src/Ocelot/Startup.cs @@ -1,6 +1,5 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; diff --git a/src/Ocelot/project.json b/src/Ocelot/project.json index ba309f23..d77d3493 100644 --- a/src/Ocelot/project.json +++ b/src/Ocelot/project.json @@ -15,7 +15,8 @@ "Microsoft.Extensions.Logging.Console": "1.0.0", "Microsoft.Extensions.Logging.Debug": "1.0.0", "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", - "Ocelot.Library": "1.0.0-*" + "Ocelot.Library": "1.0.0-*", + "NetEscapades.Configuration.Yaml": "1.1.0" }, "tools": { diff --git a/test/Ocelot.AcceptanceTests/ConfigurationReaderTests.cs b/test/Ocelot.AcceptanceTests/ConfigurationReaderTests.cs deleted file mode 100644 index 14878829..00000000 --- a/test/Ocelot.AcceptanceTests/ConfigurationReaderTests.cs +++ /dev/null @@ -1,54 +0,0 @@ -namespace Ocelot.AcceptanceTests -{ - using System.Collections.Generic; - using Library.Infrastructure.Configuration; - using Shouldly; - using TestStack.BDDfy; - using Xunit; - - public class ConfigurationReaderTests - { - private readonly IConfigurationReader _configurationReader; - private string _configPath; - private Configuration _result; - - public ConfigurationReaderTests() - { - _configurationReader = new ConfigurationReader(); - } - - [Fact] - public void can_read_configuration() - { - const string path = "./ConfigurationReaderTests.can_read_configuration.yaml"; - - var expected = - new Configuration(new List - { - new Route("productservice/category/{categoryId}/products/{productId}/variants/{variantId}", - "https://www.moonpig.com/api/products/{categoryId}/{productId}/{variantId}") - }); - - this.Given(x => x.GivenAConfigPathOf(path)) - .When(x => x.WhenICallTheConfigurationReader()) - .Then(x => x.ThenTheFollowingConfigurationIsReturned(expected)) - .BDDfy(); - } - - private void GivenAConfigPathOf(string configPath) - { - _configPath = configPath; - } - - private void WhenICallTheConfigurationReader() - { - _result = _configurationReader.Read(_configPath); - } - - private void ThenTheFollowingConfigurationIsReturned(Configuration expected) - { - _result.Routes[0].Downstream.ShouldBe(expected.Routes[0].Downstream); - _result.Routes[0].Upstream.ShouldBe(expected.Routes[0].Upstream); - } - } -} diff --git a/test/Ocelot.AcceptanceTests/OcelotTests.cs b/test/Ocelot.AcceptanceTests/OcelotTests.cs index 08a2734c..6989ce99 100644 --- a/test/Ocelot.AcceptanceTests/OcelotTests.cs +++ b/test/Ocelot.AcceptanceTests/OcelotTests.cs @@ -1,37 +1,36 @@ -using System; -using System.Net.Http; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.TestHost; -using Xunit; -using Ocelot.AcceptanceTests.Fake; -using Shouldly; - namespace Ocelot.AcceptanceTests { + using System; + using System.Net.Http; + using Microsoft.AspNetCore.Hosting; + using Microsoft.AspNetCore.TestHost; + using Xunit; + using Ocelot.AcceptanceTests.Fake; + using Shouldly; + using System.Collections.Generic; + using System.IO; using System.Net; + using Library.Infrastructure.Configuration; using TestStack.BDDfy; + using YamlDotNet.Serialization; public class OcelotTests : IDisposable { private readonly FakeService _fakeService; - private readonly TestServer _server; - private readonly HttpClient _client; + private TestServer _server; + private HttpClient _client; private HttpResponseMessage _response; public OcelotTests() { - _server = new TestServer(new WebHostBuilder() - .UseStartup()); - - _client = _server.CreateClient(); - _fakeService = new FakeService(); } [Fact] public void should_return_response_404() { - this.When(x => x.WhenIRequestTheUrl("/")) + this.Given(x => x.GivenTheApiGatewayIsRunning()) + .When(x => x.WhenIRequestTheUrlOnTheApiGateway("/")) .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound)) .BDDfy(); } @@ -39,13 +38,57 @@ namespace Ocelot.AcceptanceTests [Fact] public void should_return_response_200() { - this.When(x => x.WhenIRequestTheUrl("/")) + this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879")) + .And(x => x.GivenThereIsAConfiguration(new Configuration + { + Routes = new List + { + new Route + { + Downstream = "http://localhost:51879/", + Upstream = "/heee" + } + } + })) + .And(x => x.GivenTheApiGatewayIsRunning()) + .When(x => x.WhenIRequestTheUrlOnTheApiGateway("/")) .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) .And(x => x.ThenTheResponseBodyShouldBe("Hello from Laura")) .BDDfy(); } - private void WhenIRequestTheUrl(string url) + /// + /// This is annoying cos it should be in the constructor but we need to set up the yaml file before calling startup so its a step. + /// + private void GivenTheApiGatewayIsRunning() + { + _server = new TestServer(new WebHostBuilder() + .UseStartup()); + + _client = _server.CreateClient(); + } + + private void GivenThereIsAConfiguration(Configuration configuration) + { + var serializer = new Serializer(); + + if (File.Exists("./configuration.yaml")) + { + File.Delete("./configuration.yaml"); + } + + using (TextWriter writer = File.CreateText("./configuration.yaml")) + { + serializer.Serialize(writer, configuration); + } + } + + private void GivenThereIsAServiceRunningOn(string url) + { + _fakeService.Start(url); + } + + private void WhenIRequestTheUrlOnTheApiGateway(string url) { _response = _client.GetAsync("/").Result; } diff --git a/test/Ocelot.AcceptanceTests/configuration.yaml b/test/Ocelot.AcceptanceTests/configuration.yaml index 98c05a41..2e47e77d 100644 --- a/test/Ocelot.AcceptanceTests/configuration.yaml +++ b/test/Ocelot.AcceptanceTests/configuration.yaml @@ -1,3 +1,3 @@ -routes: - - downstream: "productservice/category/{categoryId}/products/{productId}/variants/{variantId}" - upstream: "https://www.moonpig.com/api/products/{categoryId}/{productId}/{variantId}" +Routes: +- Downstream: http://localhost:51879/ + Upstream: /heee From 71b7e7743e749d60ad831d075fe2ec7c4efcb871 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Wed, 7 Sep 2016 20:40:56 +0100 Subject: [PATCH 025/183] more simplification is that a word --- .../Configuration/Configuration.cs | 4 +- .../Infrastructure/Configuration/ReRoute.cs | 8 ++ .../Infrastructure/Configuration/Route.cs | 8 -- .../IUrlPathToUrlTemplateMatcher.cs | 2 +- .../UrlMatcher/UrlPathToUrlTemplateMatcher.cs | 18 ++-- .../DownstreamUrlTemplateVariableReplacer.cs | 4 +- ...wnstreamUrlPathTemplateVariableReplacer.cs | 2 +- .../DownstreamUrlAlreadyExists.cs | 12 --- .../DownstreamUrlDoesNotExist.cs | 12 --- .../IUrlTemplateMapRepository.cs | 11 -- .../InMemoryUrlTemplateMapRepository.cs | 39 ------- .../UrlTemplateRepository/UrlTemplateMap.cs | 14 --- .../Middleware/ProxyMiddleware.cs | 26 ++--- src/Ocelot/Startup.cs | 2 - test/Ocelot.AcceptanceTests/OcelotTests.cs | 8 +- .../Ocelot.AcceptanceTests/configuration.yaml | 6 +- ...eamUrlPathTemplateVariableReplacerTests.cs | 41 ++++--- .../UrlPathTemplateMapRepositoryTests.cs | 101 ------------------ 18 files changed, 56 insertions(+), 262 deletions(-) create mode 100644 src/Ocelot.Library/Infrastructure/Configuration/ReRoute.cs delete mode 100644 src/Ocelot.Library/Infrastructure/Configuration/Route.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlTemplateRepository/DownstreamUrlAlreadyExists.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlTemplateRepository/DownstreamUrlDoesNotExist.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlTemplateRepository/IUrlTemplateMapRepository.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlTemplateRepository/InMemoryUrlTemplateMapRepository.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlTemplateRepository/UrlTemplateMap.cs delete mode 100644 test/Ocelot.UnitTests/UrlPathTemplateMapRepositoryTests.cs diff --git a/src/Ocelot.Library/Infrastructure/Configuration/Configuration.cs b/src/Ocelot.Library/Infrastructure/Configuration/Configuration.cs index 1a118086..f1cc9b90 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/Configuration.cs +++ b/src/Ocelot.Library/Infrastructure/Configuration/Configuration.cs @@ -6,9 +6,9 @@ namespace Ocelot.Library.Infrastructure.Configuration { public Configuration() { - Routes = new List(); + ReRoutes = new List(); } - public List Routes { get; set; } + public List ReRoutes { get; set; } } } diff --git a/src/Ocelot.Library/Infrastructure/Configuration/ReRoute.cs b/src/Ocelot.Library/Infrastructure/Configuration/ReRoute.cs new file mode 100644 index 00000000..4c27ec37 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Configuration/ReRoute.cs @@ -0,0 +1,8 @@ +namespace Ocelot.Library.Infrastructure.Configuration +{ + public class ReRoute + { + public string DownstreamTemplate { get; set; } + public string UpstreamTemplate { get; set; } + } +} diff --git a/src/Ocelot.Library/Infrastructure/Configuration/Route.cs b/src/Ocelot.Library/Infrastructure/Configuration/Route.cs deleted file mode 100644 index a30d3bbf..00000000 --- a/src/Ocelot.Library/Infrastructure/Configuration/Route.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ocelot.Library.Infrastructure.Configuration -{ - public class Route - { - public string Downstream { get; set; } - public string Upstream { get; set; } - } -} diff --git a/src/Ocelot.Library/Infrastructure/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs b/src/Ocelot.Library/Infrastructure/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs index 6f96a28c..954e3fee 100644 --- a/src/Ocelot.Library/Infrastructure/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs +++ b/src/Ocelot.Library/Infrastructure/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs @@ -2,6 +2,6 @@ namespace Ocelot.Library.Infrastructure.UrlMatcher { public interface IUrlPathToUrlTemplateMatcher { - UrlMatch Match(string downstreamUrlPath, string downstreamUrlTemplate); + UrlMatch Match(string upstreamUrlPath, string upstreamUrlTemplate); } } \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlMatcher/UrlPathToUrlTemplateMatcher.cs b/src/Ocelot.Library/Infrastructure/UrlMatcher/UrlPathToUrlTemplateMatcher.cs index fc34153e..0c396e32 100644 --- a/src/Ocelot.Library/Infrastructure/UrlMatcher/UrlPathToUrlTemplateMatcher.cs +++ b/src/Ocelot.Library/Infrastructure/UrlMatcher/UrlPathToUrlTemplateMatcher.cs @@ -5,31 +5,31 @@ namespace Ocelot.Library.Infrastructure.UrlMatcher { public class UrlPathToUrlTemplateMatcher : IUrlPathToUrlTemplateMatcher { - public UrlMatch Match(string downstreamUrlPath, string downstreamUrlTemplate) + public UrlMatch Match(string upstreamUrlPath, string upstreamUrlTemplate) { - var urlPathTemplateCopy = downstreamUrlTemplate; + var urlPathTemplateCopy = upstreamUrlTemplate; var templateKeysAndValues = new List(); int counterForUrl = 0; - for (int counterForTemplate = 0; counterForTemplate < downstreamUrlTemplate.Length; counterForTemplate++) + for (int counterForTemplate = 0; counterForTemplate < upstreamUrlTemplate.Length; counterForTemplate++) { - if (CharactersDontMatch(downstreamUrlTemplate[counterForTemplate], downstreamUrlPath[counterForUrl]) && ContinueScanningUrl(counterForUrl,downstreamUrlPath.Length)) + if (CharactersDontMatch(upstreamUrlTemplate[counterForTemplate], upstreamUrlPath[counterForUrl]) && ContinueScanningUrl(counterForUrl,upstreamUrlPath.Length)) { - if (IsPlaceholder(downstreamUrlTemplate[counterForTemplate])) + if (IsPlaceholder(upstreamUrlTemplate[counterForTemplate])) { - var variableName = GetPlaceholderVariableName(downstreamUrlTemplate, counterForTemplate); + var variableName = GetPlaceholderVariableName(upstreamUrlTemplate, counterForTemplate); - var variableValue = GetPlaceholderVariableValue(downstreamUrlPath, counterForUrl); + var variableValue = GetPlaceholderVariableValue(upstreamUrlPath, counterForUrl); var templateVariableNameAndValue = new TemplateVariableNameAndValue(variableName, variableValue); templateKeysAndValues.Add(templateVariableNameAndValue); - counterForTemplate = GetNextCounterPosition(downstreamUrlTemplate, counterForTemplate, '}'); + counterForTemplate = GetNextCounterPosition(upstreamUrlTemplate, counterForTemplate, '}'); - counterForUrl = GetNextCounterPosition(downstreamUrlPath, counterForUrl, '/'); + counterForUrl = GetNextCounterPosition(upstreamUrlPath, counterForUrl, '/'); continue; } diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs index 14e99be9..35dc563c 100644 --- a/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs +++ b/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs @@ -5,11 +5,11 @@ namespace Ocelot.Library.Infrastructure.UrlTemplateReplacer { public class DownstreamUrlTemplateVariableReplacer : IDownstreamUrlTemplateVariableReplacer { - public string ReplaceTemplateVariable(string downstreamPathTemplate, UrlMatch urlMatch) + public string ReplaceTemplateVariable(UrlMatch urlMatch) { var upstreamUrl = new StringBuilder(); - upstreamUrl.Append(downstreamPathTemplate); + upstreamUrl.Append(urlMatch.DownstreamUrlTemplate); foreach (var templateVarAndValue in urlMatch.TemplateVariableNameAndValues) { diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs index 53b532f4..62eac8bc 100644 --- a/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs +++ b/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs @@ -4,6 +4,6 @@ namespace Ocelot.Library.Infrastructure.UrlTemplateReplacer { public interface IDownstreamUrlTemplateVariableReplacer { - string ReplaceTemplateVariable(string downstreamPathTemplate, UrlMatch urlMatch); + string ReplaceTemplateVariable(UrlMatch urlMatch); } } \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/DownstreamUrlAlreadyExists.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/DownstreamUrlAlreadyExists.cs deleted file mode 100644 index cf471ba3..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/DownstreamUrlAlreadyExists.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.UrlTemplateRepository -{ - public class DownstreamUrlTemplateAlreadyExists : Error - { - public DownstreamUrlTemplateAlreadyExists() - : base("This key has already been used") - { - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/DownstreamUrlDoesNotExist.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/DownstreamUrlDoesNotExist.cs deleted file mode 100644 index ba960046..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/DownstreamUrlDoesNotExist.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.UrlTemplateRepository -{ - public class DownstreamUrlTemplateDoesNotExist : Error - { - public DownstreamUrlTemplateDoesNotExist() - : base("This key does not exist") - { - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/IUrlTemplateMapRepository.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/IUrlTemplateMapRepository.cs deleted file mode 100644 index d4be69ae..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/IUrlTemplateMapRepository.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.UrlTemplateRepository -{ - public interface IUrlTemplateMapRepository - { - Response AddUrlTemplateMap(UrlTemplateMap urlPathMap); - Response> All { get; } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/InMemoryUrlTemplateMapRepository.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/InMemoryUrlTemplateMapRepository.cs deleted file mode 100644 index 0129b4d6..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/InMemoryUrlTemplateMapRepository.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.UrlTemplateRepository -{ - public class InMemoryUrlTemplateMapRepository : IUrlTemplateMapRepository - { - private readonly Dictionary _urlTemplates; - public InMemoryUrlTemplateMapRepository() - { - _urlTemplates = new Dictionary(); - } - - public Response> All - { - get - { - var routes = _urlTemplates - .Select(r => new UrlTemplateMap(r.Key, r.Value)) - .ToList(); - return new OkResponse>(routes); - } - } - - public Response AddUrlTemplateMap(UrlTemplateMap urlMap) - { - if(_urlTemplates.ContainsKey(urlMap.DownstreamUrlTemplate)) - { - return new ErrorResponse(new List(){new DownstreamUrlTemplateAlreadyExists()}); - } - - _urlTemplates.Add(urlMap.DownstreamUrlTemplate, urlMap.UpstreamUrlPathTemplate); - - return new OkResponse(); - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/UrlTemplateMap.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/UrlTemplateMap.cs deleted file mode 100644 index 198917a9..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/UrlTemplateMap.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Ocelot.Library.Infrastructure.UrlTemplateRepository -{ - public class UrlTemplateMap - { - public UrlTemplateMap(string downstreamUrlTemplate, string upstreamUrlPathTemplate) - { - DownstreamUrlTemplate = downstreamUrlTemplate; - UpstreamUrlPathTemplate = upstreamUrlPathTemplate; - } - - public string DownstreamUrlTemplate {get;private set;} - public string UpstreamUrlPathTemplate {get;private set;} - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs index 0acf6c25..e723392e 100644 --- a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs +++ b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs @@ -1,7 +1,6 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Ocelot.Library.Infrastructure.UrlMatcher; -using Ocelot.Library.Infrastructure.UrlTemplateRepository; using Ocelot.Library.Infrastructure.UrlTemplateReplacer; namespace Ocelot.Library.Middleware @@ -14,40 +13,31 @@ namespace Ocelot.Library.Middleware { private readonly RequestDelegate _next; private readonly IUrlPathToUrlTemplateMatcher _urlMatcher; - private readonly IUrlTemplateMapRepository _urlTemplateMapRepository; private readonly IDownstreamUrlTemplateVariableReplacer _urlReplacer; - private readonly IOptions _optionsAccessor; + private readonly IOptions _configuration; public ProxyMiddleware(RequestDelegate next, IUrlPathToUrlTemplateMatcher urlMatcher, - IUrlTemplateMapRepository urlPathRepository, - IDownstreamUrlTemplateVariableReplacer urlReplacer, IOptions optionsAccessor) + IDownstreamUrlTemplateVariableReplacer urlReplacer, IOptions configuration) { _next = next; _urlMatcher = urlMatcher; - _urlTemplateMapRepository = urlPathRepository; _urlReplacer = urlReplacer; - _optionsAccessor = optionsAccessor; + _configuration = configuration; } public async Task Invoke(HttpContext context) - { - - var downstreamUrlPath = context.Request.Path.ToString(); - - var upstreamUrlTemplates = _urlTemplateMapRepository.All; + { + var upstreamUrlPath = context.Request.Path.ToString(); UrlMatch urlMatch = null; - string downstreamUrlTemplate = string.Empty; - - foreach (var template in upstreamUrlTemplates.Data) + foreach (var template in _configuration.Value.ReRoutes) { - urlMatch = _urlMatcher.Match(downstreamUrlPath, template.DownstreamUrlTemplate); + urlMatch = _urlMatcher.Match(upstreamUrlPath, template.UpstreamTemplate); if (urlMatch.Match) { - downstreamUrlTemplate = template.DownstreamUrlTemplate; break; } } @@ -58,7 +48,7 @@ namespace Ocelot.Library.Middleware return; } - var downstreamUrl = _urlReplacer.ReplaceTemplateVariable(downstreamUrlTemplate, urlMatch); + var downstreamUrl = _urlReplacer.ReplaceTemplateVariable(urlMatch); //make a http request to this endpoint...maybe bring in a library diff --git a/src/Ocelot/Startup.cs b/src/Ocelot/Startup.cs index 93346a40..d9400980 100644 --- a/src/Ocelot/Startup.cs +++ b/src/Ocelot/Startup.cs @@ -10,7 +10,6 @@ namespace Ocelot using Library.Infrastructure.Configuration; using Library.Infrastructure.UrlMatcher; using Library.Infrastructure.UrlTemplateReplacer; - using Library.Infrastructure.UrlTemplateRepository; public class Startup { @@ -37,7 +36,6 @@ namespace Ocelot // Add framework services. services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. diff --git a/test/Ocelot.AcceptanceTests/OcelotTests.cs b/test/Ocelot.AcceptanceTests/OcelotTests.cs index 6989ce99..6f270e2c 100644 --- a/test/Ocelot.AcceptanceTests/OcelotTests.cs +++ b/test/Ocelot.AcceptanceTests/OcelotTests.cs @@ -41,12 +41,12 @@ namespace Ocelot.AcceptanceTests this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879")) .And(x => x.GivenThereIsAConfiguration(new Configuration { - Routes = new List + ReRoutes = new List { - new Route + new ReRoute { - Downstream = "http://localhost:51879/", - Upstream = "/heee" + DownstreamTemplate = "http://localhost:51879/", + UpstreamTemplate = "/" } } })) diff --git a/test/Ocelot.AcceptanceTests/configuration.yaml b/test/Ocelot.AcceptanceTests/configuration.yaml index 2e47e77d..97b35e41 100644 --- a/test/Ocelot.AcceptanceTests/configuration.yaml +++ b/test/Ocelot.AcceptanceTests/configuration.yaml @@ -1,3 +1,3 @@ -Routes: -- Downstream: http://localhost:51879/ - Upstream: /heee +ReRoutes: +- DownstreamTemplate: http://localhost:51879/ + UpstreamTemplate: / diff --git a/test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs b/test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs index aef6e6c6..6b55c013 100644 --- a/test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs +++ b/test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs @@ -10,7 +10,6 @@ namespace Ocelot.UnitTests public class UpstreamUrlPathTemplateVariableReplacerTests { - private string _downstreamUrlTemplate; private UrlMatch _urlMatch; private string _result; private readonly IDownstreamUrlTemplateVariableReplacer _downstreamUrlPathReplacer; @@ -23,18 +22,25 @@ namespace Ocelot.UnitTests [Fact] public void can_replace_no_template_variables() { - this.Given(x => x.GivenThereIsADownstreamUrl("")) - .And(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, new List(), ""))) + this.Given(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, new List(), ""))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("")) .BDDfy(); } + [Fact] + public void can_replace_no_template_variables_with_slash() + { + this.Given(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, new List(), "/"))) + .When(x => x.WhenIReplaceTheTemplateVariables()) + .Then(x => x.ThenTheDownstreamUrlPathIsReturned("/")) + .BDDfy(); + } + [Fact] public void can_replace_url_no_slash() { - this.Given(x => x.GivenThereIsADownstreamUrl("api")) - .And(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, new List(), "api"))) + this.Given(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, new List(), "api"))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api")) .BDDfy(); @@ -43,8 +49,7 @@ namespace Ocelot.UnitTests [Fact] public void can_replace_url_one_slash() { - this.Given(x => x.GivenThereIsADownstreamUrl("api/")) - .And(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, new List(), "api/"))) + this.Given(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, new List(), "api/"))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api/")) .BDDfy(); @@ -53,8 +58,7 @@ namespace Ocelot.UnitTests [Fact] public void can_replace_url_multiple_slash() { - this.Given(x => x.GivenThereIsADownstreamUrl("api/product/products/")) - .And(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, new List(), "api/product/products/"))) + this.Given(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, new List(), "api/product/products/"))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api/product/products/")) .BDDfy(); @@ -68,8 +72,7 @@ namespace Ocelot.UnitTests new TemplateVariableNameAndValue("{productId}", "1") }; - this.Given(x => x.GivenThereIsADownstreamUrl("productservice/products/{productId}/")) - .And(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, templateVariables, "api/products/{productId}/"))) + this.Given(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, templateVariables, "productservice/products/{productId}/"))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/")) .BDDfy(); @@ -83,8 +86,7 @@ namespace Ocelot.UnitTests new TemplateVariableNameAndValue("{productId}", "1") }; - this.Given(x => x.GivenThereIsADownstreamUrl("productservice/products/{productId}/variants")) - .And(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, templateVariables, "api/products/{productId}/"))) + this.Given(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, templateVariables, "productservice/products/{productId}/variants"))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/variants")) .BDDfy(); @@ -99,8 +101,7 @@ namespace Ocelot.UnitTests new TemplateVariableNameAndValue("{variantId}", "12") }; - this.Given(x => x.GivenThereIsADownstreamUrl("productservice/products/{productId}/variants/{variantId}")) - .And(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, templateVariables, "api/products/{productId}/{variantId}"))) + this.Given(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, templateVariables, "productservice/products/{productId}/variants/{variantId}"))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/variants/12")) .BDDfy(); @@ -116,18 +117,12 @@ namespace Ocelot.UnitTests new TemplateVariableNameAndValue("{categoryId}", "34") }; - this.Given(x => x.GivenThereIsADownstreamUrl("productservice/category/{categoryId}/products/{productId}/variants/{variantId}")) - .And(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, templateVariables, "api/products/{categoryId}/{productId}/{variantId}"))) + this.Given(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, templateVariables, "productservice/category/{categoryId}/products/{productId}/variants/{variantId}"))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/category/34/products/1/variants/12")) .BDDfy(); } - private void GivenThereIsADownstreamUrl(string downstreamUrlTemplate) - { - _downstreamUrlTemplate = downstreamUrlTemplate; - } - private void GivenThereIsAUrlMatch(UrlMatch urlMatch) { _urlMatch = urlMatch; @@ -135,7 +130,7 @@ namespace Ocelot.UnitTests private void WhenIReplaceTheTemplateVariables() { - _result = _downstreamUrlPathReplacer.ReplaceTemplateVariable(_downstreamUrlTemplate, _urlMatch); + _result = _downstreamUrlPathReplacer.ReplaceTemplateVariable(_urlMatch); } private void ThenTheDownstreamUrlPathIsReturned(string expected) diff --git a/test/Ocelot.UnitTests/UrlPathTemplateMapRepositoryTests.cs b/test/Ocelot.UnitTests/UrlPathTemplateMapRepositoryTests.cs deleted file mode 100644 index 19811718..00000000 --- a/test/Ocelot.UnitTests/UrlPathTemplateMapRepositoryTests.cs +++ /dev/null @@ -1,101 +0,0 @@ -using System.Collections.Generic; -using Ocelot.Library.Infrastructure.Responses; -using Ocelot.Library.Infrastructure.UrlTemplateRepository; -using Shouldly; -using Xunit; - -namespace Ocelot.UnitTests -{ - using TestStack.BDDfy; - - public class UrlPathTemplateMapRepositoryTests - { - private string _upstreamUrlPathTemplate; - private string _downstreamUrlTemplate; - private IUrlTemplateMapRepository _repository; - private Response _response; - private Response> _listResponse; - - public UrlPathTemplateMapRepositoryTests() - { - _repository = new InMemoryUrlTemplateMapRepository(); - } - - [Fact] - public void can_add_url_path() - { - this.Given(x => x.GivenIHaveAnUpstreamUrlPathTemplate("/api/products/products/{productId}")) - .And(x => x.GivenADownstreamUrlTemplate("/api/products/{productId}")) - .When(x => x.WhenIAddTheConfiguration()) - .Then(x => x.ThenTheResponseIsSuccesful()) - .BDDfy(); - } - - [Fact] - public void can_get_all_urls() - { - this.Given(x => x.GivenIHaveSetUpADownstreamUrlTemplateAndAnUpstreamUrlPathTemplate("/api2", "http://www.someapi.com/api2")) - .When(x => x.WhenIRetrieveTheUrls()) - .Then(x => x.ThenTheUrlsAreReturned()) - .BDDfy(); - } - - [Fact] - public void should_return_error_response_when_url_path_already_used() - { - this.Given(x => x.GivenIHaveSetUpADownstreamUrlTemplateAndAnUpstreamUrlPathTemplate("/api2", "http://www.someapi.com/api2")) - .When(x => x.WhenITryToUseTheSameDownstreamUrl()) - .Then(x => x.ThenTheDownstreamUrlAlreadyBeenUsed()) - .BDDfy(); - } - - private void WhenITryToUseTheSameDownstreamUrl() - { - WhenIAddTheConfiguration(); - } - - private void ThenTheDownstreamUrlAlreadyBeenUsed() - { - _response.ShouldNotBeNull(); - _response.ShouldBeOfType(); - _response.Errors[0].Message.ShouldBe("This key has already been used"); - } - - private void WhenIRetrieveTheUrls() - { - _listResponse = _repository.All; - } - - private void ThenTheUrlsAreReturned() - { - _listResponse.Data.Count.ShouldBeGreaterThan(0); - } - - private void GivenIHaveSetUpADownstreamUrlTemplateAndAnUpstreamUrlPathTemplate(string downstreamUrlTemplate, string upstreamUrlPathTemplate) - { - GivenIHaveAnUpstreamUrlPathTemplate(upstreamUrlPathTemplate); - GivenADownstreamUrlTemplate(downstreamUrlTemplate); - WhenIAddTheConfiguration(); - } - - private void GivenIHaveAnUpstreamUrlPathTemplate(string upstreamUrlPathTemplate) - { - _upstreamUrlPathTemplate = upstreamUrlPathTemplate; - } - - private void GivenADownstreamUrlTemplate(string downstreamUrlTemplate) - { - _downstreamUrlTemplate = downstreamUrlTemplate; - } - - private void WhenIAddTheConfiguration() - { - _response = _repository.AddUrlTemplateMap(new UrlTemplateMap(_downstreamUrlTemplate, _upstreamUrlPathTemplate)); - } - - private void ThenTheResponseIsSuccesful() - { - _response.ShouldBeOfType(); - } - } -} \ No newline at end of file From 03ef47038adb44c615a74ab5c4f24a190d553546 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Wed, 7 Sep 2016 21:47:39 +0100 Subject: [PATCH 026/183] first passing proxy acceptnace test yeyyy! --- .../DownstreamRouteFinder/DownstreamRoute.cs | 16 +++ .../DownstreamRouteFinder.cs | 38 +++++ .../IDownstreamRouteFinder.cs | 9 ++ .../UnableToFindDownstreamRouteError.cs | 15 ++ .../DownstreamUrlTemplateVariableReplacer.cs | 8 +- ...wnstreamUrlPathTemplateVariableReplacer.cs | 3 +- .../Middleware/ProxyMiddleware.cs | 52 ++++--- src/Ocelot/Startup.cs | 2 + test/Ocelot.AcceptanceTests/OcelotTests.cs | 2 +- .../DownstreamRouteFinderTests.cs | 132 ++++++++++++++++++ ...eamUrlPathTemplateVariableReplacerTests.cs | 27 ++-- test/Ocelot.UnitTests/project.json | 3 +- 12 files changed, 264 insertions(+), 43 deletions(-) create mode 100644 src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRoute.cs create mode 100644 src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRouteFinder.cs create mode 100644 src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/IDownstreamRouteFinder.cs create mode 100644 src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/UnableToFindDownstreamRouteError.cs create mode 100644 test/Ocelot.UnitTests/DownstreamRouteFinderTests.cs diff --git a/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRoute.cs b/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRoute.cs new file mode 100644 index 00000000..b88f0063 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRoute.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using Ocelot.Library.Infrastructure.UrlMatcher; + +namespace Ocelot.Library.Infrastructure.DownstreamRouteFinder +{ + public class DownstreamRoute + { + public DownstreamRoute(List templateVariableNameAndValues, string downstreamUrlTemplate) + { + TemplateVariableNameAndValues = templateVariableNameAndValues; + DownstreamUrlTemplate = downstreamUrlTemplate; + } + public List TemplateVariableNameAndValues { get; private set; } + public string DownstreamUrlTemplate { get; private set; } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRouteFinder.cs b/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRouteFinder.cs new file mode 100644 index 00000000..63ddfacd --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRouteFinder.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using Microsoft.Extensions.Options; +using Ocelot.Library.Infrastructure.Responses; +using Ocelot.Library.Infrastructure.UrlMatcher; + +namespace Ocelot.Library.Infrastructure.DownstreamRouteFinder +{ + public class DownstreamRouteFinder : IDownstreamRouteFinder + { + private readonly IOptions _configuration; + private readonly IUrlPathToUrlTemplateMatcher _urlMatcher; + + public DownstreamRouteFinder(IOptions configuration, IUrlPathToUrlTemplateMatcher urlMatcher) + { + _configuration = configuration; + _urlMatcher = urlMatcher; + } + + public Response FindDownstreamRoute(string upstreamUrlPath) + { + + foreach (var template in _configuration.Value.ReRoutes) + { + var urlMatch = _urlMatcher.Match(upstreamUrlPath, template.UpstreamTemplate); + + if (urlMatch.Match) + { + return new OkResponse(new DownstreamRoute(urlMatch.TemplateVariableNameAndValues, template.DownstreamTemplate)); + } + } + + return new ErrorResponse(new List + { + new UnableToFindDownstreamRouteError() + }); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/IDownstreamRouteFinder.cs b/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/IDownstreamRouteFinder.cs new file mode 100644 index 00000000..1394b3af --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/IDownstreamRouteFinder.cs @@ -0,0 +1,9 @@ +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.DownstreamRouteFinder +{ + public interface IDownstreamRouteFinder + { + Response FindDownstreamRoute(string upstreamUrlPath); + } +} diff --git a/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/UnableToFindDownstreamRouteError.cs b/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/UnableToFindDownstreamRouteError.cs new file mode 100644 index 00000000..62618951 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/UnableToFindDownstreamRouteError.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.DownstreamRouteFinder +{ + public class UnableToFindDownstreamRouteError : Error + { + public UnableToFindDownstreamRouteError() : base("UnableToFindDownstreamRouteError") + { + } + } +} diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs index 35dc563c..204eb212 100644 --- a/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs +++ b/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs @@ -1,17 +1,17 @@ using System.Text; -using Ocelot.Library.Infrastructure.UrlMatcher; +using Ocelot.Library.Infrastructure.DownstreamRouteFinder; namespace Ocelot.Library.Infrastructure.UrlTemplateReplacer { public class DownstreamUrlTemplateVariableReplacer : IDownstreamUrlTemplateVariableReplacer { - public string ReplaceTemplateVariable(UrlMatch urlMatch) + public string ReplaceTemplateVariable(DownstreamRoute downstreamRoute) { var upstreamUrl = new StringBuilder(); - upstreamUrl.Append(urlMatch.DownstreamUrlTemplate); + upstreamUrl.Append(downstreamRoute.DownstreamUrlTemplate); - foreach (var templateVarAndValue in urlMatch.TemplateVariableNameAndValues) + foreach (var templateVarAndValue in downstreamRoute.TemplateVariableNameAndValues) { upstreamUrl.Replace(templateVarAndValue.TemplateVariableName, templateVarAndValue.TemplateVariableValue); } diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs index 62eac8bc..bc50a8fa 100644 --- a/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs +++ b/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs @@ -1,9 +1,10 @@ +using Ocelot.Library.Infrastructure.DownstreamRouteFinder; using Ocelot.Library.Infrastructure.UrlMatcher; namespace Ocelot.Library.Infrastructure.UrlTemplateReplacer { public interface IDownstreamUrlTemplateVariableReplacer { - string ReplaceTemplateVariable(UrlMatch urlMatch); + string ReplaceTemplateVariable(DownstreamRoute downstreamRoute); } } \ No newline at end of file diff --git a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs index e723392e..1dd90dc6 100644 --- a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs +++ b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs @@ -1,56 +1,62 @@ +using System.Net; +using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; -using Ocelot.Library.Infrastructure.UrlMatcher; +using Microsoft.Extensions.Options; +using Ocelot.Library.Infrastructure.Configuration; +using Ocelot.Library.Infrastructure.DownstreamRouteFinder; using Ocelot.Library.Infrastructure.UrlTemplateReplacer; namespace Ocelot.Library.Middleware { - using System.Net; - using Infrastructure.Configuration; - using Microsoft.Extensions.Options; - public class ProxyMiddleware { private readonly RequestDelegate _next; - private readonly IUrlPathToUrlTemplateMatcher _urlMatcher; private readonly IDownstreamUrlTemplateVariableReplacer _urlReplacer; private readonly IOptions _configuration; + private readonly IDownstreamRouteFinder _downstreamRouteFinder; public ProxyMiddleware(RequestDelegate next, - IUrlPathToUrlTemplateMatcher urlMatcher, - IDownstreamUrlTemplateVariableReplacer urlReplacer, IOptions configuration) + IDownstreamUrlTemplateVariableReplacer urlReplacer, + IOptions configuration, + IDownstreamRouteFinder downstreamRouteFinder) { _next = next; - _urlMatcher = urlMatcher; _urlReplacer = urlReplacer; _configuration = configuration; + _downstreamRouteFinder = downstreamRouteFinder; } public async Task Invoke(HttpContext context) { var upstreamUrlPath = context.Request.Path.ToString(); - UrlMatch urlMatch = null; + var downstreamRoute = _downstreamRouteFinder.FindDownstreamRoute(upstreamUrlPath); - foreach (var template in _configuration.Value.ReRoutes) - { - urlMatch = _urlMatcher.Match(upstreamUrlPath, template.UpstreamTemplate); - - if (urlMatch.Match) - { - break; - } - } - - if (urlMatch == null || !urlMatch.Match) + if (downstreamRoute.IsError) { context.Response.StatusCode = (int)HttpStatusCode.NotFound; return; } - - var downstreamUrl = _urlReplacer.ReplaceTemplateVariable(urlMatch); + + var downstreamUrl = _urlReplacer.ReplaceTemplateVariable(downstreamRoute.Data); //make a http request to this endpoint...maybe bring in a library + using (var httpClient = new HttpClient()) + { + var httpMethod = new HttpMethod(context.Request.Method); + + var httpRequestMessage = new HttpRequestMessage(httpMethod, downstreamUrl); + + var response = await httpClient.SendAsync(httpRequestMessage); + + if (!response.IsSuccessStatusCode) + { + context.Response.StatusCode = (int)response.StatusCode; + return; + } + await context.Response.WriteAsync(await response.Content.ReadAsStringAsync()); + } await _next.Invoke(context); } diff --git a/src/Ocelot/Startup.cs b/src/Ocelot/Startup.cs index d9400980..18d5ba6b 100644 --- a/src/Ocelot/Startup.cs +++ b/src/Ocelot/Startup.cs @@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Ocelot.Library.Infrastructure.DownstreamRouteFinder; using Ocelot.Library.Middleware; namespace Ocelot @@ -36,6 +37,7 @@ namespace Ocelot // Add framework services. services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. diff --git a/test/Ocelot.AcceptanceTests/OcelotTests.cs b/test/Ocelot.AcceptanceTests/OcelotTests.cs index 6f270e2c..6eea27ab 100644 --- a/test/Ocelot.AcceptanceTests/OcelotTests.cs +++ b/test/Ocelot.AcceptanceTests/OcelotTests.cs @@ -90,7 +90,7 @@ namespace Ocelot.AcceptanceTests private void WhenIRequestTheUrlOnTheApiGateway(string url) { - _response = _client.GetAsync("/").Result; + _response = _client.GetAsync(url).Result; } private void ThenTheStatusCodeShouldBe(HttpStatusCode expectedHttpStatusCode) diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinderTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinderTests.cs new file mode 100644 index 00000000..212e2029 --- /dev/null +++ b/test/Ocelot.UnitTests/DownstreamRouteFinderTests.cs @@ -0,0 +1,132 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using Moq; +using Ocelot.Library.Infrastructure.Configuration; +using Ocelot.Library.Infrastructure.DownstreamRouteFinder; +using Ocelot.Library.Infrastructure.Responses; +using Ocelot.Library.Infrastructure.UrlMatcher; +using Shouldly; +using TestStack.BDDfy; +using Xunit; + +namespace Ocelot.UnitTests +{ + public class DownstreamRouteFinderTests + { + private readonly IDownstreamRouteFinder _downstreamRouteFinder; + private readonly Mock> _mockConfig; + private readonly Mock _mockMatcher; + private string _upstreamUrlPath; + private Response _result; + private Response _response; + private Configuration _configuration; + private UrlMatch _match; + + public DownstreamRouteFinderTests() + { + _mockConfig = new Mock>(); + _mockMatcher = new Mock(); + _downstreamRouteFinder = new DownstreamRouteFinder(_mockConfig.Object, _mockMatcher.Object); + } + + [Fact] + public void should_return_route() + { + this.Given(x => x.GivenThereIsAnUpstreamUrlPath("somePath")) + .And(x => x.GivenTheConfigurationIs(new Configuration { + ReRoutes = new List + { + new ReRoute() + { + UpstreamTemplate = "somePath", + DownstreamTemplate = "somPath" + } + } + })) + .And(x => x.GivenTheUrlMatcherReturns(new UrlMatch(true, new List(), "somePath"))) + .When(x => x.WhenICallTheFinder()) + .Then( + x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List(), "somePath"))) + .And(x => x.ThenTheUrlMatcherIsCalledCorrectly()) + .BDDfy(); + } + + [Fact] + public void should_not_return_route() + { + this.Given(x => x.GivenThereIsAnUpstreamUrlPath("somePath")) + .And(x => x.GivenTheConfigurationIs(new Configuration + { + ReRoutes = new List + { + new ReRoute() + { + UpstreamTemplate = "somePath", + DownstreamTemplate = "somPath" + } + } + })) + .And(x => x.GivenTheUrlMatcherReturns(new UrlMatch(false, new List(), null))) + .When(x => x.WhenICallTheFinder()) + .Then( + x => x.ThenAnErrorResponseIsReturned()) + .And(x => x.ThenTheUrlMatcherIsCalledCorrectly()) + .BDDfy(); + } + + private void ThenAnErrorResponseIsReturned() + { + _result.IsError.ShouldBeTrue(); + } + + private void ThenTheUrlMatcherIsCalledCorrectly() + { + _mockMatcher + .Verify(x => x.Match(_upstreamUrlPath, _configuration.ReRoutes[0].UpstreamTemplate), Times.Once); + } + + private void GivenTheUrlMatcherReturns(UrlMatch match) + { + _match = match; + _mockMatcher + .Setup(x => x.Match(It.IsAny(), It.IsAny())) + .Returns(_match); + } + + private void GivenTheConfigurationIs(Configuration configuration) + { + _configuration = configuration; + _mockConfig + .Setup(x => x.Value) + .Returns(_configuration); + } + + private void GivenThereIsAnUpstreamUrlPath(string upstreamUrlPath) + { + _upstreamUrlPath = upstreamUrlPath; + } + + private void WhenICallTheFinder() + { + _result = _downstreamRouteFinder.FindDownstreamRoute(_upstreamUrlPath); + } + + private void ThenTheFollowingIsReturned(DownstreamRoute expected) + { + _result.Data.DownstreamUrlTemplate.ShouldBe(expected.DownstreamUrlTemplate); + for (int i = 0; i < _result.Data.TemplateVariableNameAndValues.Count; i++) + { + _result.Data.TemplateVariableNameAndValues[i].TemplateVariableName.ShouldBe( + expected.TemplateVariableNameAndValues[i].TemplateVariableName); + + _result.Data.TemplateVariableNameAndValues[i].TemplateVariableValue.ShouldBe( + expected.TemplateVariableNameAndValues[i].TemplateVariableValue); + } + + _result.IsError.ShouldBeFalse(); + } + } +} diff --git a/test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs b/test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs index 6b55c013..b280e04f 100644 --- a/test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs +++ b/test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Ocelot.Library.Infrastructure.DownstreamRouteFinder; using Ocelot.Library.Infrastructure.UrlMatcher; using Ocelot.Library.Infrastructure.UrlTemplateReplacer; using Shouldly; @@ -10,7 +11,7 @@ namespace Ocelot.UnitTests public class UpstreamUrlPathTemplateVariableReplacerTests { - private UrlMatch _urlMatch; + private DownstreamRoute _downstreamRoute; private string _result; private readonly IDownstreamUrlTemplateVariableReplacer _downstreamUrlPathReplacer; @@ -22,7 +23,7 @@ namespace Ocelot.UnitTests [Fact] public void can_replace_no_template_variables() { - this.Given(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, new List(), ""))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), ""))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("")) .BDDfy(); @@ -31,7 +32,7 @@ namespace Ocelot.UnitTests [Fact] public void can_replace_no_template_variables_with_slash() { - this.Given(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, new List(), "/"))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), "/"))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("/")) .BDDfy(); @@ -40,7 +41,7 @@ namespace Ocelot.UnitTests [Fact] public void can_replace_url_no_slash() { - this.Given(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, new List(), "api"))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), "api"))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api")) .BDDfy(); @@ -49,7 +50,7 @@ namespace Ocelot.UnitTests [Fact] public void can_replace_url_one_slash() { - this.Given(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, new List(), "api/"))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), "api/"))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api/")) .BDDfy(); @@ -58,7 +59,7 @@ namespace Ocelot.UnitTests [Fact] public void can_replace_url_multiple_slash() { - this.Given(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, new List(), "api/product/products/"))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), "api/product/products/"))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api/product/products/")) .BDDfy(); @@ -72,7 +73,7 @@ namespace Ocelot.UnitTests new TemplateVariableNameAndValue("{productId}", "1") }; - this.Given(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, templateVariables, "productservice/products/{productId}/"))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, "productservice/products/{productId}/"))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/")) .BDDfy(); @@ -86,7 +87,7 @@ namespace Ocelot.UnitTests new TemplateVariableNameAndValue("{productId}", "1") }; - this.Given(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, templateVariables, "productservice/products/{productId}/variants"))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, "productservice/products/{productId}/variants"))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/variants")) .BDDfy(); @@ -101,7 +102,7 @@ namespace Ocelot.UnitTests new TemplateVariableNameAndValue("{variantId}", "12") }; - this.Given(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, templateVariables, "productservice/products/{productId}/variants/{variantId}"))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, "productservice/products/{productId}/variants/{variantId}"))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/variants/12")) .BDDfy(); @@ -117,20 +118,20 @@ namespace Ocelot.UnitTests new TemplateVariableNameAndValue("{categoryId}", "34") }; - this.Given(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, templateVariables, "productservice/category/{categoryId}/products/{productId}/variants/{variantId}"))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, "productservice/category/{categoryId}/products/{productId}/variants/{variantId}"))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/category/34/products/1/variants/12")) .BDDfy(); } - private void GivenThereIsAUrlMatch(UrlMatch urlMatch) + private void GivenThereIsAUrlMatch(DownstreamRoute downstreamRoute) { - _urlMatch = urlMatch; + _downstreamRoute = downstreamRoute; } private void WhenIReplaceTheTemplateVariables() { - _result = _downstreamUrlPathReplacer.ReplaceTemplateVariable(_urlMatch); + _result = _downstreamUrlPathReplacer.ReplaceTemplateVariable(_downstreamRoute); } private void ThenTheDownstreamUrlPathIsReturned(string expected) diff --git a/test/Ocelot.UnitTests/project.json b/test/Ocelot.UnitTests/project.json index f8c0cf9d..7b0acc6e 100644 --- a/test/Ocelot.UnitTests/project.json +++ b/test/Ocelot.UnitTests/project.json @@ -24,7 +24,8 @@ "dotnet-test-xunit": "2.2.0-preview2-build1029", "Shouldly": "2.8.0", "TestStack.BDDfy": "4.3.1", - "YamlDotNet": "3.9.0" + "YamlDotNet": "3.9.0", + "Moq": "4.6.38-alpha" }, "frameworks": { From 912063fe77d10dbea98913b18700b3721e793c67 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Wed, 7 Sep 2016 21:57:46 +0100 Subject: [PATCH 027/183] updated readme --- README.md | 19 +++++++++++++++++++ .../Middleware/ProxyMiddleware.cs | 1 - 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 85884775..9d9915bf 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,22 @@ # Ocelot Attempt at a .NET Api Gateway + +This project is aimed at people using .NET running +a micro services / service orientated architecture +that need a unified point of entry into their system. + +In particular I want easy integration with +IdentityServer reference and bearer tokens. + +We have been unable to find this in my current workplace +without having to write our own Javascript middlewares +to handle the IdentityServer reference tokens. We would +rather use the IdentityServer code that already exists +to do this. + +Priorities + +- Route configuration +- IdentityServer reference & bearer tokens +- Output Caching \ No newline at end of file diff --git a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs index 1dd90dc6..b155dc15 100644 --- a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs +++ b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs @@ -41,7 +41,6 @@ namespace Ocelot.Library.Middleware var downstreamUrl = _urlReplacer.ReplaceTemplateVariable(downstreamRoute.Data); - //make a http request to this endpoint...maybe bring in a library using (var httpClient = new HttpClient()) { var httpMethod = new HttpMethod(context.Request.Method); From 484270edbc188e3db0916ed80b6ee46b6caf00c5 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Wed, 7 Sep 2016 21:59:41 +0100 Subject: [PATCH 028/183] updated readme --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9d9915bf..b507c955 100644 --- a/README.md +++ b/README.md @@ -19,4 +19,10 @@ Priorities - Route configuration - IdentityServer reference & bearer tokens -- Output Caching \ No newline at end of file +- Strip claims from tokens and use in proxy request +- Authorise access to routes based on claims in token +- Output Caching +- Monitoring +- Logging +- Rate Limiting +- Then a big list of cool things... From 87702141e2b9151b0be6beceff57c47dce549954 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Wed, 7 Sep 2016 22:53:39 +0100 Subject: [PATCH 029/183] Added some configuration validation stuff but then realised probablt wont need this for a while --- .../ConfigurationValidationResult.cs | 11 +++ .../Configuration/ConfigurationValidator.cs | 37 ++++++++ .../DownstreamTemplateAlreadyUsedError.cs | 15 ++++ .../Configuration/IConfigurationValidator.cs | 13 +++ .../ConfigurationValidationTests.cs | 84 +++++++++++++++++++ 5 files changed, 160 insertions(+) create mode 100644 src/Ocelot.Library/Infrastructure/Configuration/ConfigurationValidationResult.cs create mode 100644 src/Ocelot.Library/Infrastructure/Configuration/ConfigurationValidator.cs create mode 100644 src/Ocelot.Library/Infrastructure/Configuration/DownstreamTemplateAlreadyUsedError.cs create mode 100644 src/Ocelot.Library/Infrastructure/Configuration/IConfigurationValidator.cs create mode 100644 test/Ocelot.UnitTests/ConfigurationValidationTests.cs diff --git a/src/Ocelot.Library/Infrastructure/Configuration/ConfigurationValidationResult.cs b/src/Ocelot.Library/Infrastructure/Configuration/ConfigurationValidationResult.cs new file mode 100644 index 00000000..976279ca --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Configuration/ConfigurationValidationResult.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Ocelot.Library.Infrastructure.Configuration +{ + public class ConfigurationValidationResult + { + } +} diff --git a/src/Ocelot.Library/Infrastructure/Configuration/ConfigurationValidator.cs b/src/Ocelot.Library/Infrastructure/Configuration/ConfigurationValidator.cs new file mode 100644 index 00000000..bcb6b0bb --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Configuration/ConfigurationValidator.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.Configuration +{ + public class ConfigurationValidator : IConfigurationValidator + { + public Response IsValid(Configuration configuration) + { + var duplicateUpstreamTemplates = configuration.ReRoutes + .Select(r => r.DownstreamTemplate) + .GroupBy(r => r) + .Where(r => r.Count() > 1) + .Select(r => r.Key) + .ToList(); + + if (duplicateUpstreamTemplates.Count <= 0) + { + return new OkResponse(new ConfigurationValidationResult()); + } + + var errors = new List(); + + foreach (var duplicateUpstreamTemplate in duplicateUpstreamTemplates) + { + var error = new DownstreamTemplateAlreadyUsedError(string.Format("Duplicate DownstreamTemplate: {0}", + duplicateUpstreamTemplate)); + errors.Add(error); + } + + return new ErrorResponse(errors); + } + } +} diff --git a/src/Ocelot.Library/Infrastructure/Configuration/DownstreamTemplateAlreadyUsedError.cs b/src/Ocelot.Library/Infrastructure/Configuration/DownstreamTemplateAlreadyUsedError.cs new file mode 100644 index 00000000..3992cb4e --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Configuration/DownstreamTemplateAlreadyUsedError.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.Configuration +{ + public class DownstreamTemplateAlreadyUsedError : Error + { + public DownstreamTemplateAlreadyUsedError(string message) : base(message) + { + } + } +} diff --git a/src/Ocelot.Library/Infrastructure/Configuration/IConfigurationValidator.cs b/src/Ocelot.Library/Infrastructure/Configuration/IConfigurationValidator.cs new file mode 100644 index 00000000..595ea21f --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Configuration/IConfigurationValidator.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.Configuration +{ + public interface IConfigurationValidator + { + Response IsValid(Configuration configuration); + } +} diff --git a/test/Ocelot.UnitTests/ConfigurationValidationTests.cs b/test/Ocelot.UnitTests/ConfigurationValidationTests.cs new file mode 100644 index 00000000..1a65e3db --- /dev/null +++ b/test/Ocelot.UnitTests/ConfigurationValidationTests.cs @@ -0,0 +1,84 @@ +using System.Collections.Generic; +using Ocelot.Library.Infrastructure.Configuration; +using Ocelot.Library.Infrastructure.Responses; +using Shouldly; +using TestStack.BDDfy; +using Xunit; + +namespace Ocelot.UnitTests +{ + public class ConfigurationValidationTests + { + private Configuration _configuration; + private readonly IConfigurationValidator _configurationValidator; + private Response _result; + + public ConfigurationValidationTests() + { + _configurationValidator = new ConfigurationValidator(); + } + + [Fact] + public void configuration_is_valid_with_one_reroute() + { + this.Given(x => x.GivenAConfiguration(new Configuration() + { + ReRoutes = new List + { + new ReRoute + { + DownstreamTemplate = "http://www.bbc.co.uk", + UpstreamTemplate = "http://asdf.com" + } + } + })) + .When(x => x.WhenIValidateTheConfiguration()) + .Then(x => x.ThenTheResultIsValid()) + .BDDfy(); + } + + [Fact] + public void configuration_is_not_valid_with_duplicate_reroutes() + { + this.Given(x => x.GivenAConfiguration(new Configuration() + { + ReRoutes = new List + { + new ReRoute + { + DownstreamTemplate = "http://www.bbc.co.uk", + UpstreamTemplate = "http://asdf.com" + }, + new ReRoute + { + DownstreamTemplate = "http://www.bbc.co.uk", + UpstreamTemplate = "http://lol.com" + } + } + })) + .When(x => x.WhenIValidateTheConfiguration()) + .Then(x => x.ThenTheResultIsNotValid()) + .BDDfy(); + } + + private void GivenAConfiguration(Configuration configuration) + { + _configuration = configuration; + } + + private void WhenIValidateTheConfiguration() + { + _result = _configurationValidator.IsValid(_configuration); + } + + private void ThenTheResultIsValid() + { + _result.IsError.ShouldBeFalse(); + } + + private void ThenTheResultIsNotValid() + { + _result.IsError.ShouldBeTrue(); + } + } +} From 72cec38c0e05cfd723960161ec1f36704d3c13f7 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Sun, 11 Sep 2016 21:32:56 +0100 Subject: [PATCH 030/183] some tidying up and a bit of refactoring...not too happy about how the proxy is working at the moment! May need a rethink! --- .../ConfigurationValidationResult.cs | 21 ++++++++--- .../Configuration/ConfigurationValidator.cs | 8 ++--- .../DownstreamRouteFinder.cs | 1 - .../Requester/HttpClientHttpRequester.cs | 21 +++++++++++ .../Requester/IHttpRequester.cs | 11 ++++++ .../Responder/HttpContextResponder.cs | 27 ++++++++++++++ .../Responder/IHttpResponder.cs | 13 +++++++ .../DownstreamUrlTemplateVariableReplacer.cs | 2 +- ...wnstreamUrlPathTemplateVariableReplacer.cs | 2 +- .../Middleware/ProxyMiddleware.cs | 32 +++++++---------- src/Ocelot.Library/project.json | 35 ++++++++++--------- src/Ocelot/Startup.cs | 4 +++ test/Ocelot.AcceptanceTests/OcelotTests.cs | 11 +++--- .../ConfigurationValidationTests.cs | 10 ++++-- .../DownstreamRouteFinderTests.cs | 11 +++--- ...eamUrlPathTemplateVariableReplacerTests.cs | 2 +- 16 files changed, 151 insertions(+), 60 deletions(-) create mode 100644 src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs create mode 100644 src/Ocelot.Library/Infrastructure/Requester/IHttpRequester.cs create mode 100644 src/Ocelot.Library/Infrastructure/Responder/HttpContextResponder.cs create mode 100644 src/Ocelot.Library/Infrastructure/Responder/IHttpResponder.cs diff --git a/src/Ocelot.Library/Infrastructure/Configuration/ConfigurationValidationResult.cs b/src/Ocelot.Library/Infrastructure/Configuration/ConfigurationValidationResult.cs index 976279ca..abbbcfae 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/ConfigurationValidationResult.cs +++ b/src/Ocelot.Library/Infrastructure/Configuration/ConfigurationValidationResult.cs @@ -1,11 +1,24 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using System.Collections.Generic; +using Ocelot.Library.Infrastructure.Responses; namespace Ocelot.Library.Infrastructure.Configuration { public class ConfigurationValidationResult { + public ConfigurationValidationResult(bool isError) + { + IsError = isError; + Errors = new List(); + } + + public ConfigurationValidationResult(bool isError, List errors) + { + IsError = isError; + Errors = errors; + } + + public bool IsError { get; private set; } + + public List Errors { get; private set; } } } diff --git a/src/Ocelot.Library/Infrastructure/Configuration/ConfigurationValidator.cs b/src/Ocelot.Library/Infrastructure/Configuration/ConfigurationValidator.cs index bcb6b0bb..5038baf3 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/ConfigurationValidator.cs +++ b/src/Ocelot.Library/Infrastructure/Configuration/ConfigurationValidator.cs @@ -1,7 +1,5 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; -using System.Text; using Ocelot.Library.Infrastructure.Responses; namespace Ocelot.Library.Infrastructure.Configuration @@ -19,7 +17,7 @@ namespace Ocelot.Library.Infrastructure.Configuration if (duplicateUpstreamTemplates.Count <= 0) { - return new OkResponse(new ConfigurationValidationResult()); + return new OkResponse(new ConfigurationValidationResult(false)); } var errors = new List(); @@ -31,7 +29,7 @@ namespace Ocelot.Library.Infrastructure.Configuration errors.Add(error); } - return new ErrorResponse(errors); + return new OkResponse(new ConfigurationValidationResult(true, errors)); } } } diff --git a/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRouteFinder.cs b/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRouteFinder.cs index 63ddfacd..0cc2f18e 100644 --- a/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRouteFinder.cs +++ b/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRouteFinder.cs @@ -18,7 +18,6 @@ namespace Ocelot.Library.Infrastructure.DownstreamRouteFinder public Response FindDownstreamRoute(string upstreamUrlPath) { - foreach (var template in _configuration.Value.ReRoutes) { var urlMatch = _urlMatcher.Match(upstreamUrlPath, template.UpstreamTemplate); diff --git a/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs b/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs new file mode 100644 index 00000000..1b76ba8c --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs @@ -0,0 +1,21 @@ +using System.Net.Http; +using System.Threading.Tasks; + +namespace Ocelot.Library.Infrastructure.Requester +{ + public class HttpClientHttpRequester : IHttpRequester + { + public async Task GetResponse(string httpMethod, string downstreamUrl) + { + var method = new HttpMethod(httpMethod); + + var httpRequestMessage = new HttpRequestMessage(method, downstreamUrl); + + using (var httpClient = new HttpClient()) + { + var response = await httpClient.SendAsync(httpRequestMessage); + return response; + } + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Requester/IHttpRequester.cs b/src/Ocelot.Library/Infrastructure/Requester/IHttpRequester.cs new file mode 100644 index 00000000..310f25b3 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Requester/IHttpRequester.cs @@ -0,0 +1,11 @@ +using System.Net.Http; +using System.Threading.Tasks; +using Flurl.Http; + +namespace Ocelot.Library.Infrastructure.Requester +{ + public interface IHttpRequester + { + Task GetResponse(string httpMethod, string downstreamUrl); + } +} diff --git a/src/Ocelot.Library/Infrastructure/Responder/HttpContextResponder.cs b/src/Ocelot.Library/Infrastructure/Responder/HttpContextResponder.cs new file mode 100644 index 00000000..a90543fc --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Responder/HttpContextResponder.cs @@ -0,0 +1,27 @@ +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; + +namespace Ocelot.Library.Infrastructure.Responder +{ + public class HttpContextResponder : IHttpResponder + { + public async Task CreateSuccessResponse(HttpContext context, HttpResponseMessage response) + { + if (!response.IsSuccessStatusCode) + { + context.Response.StatusCode = (int)response.StatusCode; + return context; + } + await context.Response.WriteAsync(await response.Content.ReadAsStringAsync()); + return context; + } + + public async Task CreateNotFoundResponse(HttpContext context) + { + context.Response.StatusCode = (int)HttpStatusCode.NotFound; + return context; + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Responder/IHttpResponder.cs b/src/Ocelot.Library/Infrastructure/Responder/IHttpResponder.cs new file mode 100644 index 00000000..3e2dc91b --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Responder/IHttpResponder.cs @@ -0,0 +1,13 @@ +using System.Net.Http; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; + +namespace Ocelot.Library.Infrastructure.Responder +{ + public interface IHttpResponder + { + Task CreateSuccessResponse(HttpContext context, HttpResponseMessage response); + Task CreateNotFoundResponse(HttpContext context); + + } +} diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs index 204eb212..34987a8b 100644 --- a/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs +++ b/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs @@ -5,7 +5,7 @@ namespace Ocelot.Library.Infrastructure.UrlTemplateReplacer { public class DownstreamUrlTemplateVariableReplacer : IDownstreamUrlTemplateVariableReplacer { - public string ReplaceTemplateVariable(DownstreamRoute downstreamRoute) + public string ReplaceTemplateVariables(DownstreamRoute downstreamRoute) { var upstreamUrl = new StringBuilder(); diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs index bc50a8fa..9f27db84 100644 --- a/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs +++ b/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs @@ -5,6 +5,6 @@ namespace Ocelot.Library.Infrastructure.UrlTemplateReplacer { public interface IDownstreamUrlTemplateVariableReplacer { - string ReplaceTemplateVariable(DownstreamRoute downstreamRoute); + string ReplaceTemplateVariables(DownstreamRoute downstreamRoute); } } \ No newline at end of file diff --git a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs index b155dc15..31b7c487 100644 --- a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs +++ b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs @@ -1,10 +1,10 @@ -using System.Net; -using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Options; using Ocelot.Library.Infrastructure.Configuration; using Ocelot.Library.Infrastructure.DownstreamRouteFinder; +using Ocelot.Library.Infrastructure.Requester; +using Ocelot.Library.Infrastructure.Responder; using Ocelot.Library.Infrastructure.UrlTemplateReplacer; namespace Ocelot.Library.Middleware @@ -15,16 +15,22 @@ namespace Ocelot.Library.Middleware private readonly IDownstreamUrlTemplateVariableReplacer _urlReplacer; private readonly IOptions _configuration; private readonly IDownstreamRouteFinder _downstreamRouteFinder; + private readonly IHttpRequester _requester; + private readonly IHttpResponder _responder; public ProxyMiddleware(RequestDelegate next, IDownstreamUrlTemplateVariableReplacer urlReplacer, IOptions configuration, - IDownstreamRouteFinder downstreamRouteFinder) + IDownstreamRouteFinder downstreamRouteFinder, + IHttpRequester requester, + IHttpResponder responder) { _next = next; _urlReplacer = urlReplacer; _configuration = configuration; _downstreamRouteFinder = downstreamRouteFinder; + _requester = requester; + _responder = responder; } public async Task Invoke(HttpContext context) @@ -35,27 +41,15 @@ namespace Ocelot.Library.Middleware if (downstreamRoute.IsError) { - context.Response.StatusCode = (int)HttpStatusCode.NotFound; + await _responder.CreateNotFoundResponse(context); return; } - var downstreamUrl = _urlReplacer.ReplaceTemplateVariable(downstreamRoute.Data); + var downstreamUrl = _urlReplacer.ReplaceTemplateVariables(downstreamRoute.Data); - using (var httpClient = new HttpClient()) - { - var httpMethod = new HttpMethod(context.Request.Method); + var response = await _requester.GetResponse(context.Request.Method, downstreamUrl); - var httpRequestMessage = new HttpRequestMessage(httpMethod, downstreamUrl); - - var response = await httpClient.SendAsync(httpRequestMessage); - - if (!response.IsSuccessStatusCode) - { - context.Response.StatusCode = (int)response.StatusCode; - return; - } - await context.Response.WriteAsync(await response.Content.ReadAsStringAsync()); - } + context = await _responder.CreateSuccessResponse(context, response); await _next.Invoke(context); } diff --git a/src/Ocelot.Library/project.json b/src/Ocelot.Library/project.json index 7037f0a7..07d34181 100644 --- a/src/Ocelot.Library/project.json +++ b/src/Ocelot.Library/project.json @@ -1,24 +1,25 @@ { "version": "1.0.0-*", - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.0.0", - "type": "platform" + "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.0.0", + "type": "platform" + }, + "Microsoft.AspNetCore.Mvc": "1.0.0", + "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", + "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", + "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0", + "Microsoft.Extensions.Configuration.Json": "1.0.0", + "Microsoft.Extensions.Logging": "1.0.0", + "Microsoft.Extensions.Logging.Console": "1.0.0", + "Microsoft.Extensions.Logging.Debug": "1.0.0", + "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", + "Microsoft.AspNetCore.Http": "1.0.0", + "YamlDotNet": "3.9.0", + "Flurl.Http": "1.0.1" }, - "Microsoft.AspNetCore.Mvc": "1.0.0", - "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", - "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", - "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", - "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0", - "Microsoft.Extensions.Configuration.Json": "1.0.0", - "Microsoft.Extensions.Logging": "1.0.0", - "Microsoft.Extensions.Logging.Console": "1.0.0", - "Microsoft.Extensions.Logging.Debug": "1.0.0", - "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", - "Microsoft.AspNetCore.Http": "1.0.0", - "YamlDotNet": "3.9.0" - }, "frameworks": { "netcoreapp1.0": { diff --git a/src/Ocelot/Startup.cs b/src/Ocelot/Startup.cs index 18d5ba6b..5b1fff8e 100644 --- a/src/Ocelot/Startup.cs +++ b/src/Ocelot/Startup.cs @@ -4,6 +4,8 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Ocelot.Library.Infrastructure.DownstreamRouteFinder; +using Ocelot.Library.Infrastructure.Requester; +using Ocelot.Library.Infrastructure.Responder; using Ocelot.Library.Middleware; namespace Ocelot @@ -38,6 +40,8 @@ namespace Ocelot services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. diff --git a/test/Ocelot.AcceptanceTests/OcelotTests.cs b/test/Ocelot.AcceptanceTests/OcelotTests.cs index 6eea27ab..20164ea8 100644 --- a/test/Ocelot.AcceptanceTests/OcelotTests.cs +++ b/test/Ocelot.AcceptanceTests/OcelotTests.cs @@ -20,16 +20,19 @@ namespace Ocelot.AcceptanceTests private TestServer _server; private HttpClient _client; private HttpResponseMessage _response; + private readonly string _configurationPath; public OcelotTests() { + _configurationPath = "./bin/Debug/netcoreapp1.0/configuration.yaml"; _fakeService = new FakeService(); } [Fact] public void should_return_response_404() { - this.Given(x => x.GivenTheApiGatewayIsRunning()) + this.Given(x => x.GivenThereIsAConfiguration(new Configuration())) + .And(x => x.GivenTheApiGatewayIsRunning()) .When(x => x.WhenIRequestTheUrlOnTheApiGateway("/")) .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound)) .BDDfy(); @@ -72,12 +75,12 @@ namespace Ocelot.AcceptanceTests { var serializer = new Serializer(); - if (File.Exists("./configuration.yaml")) + if (File.Exists(_configurationPath)) { - File.Delete("./configuration.yaml"); + File.Delete(_configurationPath); } - using (TextWriter writer = File.CreateText("./configuration.yaml")) + using (TextWriter writer = File.CreateText(_configurationPath)) { serializer.Serialize(writer, configuration); } diff --git a/test/Ocelot.UnitTests/ConfigurationValidationTests.cs b/test/Ocelot.UnitTests/ConfigurationValidationTests.cs index 1a65e3db..615e6e90 100644 --- a/test/Ocelot.UnitTests/ConfigurationValidationTests.cs +++ b/test/Ocelot.UnitTests/ConfigurationValidationTests.cs @@ -58,6 +58,7 @@ namespace Ocelot.UnitTests })) .When(x => x.WhenIValidateTheConfiguration()) .Then(x => x.ThenTheResultIsNotValid()) + .And(x => x.ThenTheErrorIs()) .BDDfy(); } @@ -73,12 +74,17 @@ namespace Ocelot.UnitTests private void ThenTheResultIsValid() { - _result.IsError.ShouldBeFalse(); + _result.Data.IsError.ShouldBeFalse(); } private void ThenTheResultIsNotValid() { - _result.IsError.ShouldBeTrue(); + _result.Data.IsError.ShouldBeTrue(); + } + + private void ThenTheErrorIs() + { + _result.Data.Errors[0].ShouldBeOfType(); } } } diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinderTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinderTests.cs index 212e2029..1f796adb 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinderTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinderTests.cs @@ -35,21 +35,21 @@ namespace Ocelot.UnitTests [Fact] public void should_return_route() { - this.Given(x => x.GivenThereIsAnUpstreamUrlPath("somePath")) + this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath")) .And(x => x.GivenTheConfigurationIs(new Configuration { ReRoutes = new List { new ReRoute() { - UpstreamTemplate = "somePath", - DownstreamTemplate = "somPath" + UpstreamTemplate = "someUpstreamPath", + DownstreamTemplate = "someDownstreamPath" } } })) - .And(x => x.GivenTheUrlMatcherReturns(new UrlMatch(true, new List(), "somePath"))) + .And(x => x.GivenTheUrlMatcherReturns(new UrlMatch(true, new List(), "someDownstreamPath"))) .When(x => x.WhenICallTheFinder()) .Then( - x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List(), "somePath"))) + x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List(), "someDownstreamPath"))) .And(x => x.ThenTheUrlMatcherIsCalledCorrectly()) .BDDfy(); } @@ -117,6 +117,7 @@ namespace Ocelot.UnitTests private void ThenTheFollowingIsReturned(DownstreamRoute expected) { _result.Data.DownstreamUrlTemplate.ShouldBe(expected.DownstreamUrlTemplate); + for (int i = 0; i < _result.Data.TemplateVariableNameAndValues.Count; i++) { _result.Data.TemplateVariableNameAndValues[i].TemplateVariableName.ShouldBe( diff --git a/test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs b/test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs index b280e04f..64bd0a1f 100644 --- a/test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs +++ b/test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs @@ -131,7 +131,7 @@ namespace Ocelot.UnitTests private void WhenIReplaceTheTemplateVariables() { - _result = _downstreamUrlPathReplacer.ReplaceTemplateVariable(_downstreamRoute); + _result = _downstreamUrlPathReplacer.ReplaceTemplateVariables(_downstreamRoute); } private void ThenTheDownstreamUrlPathIsReturned(string expected) From 8423199754103040db3b4c09eae615fe55ccedcd Mon Sep 17 00:00:00 2001 From: TomPallister Date: Tue, 13 Sep 2016 19:34:53 +0100 Subject: [PATCH 031/183] hacking around to get a POST acceptance test working, doesnt really mean anything tbh --- .../Responder/HttpContextResponder.cs | 4 +-- .../Fake/FakeStartup.cs | 9 +++++- test/Ocelot.AcceptanceTests/OcelotTests.cs | 32 +++++++++++++++++-- 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/Ocelot.Library/Infrastructure/Responder/HttpContextResponder.cs b/src/Ocelot.Library/Infrastructure/Responder/HttpContextResponder.cs index a90543fc..fed95e9e 100644 --- a/src/Ocelot.Library/Infrastructure/Responder/HttpContextResponder.cs +++ b/src/Ocelot.Library/Infrastructure/Responder/HttpContextResponder.cs @@ -9,12 +9,12 @@ namespace Ocelot.Library.Infrastructure.Responder { public async Task CreateSuccessResponse(HttpContext context, HttpResponseMessage response) { - if (!response.IsSuccessStatusCode) + if (response.IsSuccessStatusCode) { context.Response.StatusCode = (int)response.StatusCode; + await context.Response.WriteAsync(await response.Content.ReadAsStringAsync()); return context; } - await context.Response.WriteAsync(await response.Content.ReadAsStringAsync()); return context; } diff --git a/test/Ocelot.AcceptanceTests/Fake/FakeStartup.cs b/test/Ocelot.AcceptanceTests/Fake/FakeStartup.cs index 35d5e644..7f8ceaea 100644 --- a/test/Ocelot.AcceptanceTests/Fake/FakeStartup.cs +++ b/test/Ocelot.AcceptanceTests/Fake/FakeStartup.cs @@ -33,7 +33,14 @@ namespace Ocelot.AcceptanceTests.Fake { app.Run(async context => { - await context.Response.WriteAsync("Hello from Laura"); + if (context.Request.Method.ToLower() == "get") + { + await context.Response.WriteAsync("Hello from Laura"); + } + else + { + context.Response.StatusCode = 201; + } }); } } diff --git a/test/Ocelot.AcceptanceTests/OcelotTests.cs b/test/Ocelot.AcceptanceTests/OcelotTests.cs index 20164ea8..41911a4d 100644 --- a/test/Ocelot.AcceptanceTests/OcelotTests.cs +++ b/test/Ocelot.AcceptanceTests/OcelotTests.cs @@ -33,7 +33,7 @@ namespace Ocelot.AcceptanceTests { this.Given(x => x.GivenThereIsAConfiguration(new Configuration())) .And(x => x.GivenTheApiGatewayIsRunning()) - .When(x => x.WhenIRequestTheUrlOnTheApiGateway("/")) + .When(x => x.WhenIGetUrlOnTheApiGateway("/")) .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound)) .BDDfy(); } @@ -54,12 +54,33 @@ namespace Ocelot.AcceptanceTests } })) .And(x => x.GivenTheApiGatewayIsRunning()) - .When(x => x.WhenIRequestTheUrlOnTheApiGateway("/")) + .When(x => x.WhenIGetUrlOnTheApiGateway("/")) .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) .And(x => x.ThenTheResponseBodyShouldBe("Hello from Laura")) .BDDfy(); } + [Fact] + public void should_return_response_201() + { + this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879")) + .And(x => x.GivenThereIsAConfiguration(new Configuration + { + ReRoutes = new List + { + new ReRoute + { + DownstreamTemplate = "http://localhost:51879/", + UpstreamTemplate = "/" + } + } + })) + .And(x => x.GivenTheApiGatewayIsRunning()) + .When(x => x.WhenIPostUrlOnTheApiGateway("/")) + .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.Created)) + .BDDfy(); + } + /// /// This is annoying cos it should be in the constructor but we need to set up the yaml file before calling startup so its a step. /// @@ -91,11 +112,16 @@ namespace Ocelot.AcceptanceTests _fakeService.Start(url); } - private void WhenIRequestTheUrlOnTheApiGateway(string url) + private void WhenIGetUrlOnTheApiGateway(string url) { _response = _client.GetAsync(url).Result; } + private void WhenIPostUrlOnTheApiGateway(string url) + { + _response = _client.PostAsync(url, new StringContent(string.Empty)).Result; + } + private void ThenTheStatusCodeShouldBe(HttpStatusCode expectedHttpStatusCode) { _response.StatusCode.ShouldBe(expectedHttpStatusCode); From 0627e9399be69c7d0a23e3ffb7b7f2593fd571ee Mon Sep 17 00:00:00 2001 From: TomPallister Date: Tue, 13 Sep 2016 20:29:00 +0100 Subject: [PATCH 032/183] brought in flurl and stated adding tests for the requester --- .../Requester/HttpClientHttpRequester.cs | 14 +-- .../Requester/IHttpRequester.cs | 5 +- .../Responder/HttpContextResponder.cs | 2 +- .../Responder/IHttpResponder.cs | 2 +- .../Middleware/ProxyMiddleware.cs | 4 +- .../ConfigurationValidationTests.cs | 10 +- .../DownstreamRouteFinderTests.cs | 21 ++-- .../Requester/RequesterTests.cs | 119 ++++++++++++++++++ .../Responder/ResponderTests.cs | 14 +++ .../UrlPathToUrlTemplateMatcherTests.cs | 5 +- ...eamUrlPathTemplateVariableReplacerTests.cs | 5 +- 11 files changed, 163 insertions(+), 38 deletions(-) rename test/Ocelot.UnitTests/{ => Configuration}/ConfigurationValidationTests.cs (84%) rename test/Ocelot.UnitTests/{ => DownstreamRouteFinder}/DownstreamRouteFinderTests.cs (83%) create mode 100644 test/Ocelot.UnitTests/Requester/RequesterTests.cs create mode 100644 test/Ocelot.UnitTests/Responder/ResponderTests.cs rename test/Ocelot.UnitTests/{ => UrlMatcher}/UrlPathToUrlTemplateMatcherTests.cs (99%) rename test/Ocelot.UnitTests/{ => UrlTemplateReplacer}/UpstreamUrlPathTemplateVariableReplacerTests.cs (98%) diff --git a/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs b/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs index 1b76ba8c..0f3bbbec 100644 --- a/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs +++ b/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs @@ -1,21 +1,17 @@ -using System.Net.Http; +using System.IO; +using System.Net.Http; using System.Threading.Tasks; +using Flurl.Http; namespace Ocelot.Library.Infrastructure.Requester { public class HttpClientHttpRequester : IHttpRequester { - public async Task GetResponse(string httpMethod, string downstreamUrl) + public async Task GetResponse(string httpMethod, string downstreamUrl, Stream content = null) { var method = new HttpMethod(httpMethod); - var httpRequestMessage = new HttpRequestMessage(method, downstreamUrl); - - using (var httpClient = new HttpClient()) - { - var response = await httpClient.SendAsync(httpRequestMessage); - return response; - } + return await downstreamUrl.SendAsync(method, new StreamContent(content)); } } } \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Requester/IHttpRequester.cs b/src/Ocelot.Library/Infrastructure/Requester/IHttpRequester.cs index 310f25b3..9d38cc25 100644 --- a/src/Ocelot.Library/Infrastructure/Requester/IHttpRequester.cs +++ b/src/Ocelot.Library/Infrastructure/Requester/IHttpRequester.cs @@ -1,4 +1,5 @@ -using System.Net.Http; +using System.IO; +using System.Net.Http; using System.Threading.Tasks; using Flurl.Http; @@ -6,6 +7,6 @@ namespace Ocelot.Library.Infrastructure.Requester { public interface IHttpRequester { - Task GetResponse(string httpMethod, string downstreamUrl); + Task GetResponse(string httpMethod, string downstreamUrl, Stream content = null); } } diff --git a/src/Ocelot.Library/Infrastructure/Responder/HttpContextResponder.cs b/src/Ocelot.Library/Infrastructure/Responder/HttpContextResponder.cs index fed95e9e..1569e58a 100644 --- a/src/Ocelot.Library/Infrastructure/Responder/HttpContextResponder.cs +++ b/src/Ocelot.Library/Infrastructure/Responder/HttpContextResponder.cs @@ -7,7 +7,7 @@ namespace Ocelot.Library.Infrastructure.Responder { public class HttpContextResponder : IHttpResponder { - public async Task CreateSuccessResponse(HttpContext context, HttpResponseMessage response) + public async Task CreateResponse(HttpContext context, HttpResponseMessage response) { if (response.IsSuccessStatusCode) { diff --git a/src/Ocelot.Library/Infrastructure/Responder/IHttpResponder.cs b/src/Ocelot.Library/Infrastructure/Responder/IHttpResponder.cs index 3e2dc91b..97bb4995 100644 --- a/src/Ocelot.Library/Infrastructure/Responder/IHttpResponder.cs +++ b/src/Ocelot.Library/Infrastructure/Responder/IHttpResponder.cs @@ -6,7 +6,7 @@ namespace Ocelot.Library.Infrastructure.Responder { public interface IHttpResponder { - Task CreateSuccessResponse(HttpContext context, HttpResponseMessage response); + Task CreateResponse(HttpContext context, HttpResponseMessage response); Task CreateNotFoundResponse(HttpContext context); } diff --git a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs index 31b7c487..9eb93e07 100644 --- a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs +++ b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs @@ -47,9 +47,9 @@ namespace Ocelot.Library.Middleware var downstreamUrl = _urlReplacer.ReplaceTemplateVariables(downstreamRoute.Data); - var response = await _requester.GetResponse(context.Request.Method, downstreamUrl); + var response = await _requester.GetResponse(context.Request.Method, downstreamUrl, context.Request.Body); - context = await _responder.CreateSuccessResponse(context, response); + await _responder.CreateResponse(context, response); await _next.Invoke(context); } diff --git a/test/Ocelot.UnitTests/ConfigurationValidationTests.cs b/test/Ocelot.UnitTests/Configuration/ConfigurationValidationTests.cs similarity index 84% rename from test/Ocelot.UnitTests/ConfigurationValidationTests.cs rename to test/Ocelot.UnitTests/Configuration/ConfigurationValidationTests.cs index 615e6e90..3ddc8d38 100644 --- a/test/Ocelot.UnitTests/ConfigurationValidationTests.cs +++ b/test/Ocelot.UnitTests/Configuration/ConfigurationValidationTests.cs @@ -5,11 +5,11 @@ using Shouldly; using TestStack.BDDfy; using Xunit; -namespace Ocelot.UnitTests +namespace Ocelot.UnitTests.Configuration { public class ConfigurationValidationTests { - private Configuration _configuration; + private Library.Infrastructure.Configuration.Configuration _configuration; private readonly IConfigurationValidator _configurationValidator; private Response _result; @@ -21,7 +21,7 @@ namespace Ocelot.UnitTests [Fact] public void configuration_is_valid_with_one_reroute() { - this.Given(x => x.GivenAConfiguration(new Configuration() + this.Given(x => x.GivenAConfiguration(new Library.Infrastructure.Configuration.Configuration() { ReRoutes = new List { @@ -40,7 +40,7 @@ namespace Ocelot.UnitTests [Fact] public void configuration_is_not_valid_with_duplicate_reroutes() { - this.Given(x => x.GivenAConfiguration(new Configuration() + this.Given(x => x.GivenAConfiguration(new Library.Infrastructure.Configuration.Configuration() { ReRoutes = new List { @@ -62,7 +62,7 @@ namespace Ocelot.UnitTests .BDDfy(); } - private void GivenAConfiguration(Configuration configuration) + private void GivenAConfiguration(Library.Infrastructure.Configuration.Configuration configuration) { _configuration = configuration; } diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinderTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs similarity index 83% rename from test/Ocelot.UnitTests/DownstreamRouteFinderTests.cs rename to test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs index 1f796adb..6d115a66 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinderTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using System.Collections.Generic; using Microsoft.Extensions.Options; using Moq; using Ocelot.Library.Infrastructure.Configuration; @@ -12,31 +9,31 @@ using Shouldly; using TestStack.BDDfy; using Xunit; -namespace Ocelot.UnitTests +namespace Ocelot.UnitTests.DownstreamRouteFinder { public class DownstreamRouteFinderTests { private readonly IDownstreamRouteFinder _downstreamRouteFinder; - private readonly Mock> _mockConfig; + private readonly Mock> _mockConfig; private readonly Mock _mockMatcher; private string _upstreamUrlPath; private Response _result; private Response _response; - private Configuration _configuration; + private Library.Infrastructure.Configuration.Configuration _configuration; private UrlMatch _match; public DownstreamRouteFinderTests() { - _mockConfig = new Mock>(); + _mockConfig = new Mock>(); _mockMatcher = new Mock(); - _downstreamRouteFinder = new DownstreamRouteFinder(_mockConfig.Object, _mockMatcher.Object); + _downstreamRouteFinder = new Library.Infrastructure.DownstreamRouteFinder.DownstreamRouteFinder(_mockConfig.Object, _mockMatcher.Object); } [Fact] public void should_return_route() { this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath")) - .And(x => x.GivenTheConfigurationIs(new Configuration { + .And(x => x.GivenTheConfigurationIs(new Library.Infrastructure.Configuration.Configuration { ReRoutes = new List { new ReRoute() @@ -58,7 +55,7 @@ namespace Ocelot.UnitTests public void should_not_return_route() { this.Given(x => x.GivenThereIsAnUpstreamUrlPath("somePath")) - .And(x => x.GivenTheConfigurationIs(new Configuration + .And(x => x.GivenTheConfigurationIs(new Library.Infrastructure.Configuration.Configuration { ReRoutes = new List { @@ -96,7 +93,7 @@ namespace Ocelot.UnitTests .Returns(_match); } - private void GivenTheConfigurationIs(Configuration configuration) + private void GivenTheConfigurationIs(Library.Infrastructure.Configuration.Configuration configuration) { _configuration = configuration; _mockConfig diff --git a/test/Ocelot.UnitTests/Requester/RequesterTests.cs b/test/Ocelot.UnitTests/Requester/RequesterTests.cs new file mode 100644 index 00000000..dd9d86d4 --- /dev/null +++ b/test/Ocelot.UnitTests/Requester/RequesterTests.cs @@ -0,0 +1,119 @@ +using System; +using System.IO; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using Flurl.Http.Testing; +using Ocelot.Library.Infrastructure.Requester; +using Shouldly; +using TestStack.BDDfy; +using Xunit; + +namespace Ocelot.UnitTests.Requester +{ + public class RequesterTests : IDisposable + { + private readonly IHttpRequester _httpRequester; + private readonly HttpTest _httpTest; + private string _httpMethod; + private string _downstreamUrl; + private HttpResponseMessage _result; + private HttpContent _content; + + public RequesterTests() + { + _httpTest = new HttpTest(); + _httpRequester = new HttpClientHttpRequester(); + } + + [Fact] + public void should_call_downstream_url_correctly() + { + this.Given(x => x.GivenIHaveHttpMethod("GET")) + .And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk")) + .And(x => x.GivenTheDownstreamServerReturns(HttpStatusCode.OK)) + .When(x => x.WhenIMakeARequest()) + .Then(x => x.ThenTheFollowingIsReturned(HttpStatusCode.OK)) + .And(x => x.ThenTheDownstreamServerIsCalledCorrectly()) + .BDDfy(); + } + + [Fact] + public void should_obey_http_method() + { + this.Given(x => x.GivenIHaveHttpMethod("POST")) + .And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk")) + .And(x => x.GivenTheDownstreamServerReturns(HttpStatusCode.Created)) + .When(x => x.WhenIMakeARequest()) + .Then(x => x.ThenTheFollowingIsReturned(HttpStatusCode.Created)) + .And(x => x.ThenTheDownstreamServerIsCalledCorrectly()) + .And(x => x.ThenTheCorrectHttpMethodIsUsed(HttpMethod.Post)) + .BDDfy(); + } + + [Fact] + public void should_forward_http_content() + { + 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.GivenTheDownstreamServerReturns(HttpStatusCode.Created)) + .When(x => x.WhenIMakeARequest()) + .Then(x => x.ThenTheFollowingIsReturned(HttpStatusCode.Created)) + .And(x => x.ThenTheDownstreamServerIsCalledCorrectly()) + .And(x => x.ThenTheCorrectHttpMethodIsUsed(HttpMethod.Post)) + .And(x => x.ThenTheCorrectContentIsUsed(new StringContent("Hi from Tom"))) + .BDDfy(); + } + + private void GivenIHaveTheHttpContent(HttpContent content) + { + _content = content; + } + + private void GivenIHaveHttpMethod(string httpMethod) + { + _httpMethod = httpMethod; + } + + private void GivenIHaveDownstreamUrl(string downstreamUrl) + { + _downstreamUrl = downstreamUrl; + } + + private void GivenTheDownstreamServerReturns(HttpStatusCode statusCode) + { + _httpTest.RespondWith(_content != null ? _content.ReadAsStringAsync().Result : string.Empty, (int)statusCode); + } + + private void WhenIMakeARequest() + { + _result = _httpRequester.GetResponse(_httpMethod, _downstreamUrl, _content != null ? _content.ReadAsStreamAsync().Result : Stream.Null).Result; + } + + private void ThenTheFollowingIsReturned(HttpStatusCode expected) + { + _result.StatusCode.ShouldBe(expected); + } + + private void ThenTheDownstreamServerIsCalledCorrectly() + { + _httpTest.ShouldHaveCalled(_downstreamUrl); + } + + private void ThenTheCorrectHttpMethodIsUsed(HttpMethod expected) + { + _httpTest.CallLog[0].Request.Method.ShouldBe(expected); + } + + private void ThenTheCorrectContentIsUsed(HttpContent content) + { + _httpTest.CallLog[0].Response.Content.ReadAsStringAsync().Result.ShouldBe(content.ReadAsStringAsync().Result); + } + + public void Dispose() + { + _httpTest.Dispose(); + } + } +} diff --git a/test/Ocelot.UnitTests/Responder/ResponderTests.cs b/test/Ocelot.UnitTests/Responder/ResponderTests.cs new file mode 100644 index 00000000..60a20153 --- /dev/null +++ b/test/Ocelot.UnitTests/Responder/ResponderTests.cs @@ -0,0 +1,14 @@ +using Microsoft.AspNetCore.Http; +using Xunit; + +namespace Ocelot.UnitTests.Responder +{ + public class ResponderTests + { + [Fact] + public void should_do_something() + { + + } + } +} diff --git a/test/Ocelot.UnitTests/UrlPathToUrlTemplateMatcherTests.cs b/test/Ocelot.UnitTests/UrlMatcher/UrlPathToUrlTemplateMatcherTests.cs similarity index 99% rename from test/Ocelot.UnitTests/UrlPathToUrlTemplateMatcherTests.cs rename to test/Ocelot.UnitTests/UrlMatcher/UrlPathToUrlTemplateMatcherTests.cs index eb3ff139..c2f64419 100644 --- a/test/Ocelot.UnitTests/UrlPathToUrlTemplateMatcherTests.cs +++ b/test/Ocelot.UnitTests/UrlMatcher/UrlPathToUrlTemplateMatcherTests.cs @@ -2,12 +2,11 @@ using System.Collections.Generic; using System.Linq; using Ocelot.Library.Infrastructure.UrlMatcher; using Shouldly; +using TestStack.BDDfy; using Xunit; -namespace Ocelot.UnitTests +namespace Ocelot.UnitTests.UrlMatcher { - using TestStack.BDDfy; - public class UrlPathToUrlTemplateMatcherTests { private readonly IUrlPathToUrlTemplateMatcher _urlMatcher; diff --git a/test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs b/test/Ocelot.UnitTests/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs similarity index 98% rename from test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs rename to test/Ocelot.UnitTests/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs index 64bd0a1f..ef03aa70 100644 --- a/test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs +++ b/test/Ocelot.UnitTests/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs @@ -3,12 +3,11 @@ using Ocelot.Library.Infrastructure.DownstreamRouteFinder; using Ocelot.Library.Infrastructure.UrlMatcher; using Ocelot.Library.Infrastructure.UrlTemplateReplacer; using Shouldly; +using TestStack.BDDfy; using Xunit; -namespace Ocelot.UnitTests +namespace Ocelot.UnitTests.UrlTemplateReplacer { - using TestStack.BDDfy; - public class UpstreamUrlPathTemplateVariableReplacerTests { private DownstreamRoute _downstreamRoute; From f3128cffe068a60ea267a96b6c3f79c141c42f42 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Wed, 14 Sep 2016 21:18:25 +0100 Subject: [PATCH 033/183] failing pesky test --- .../Requester/HttpClientHttpRequester.cs | 26 ++- .../Requester/IHttpRequester.cs | 9 +- .../Middleware/ProxyMiddleware.cs | 4 +- test/Ocelot.AcceptanceTests/OcelotTests.cs | 10 +- .../Requester/RequesterTests.cs | 160 +++++++++++++++++- 5 files changed, 203 insertions(+), 6 deletions(-) diff --git a/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs b/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs index 0f3bbbec..a43f4f8b 100644 --- a/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs +++ b/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs @@ -1,17 +1,39 @@ using System.IO; using System.Net.Http; using System.Threading.Tasks; +using Flurl; using Flurl.Http; +using Microsoft.AspNetCore.Http; namespace Ocelot.Library.Infrastructure.Requester { public class HttpClientHttpRequester : IHttpRequester { - public async Task GetResponse(string httpMethod, string downstreamUrl, Stream content = null) + public async Task GetResponse( + string httpMethod, + string downstreamUrl, + Stream content, + IHeaderDictionary headers, + IRequestCookieCollection cookies, + IQueryCollection queryString) { var method = new HttpMethod(httpMethod); + var streamContent = new StreamContent(content); - return await downstreamUrl.SendAsync(method, new StreamContent(content)); + if (content.Length > 0) + { + return await downstreamUrl + .SetQueryParams(queryString) + .WithCookies(cookies) + .WithHeaders(streamContent.Headers) + .SendAsync(method, streamContent); + } + + return await downstreamUrl + .SetQueryParams(queryString) + .WithHeaders(headers) + .WithCookies(cookies) + .SendAsync(method, streamContent); } } } \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Requester/IHttpRequester.cs b/src/Ocelot.Library/Infrastructure/Requester/IHttpRequester.cs index 9d38cc25..90ff384a 100644 --- a/src/Ocelot.Library/Infrastructure/Requester/IHttpRequester.cs +++ b/src/Ocelot.Library/Infrastructure/Requester/IHttpRequester.cs @@ -2,11 +2,18 @@ using System.Net.Http; using System.Threading.Tasks; using Flurl.Http; +using Microsoft.AspNetCore.Http; namespace Ocelot.Library.Infrastructure.Requester { public interface IHttpRequester { - Task GetResponse(string httpMethod, string downstreamUrl, Stream content = null); + Task GetResponse( + string httpMethod, + string downstreamUrl, + Stream content, + IHeaderDictionary headers, + IRequestCookieCollection cookies, + IQueryCollection queryString); } } diff --git a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs index 9eb93e07..8749ac29 100644 --- a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs +++ b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs @@ -47,7 +47,9 @@ namespace Ocelot.Library.Middleware var downstreamUrl = _urlReplacer.ReplaceTemplateVariables(downstreamRoute.Data); - var response = await _requester.GetResponse(context.Request.Method, downstreamUrl, context.Request.Body); + var response = await _requester + .GetResponse(context.Request.Method, downstreamUrl, context.Request.Body, + context.Request.Headers, context.Request.Cookies, context.Request.Query); await _responder.CreateResponse(context, response); diff --git a/test/Ocelot.AcceptanceTests/OcelotTests.cs b/test/Ocelot.AcceptanceTests/OcelotTests.cs index 41911a4d..427dab0e 100644 --- a/test/Ocelot.AcceptanceTests/OcelotTests.cs +++ b/test/Ocelot.AcceptanceTests/OcelotTests.cs @@ -21,6 +21,7 @@ namespace Ocelot.AcceptanceTests private HttpClient _client; private HttpResponseMessage _response; private readonly string _configurationPath; + private string _postContent; public OcelotTests() { @@ -76,11 +77,17 @@ namespace Ocelot.AcceptanceTests } })) .And(x => x.GivenTheApiGatewayIsRunning()) + .And(x => x.GivenThePostHasContent("postContent")) .When(x => x.WhenIPostUrlOnTheApiGateway("/")) .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.Created)) .BDDfy(); } + private void GivenThePostHasContent(string postcontent) + { + _postContent = postcontent; + } + /// /// This is annoying cos it should be in the constructor but we need to set up the yaml file before calling startup so its a step. /// @@ -119,7 +126,8 @@ namespace Ocelot.AcceptanceTests private void WhenIPostUrlOnTheApiGateway(string url) { - _response = _client.PostAsync(url, new StringContent(string.Empty)).Result; + var content = new StringContent(_postContent); + _response = _client.PostAsync(url, content).Result; } private void ThenTheStatusCodeShouldBe(HttpStatusCode expectedHttpStatusCode) diff --git a/test/Ocelot.UnitTests/Requester/RequesterTests.cs b/test/Ocelot.UnitTests/Requester/RequesterTests.cs index dd9d86d4..64785665 100644 --- a/test/Ocelot.UnitTests/Requester/RequesterTests.cs +++ b/test/Ocelot.UnitTests/Requester/RequesterTests.cs @@ -1,9 +1,14 @@ using System; +using System.Collections.Generic; using System.IO; +using System.Linq; using System.Net; using System.Net.Http; using System.Threading.Tasks; using Flurl.Http.Testing; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Internal; +using Microsoft.Extensions.Primitives; using Ocelot.Library.Infrastructure.Requester; using Shouldly; using TestStack.BDDfy; @@ -19,6 +24,9 @@ namespace Ocelot.UnitTests.Requester private string _downstreamUrl; private HttpResponseMessage _result; private HttpContent _content; + private IHeaderDictionary _headers; + private IRequestCookieCollection _cookies; + private IQueryCollection _query; public RequesterTests() { @@ -66,6 +74,153 @@ namespace Ocelot.UnitTests.Requester .BDDfy(); } + [Fact] + public void should_forward_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") + { + Headers = + { + {"Boom", "TickTick"} + } + })) + .And(x => x.GivenTheDownstreamServerReturns(HttpStatusCode.Created)) + .When(x => x.WhenIMakeARequest()) + .Then(x => x.ThenTheFollowingIsReturned(HttpStatusCode.Created)) + .And(x => x.ThenTheDownstreamServerIsCalledCorrectly()) + .And(x => x.ThenTheCorrectHttpMethodIsUsed(HttpMethod.Post)) + .And(x => x.ThenTheCorrectContentIsUsed(new StringContent("Hi from Tom") + { + Headers = + { + { "Boom", "TickTick" } + } + })) + .And(x => x.ThenTheCorrectContentHeadersAreUsed(new HeaderDictionary + { + { + "Boom", "TickTick" + } + })) + .BDDfy(); + } + + [Fact] + public void should_forward_headers() + { + this.Given(x => x.GivenIHaveHttpMethod("GET")) + .And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk")) + .And(x => x.GivenTheHttpHeadersAre(new HeaderDictionary + { + {"ChopSticks", "Bubbles" } + })) + .And(x => x.GivenTheDownstreamServerReturns(HttpStatusCode.OK)) + .When(x => x.WhenIMakeARequest()) + .Then(x => x.ThenTheFollowingIsReturned(HttpStatusCode.OK)) + .And(x => x.ThenTheDownstreamServerIsCalledCorrectly()) + .And(x => x.ThenTheCorrectHeadersAreUsed(new HeaderDictionary + { + {"ChopSticks", "Bubbles" } + })) + .BDDfy(); + } + + [Fact] + public void should_forward_cookies() + { + this.Given(x => x.GivenIHaveHttpMethod("GET")) + .And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk")) + .And(x => x.GivenTheCookiesAre(new RequestCookieCollection(new Dictionary + { + { "TheCookie","Monster" } + }))) + .And(x => x.GivenTheDownstreamServerReturns(HttpStatusCode.OK)) + .When(x => x.WhenIMakeARequest()) + .Then(x => x.ThenTheFollowingIsReturned(HttpStatusCode.OK)) + .And(x => x.ThenTheDownstreamServerIsCalledCorrectly()) + .And(x => x.ThenTheCorrectCookiesAreUsed(new RequestCookieCollection(new Dictionary + { + { "TheCookie","Monster" } + }))) + .BDDfy(); + } + + [Fact] + public void should_forward_query_string() + { + this.Given(x => x.GivenIHaveHttpMethod("POST")) + .And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk")) + .And(x => x.GivenTheQueryStringIs(new QueryCollection(new Dictionary + { + { "jeff", "1" }, + { "geoff", "2" } + }))) + .And(x => x.GivenTheDownstreamServerReturns(HttpStatusCode.Created)) + .When(x => x.WhenIMakeARequest()) + .Then(x => x.ThenTheFollowingIsReturned(HttpStatusCode.Created)) + .And(x => x.ThenTheDownstreamServerIsCalledCorrectly()) + .And(x => x.ThenTheCorrectQueryStringIsUsed("?jeff=1&geoff=2")) + .BDDfy(); + } + + private void ThenTheCorrectQueryStringIsUsed(string expected) + { + _httpTest.CallLog[0].Request.RequestUri.Query.ShouldBe(expected); + } + + private void GivenTheQueryStringIs(IQueryCollection query) + { + _query = query; + } + + private void ThenTheCorrectCookiesAreUsed(IRequestCookieCollection cookies) + { + var expectedCookies = cookies.Select(x => new KeyValuePair(x.Key, x.Value)); + + foreach (var expectedCookie in expectedCookies) + { + _httpTest + .CallLog[0] + .Request + .Headers + .ShouldContain(x => x.Key == "Cookie" && x.Value.First() == string.Format("{0}={1}", expectedCookie.Key, expectedCookie.Value)); + } + } + + private void GivenTheCookiesAre(IRequestCookieCollection cookies) + { + _cookies = cookies; + } + + private void ThenTheCorrectHeadersAreUsed(IHeaderDictionary headers) + { + var expectedHeaders = headers.Select(x => new KeyValuePair(x.Key, x.Value)); + + foreach (var expectedHeader in expectedHeaders) + { + _httpTest.CallLog[0].Request.Headers.ShouldContain(x => x.Key == expectedHeader.Key && x.Value.First() == expectedHeader.Value[0]); + } + } + + private void ThenTheCorrectContentHeadersAreUsed(IHeaderDictionary headers) + { + var expectedHeaders = headers.Select(x => new KeyValuePair(x.Key, x.Value)); + + foreach (var expectedHeader in expectedHeaders) + { + _httpTest.CallLog[0].Request.Content.Headers.ShouldContain(x => x.Key == expectedHeader.Key + //&& x.Value.First() == expectedHeader.Value[0] + ); + } + } + + private void GivenTheHttpHeadersAre(IHeaderDictionary headers) + { + _headers = headers; + } + private void GivenIHaveTheHttpContent(HttpContent content) { _content = content; @@ -88,7 +243,10 @@ namespace Ocelot.UnitTests.Requester private void WhenIMakeARequest() { - _result = _httpRequester.GetResponse(_httpMethod, _downstreamUrl, _content != null ? _content.ReadAsStreamAsync().Result : Stream.Null).Result; + _result = _httpRequester + .GetResponse(_httpMethod, _downstreamUrl, + _content != null ? _content.ReadAsStreamAsync().Result : Stream.Null, + _headers, _cookies, _query).Result; } private void ThenTheFollowingIsReturned(HttpStatusCode expected) From 741fcc644d734baa8ec80d2a5b177c4f5d5d7b8a Mon Sep 17 00:00:00 2001 From: TomPallister Date: Mon, 19 Sep 2016 16:26:44 +0100 Subject: [PATCH 034/183] Got the forwarding http content properly tests working, way to much going on in the requester --- .../Requester/HttpClientHttpRequester.cs | 18 ++++++++-- .../Requester/IHttpRequester.cs | 3 +- .../Middleware/ProxyMiddleware.cs | 2 +- test/Ocelot.AcceptanceTests/OcelotTests.cs | 36 +++++++++---------- .../Requester/RequesterTests.cs | 30 +++++++--------- 5 files changed, 49 insertions(+), 40 deletions(-) diff --git a/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs b/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs index a43f4f8b..977526fb 100644 --- a/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs +++ b/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs @@ -1,5 +1,6 @@ using System.IO; using System.Net.Http; +using System.Net.Http.Headers; using System.Threading.Tasks; using Flurl; using Flurl.Http; @@ -15,17 +16,30 @@ namespace Ocelot.Library.Infrastructure.Requester Stream content, IHeaderDictionary headers, IRequestCookieCollection cookies, - IQueryCollection queryString) + IQueryCollection queryString, + string contentType) { var method = new HttpMethod(httpMethod); var streamContent = new StreamContent(content); + if (!string.IsNullOrEmpty(contentType)) + { + var splitCt = contentType.Split(';'); + var cT = splitCt[0]; + streamContent.Headers.ContentType = new MediaTypeHeaderValue(cT); + } + + if (headers != null) + { + headers.Remove("Content-Type"); + } + if (content.Length > 0) { return await downstreamUrl .SetQueryParams(queryString) .WithCookies(cookies) - .WithHeaders(streamContent.Headers) + .WithHeaders(headers) .SendAsync(method, streamContent); } diff --git a/src/Ocelot.Library/Infrastructure/Requester/IHttpRequester.cs b/src/Ocelot.Library/Infrastructure/Requester/IHttpRequester.cs index 90ff384a..eaacbc54 100644 --- a/src/Ocelot.Library/Infrastructure/Requester/IHttpRequester.cs +++ b/src/Ocelot.Library/Infrastructure/Requester/IHttpRequester.cs @@ -14,6 +14,7 @@ namespace Ocelot.Library.Infrastructure.Requester Stream content, IHeaderDictionary headers, IRequestCookieCollection cookies, - IQueryCollection queryString); + IQueryCollection queryString, + string contentType); } } diff --git a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs index 8749ac29..4540b25b 100644 --- a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs +++ b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs @@ -49,7 +49,7 @@ namespace Ocelot.Library.Middleware var response = await _requester .GetResponse(context.Request.Method, downstreamUrl, context.Request.Body, - context.Request.Headers, context.Request.Cookies, context.Request.Query); + context.Request.Headers, context.Request.Cookies, context.Request.Query, context.Request.ContentType); await _responder.CreateResponse(context, response); diff --git a/test/Ocelot.AcceptanceTests/OcelotTests.cs b/test/Ocelot.AcceptanceTests/OcelotTests.cs index 427dab0e..2d2a348b 100644 --- a/test/Ocelot.AcceptanceTests/OcelotTests.cs +++ b/test/Ocelot.AcceptanceTests/OcelotTests.cs @@ -1,19 +1,19 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Http; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.TestHost; +using Ocelot.AcceptanceTests.Fake; +using Ocelot.Library.Infrastructure.Configuration; +using Shouldly; +using TestStack.BDDfy; +using Xunit; +using YamlDotNet.Serialization; + namespace Ocelot.AcceptanceTests { - using System; - using System.Net.Http; - using Microsoft.AspNetCore.Hosting; - using Microsoft.AspNetCore.TestHost; - using Xunit; - using Ocelot.AcceptanceTests.Fake; - using Shouldly; - using System.Collections.Generic; - using System.IO; - using System.Net; - using Library.Infrastructure.Configuration; - using TestStack.BDDfy; - using YamlDotNet.Serialization; - public class OcelotTests : IDisposable { private readonly FakeService _fakeService; @@ -21,7 +21,7 @@ namespace Ocelot.AcceptanceTests private HttpClient _client; private HttpResponseMessage _response; private readonly string _configurationPath; - private string _postContent; + private StringContent _postContent; public OcelotTests() { @@ -82,10 +82,9 @@ namespace Ocelot.AcceptanceTests .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.Created)) .BDDfy(); } - private void GivenThePostHasContent(string postcontent) { - _postContent = postcontent; + _postContent = new StringContent(postcontent); } /// @@ -126,8 +125,7 @@ namespace Ocelot.AcceptanceTests private void WhenIPostUrlOnTheApiGateway(string url) { - var content = new StringContent(_postContent); - _response = _client.PostAsync(url, content).Result; + _response = _client.PostAsync(url, _postContent).Result; } private void ThenTheStatusCodeShouldBe(HttpStatusCode expectedHttpStatusCode) diff --git a/test/Ocelot.UnitTests/Requester/RequesterTests.cs b/test/Ocelot.UnitTests/Requester/RequesterTests.cs index 64785665..9e3b4f61 100644 --- a/test/Ocelot.UnitTests/Requester/RequesterTests.cs +++ b/test/Ocelot.UnitTests/Requester/RequesterTests.cs @@ -27,6 +27,7 @@ namespace Ocelot.UnitTests.Requester private IHeaderDictionary _headers; private IRequestCookieCollection _cookies; private IQueryCollection _query; + private string _contentType; public RequesterTests() { @@ -65,6 +66,7 @@ namespace Ocelot.UnitTests.Requester 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")) .And(x => x.GivenTheDownstreamServerReturns(HttpStatusCode.Created)) .When(x => x.WhenIMakeARequest()) .Then(x => x.ThenTheFollowingIsReturned(HttpStatusCode.Created)) @@ -79,29 +81,18 @@ namespace Ocelot.UnitTests.Requester { this.Given(x => x.GivenIHaveHttpMethod("POST")) .And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk")) - .And(x => x.GivenIHaveTheHttpContent(new StringContent("Hi from Tom") - { - Headers = - { - {"Boom", "TickTick"} - } - })) + .And(x => x.GivenIHaveTheHttpContent(new StringContent("Hi from Tom"))) + .And(x => x.GivenTheContentTypeIs("application/json")) .And(x => x.GivenTheDownstreamServerReturns(HttpStatusCode.Created)) .When(x => x.WhenIMakeARequest()) .Then(x => x.ThenTheFollowingIsReturned(HttpStatusCode.Created)) .And(x => x.ThenTheDownstreamServerIsCalledCorrectly()) .And(x => x.ThenTheCorrectHttpMethodIsUsed(HttpMethod.Post)) - .And(x => x.ThenTheCorrectContentIsUsed(new StringContent("Hi from Tom") - { - Headers = - { - { "Boom", "TickTick" } - } - })) + .And(x => x.ThenTheCorrectContentIsUsed(new StringContent("Hi from Tom"))) .And(x => x.ThenTheCorrectContentHeadersAreUsed(new HeaderDictionary { { - "Boom", "TickTick" + "Content-Type", "application/json" } })) .BDDfy(); @@ -165,6 +156,11 @@ namespace Ocelot.UnitTests.Requester .BDDfy(); } + private void GivenTheContentTypeIs(string contentType) + { + _contentType = contentType; + } + private void ThenTheCorrectQueryStringIsUsed(string expected) { _httpTest.CallLog[0].Request.RequestUri.Query.ShouldBe(expected); @@ -211,7 +207,7 @@ namespace Ocelot.UnitTests.Requester foreach (var expectedHeader in expectedHeaders) { _httpTest.CallLog[0].Request.Content.Headers.ShouldContain(x => x.Key == expectedHeader.Key - //&& x.Value.First() == expectedHeader.Value[0] + && x.Value.First() == expectedHeader.Value[0] ); } } @@ -246,7 +242,7 @@ namespace Ocelot.UnitTests.Requester _result = _httpRequester .GetResponse(_httpMethod, _downstreamUrl, _content != null ? _content.ReadAsStreamAsync().Result : Stream.Null, - _headers, _cookies, _query).Result; + _headers, _cookies, _query, _contentType).Result; } private void ThenTheFollowingIsReturned(HttpStatusCode expected) From 61dbb675c557bdb88f8cc6bad563433b29086dc7 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Thu, 22 Sep 2016 20:52:37 +0100 Subject: [PATCH 035/183] Changed scripts so acceptance tests pass when you run them from root --- build.sh | 6 ++++-- run-tests.sh | 7 ++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/build.sh b/build.sh index 0544184e..1f04f561 100755 --- a/build.sh +++ b/build.sh @@ -8,8 +8,10 @@ dotnet test test/Ocelot.UnitTests/ echo Running Ocelot.AcceptanceTests -dotnet restore test/Ocelot.AcceptanceTests/ -dotnet test test/Ocelot.AcceptanceTests/ +cd test/Ocelot.AcceptanceTests/ +dotnet restore +dotnet test +cd ../../ echo Building Ocelot diff --git a/run-tests.sh b/run-tests.sh index c7922173..c2a65fc7 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -8,7 +8,8 @@ dotnet test test/Ocelot.UnitTests/ echo Running Ocelot.AcceptanceTests -dotnet restore test/Ocelot.AcceptanceTests/ -dotnet test test/Ocelot.AcceptanceTests/ - +cd test/Ocelot.AcceptanceTests/ +dotnet restore +dotnet test +cd ../../ From da1957311b667d98c9fe88c174badabf2ce4aa30 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Thu, 22 Sep 2016 20:52:59 +0100 Subject: [PATCH 036/183] Changed scripts so acceptance tests pass when you run them from root --- Ocelot.sln | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Ocelot.sln b/Ocelot.sln index 4387cd03..73df0502 100644 --- a/Ocelot.sln +++ b/Ocelot.sln @@ -7,9 +7,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{5CFB79B7-C9D EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3FA7C349-DBE8-4904-A2CE-015B8869CE6C}" ProjectSection(SolutionItems) = preProject + build.sh = build.sh global.json = global.json LICENSE.md = LICENSE.md README.md = README.md + run-benchmarks.sh = run-benchmarks.sh + run-tests.sh = run-tests.sh EndProjectSection EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Ocelot", "src\Ocelot\Ocelot.xproj", "{AEC8FB40-B370-48A6-9B38-78E560041F01}" From ab8407e7dc8459571f5f76349c2428f0cb81c687 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Tue, 4 Oct 2016 21:30:16 +0100 Subject: [PATCH 037/183] Now supports the same upstream url by difrenciating by http method. Also broke up the proxy middleware into three seperate pieces that do their thing and stick something into the OWIN context --- .../Infrastructure/Configuration/ReRoute.cs | 1 + .../DownstreamRouteFinder.cs | 8 ++- .../IDownstreamRouteFinder.cs | 2 +- .../DownstreamRouteFinderMiddleware.cs | 40 +++++++++++++ ...wnstreamRouteFinderMiddlewareExtensions.cs | 12 ++++ .../DownstreamUrlCreatorMiddleware.cs | 42 +++++++++++++ ...ownstreamUrlCreatorMiddlewareExtensions.cs | 12 ++++ .../Middleware/HttpRequesterMiddleware.cs | 47 +++++++++++++++ .../HttpRequesterMiddlewareExtensions.cs | 12 ++++ .../Middleware/ProxyExtensions.cs | 12 ---- .../Middleware/ProxyMiddleware.cs | 59 ------------------- src/Ocelot/Startup.cs | 6 +- test/Ocelot.AcceptanceTests/OcelotTests.cs | 6 +- .../Ocelot.AcceptanceTests/configuration.yaml | 1 + .../Requester/RequesterTests.cs | 0 .../DownstreamRouteFinderTests.cs | 46 ++++++++++++++- test/Ocelot.UnitTests/project.json | 3 +- 17 files changed, 227 insertions(+), 82 deletions(-) create mode 100644 src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddleware.cs create mode 100644 src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs create mode 100644 src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddleware.cs create mode 100644 src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs create mode 100644 src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs create mode 100644 src/Ocelot.Library/Middleware/HttpRequesterMiddlewareExtensions.cs delete mode 100644 src/Ocelot.Library/Middleware/ProxyExtensions.cs delete mode 100644 src/Ocelot.Library/Middleware/ProxyMiddleware.cs rename test/Ocelot.UnitTests/{ => Configuration}/Requester/RequesterTests.cs (100%) diff --git a/src/Ocelot.Library/Infrastructure/Configuration/ReRoute.cs b/src/Ocelot.Library/Infrastructure/Configuration/ReRoute.cs index 4c27ec37..12698ed4 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/ReRoute.cs +++ b/src/Ocelot.Library/Infrastructure/Configuration/ReRoute.cs @@ -4,5 +4,6 @@ { public string DownstreamTemplate { get; set; } public string UpstreamTemplate { get; set; } + public string UpstreamHttpMethod { get; set; } } } diff --git a/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRouteFinder.cs b/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRouteFinder.cs index 0cc2f18e..f02000c3 100644 --- a/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRouteFinder.cs +++ b/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRouteFinder.cs @@ -1,4 +1,6 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Linq; using Microsoft.Extensions.Options; using Ocelot.Library.Infrastructure.Responses; using Ocelot.Library.Infrastructure.UrlMatcher; @@ -16,9 +18,9 @@ namespace Ocelot.Library.Infrastructure.DownstreamRouteFinder _urlMatcher = urlMatcher; } - public Response FindDownstreamRoute(string upstreamUrlPath) + public Response FindDownstreamRoute(string upstreamUrlPath, string upstreamHttpMethod) { - foreach (var template in _configuration.Value.ReRoutes) + foreach (var template in _configuration.Value.ReRoutes.Where(r => string.Equals(r.UpstreamHttpMethod, upstreamHttpMethod, StringComparison.CurrentCultureIgnoreCase))) { var urlMatch = _urlMatcher.Match(upstreamUrlPath, template.UpstreamTemplate); diff --git a/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/IDownstreamRouteFinder.cs b/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/IDownstreamRouteFinder.cs index 1394b3af..4b8f7105 100644 --- a/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/IDownstreamRouteFinder.cs +++ b/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/IDownstreamRouteFinder.cs @@ -4,6 +4,6 @@ namespace Ocelot.Library.Infrastructure.DownstreamRouteFinder { public interface IDownstreamRouteFinder { - Response FindDownstreamRoute(string upstreamUrlPath); + Response FindDownstreamRoute(string upstreamUrlPath, string upstreamHttpMethod); } } diff --git a/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddleware.cs b/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddleware.cs new file mode 100644 index 00000000..a4c4738a --- /dev/null +++ b/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddleware.cs @@ -0,0 +1,40 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Ocelot.Library.Infrastructure.DownstreamRouteFinder; +using Ocelot.Library.Infrastructure.Responder; + +namespace Ocelot.Library.Middleware +{ + public class DownstreamRouteFinderMiddleware + { + private readonly RequestDelegate _next; + private readonly IDownstreamRouteFinder _downstreamRouteFinder; + private readonly IHttpResponder _responder; + + public DownstreamRouteFinderMiddleware(RequestDelegate next, + IDownstreamRouteFinder downstreamRouteFinder, + IHttpResponder responder) + { + _next = next; + _downstreamRouteFinder = downstreamRouteFinder; + _responder = responder; + } + + public async Task Invoke(HttpContext context) + { + var upstreamUrlPath = context.Request.Path.ToString(); + + var downstreamRoute = _downstreamRouteFinder.FindDownstreamRoute(upstreamUrlPath, context.Request.Method); + + if (downstreamRoute.IsError) + { + await _responder.CreateNotFoundResponse(context); + return; + } + + context.Items.Add("DownstreamRoute", downstreamRoute.Data); + + await _next.Invoke(context); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs b/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs new file mode 100644 index 00000000..ec454bf4 --- /dev/null +++ b/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs @@ -0,0 +1,12 @@ +using Microsoft.AspNetCore.Builder; + +namespace Ocelot.Library.Middleware +{ + public static class DownstreamRouteFinderMiddlewareExtensions + { + public static IApplicationBuilder UseDownstreamRouteFinderMiddleware(this IApplicationBuilder builder) + { + return builder.UseMiddleware(); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddleware.cs b/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddleware.cs new file mode 100644 index 00000000..30e41802 --- /dev/null +++ b/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddleware.cs @@ -0,0 +1,42 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Ocelot.Library.Infrastructure.DownstreamRouteFinder; +using Ocelot.Library.Infrastructure.UrlTemplateReplacer; + +namespace Ocelot.Library.Middleware +{ + public class DownstreamUrlCreatorMiddleware + { + private readonly RequestDelegate _next; + private readonly IDownstreamUrlTemplateVariableReplacer _urlReplacer; + + public DownstreamUrlCreatorMiddleware(RequestDelegate next, + IDownstreamUrlTemplateVariableReplacer urlReplacer) + { + _next = next; + _urlReplacer = urlReplacer; + } + + public async Task Invoke(HttpContext context) + { + var downstreamRoute = GetDownstreamRouteFromOwinItems(context); + + var downstreamUrl = _urlReplacer.ReplaceTemplateVariables(downstreamRoute); + + context.Items.Add("DownstreamUrl", downstreamUrl); + + await _next.Invoke(context); + } + + private DownstreamRoute GetDownstreamRouteFromOwinItems(HttpContext context) + { + object obj; + DownstreamRoute downstreamRoute = null; + if (context.Items.TryGetValue("DownstreamRoute", out obj)) + { + downstreamRoute = (DownstreamRoute) obj; + } + return downstreamRoute; + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs b/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs new file mode 100644 index 00000000..0ba3e58c --- /dev/null +++ b/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs @@ -0,0 +1,12 @@ +using Microsoft.AspNetCore.Builder; + +namespace Ocelot.Library.Middleware +{ + public static class DownstreamUrlCreatorMiddlewareExtensions + { + public static IApplicationBuilder UserDownstreamUrlCreatorMiddleware(this IApplicationBuilder builder) + { + return builder.UseMiddleware(); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs b/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs new file mode 100644 index 00000000..d2b4b1e1 --- /dev/null +++ b/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs @@ -0,0 +1,47 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Ocelot.Library.Infrastructure.Requester; +using Ocelot.Library.Infrastructure.Responder; + +namespace Ocelot.Library.Middleware +{ + public class HttpRequesterMiddleware + { + private readonly RequestDelegate _next; + private readonly IHttpRequester _requester; + private readonly IHttpResponder _responder; + + public HttpRequesterMiddleware(RequestDelegate next, + IHttpRequester requester, + IHttpResponder responder) + { + _next = next; + _requester = requester; + _responder = responder; + } + + public async Task Invoke(HttpContext context) + { + var downstreamUrl = GetDownstreamUrlFromOwinItems(context); + + var response = await _requester + .GetResponse(context.Request.Method, downstreamUrl, context.Request.Body, + context.Request.Headers, context.Request.Cookies, context.Request.Query, context.Request.ContentType); + + await _responder.CreateResponse(context, response); + + await _next.Invoke(context); + } + + private string GetDownstreamUrlFromOwinItems(HttpContext context) + { + object obj; + string downstreamUrl = null; + if (context.Items.TryGetValue("DownstreamUrl", out obj)) + { + downstreamUrl = (string) obj; + } + return downstreamUrl; + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Middleware/HttpRequesterMiddlewareExtensions.cs b/src/Ocelot.Library/Middleware/HttpRequesterMiddlewareExtensions.cs new file mode 100644 index 00000000..8aead7bc --- /dev/null +++ b/src/Ocelot.Library/Middleware/HttpRequesterMiddlewareExtensions.cs @@ -0,0 +1,12 @@ +using Microsoft.AspNetCore.Builder; + +namespace Ocelot.Library.Middleware +{ + public static class HttpRequesterMiddlewareExtensions + { + public static IApplicationBuilder UseHttpRequesterMiddleware(this IApplicationBuilder builder) + { + return builder.UseMiddleware(); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Middleware/ProxyExtensions.cs b/src/Ocelot.Library/Middleware/ProxyExtensions.cs deleted file mode 100644 index 83777448..00000000 --- a/src/Ocelot.Library/Middleware/ProxyExtensions.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Microsoft.AspNetCore.Builder; - -namespace Ocelot.Library.Middleware -{ - public static class ProxyExtensions - { - public static IApplicationBuilder UseProxy(this IApplicationBuilder builder) - { - return builder.UseMiddleware(); - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs deleted file mode 100644 index 4540b25b..00000000 --- a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Options; -using Ocelot.Library.Infrastructure.Configuration; -using Ocelot.Library.Infrastructure.DownstreamRouteFinder; -using Ocelot.Library.Infrastructure.Requester; -using Ocelot.Library.Infrastructure.Responder; -using Ocelot.Library.Infrastructure.UrlTemplateReplacer; - -namespace Ocelot.Library.Middleware -{ - public class ProxyMiddleware - { - private readonly RequestDelegate _next; - private readonly IDownstreamUrlTemplateVariableReplacer _urlReplacer; - private readonly IOptions _configuration; - private readonly IDownstreamRouteFinder _downstreamRouteFinder; - private readonly IHttpRequester _requester; - private readonly IHttpResponder _responder; - - public ProxyMiddleware(RequestDelegate next, - IDownstreamUrlTemplateVariableReplacer urlReplacer, - IOptions configuration, - IDownstreamRouteFinder downstreamRouteFinder, - IHttpRequester requester, - IHttpResponder responder) - { - _next = next; - _urlReplacer = urlReplacer; - _configuration = configuration; - _downstreamRouteFinder = downstreamRouteFinder; - _requester = requester; - _responder = responder; - } - - public async Task Invoke(HttpContext context) - { - var upstreamUrlPath = context.Request.Path.ToString(); - - var downstreamRoute = _downstreamRouteFinder.FindDownstreamRoute(upstreamUrlPath); - - if (downstreamRoute.IsError) - { - await _responder.CreateNotFoundResponse(context); - return; - } - - var downstreamUrl = _urlReplacer.ReplaceTemplateVariables(downstreamRoute.Data); - - var response = await _requester - .GetResponse(context.Request.Method, downstreamUrl, context.Request.Body, - context.Request.Headers, context.Request.Cookies, context.Request.Query, context.Request.ContentType); - - await _responder.CreateResponse(context, response); - - await _next.Invoke(context); - } - } -} \ No newline at end of file diff --git a/src/Ocelot/Startup.cs b/src/Ocelot/Startup.cs index 5b1fff8e..1142231f 100644 --- a/src/Ocelot/Startup.cs +++ b/src/Ocelot/Startup.cs @@ -51,7 +51,11 @@ namespace Ocelot loggerFactory.AddDebug(); - app.UseProxy(); + app.UseDownstreamRouteFinderMiddleware(); + + app.UserDownstreamUrlCreatorMiddleware(); + + app.UseHttpRequesterMiddleware(); } } } diff --git a/test/Ocelot.AcceptanceTests/OcelotTests.cs b/test/Ocelot.AcceptanceTests/OcelotTests.cs index 2d2a348b..4d57adf2 100644 --- a/test/Ocelot.AcceptanceTests/OcelotTests.cs +++ b/test/Ocelot.AcceptanceTests/OcelotTests.cs @@ -50,7 +50,8 @@ namespace Ocelot.AcceptanceTests new ReRoute { DownstreamTemplate = "http://localhost:51879/", - UpstreamTemplate = "/" + UpstreamTemplate = "/", + UpstreamHttpMethod = "Get" } } })) @@ -72,7 +73,8 @@ namespace Ocelot.AcceptanceTests new ReRoute { DownstreamTemplate = "http://localhost:51879/", - UpstreamTemplate = "/" + UpstreamTemplate = "/", + UpstreamHttpMethod = "Post" } } })) diff --git a/test/Ocelot.AcceptanceTests/configuration.yaml b/test/Ocelot.AcceptanceTests/configuration.yaml index 97b35e41..8dda884b 100644 --- a/test/Ocelot.AcceptanceTests/configuration.yaml +++ b/test/Ocelot.AcceptanceTests/configuration.yaml @@ -1,3 +1,4 @@ ReRoutes: - DownstreamTemplate: http://localhost:51879/ UpstreamTemplate: / + HttpMethod: Get diff --git a/test/Ocelot.UnitTests/Requester/RequesterTests.cs b/test/Ocelot.UnitTests/Configuration/Requester/RequesterTests.cs similarity index 100% rename from test/Ocelot.UnitTests/Requester/RequesterTests.cs rename to test/Ocelot.UnitTests/Configuration/Requester/RequesterTests.cs diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs index 6d115a66..a1c23bee 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs @@ -21,6 +21,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder private Response _response; private Library.Infrastructure.Configuration.Configuration _configuration; private UrlMatch _match; + private string _upstreamHttpMethod; public DownstreamRouteFinderTests() { @@ -39,11 +40,13 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder new ReRoute() { UpstreamTemplate = "someUpstreamPath", - DownstreamTemplate = "someDownstreamPath" + DownstreamTemplate = "someDownstreamPath", + UpstreamHttpMethod = "Get" } } })) .And(x => x.GivenTheUrlMatcherReturns(new UrlMatch(true, new List(), "someDownstreamPath"))) + .And(x => x.GivenTheUpstreamHttpMethodIs("Get")) .When(x => x.WhenICallTheFinder()) .Then( x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List(), "someDownstreamPath"))) @@ -51,6 +54,36 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .BDDfy(); } + [Fact] + public void should_return_correct_route_for_http_verb() + { + this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath")) + .And(x => x.GivenTheConfigurationIs(new Library.Infrastructure.Configuration.Configuration + { + ReRoutes = new List + { + new ReRoute() + { + UpstreamTemplate = "someUpstreamPath", + DownstreamTemplate = "someDownstreamPath", + UpstreamHttpMethod = "Get" + }, + new ReRoute() + { + UpstreamTemplate = "someUpstreamPath", + DownstreamTemplate = "someDownstreamPathForAPost", + UpstreamHttpMethod = "Post" + } + } + })) + .And(x => x.GivenTheUrlMatcherReturns(new UrlMatch(true, new List(), "someDownstreamPathForAPost"))) + .And(x => x.GivenTheUpstreamHttpMethodIs("Post")) + .When(x => x.WhenICallTheFinder()) + .Then( + x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List(), "someDownstreamPathForAPost"))) + .BDDfy(); + } + [Fact] public void should_not_return_route() { @@ -62,11 +95,13 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder new ReRoute() { UpstreamTemplate = "somePath", - DownstreamTemplate = "somPath" + DownstreamTemplate = "somPath", + UpstreamHttpMethod = "Get" } } })) .And(x => x.GivenTheUrlMatcherReturns(new UrlMatch(false, new List(), null))) + .And(x => x.GivenTheUpstreamHttpMethodIs("Get")) .When(x => x.WhenICallTheFinder()) .Then( x => x.ThenAnErrorResponseIsReturned()) @@ -74,6 +109,11 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .BDDfy(); } + private void GivenTheUpstreamHttpMethodIs(string upstreamHttpMethod) + { + _upstreamHttpMethod = upstreamHttpMethod; + } + private void ThenAnErrorResponseIsReturned() { _result.IsError.ShouldBeTrue(); @@ -108,7 +148,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder private void WhenICallTheFinder() { - _result = _downstreamRouteFinder.FindDownstreamRoute(_upstreamUrlPath); + _result = _downstreamRouteFinder.FindDownstreamRoute(_upstreamUrlPath, _upstreamHttpMethod); } private void ThenTheFollowingIsReturned(DownstreamRoute expected) diff --git a/test/Ocelot.UnitTests/project.json b/test/Ocelot.UnitTests/project.json index 7b0acc6e..6e5a6811 100644 --- a/test/Ocelot.UnitTests/project.json +++ b/test/Ocelot.UnitTests/project.json @@ -25,7 +25,8 @@ "Shouldly": "2.8.0", "TestStack.BDDfy": "4.3.1", "YamlDotNet": "3.9.0", - "Moq": "4.6.38-alpha" + "Moq": "4.6.38-alpha", + "Microsoft.AspNetCore.TestHost": "1.0.0" }, "frameworks": { From 229c0878ed0ba5223085250873266a6ce13f4fa9 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Wed, 5 Oct 2016 20:46:00 +0100 Subject: [PATCH 038/183] Added some wrapper around the http context so i can at least pretend to access things from it without casting them --- .../Services/CannotAddDataError.cs | 11 +++ .../Services/CannotFindDataError.cs | 11 +++ .../Services/IRequestDataService.cs | 10 +++ .../Services/RequestDataService.cs | 49 +++++++++++ .../DownstreamRouteFinderMiddleware.cs | 8 +- .../DownstreamUrlCreatorMiddleware.cs | 35 ++++---- .../Middleware/HttpRequesterMiddleware.cs | 27 +++--- src/Ocelot/Startup.cs | 6 ++ .../Services/RequestDataServiceTests.cs | 83 +++++++++++++++++++ 9 files changed, 208 insertions(+), 32 deletions(-) create mode 100644 src/Ocelot.Library/Infrastructure/Services/CannotAddDataError.cs create mode 100644 src/Ocelot.Library/Infrastructure/Services/CannotFindDataError.cs create mode 100644 src/Ocelot.Library/Infrastructure/Services/IRequestDataService.cs create mode 100644 src/Ocelot.Library/Infrastructure/Services/RequestDataService.cs create mode 100644 test/Ocelot.UnitTests/Services/RequestDataServiceTests.cs diff --git a/src/Ocelot.Library/Infrastructure/Services/CannotAddDataError.cs b/src/Ocelot.Library/Infrastructure/Services/CannotAddDataError.cs new file mode 100644 index 00000000..6a05b321 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Services/CannotAddDataError.cs @@ -0,0 +1,11 @@ +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.Services +{ + public class CannotAddDataError : Error + { + public CannotAddDataError(string message) : base(message) + { + } + } +} diff --git a/src/Ocelot.Library/Infrastructure/Services/CannotFindDataError.cs b/src/Ocelot.Library/Infrastructure/Services/CannotFindDataError.cs new file mode 100644 index 00000000..660df5b3 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Services/CannotFindDataError.cs @@ -0,0 +1,11 @@ +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.Services +{ + public class CannotFindDataError : Error + { + public CannotFindDataError(string message) : base(message) + { + } + } +} diff --git a/src/Ocelot.Library/Infrastructure/Services/IRequestDataService.cs b/src/Ocelot.Library/Infrastructure/Services/IRequestDataService.cs new file mode 100644 index 00000000..5af72678 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Services/IRequestDataService.cs @@ -0,0 +1,10 @@ +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.Services +{ + public interface IRequestDataService + { + Response Add(string key, T value); + Response Get(string key); + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Services/RequestDataService.cs b/src/Ocelot.Library/Infrastructure/Services/RequestDataService.cs new file mode 100644 index 00000000..28cd07e3 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Services/RequestDataService.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using Microsoft.AspNetCore.Http; +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.Services +{ + public class RequestDataService : IRequestDataService + { + private readonly IHttpContextAccessor _httpContextAccessor; + + public RequestDataService(IHttpContextAccessor httpContextAccessor) + { + _httpContextAccessor = httpContextAccessor; + } + + public Response Add(string key, T value) + { + try + { + _httpContextAccessor.HttpContext.Items.Add(key, value); + return new OkResponse(); + } + catch (Exception exception) + { + return new ErrorResponse(new List + { + new CannotAddDataError(string.Format($"Unable to add data for key: {key}, exception: {exception.Message}")) + }); + } + } + + public Response Get(string key) + { + object obj; + + if(_httpContextAccessor.HttpContext.Items.TryGetValue(key, out obj)) + { + var data = (T) obj; + return new OkResponse(data); + } + + return new ErrorResponse(new List + { + new CannotFindDataError($"Unable to find data for key: {key}") + }); + } + } +} diff --git a/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddleware.cs b/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddleware.cs index a4c4738a..1b17c124 100644 --- a/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddleware.cs +++ b/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddleware.cs @@ -2,6 +2,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Ocelot.Library.Infrastructure.DownstreamRouteFinder; using Ocelot.Library.Infrastructure.Responder; +using Ocelot.Library.Infrastructure.Services; namespace Ocelot.Library.Middleware { @@ -10,14 +11,17 @@ namespace Ocelot.Library.Middleware private readonly RequestDelegate _next; private readonly IDownstreamRouteFinder _downstreamRouteFinder; private readonly IHttpResponder _responder; + private readonly IRequestDataService _requestDataService; public DownstreamRouteFinderMiddleware(RequestDelegate next, IDownstreamRouteFinder downstreamRouteFinder, - IHttpResponder responder) + IHttpResponder responder, + IRequestDataService requestDataService) { _next = next; _downstreamRouteFinder = downstreamRouteFinder; _responder = responder; + _requestDataService = requestDataService; } public async Task Invoke(HttpContext context) @@ -32,7 +36,7 @@ namespace Ocelot.Library.Middleware return; } - context.Items.Add("DownstreamRoute", downstreamRoute.Data); + _requestDataService.Add("DownstreamRoute", downstreamRoute.Data); await _next.Invoke(context); } diff --git a/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddleware.cs b/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddleware.cs index 30e41802..b8e04ef7 100644 --- a/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddleware.cs +++ b/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddleware.cs @@ -1,6 +1,8 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Ocelot.Library.Infrastructure.DownstreamRouteFinder; +using Ocelot.Library.Infrastructure.Responder; +using Ocelot.Library.Infrastructure.Services; using Ocelot.Library.Infrastructure.UrlTemplateReplacer; namespace Ocelot.Library.Middleware @@ -9,34 +11,35 @@ namespace Ocelot.Library.Middleware { private readonly RequestDelegate _next; private readonly IDownstreamUrlTemplateVariableReplacer _urlReplacer; + private readonly IRequestDataService _requestDataService; + private readonly IHttpResponder _responder; public DownstreamUrlCreatorMiddleware(RequestDelegate next, - IDownstreamUrlTemplateVariableReplacer urlReplacer) + IDownstreamUrlTemplateVariableReplacer urlReplacer, + IRequestDataService requestDataService, + IHttpResponder responder) { _next = next; _urlReplacer = urlReplacer; + _requestDataService = requestDataService; + _responder = responder; } public async Task Invoke(HttpContext context) { - var downstreamRoute = GetDownstreamRouteFromOwinItems(context); + var downstreamRoute = _requestDataService.Get("DownstreamRoute"); - var downstreamUrl = _urlReplacer.ReplaceTemplateVariables(downstreamRoute); - - context.Items.Add("DownstreamUrl", downstreamUrl); - - await _next.Invoke(context); - } - - private DownstreamRoute GetDownstreamRouteFromOwinItems(HttpContext context) - { - object obj; - DownstreamRoute downstreamRoute = null; - if (context.Items.TryGetValue("DownstreamRoute", out obj)) + if (downstreamRoute.IsError) { - downstreamRoute = (DownstreamRoute) obj; + await _responder.CreateNotFoundResponse(context); + return; } - return downstreamRoute; + + var downstreamUrl = _urlReplacer.ReplaceTemplateVariables(downstreamRoute.Data); + + _requestDataService.Add("DownstreamUrl", downstreamUrl); + + await _next.Invoke(context); } } } \ No newline at end of file diff --git a/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs b/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs index d2b4b1e1..f564bca1 100644 --- a/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs +++ b/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs @@ -2,6 +2,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Ocelot.Library.Infrastructure.Requester; using Ocelot.Library.Infrastructure.Responder; +using Ocelot.Library.Infrastructure.Services; namespace Ocelot.Library.Middleware { @@ -10,38 +11,36 @@ namespace Ocelot.Library.Middleware private readonly RequestDelegate _next; private readonly IHttpRequester _requester; private readonly IHttpResponder _responder; + private readonly IRequestDataService _requestDataService; public HttpRequesterMiddleware(RequestDelegate next, IHttpRequester requester, - IHttpResponder responder) + IHttpResponder responder, + IRequestDataService requestDataService) { _next = next; _requester = requester; _responder = responder; + _requestDataService = requestDataService; } public async Task Invoke(HttpContext context) { - var downstreamUrl = GetDownstreamUrlFromOwinItems(context); + var downstreamUrl = _requestDataService.Get("DownstreamUrl"); + + if (downstreamUrl.IsError) + { + await _responder.CreateNotFoundResponse(context); + return; + } var response = await _requester - .GetResponse(context.Request.Method, downstreamUrl, context.Request.Body, + .GetResponse(context.Request.Method, downstreamUrl.Data, context.Request.Body, context.Request.Headers, context.Request.Cookies, context.Request.Query, context.Request.ContentType); await _responder.CreateResponse(context, response); await _next.Invoke(context); } - - private string GetDownstreamUrlFromOwinItems(HttpContext context) - { - object obj; - string downstreamUrl = null; - if (context.Items.TryGetValue("DownstreamUrl", out obj)) - { - downstreamUrl = (string) obj; - } - return downstreamUrl; - } } } \ No newline at end of file diff --git a/src/Ocelot/Startup.cs b/src/Ocelot/Startup.cs index 1142231f..bd592588 100644 --- a/src/Ocelot/Startup.cs +++ b/src/Ocelot/Startup.cs @@ -1,11 +1,13 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Ocelot.Library.Infrastructure.DownstreamRouteFinder; using Ocelot.Library.Infrastructure.Requester; using Ocelot.Library.Infrastructure.Responder; +using Ocelot.Library.Infrastructure.Services; using Ocelot.Library.Middleware; namespace Ocelot @@ -42,6 +44,10 @@ namespace Ocelot services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + + // see this for why we register this as singleton http://stackoverflow.com/questions/37371264/invalidoperationexception-unable-to-resolve-service-for-type-microsoft-aspnetc + services.AddSingleton(); + services.AddScoped(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. diff --git a/test/Ocelot.UnitTests/Services/RequestDataServiceTests.cs b/test/Ocelot.UnitTests/Services/RequestDataServiceTests.cs new file mode 100644 index 00000000..84921c34 --- /dev/null +++ b/test/Ocelot.UnitTests/Services/RequestDataServiceTests.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Moq; +using Ocelot.Library.Infrastructure.Responses; +using Ocelot.Library.Infrastructure.Services; +using Shouldly; +using TestStack.BDDfy; +using Xunit; + +namespace Ocelot.UnitTests.Services +{ + public class RequestDataServiceTests + { + private IRequestDataService _requestDataService; + private IHttpContextAccessor _httpContextAccesor; + private string _key; + private object _toAdd; + private Response _result; + + public RequestDataServiceTests() + { + _httpContextAccesor = new HttpContextAccessor(); + _httpContextAccesor.HttpContext = new DefaultHttpContext(); + _requestDataService = new RequestDataService(_httpContextAccesor); + } + + [Fact] + public void should_add_item() + { + this.Given(x => x.GivenIHaveAnItemToAdd("blahh", new [] {1,2,3,4})) + .When(x => x.WhenIAddTheItem()) + .Then(x => x.ThenTheItemIsAdded()) + .BDDfy(); + } + + [Fact] + public void should_get_item() + { + this.Given(x => x.GivenThereIsAnItemInTheContext("chest")) + .When(x => x.WhenIGetTheItem()) + .Then(x => x.ThenTheItemIsReturned()) + .BDDfy(); + } + + private void ThenTheItemIsReturned() + { + _result.IsError.ShouldBeFalse(); + _result.Data.ShouldNotBeNull(); + } + + private void WhenIGetTheItem() + { + _result = _requestDataService.Get(_key); + } + + private void GivenThereIsAnItemInTheContext(string key) + { + _key = key; + var data = new[] {5435345}; + _httpContextAccesor.HttpContext.Items.Add(key, data); + } + + private void GivenIHaveAnItemToAdd(string key, object toAdd) + { + _key = key; + _toAdd = toAdd; + } + + private void WhenIAddTheItem() + { + _requestDataService.Add(_key, _toAdd); + } + + private void ThenTheItemIsAdded() + { + object obj; + _httpContextAccesor.HttpContext.Items.TryGetValue(_key, out obj).ShouldBeTrue(); + } + } +} From f505fd6e90de91d12183ef3f1feba298a8bd6683 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Wed, 5 Oct 2016 20:49:22 +0100 Subject: [PATCH 039/183] renamed from service to repository, makes more sense i guess --- ...ice.cs => IScopedRequestDataRepository.cs} | 2 +- ...vice.cs => ScopedRequestDataRepository.cs} | 4 ++-- .../DownstreamRouteFinderMiddleware.cs | 8 ++++---- .../DownstreamUrlCreatorMiddleware.cs | 10 +++++----- .../Middleware/HttpRequesterMiddleware.cs | 8 ++++---- src/Ocelot/Startup.cs | 2 +- ...cs => ScopedRequestDataRepositoryTests.cs} | 19 +++++++------------ 7 files changed, 24 insertions(+), 29 deletions(-) rename src/Ocelot.Library/Infrastructure/Services/{IRequestDataService.cs => IScopedRequestDataRepository.cs} (79%) rename src/Ocelot.Library/Infrastructure/Services/{RequestDataService.cs => ScopedRequestDataRepository.cs} (89%) rename test/Ocelot.UnitTests/Services/{RequestDataServiceTests.cs => ScopedRequestDataRepositoryTests.cs} (79%) diff --git a/src/Ocelot.Library/Infrastructure/Services/IRequestDataService.cs b/src/Ocelot.Library/Infrastructure/Services/IScopedRequestDataRepository.cs similarity index 79% rename from src/Ocelot.Library/Infrastructure/Services/IRequestDataService.cs rename to src/Ocelot.Library/Infrastructure/Services/IScopedRequestDataRepository.cs index 5af72678..cb5e60a9 100644 --- a/src/Ocelot.Library/Infrastructure/Services/IRequestDataService.cs +++ b/src/Ocelot.Library/Infrastructure/Services/IScopedRequestDataRepository.cs @@ -2,7 +2,7 @@ using Ocelot.Library.Infrastructure.Responses; namespace Ocelot.Library.Infrastructure.Services { - public interface IRequestDataService + public interface IScopedRequestDataRepository { Response Add(string key, T value); Response Get(string key); diff --git a/src/Ocelot.Library/Infrastructure/Services/RequestDataService.cs b/src/Ocelot.Library/Infrastructure/Services/ScopedRequestDataRepository.cs similarity index 89% rename from src/Ocelot.Library/Infrastructure/Services/RequestDataService.cs rename to src/Ocelot.Library/Infrastructure/Services/ScopedRequestDataRepository.cs index 28cd07e3..71d94659 100644 --- a/src/Ocelot.Library/Infrastructure/Services/RequestDataService.cs +++ b/src/Ocelot.Library/Infrastructure/Services/ScopedRequestDataRepository.cs @@ -5,11 +5,11 @@ using Ocelot.Library.Infrastructure.Responses; namespace Ocelot.Library.Infrastructure.Services { - public class RequestDataService : IRequestDataService + public class ScopedRequestDataRepository : IScopedRequestDataRepository { private readonly IHttpContextAccessor _httpContextAccessor; - public RequestDataService(IHttpContextAccessor httpContextAccessor) + public ScopedRequestDataRepository(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; } diff --git a/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddleware.cs b/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddleware.cs index 1b17c124..28afbfe1 100644 --- a/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddleware.cs +++ b/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddleware.cs @@ -11,17 +11,17 @@ namespace Ocelot.Library.Middleware private readonly RequestDelegate _next; private readonly IDownstreamRouteFinder _downstreamRouteFinder; private readonly IHttpResponder _responder; - private readonly IRequestDataService _requestDataService; + private readonly IScopedRequestDataRepository _scopedRequestDataRepository; public DownstreamRouteFinderMiddleware(RequestDelegate next, IDownstreamRouteFinder downstreamRouteFinder, IHttpResponder responder, - IRequestDataService requestDataService) + IScopedRequestDataRepository scopedRequestDataRepository) { _next = next; _downstreamRouteFinder = downstreamRouteFinder; _responder = responder; - _requestDataService = requestDataService; + _scopedRequestDataRepository = scopedRequestDataRepository; } public async Task Invoke(HttpContext context) @@ -36,7 +36,7 @@ namespace Ocelot.Library.Middleware return; } - _requestDataService.Add("DownstreamRoute", downstreamRoute.Data); + _scopedRequestDataRepository.Add("DownstreamRoute", downstreamRoute.Data); await _next.Invoke(context); } diff --git a/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddleware.cs b/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddleware.cs index b8e04ef7..d69ae887 100644 --- a/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddleware.cs +++ b/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddleware.cs @@ -11,23 +11,23 @@ namespace Ocelot.Library.Middleware { private readonly RequestDelegate _next; private readonly IDownstreamUrlTemplateVariableReplacer _urlReplacer; - private readonly IRequestDataService _requestDataService; + private readonly IScopedRequestDataRepository _scopedRequestDataRepository; private readonly IHttpResponder _responder; public DownstreamUrlCreatorMiddleware(RequestDelegate next, IDownstreamUrlTemplateVariableReplacer urlReplacer, - IRequestDataService requestDataService, + IScopedRequestDataRepository scopedRequestDataRepository, IHttpResponder responder) { _next = next; _urlReplacer = urlReplacer; - _requestDataService = requestDataService; + _scopedRequestDataRepository = scopedRequestDataRepository; _responder = responder; } public async Task Invoke(HttpContext context) { - var downstreamRoute = _requestDataService.Get("DownstreamRoute"); + var downstreamRoute = _scopedRequestDataRepository.Get("DownstreamRoute"); if (downstreamRoute.IsError) { @@ -37,7 +37,7 @@ namespace Ocelot.Library.Middleware var downstreamUrl = _urlReplacer.ReplaceTemplateVariables(downstreamRoute.Data); - _requestDataService.Add("DownstreamUrl", downstreamUrl); + _scopedRequestDataRepository.Add("DownstreamUrl", downstreamUrl); await _next.Invoke(context); } diff --git a/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs b/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs index f564bca1..b154276f 100644 --- a/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs +++ b/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs @@ -11,22 +11,22 @@ namespace Ocelot.Library.Middleware private readonly RequestDelegate _next; private readonly IHttpRequester _requester; private readonly IHttpResponder _responder; - private readonly IRequestDataService _requestDataService; + private readonly IScopedRequestDataRepository _scopedRequestDataRepository; public HttpRequesterMiddleware(RequestDelegate next, IHttpRequester requester, IHttpResponder responder, - IRequestDataService requestDataService) + IScopedRequestDataRepository scopedRequestDataRepository) { _next = next; _requester = requester; _responder = responder; - _requestDataService = requestDataService; + _scopedRequestDataRepository = scopedRequestDataRepository; } public async Task Invoke(HttpContext context) { - var downstreamUrl = _requestDataService.Get("DownstreamUrl"); + var downstreamUrl = _scopedRequestDataRepository.Get("DownstreamUrl"); if (downstreamUrl.IsError) { diff --git a/src/Ocelot/Startup.cs b/src/Ocelot/Startup.cs index bd592588..7645a3db 100644 --- a/src/Ocelot/Startup.cs +++ b/src/Ocelot/Startup.cs @@ -47,7 +47,7 @@ namespace Ocelot // see this for why we register this as singleton http://stackoverflow.com/questions/37371264/invalidoperationexception-unable-to-resolve-service-for-type-microsoft-aspnetc services.AddSingleton(); - services.AddScoped(); + services.AddScoped(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. diff --git a/test/Ocelot.UnitTests/Services/RequestDataServiceTests.cs b/test/Ocelot.UnitTests/Services/ScopedRequestDataRepositoryTests.cs similarity index 79% rename from test/Ocelot.UnitTests/Services/RequestDataServiceTests.cs rename to test/Ocelot.UnitTests/Services/ScopedRequestDataRepositoryTests.cs index 84921c34..4b07437e 100644 --- a/test/Ocelot.UnitTests/Services/RequestDataServiceTests.cs +++ b/test/Ocelot.UnitTests/Services/ScopedRequestDataRepositoryTests.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using Moq; +using Microsoft.AspNetCore.Http; using Ocelot.Library.Infrastructure.Responses; using Ocelot.Library.Infrastructure.Services; using Shouldly; @@ -12,19 +7,19 @@ using Xunit; namespace Ocelot.UnitTests.Services { - public class RequestDataServiceTests + public class ScopedRequestDataRepositoryTests { - private IRequestDataService _requestDataService; + private IScopedRequestDataRepository _scopedRequestDataRepository; private IHttpContextAccessor _httpContextAccesor; private string _key; private object _toAdd; private Response _result; - public RequestDataServiceTests() + public ScopedRequestDataRepositoryTests() { _httpContextAccesor = new HttpContextAccessor(); _httpContextAccesor.HttpContext = new DefaultHttpContext(); - _requestDataService = new RequestDataService(_httpContextAccesor); + _scopedRequestDataRepository = new ScopedRequestDataRepository(_httpContextAccesor); } [Fact] @@ -53,7 +48,7 @@ namespace Ocelot.UnitTests.Services private void WhenIGetTheItem() { - _result = _requestDataService.Get(_key); + _result = _scopedRequestDataRepository.Get(_key); } private void GivenThereIsAnItemInTheContext(string key) @@ -71,7 +66,7 @@ namespace Ocelot.UnitTests.Services private void WhenIAddTheItem() { - _requestDataService.Add(_key, _toAdd); + _scopedRequestDataRepository.Add(_key, _toAdd); } private void ThenTheItemIsAdded() From d86a52c1b8b3fe2ccd2fe2a467e66bb28f3671b4 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Wed, 5 Oct 2016 20:51:02 +0100 Subject: [PATCH 040/183] renamed from service to repository, makes more sense i guess --- .../{Services => Repository}/CannotAddDataError.cs | 2 +- .../{Services => Repository}/CannotFindDataError.cs | 2 +- .../{Services => Repository}/IScopedRequestDataRepository.cs | 2 +- .../{Services => Repository}/ScopedRequestDataRepository.cs | 2 +- .../Middleware/DownstreamRouteFinderMiddleware.cs | 2 +- .../Middleware/DownstreamUrlCreatorMiddleware.cs | 2 +- src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs | 2 +- src/Ocelot/Startup.cs | 2 +- .../ScopedRequestDataRepositoryTests.cs | 4 ++-- 9 files changed, 10 insertions(+), 10 deletions(-) rename src/Ocelot.Library/Infrastructure/{Services => Repository}/CannotAddDataError.cs (79%) rename src/Ocelot.Library/Infrastructure/{Services => Repository}/CannotFindDataError.cs (79%) rename src/Ocelot.Library/Infrastructure/{Services => Repository}/IScopedRequestDataRepository.cs (79%) rename src/Ocelot.Library/Infrastructure/{Services => Repository}/ScopedRequestDataRepository.cs (96%) rename test/Ocelot.UnitTests/{Services => Repository}/ScopedRequestDataRepositoryTests.cs (96%) diff --git a/src/Ocelot.Library/Infrastructure/Services/CannotAddDataError.cs b/src/Ocelot.Library/Infrastructure/Repository/CannotAddDataError.cs similarity index 79% rename from src/Ocelot.Library/Infrastructure/Services/CannotAddDataError.cs rename to src/Ocelot.Library/Infrastructure/Repository/CannotAddDataError.cs index 6a05b321..ea9d9b75 100644 --- a/src/Ocelot.Library/Infrastructure/Services/CannotAddDataError.cs +++ b/src/Ocelot.Library/Infrastructure/Repository/CannotAddDataError.cs @@ -1,6 +1,6 @@ using Ocelot.Library.Infrastructure.Responses; -namespace Ocelot.Library.Infrastructure.Services +namespace Ocelot.Library.Infrastructure.Repository { public class CannotAddDataError : Error { diff --git a/src/Ocelot.Library/Infrastructure/Services/CannotFindDataError.cs b/src/Ocelot.Library/Infrastructure/Repository/CannotFindDataError.cs similarity index 79% rename from src/Ocelot.Library/Infrastructure/Services/CannotFindDataError.cs rename to src/Ocelot.Library/Infrastructure/Repository/CannotFindDataError.cs index 660df5b3..41699f12 100644 --- a/src/Ocelot.Library/Infrastructure/Services/CannotFindDataError.cs +++ b/src/Ocelot.Library/Infrastructure/Repository/CannotFindDataError.cs @@ -1,6 +1,6 @@ using Ocelot.Library.Infrastructure.Responses; -namespace Ocelot.Library.Infrastructure.Services +namespace Ocelot.Library.Infrastructure.Repository { public class CannotFindDataError : Error { diff --git a/src/Ocelot.Library/Infrastructure/Services/IScopedRequestDataRepository.cs b/src/Ocelot.Library/Infrastructure/Repository/IScopedRequestDataRepository.cs similarity index 79% rename from src/Ocelot.Library/Infrastructure/Services/IScopedRequestDataRepository.cs rename to src/Ocelot.Library/Infrastructure/Repository/IScopedRequestDataRepository.cs index cb5e60a9..b88605d6 100644 --- a/src/Ocelot.Library/Infrastructure/Services/IScopedRequestDataRepository.cs +++ b/src/Ocelot.Library/Infrastructure/Repository/IScopedRequestDataRepository.cs @@ -1,6 +1,6 @@ using Ocelot.Library.Infrastructure.Responses; -namespace Ocelot.Library.Infrastructure.Services +namespace Ocelot.Library.Infrastructure.Repository { public interface IScopedRequestDataRepository { diff --git a/src/Ocelot.Library/Infrastructure/Services/ScopedRequestDataRepository.cs b/src/Ocelot.Library/Infrastructure/Repository/ScopedRequestDataRepository.cs similarity index 96% rename from src/Ocelot.Library/Infrastructure/Services/ScopedRequestDataRepository.cs rename to src/Ocelot.Library/Infrastructure/Repository/ScopedRequestDataRepository.cs index 71d94659..f49de35b 100644 --- a/src/Ocelot.Library/Infrastructure/Services/ScopedRequestDataRepository.cs +++ b/src/Ocelot.Library/Infrastructure/Repository/ScopedRequestDataRepository.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using Microsoft.AspNetCore.Http; using Ocelot.Library.Infrastructure.Responses; -namespace Ocelot.Library.Infrastructure.Services +namespace Ocelot.Library.Infrastructure.Repository { public class ScopedRequestDataRepository : IScopedRequestDataRepository { diff --git a/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddleware.cs b/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddleware.cs index 28afbfe1..eff4b94e 100644 --- a/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddleware.cs +++ b/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddleware.cs @@ -1,8 +1,8 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Ocelot.Library.Infrastructure.DownstreamRouteFinder; +using Ocelot.Library.Infrastructure.Repository; using Ocelot.Library.Infrastructure.Responder; -using Ocelot.Library.Infrastructure.Services; namespace Ocelot.Library.Middleware { diff --git a/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddleware.cs b/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddleware.cs index d69ae887..ed0f330d 100644 --- a/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddleware.cs +++ b/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddleware.cs @@ -1,8 +1,8 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Ocelot.Library.Infrastructure.DownstreamRouteFinder; +using Ocelot.Library.Infrastructure.Repository; using Ocelot.Library.Infrastructure.Responder; -using Ocelot.Library.Infrastructure.Services; using Ocelot.Library.Infrastructure.UrlTemplateReplacer; namespace Ocelot.Library.Middleware diff --git a/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs b/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs index b154276f..bc767a22 100644 --- a/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs +++ b/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs @@ -1,8 +1,8 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; +using Ocelot.Library.Infrastructure.Repository; using Ocelot.Library.Infrastructure.Requester; using Ocelot.Library.Infrastructure.Responder; -using Ocelot.Library.Infrastructure.Services; namespace Ocelot.Library.Middleware { diff --git a/src/Ocelot/Startup.cs b/src/Ocelot/Startup.cs index 7645a3db..17f68c6c 100644 --- a/src/Ocelot/Startup.cs +++ b/src/Ocelot/Startup.cs @@ -5,9 +5,9 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Ocelot.Library.Infrastructure.DownstreamRouteFinder; +using Ocelot.Library.Infrastructure.Repository; using Ocelot.Library.Infrastructure.Requester; using Ocelot.Library.Infrastructure.Responder; -using Ocelot.Library.Infrastructure.Services; using Ocelot.Library.Middleware; namespace Ocelot diff --git a/test/Ocelot.UnitTests/Services/ScopedRequestDataRepositoryTests.cs b/test/Ocelot.UnitTests/Repository/ScopedRequestDataRepositoryTests.cs similarity index 96% rename from test/Ocelot.UnitTests/Services/ScopedRequestDataRepositoryTests.cs rename to test/Ocelot.UnitTests/Repository/ScopedRequestDataRepositoryTests.cs index 4b07437e..3236521d 100644 --- a/test/Ocelot.UnitTests/Services/ScopedRequestDataRepositoryTests.cs +++ b/test/Ocelot.UnitTests/Repository/ScopedRequestDataRepositoryTests.cs @@ -1,11 +1,11 @@ using Microsoft.AspNetCore.Http; +using Ocelot.Library.Infrastructure.Repository; using Ocelot.Library.Infrastructure.Responses; -using Ocelot.Library.Infrastructure.Services; using Shouldly; using TestStack.BDDfy; using Xunit; -namespace Ocelot.UnitTests.Services +namespace Ocelot.UnitTests.Repository { public class ScopedRequestDataRepositoryTests { From 27f012135d5abc14ca9cc6204fdec9be2afb7f4f Mon Sep 17 00:00:00 2001 From: TomPallister Date: Wed, 5 Oct 2016 21:35:54 +0100 Subject: [PATCH 041/183] deloyed to azure web apps but not working because flurl is a bit wonky...will probably revert to http client --- README.md | 2 + src/Ocelot/configuration.yaml | 4 + src/Ocelot/project.json | 116 ++++++++++-------- .../Ocelot.AcceptanceTests/configuration.yaml | 2 +- 4 files changed, 69 insertions(+), 55 deletions(-) create mode 100644 src/Ocelot/configuration.yaml diff --git a/README.md b/README.md index b507c955..8ea56778 100644 --- a/README.md +++ b/README.md @@ -26,3 +26,5 @@ Priorities - Logging - Rate Limiting - Then a big list of cool things... + +## How to use diff --git a/src/Ocelot/configuration.yaml b/src/Ocelot/configuration.yaml new file mode 100644 index 00000000..04ac7018 --- /dev/null +++ b/src/Ocelot/configuration.yaml @@ -0,0 +1,4 @@ +ReRoutes: +- DownstreamTemplate: http://www.bbc.co.uk + UpstreamTemplate: / + UpstreamHttpMethod: Get diff --git a/src/Ocelot/project.json b/src/Ocelot/project.json index d77d3493..5a1d73de 100644 --- a/src/Ocelot/project.json +++ b/src/Ocelot/project.json @@ -1,59 +1,67 @@ { - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.0.0", - "type": "platform" + "version": "1.0.0-*", + + "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.0.0", + "type": "platform" + }, + "Microsoft.AspNetCore.Mvc": "1.0.0", + "Microsoft.AspNetCore.Http": "1.0.0", + "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", + "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", + "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0", + "Microsoft.Extensions.Configuration.Json": "1.0.0", + "Microsoft.Extensions.Logging": "1.0.0", + "Microsoft.Extensions.Logging.Console": "1.0.0", + "Microsoft.Extensions.Logging.Debug": "1.0.0", + "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", + "Ocelot.Library": "1.0.0-*", + "NetEscapades.Configuration.Yaml": "1.1.0" }, - "Microsoft.AspNetCore.Mvc": "1.0.0", - "Microsoft.AspNetCore.Http": "1.0.0", - "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", - "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", - "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", - "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0", - "Microsoft.Extensions.Configuration.Json": "1.0.0", - "Microsoft.Extensions.Logging": "1.0.0", - "Microsoft.Extensions.Logging.Console": "1.0.0", - "Microsoft.Extensions.Logging.Debug": "1.0.0", - "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", - "Ocelot.Library": "1.0.0-*", - "NetEscapades.Configuration.Yaml": "1.1.0" - }, - "tools": { - "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final" - }, + "tools": { + "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final" + }, - "frameworks": { - "netcoreapp1.0": { - "imports": [ - "dotnet5.6", - "portable-net45+win8" - ] + "frameworks": { + "netcoreapp1.0": { + "imports": [ + "dotnet5.6", + "portable-net45+win8" + ] + } + }, + + "buildOptions": { + "emitEntryPoint": true, + "preserveCompilationContext": true, + "copyToOutput": { + "include": [ + "configuration.yaml" + ] + } + }, + + "runtimeOptions": { + "configProperties": { + "System.GC.Server": true + } + }, + + "publishOptions": { + "include": [ + "wwwroot", + "Views", + "Areas/**/Views", + "appsettings.json", + "web.config", + "configuration.yaml" + ] + }, + + "scripts": { + "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ] + } } - }, - - "buildOptions": { - "emitEntryPoint": true, - "preserveCompilationContext": true - }, - - "runtimeOptions": { - "configProperties": { - "System.GC.Server": true - } - }, - - "publishOptions": { - "include": [ - "wwwroot", - "Views", - "Areas/**/Views", - "appsettings.json", - "web.config" - ] - }, - - "scripts": { - "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ] - } -} diff --git a/test/Ocelot.AcceptanceTests/configuration.yaml b/test/Ocelot.AcceptanceTests/configuration.yaml index 8dda884b..7a2db711 100644 --- a/test/Ocelot.AcceptanceTests/configuration.yaml +++ b/test/Ocelot.AcceptanceTests/configuration.yaml @@ -1,4 +1,4 @@ ReRoutes: - DownstreamTemplate: http://localhost:51879/ UpstreamTemplate: / - HttpMethod: Get + UpstreamHttpMethod: Get From 3a18de036d30c5559fe854e6592e9f38dbded0d4 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Wed, 5 Oct 2016 21:36:58 +0100 Subject: [PATCH 042/183] updated readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 8ea56778..8494c6ff 100644 --- a/README.md +++ b/README.md @@ -28,3 +28,5 @@ Priorities - Then a big list of cool things... ## How to use + +TBC.... \ No newline at end of file From 74a7f5d2701c93dc69669d20491e623aa4316cdf Mon Sep 17 00:00:00 2001 From: "tom.pallister" Date: Thu, 6 Oct 2016 21:18:12 +0100 Subject: [PATCH 043/183] ripping out flurl...sorry flurl --- .../HttpClient/HttpClientWrapper.cs | 210 ++++++++++++++++++ .../Infrastructure/HttpClient/IHttpClient.cs | 49 ++++ .../RequestBuilder/IRequestBuilder.cs | 17 ++ .../RequestBuilder/RequestBuilder.cs | 49 ++++ .../Requester/HttpClientHttpRequester.cs | 53 +---- .../Requester/IHttpRequester.cs | 14 +- .../Middleware/HttpRequesterMiddleware.cs | 14 +- src/Ocelot.Library/project.json | 5 +- src/Ocelot/Startup.cs | 6 + .../Configuration/Requester/RequesterTests.cs | 82 ++++--- 10 files changed, 406 insertions(+), 93 deletions(-) create mode 100644 src/Ocelot.Library/Infrastructure/HttpClient/HttpClientWrapper.cs create mode 100644 src/Ocelot.Library/Infrastructure/HttpClient/IHttpClient.cs create mode 100644 src/Ocelot.Library/Infrastructure/RequestBuilder/IRequestBuilder.cs create mode 100644 src/Ocelot.Library/Infrastructure/RequestBuilder/RequestBuilder.cs diff --git a/src/Ocelot.Library/Infrastructure/HttpClient/HttpClientWrapper.cs b/src/Ocelot.Library/Infrastructure/HttpClient/HttpClientWrapper.cs new file mode 100644 index 00000000..9a08eb1c --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/HttpClient/HttpClientWrapper.cs @@ -0,0 +1,210 @@ +namespace Ocelot.Library.Infrastructure.HttpClient +{ + using System; + using System.IO; + using System.Net.Http; + using System.Net.Http.Headers; + using System.Threading; + using System.Threading.Tasks; + + public class HttpClientWrapper : IHttpClient + { + private readonly HttpClient _httpClient; + + public HttpClientWrapper(HttpClient httpClient) + { + _httpClient = httpClient; + } + + public void Dispose() + { + _httpClient.Dispose(); + } + + public Uri BaseAddress + { + get { return _httpClient.BaseAddress; } + set { _httpClient.BaseAddress = value; } + } + + public HttpRequestHeaders DefaultRequestHeaders + { + get { return _httpClient.DefaultRequestHeaders; } + } + + public long MaxResponseContentBufferSize + { + get { return _httpClient.MaxResponseContentBufferSize; } + set { _httpClient.MaxResponseContentBufferSize = value; } + } + + public TimeSpan Timeout + { + get { return _httpClient.Timeout; } + set { _httpClient.Timeout = value; } + } + + public void CancelPendingRequests() + { + _httpClient.CancelPendingRequests(); + } + + public async Task DeleteAsync(string requestUri) + { + return await _httpClient.DeleteAsync(requestUri); + } + + public async Task DeleteAsync(Uri requestUri) + { + return await _httpClient.DeleteAsync(requestUri); + } + + public async Task DeleteAsync(Uri requestUri, CancellationToken cancellationToken) + { + return await _httpClient.DeleteAsync(requestUri, cancellationToken); + } + + public async Task DeleteAsync(string requestUri, CancellationToken cancellationToken) + { + return await _httpClient.DeleteAsync(requestUri, cancellationToken); + } + + public async Task GetAsync(string requestUri) + { + return await _httpClient.GetAsync(requestUri); + } + + public async Task GetAsync(Uri requestUri) + { + return await _httpClient.GetAsync(requestUri); + } + + public async Task GetAsync(string requestUri, HttpCompletionOption completionOption) + { + return await _httpClient.GetAsync(requestUri, completionOption); + } + + public async Task GetAsync(string requestUri, CancellationToken cancellationToken) + { + return await _httpClient.GetAsync(requestUri, cancellationToken); + } + + public async Task GetAsync(Uri requestUri, HttpCompletionOption completionOption) + { + return await _httpClient.GetAsync(requestUri, completionOption); + } + + public async Task GetAsync(Uri requestUri, CancellationToken cancellationToken) + { + return await _httpClient.GetAsync(requestUri, cancellationToken); + } + + public async Task GetAsync(string requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken) + { + return await _httpClient.GetAsync(requestUri, completionOption, cancellationToken); + } + + public async Task GetAsync(Uri requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken) + { + return await _httpClient.GetAsync(requestUri, completionOption, cancellationToken); + } + + public async Task GetByteArrayAsync(string requestUri) + { + return await _httpClient.GetByteArrayAsync(requestUri); + } + + public async Task GetByteArrayAsync(Uri requestUri) + { + return await _httpClient.GetByteArrayAsync(requestUri); + } + + public async Task GetStreamAsync(string requestUri) + { + return await _httpClient.GetStreamAsync(requestUri); + } + + public async Task GetStreamAsync(Uri requestUri) + { + return await _httpClient.GetStreamAsync(requestUri); + } + + public async Task GetStringAsync(string requestUri) + { + return await _httpClient.GetStringAsync(requestUri); + } + + public async Task GetStringAsync(Uri requestUri) + { + return await _httpClient.GetStringAsync(requestUri); + } + + public async Task PostAsync(string requestUri, HttpContent content) + { + return await _httpClient.PostAsync(requestUri, content); + } + + public async Task PostAsync(Uri requestUri, HttpContent content) + { + return await _httpClient.PostAsync(requestUri, content); + } + + public async Task PostAsync(string requestUri, HttpContent content, CancellationToken cancellationToken) + { + return await _httpClient.PostAsync(requestUri, content, cancellationToken); + } + + public async Task PostAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken) + { + return await _httpClient.PostAsync(requestUri, content, cancellationToken); + } + + public async Task PutAsync(string requestUri, HttpContent content) + { + return await _httpClient.PutAsync(requestUri, content); + } + + public async Task PutAsync(Uri requestUri, HttpContent content) + { + return await _httpClient.PutAsync(requestUri, content); + } + + public async Task PutAsync(string requestUri, HttpContent content, CancellationToken cancellationToken) + { + return await _httpClient.PutAsync(requestUri, content, cancellationToken); + } + + public async Task PutAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken) + { + return await _httpClient.PutAsync(requestUri, content, cancellationToken); + } + + public async Task SendAsync(HttpRequestMessage request) + { + return await _httpClient.SendAsync(request); + } + + public async Task SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption) + { + return await _httpClient.SendAsync(request, completionOption); + } + + public async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + return await _httpClient.SendAsync(request, cancellationToken); + } + + public async Task SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken) + { + return await _httpClient.SendAsync(request, completionOption, cancellationToken); + } + + public void Dispose(bool disposing) + { + if (!disposing) + { + _httpClient.Dispose(); + } + } + } +} diff --git a/src/Ocelot.Library/Infrastructure/HttpClient/IHttpClient.cs b/src/Ocelot.Library/Infrastructure/HttpClient/IHttpClient.cs new file mode 100644 index 00000000..b74a4246 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/HttpClient/IHttpClient.cs @@ -0,0 +1,49 @@ +namespace Ocelot.Library.Infrastructure.HttpClient +{ + using System; + using System.IO; + using System.Net.Http; + using System.Net.Http.Headers; + using System.Threading; + using System.Threading.Tasks; + + public interface IHttpClient + { + Uri BaseAddress { get; set; } + HttpRequestHeaders DefaultRequestHeaders { get; } + long MaxResponseContentBufferSize { get; set; } + TimeSpan Timeout { get; set; } + void CancelPendingRequests(); + Task DeleteAsync(string requestUri); + Task DeleteAsync(Uri requestUri); + Task DeleteAsync(Uri requestUri, CancellationToken cancellationToken); + Task DeleteAsync(string requestUri, CancellationToken cancellationToken); + Task GetAsync(string requestUri); + Task GetAsync(Uri requestUri); + Task GetAsync(string requestUri, HttpCompletionOption completionOption); + Task GetAsync(string requestUri, CancellationToken cancellationToken); + Task GetAsync(Uri requestUri, HttpCompletionOption completionOption); + Task GetAsync(Uri requestUri, CancellationToken cancellationToken); + Task GetAsync(string requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken); + Task GetAsync(Uri requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken); + Task GetByteArrayAsync(string requestUri); + Task GetByteArrayAsync(Uri requestUri); + Task GetStreamAsync(string requestUri); + Task GetStreamAsync(Uri requestUri); + Task GetStringAsync(string requestUri); + Task GetStringAsync(Uri requestUri); + Task PostAsync(string requestUri, HttpContent content); + Task PostAsync(Uri requestUri, HttpContent content); + Task PostAsync(string requestUri, HttpContent content, CancellationToken cancellationToken); + Task PostAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken); + Task PutAsync(string requestUri, HttpContent content); + Task PutAsync(Uri requestUri, HttpContent content); + Task PutAsync(string requestUri, HttpContent content, CancellationToken cancellationToken); + Task PutAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken); + Task SendAsync(HttpRequestMessage request); + Task SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption); + Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken); + Task SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken); + void Dispose(bool disposing); + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/RequestBuilder/IRequestBuilder.cs b/src/Ocelot.Library/Infrastructure/RequestBuilder/IRequestBuilder.cs new file mode 100644 index 00000000..5bb6e27d --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/RequestBuilder/IRequestBuilder.cs @@ -0,0 +1,17 @@ +namespace Ocelot.Library.Infrastructure.RequestBuilder +{ + using System.IO; + using System.Net.Http; + using Microsoft.AspNetCore.Http; + + public interface IRequestBuilder + { + HttpRequestMessage Build(string httpMethod, + string downstreamUrl, + Stream content, + IHeaderDictionary headers, + IRequestCookieCollection cookies, + IQueryCollection queryString, + string contentType); + } +} diff --git a/src/Ocelot.Library/Infrastructure/RequestBuilder/RequestBuilder.cs b/src/Ocelot.Library/Infrastructure/RequestBuilder/RequestBuilder.cs new file mode 100644 index 00000000..578b60b5 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/RequestBuilder/RequestBuilder.cs @@ -0,0 +1,49 @@ +namespace Ocelot.Library.Infrastructure.RequestBuilder +{ + using System; + using System.IO; + using System.Net.Http; + using System.Net.Http.Headers; + using Microsoft.AspNetCore.Http; + + public class RequestBuilder : IRequestBuilder + { + public HttpRequestMessage Build(string httpMethod, string downstreamUrl, Stream content, IHeaderDictionary headers, + IRequestCookieCollection cookies, IQueryCollection queryString, string contentType) + { + var method = new HttpMethod(httpMethod); + + var uri = new Uri(downstreamUrl + queryString); + + var httpRequestMessage = new HttpRequestMessage(method, uri) + { + Content = new StreamContent(content), + }; + + if (!string.IsNullOrEmpty(contentType)) + { + var splitCt = contentType.Split(';'); + var cT = splitCt[0]; + httpRequestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue(cT); + } + + //todo get rid of if + if (headers != null) + { + headers.Remove("Content-Type"); + } + + //todo get rid of if + if (headers != null) + { + foreach (var header in headers) + { + httpRequestMessage.Headers.Add(header.Key, header.Value.ToArray()); + } + } + + return httpRequestMessage; + + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs b/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs index 977526fb..b2a14c7e 100644 --- a/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs +++ b/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs @@ -1,53 +1,22 @@ -using System.IO; -using System.Net.Http; -using System.Net.Http.Headers; +using System.Net.Http; using System.Threading.Tasks; -using Flurl; -using Flurl.Http; -using Microsoft.AspNetCore.Http; namespace Ocelot.Library.Infrastructure.Requester { + using HttpClient; + public class HttpClientHttpRequester : IHttpRequester { - public async Task GetResponse( - string httpMethod, - string downstreamUrl, - Stream content, - IHeaderDictionary headers, - IRequestCookieCollection cookies, - IQueryCollection queryString, - string contentType) + private readonly IHttpClient _httpClient; + + public HttpClientHttpRequester(IHttpClient httpClient) { - var method = new HttpMethod(httpMethod); - var streamContent = new StreamContent(content); + _httpClient = httpClient; + } - if (!string.IsNullOrEmpty(contentType)) - { - var splitCt = contentType.Split(';'); - var cT = splitCt[0]; - streamContent.Headers.ContentType = new MediaTypeHeaderValue(cT); - } - - if (headers != null) - { - headers.Remove("Content-Type"); - } - - if (content.Length > 0) - { - return await downstreamUrl - .SetQueryParams(queryString) - .WithCookies(cookies) - .WithHeaders(headers) - .SendAsync(method, streamContent); - } - - return await downstreamUrl - .SetQueryParams(queryString) - .WithHeaders(headers) - .WithCookies(cookies) - .SendAsync(method, streamContent); + public async Task GetResponse(HttpRequestMessage httpRequestMessage) + { + return await _httpClient.SendAsync(httpRequestMessage); } } } \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Requester/IHttpRequester.cs b/src/Ocelot.Library/Infrastructure/Requester/IHttpRequester.cs index eaacbc54..2a426d52 100644 --- a/src/Ocelot.Library/Infrastructure/Requester/IHttpRequester.cs +++ b/src/Ocelot.Library/Infrastructure/Requester/IHttpRequester.cs @@ -1,20 +1,10 @@ -using System.IO; -using System.Net.Http; +using System.Net.Http; using System.Threading.Tasks; -using Flurl.Http; -using Microsoft.AspNetCore.Http; namespace Ocelot.Library.Infrastructure.Requester { public interface IHttpRequester { - Task GetResponse( - string httpMethod, - string downstreamUrl, - Stream content, - IHeaderDictionary headers, - IRequestCookieCollection cookies, - IQueryCollection queryString, - string contentType); + Task GetResponse(HttpRequestMessage httpRequestMessage); } } diff --git a/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs b/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs index bc767a22..4521e858 100644 --- a/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs +++ b/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs @@ -6,22 +6,27 @@ using Ocelot.Library.Infrastructure.Responder; namespace Ocelot.Library.Middleware { + using Infrastructure.RequestBuilder; + public class HttpRequesterMiddleware { private readonly RequestDelegate _next; private readonly IHttpRequester _requester; private readonly IHttpResponder _responder; private readonly IScopedRequestDataRepository _scopedRequestDataRepository; + private readonly IRequestBuilder _requestBuilder; public HttpRequesterMiddleware(RequestDelegate next, IHttpRequester requester, IHttpResponder responder, - IScopedRequestDataRepository scopedRequestDataRepository) + IScopedRequestDataRepository scopedRequestDataRepository, + IRequestBuilder requestBuilder) { _next = next; _requester = requester; _responder = responder; _scopedRequestDataRepository = scopedRequestDataRepository; + _requestBuilder = requestBuilder; } public async Task Invoke(HttpContext context) @@ -34,9 +39,12 @@ namespace Ocelot.Library.Middleware return; } + var request = _requestBuilder + .Build(context.Request.Method, downstreamUrl.Data, context.Request.Body, + context.Request.Headers, context.Request.Cookies, context.Request.Query, context.Request.ContentType); + var response = await _requester - .GetResponse(context.Request.Method, downstreamUrl.Data, context.Request.Body, - context.Request.Headers, context.Request.Cookies, context.Request.Query, context.Request.ContentType); + .GetResponse(request); await _responder.CreateResponse(context, response); diff --git a/src/Ocelot.Library/project.json b/src/Ocelot.Library/project.json index 07d34181..b3d22c5c 100644 --- a/src/Ocelot.Library/project.json +++ b/src/Ocelot.Library/project.json @@ -1,4 +1,4 @@ -{ +{ "version": "1.0.0-*", "dependencies": { @@ -17,8 +17,7 @@ "Microsoft.Extensions.Logging.Debug": "1.0.0", "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", "Microsoft.AspNetCore.Http": "1.0.0", - "YamlDotNet": "3.9.0", - "Flurl.Http": "1.0.1" + "YamlDotNet": "3.9.0" }, "frameworks": { diff --git a/src/Ocelot/Startup.cs b/src/Ocelot/Startup.cs index 17f68c6c..71d329a5 100644 --- a/src/Ocelot/Startup.cs +++ b/src/Ocelot/Startup.cs @@ -12,7 +12,10 @@ using Ocelot.Library.Middleware; namespace Ocelot { + using System.Net.Http; using Library.Infrastructure.Configuration; + using Library.Infrastructure.HttpClient; + using Library.Infrastructure.RequestBuilder; using Library.Infrastructure.UrlMatcher; using Library.Infrastructure.UrlTemplateReplacer; @@ -44,6 +47,9 @@ namespace Ocelot services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddTransient(); + services.AddTransient(); + services.AddSingleton(); // see this for why we register this as singleton http://stackoverflow.com/questions/37371264/invalidoperationexception-unable-to-resolve-service-for-type-microsoft-aspnetc services.AddSingleton(); diff --git a/test/Ocelot.UnitTests/Configuration/Requester/RequesterTests.cs b/test/Ocelot.UnitTests/Configuration/Requester/RequesterTests.cs index 9e3b4f61..46708773 100644 --- a/test/Ocelot.UnitTests/Configuration/Requester/RequesterTests.cs +++ b/test/Ocelot.UnitTests/Configuration/Requester/RequesterTests.cs @@ -1,11 +1,8 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Net.Http; -using System.Threading.Tasks; -using Flurl.Http.Testing; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Internal; using Microsoft.Extensions.Primitives; @@ -16,10 +13,13 @@ using Xunit; namespace Ocelot.UnitTests.Requester { - public class RequesterTests : IDisposable + using System; + using Library.Infrastructure.HttpClient; + using Moq; + + public class RequesterTests { private readonly IHttpRequester _httpRequester; - private readonly HttpTest _httpTest; private string _httpMethod; private string _downstreamUrl; private HttpResponseMessage _result; @@ -28,11 +28,12 @@ namespace Ocelot.UnitTests.Requester private IRequestCookieCollection _cookies; private IQueryCollection _query; private string _contentType; + private Mock _httpClient; public RequesterTests() { - _httpTest = new HttpTest(); - _httpRequester = new HttpClientHttpRequester(); + _httpClient = new Mock(); + _httpRequester = new HttpClientHttpRequester(_httpClient.Object); } [Fact] @@ -163,7 +164,8 @@ namespace Ocelot.UnitTests.Requester private void ThenTheCorrectQueryStringIsUsed(string expected) { - _httpTest.CallLog[0].Request.RequestUri.Query.ShouldBe(expected); + throw new NotImplementedException(); + //_httpTest.CallLog[0].Request.RequestUri.Query.ShouldBe(expected); } private void GivenTheQueryStringIs(IQueryCollection query) @@ -173,16 +175,18 @@ namespace Ocelot.UnitTests.Requester private void ThenTheCorrectCookiesAreUsed(IRequestCookieCollection cookies) { - var expectedCookies = cookies.Select(x => new KeyValuePair(x.Key, x.Value)); + throw new NotImplementedException(); - foreach (var expectedCookie in expectedCookies) - { - _httpTest - .CallLog[0] - .Request - .Headers - .ShouldContain(x => x.Key == "Cookie" && x.Value.First() == string.Format("{0}={1}", expectedCookie.Key, expectedCookie.Value)); - } + /* var expectedCookies = cookies.Select(x => new KeyValuePair(x.Key, x.Value)); + + foreach (var expectedCookie in expectedCookies) + { + _httpTest + .CallLog[0] + .Request + .Headers + .ShouldContain(x => x.Key == "Cookie" && x.Value.First() == string.Format("{0}={1}", expectedCookie.Key, expectedCookie.Value)); + }*/ } private void GivenTheCookiesAre(IRequestCookieCollection cookies) @@ -192,24 +196,28 @@ namespace Ocelot.UnitTests.Requester private void ThenTheCorrectHeadersAreUsed(IHeaderDictionary headers) { - var expectedHeaders = headers.Select(x => new KeyValuePair(x.Key, x.Value)); + throw new NotImplementedException(); + + /*var expectedHeaders = headers.Select(x => new KeyValuePair(x.Key, x.Value)); foreach (var expectedHeader in expectedHeaders) { _httpTest.CallLog[0].Request.Headers.ShouldContain(x => x.Key == expectedHeader.Key && x.Value.First() == expectedHeader.Value[0]); - } + }*/ } private void ThenTheCorrectContentHeadersAreUsed(IHeaderDictionary headers) { - var expectedHeaders = headers.Select(x => new KeyValuePair(x.Key, x.Value)); + throw new NotImplementedException(); + + /*var expectedHeaders = headers.Select(x => new KeyValuePair(x.Key, x.Value)); foreach (var expectedHeader in expectedHeaders) { _httpTest.CallLog[0].Request.Content.Headers.ShouldContain(x => x.Key == expectedHeader.Key && x.Value.First() == expectedHeader.Value[0] ); - } + }*/ } private void GivenTheHttpHeadersAre(IHeaderDictionary headers) @@ -234,15 +242,22 @@ namespace Ocelot.UnitTests.Requester private void GivenTheDownstreamServerReturns(HttpStatusCode statusCode) { - _httpTest.RespondWith(_content != null ? _content.ReadAsStringAsync().Result : string.Empty, (int)statusCode); + _httpClient + .Setup(x => x.SendAsync(It.IsAny())) + .ReturnsAsync(new HttpResponseMessage() + { + StatusCode = statusCode, + Content = _content != null ? _content : null + + }); + /* _httpTest + .RespondWith(_content != null ? _content.ReadAsStringAsync().Result : string.Empty, (int)statusCode);*/ } private void WhenIMakeARequest() { _result = _httpRequester - .GetResponse(_httpMethod, _downstreamUrl, - _content != null ? _content.ReadAsStreamAsync().Result : Stream.Null, - _headers, _cookies, _query, _contentType).Result; + .GetResponse(new HttpRequestMessage()).Result; } private void ThenTheFollowingIsReturned(HttpStatusCode expected) @@ -252,22 +267,23 @@ namespace Ocelot.UnitTests.Requester private void ThenTheDownstreamServerIsCalledCorrectly() { - _httpTest.ShouldHaveCalled(_downstreamUrl); + throw new NotImplementedException(); + + //_httpTest.ShouldHaveCalled(_downstreamUrl); } private void ThenTheCorrectHttpMethodIsUsed(HttpMethod expected) { - _httpTest.CallLog[0].Request.Method.ShouldBe(expected); + throw new NotImplementedException(); + + //_httpTest.CallLog[0].Request.Method.ShouldBe(expected); } private void ThenTheCorrectContentIsUsed(HttpContent content) { - _httpTest.CallLog[0].Response.Content.ReadAsStringAsync().Result.ShouldBe(content.ReadAsStringAsync().Result); - } + throw new NotImplementedException(); - public void Dispose() - { - _httpTest.Dispose(); + //_httpTest.CallLog[0].Response.Content.ReadAsStringAsync().Result.ShouldBe(content.ReadAsStringAsync().Result); } } } From 8688c1eb6f8edb14a088e90759a3c6445406bee9 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Fri, 7 Oct 2016 12:54:50 +0100 Subject: [PATCH 044/183] removed flurl and made a request creator --- .../HttpClient/HttpClientWrapper.cs | 210 ------------- .../Infrastructure/HttpClient/IHttpClient.cs | 49 --- .../RequestBuilder/IRequestBuilder.cs | 13 +- .../Infrastructure/RequestBuilder/Request.cs | 17 ++ .../RequestBuilder/RequestBuilder.cs | 42 ++- .../Requester/HttpClientHttpRequester.cs | 18 +- .../Requester/IHttpRequester.cs | 3 +- .../Middleware/HttpRequesterMiddleware.cs | 2 +- src/Ocelot/Startup.cs | 13 +- .../Configuration/Requester/RequesterTests.cs | 289 ------------------ .../RequestBuilder/RequestBuilderTests.cs | 224 ++++++++++++++ 11 files changed, 289 insertions(+), 591 deletions(-) delete mode 100644 src/Ocelot.Library/Infrastructure/HttpClient/HttpClientWrapper.cs delete mode 100644 src/Ocelot.Library/Infrastructure/HttpClient/IHttpClient.cs create mode 100644 src/Ocelot.Library/Infrastructure/RequestBuilder/Request.cs delete mode 100644 test/Ocelot.UnitTests/Configuration/Requester/RequesterTests.cs create mode 100644 test/Ocelot.UnitTests/RequestBuilder/RequestBuilderTests.cs diff --git a/src/Ocelot.Library/Infrastructure/HttpClient/HttpClientWrapper.cs b/src/Ocelot.Library/Infrastructure/HttpClient/HttpClientWrapper.cs deleted file mode 100644 index 9a08eb1c..00000000 --- a/src/Ocelot.Library/Infrastructure/HttpClient/HttpClientWrapper.cs +++ /dev/null @@ -1,210 +0,0 @@ -namespace Ocelot.Library.Infrastructure.HttpClient -{ - using System; - using System.IO; - using System.Net.Http; - using System.Net.Http.Headers; - using System.Threading; - using System.Threading.Tasks; - - public class HttpClientWrapper : IHttpClient - { - private readonly HttpClient _httpClient; - - public HttpClientWrapper(HttpClient httpClient) - { - _httpClient = httpClient; - } - - public void Dispose() - { - _httpClient.Dispose(); - } - - public Uri BaseAddress - { - get { return _httpClient.BaseAddress; } - set { _httpClient.BaseAddress = value; } - } - - public HttpRequestHeaders DefaultRequestHeaders - { - get { return _httpClient.DefaultRequestHeaders; } - } - - public long MaxResponseContentBufferSize - { - get { return _httpClient.MaxResponseContentBufferSize; } - set { _httpClient.MaxResponseContentBufferSize = value; } - } - - public TimeSpan Timeout - { - get { return _httpClient.Timeout; } - set { _httpClient.Timeout = value; } - } - - public void CancelPendingRequests() - { - _httpClient.CancelPendingRequests(); - } - - public async Task DeleteAsync(string requestUri) - { - return await _httpClient.DeleteAsync(requestUri); - } - - public async Task DeleteAsync(Uri requestUri) - { - return await _httpClient.DeleteAsync(requestUri); - } - - public async Task DeleteAsync(Uri requestUri, CancellationToken cancellationToken) - { - return await _httpClient.DeleteAsync(requestUri, cancellationToken); - } - - public async Task DeleteAsync(string requestUri, CancellationToken cancellationToken) - { - return await _httpClient.DeleteAsync(requestUri, cancellationToken); - } - - public async Task GetAsync(string requestUri) - { - return await _httpClient.GetAsync(requestUri); - } - - public async Task GetAsync(Uri requestUri) - { - return await _httpClient.GetAsync(requestUri); - } - - public async Task GetAsync(string requestUri, HttpCompletionOption completionOption) - { - return await _httpClient.GetAsync(requestUri, completionOption); - } - - public async Task GetAsync(string requestUri, CancellationToken cancellationToken) - { - return await _httpClient.GetAsync(requestUri, cancellationToken); - } - - public async Task GetAsync(Uri requestUri, HttpCompletionOption completionOption) - { - return await _httpClient.GetAsync(requestUri, completionOption); - } - - public async Task GetAsync(Uri requestUri, CancellationToken cancellationToken) - { - return await _httpClient.GetAsync(requestUri, cancellationToken); - } - - public async Task GetAsync(string requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken) - { - return await _httpClient.GetAsync(requestUri, completionOption, cancellationToken); - } - - public async Task GetAsync(Uri requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken) - { - return await _httpClient.GetAsync(requestUri, completionOption, cancellationToken); - } - - public async Task GetByteArrayAsync(string requestUri) - { - return await _httpClient.GetByteArrayAsync(requestUri); - } - - public async Task GetByteArrayAsync(Uri requestUri) - { - return await _httpClient.GetByteArrayAsync(requestUri); - } - - public async Task GetStreamAsync(string requestUri) - { - return await _httpClient.GetStreamAsync(requestUri); - } - - public async Task GetStreamAsync(Uri requestUri) - { - return await _httpClient.GetStreamAsync(requestUri); - } - - public async Task GetStringAsync(string requestUri) - { - return await _httpClient.GetStringAsync(requestUri); - } - - public async Task GetStringAsync(Uri requestUri) - { - return await _httpClient.GetStringAsync(requestUri); - } - - public async Task PostAsync(string requestUri, HttpContent content) - { - return await _httpClient.PostAsync(requestUri, content); - } - - public async Task PostAsync(Uri requestUri, HttpContent content) - { - return await _httpClient.PostAsync(requestUri, content); - } - - public async Task PostAsync(string requestUri, HttpContent content, CancellationToken cancellationToken) - { - return await _httpClient.PostAsync(requestUri, content, cancellationToken); - } - - public async Task PostAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken) - { - return await _httpClient.PostAsync(requestUri, content, cancellationToken); - } - - public async Task PutAsync(string requestUri, HttpContent content) - { - return await _httpClient.PutAsync(requestUri, content); - } - - public async Task PutAsync(Uri requestUri, HttpContent content) - { - return await _httpClient.PutAsync(requestUri, content); - } - - public async Task PutAsync(string requestUri, HttpContent content, CancellationToken cancellationToken) - { - return await _httpClient.PutAsync(requestUri, content, cancellationToken); - } - - public async Task PutAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken) - { - return await _httpClient.PutAsync(requestUri, content, cancellationToken); - } - - public async Task SendAsync(HttpRequestMessage request) - { - return await _httpClient.SendAsync(request); - } - - public async Task SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption) - { - return await _httpClient.SendAsync(request, completionOption); - } - - public async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) - { - return await _httpClient.SendAsync(request, cancellationToken); - } - - public async Task SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken) - { - return await _httpClient.SendAsync(request, completionOption, cancellationToken); - } - - public void Dispose(bool disposing) - { - if (!disposing) - { - _httpClient.Dispose(); - } - } - } -} diff --git a/src/Ocelot.Library/Infrastructure/HttpClient/IHttpClient.cs b/src/Ocelot.Library/Infrastructure/HttpClient/IHttpClient.cs deleted file mode 100644 index b74a4246..00000000 --- a/src/Ocelot.Library/Infrastructure/HttpClient/IHttpClient.cs +++ /dev/null @@ -1,49 +0,0 @@ -namespace Ocelot.Library.Infrastructure.HttpClient -{ - using System; - using System.IO; - using System.Net.Http; - using System.Net.Http.Headers; - using System.Threading; - using System.Threading.Tasks; - - public interface IHttpClient - { - Uri BaseAddress { get; set; } - HttpRequestHeaders DefaultRequestHeaders { get; } - long MaxResponseContentBufferSize { get; set; } - TimeSpan Timeout { get; set; } - void CancelPendingRequests(); - Task DeleteAsync(string requestUri); - Task DeleteAsync(Uri requestUri); - Task DeleteAsync(Uri requestUri, CancellationToken cancellationToken); - Task DeleteAsync(string requestUri, CancellationToken cancellationToken); - Task GetAsync(string requestUri); - Task GetAsync(Uri requestUri); - Task GetAsync(string requestUri, HttpCompletionOption completionOption); - Task GetAsync(string requestUri, CancellationToken cancellationToken); - Task GetAsync(Uri requestUri, HttpCompletionOption completionOption); - Task GetAsync(Uri requestUri, CancellationToken cancellationToken); - Task GetAsync(string requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken); - Task GetAsync(Uri requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken); - Task GetByteArrayAsync(string requestUri); - Task GetByteArrayAsync(Uri requestUri); - Task GetStreamAsync(string requestUri); - Task GetStreamAsync(Uri requestUri); - Task GetStringAsync(string requestUri); - Task GetStringAsync(Uri requestUri); - Task PostAsync(string requestUri, HttpContent content); - Task PostAsync(Uri requestUri, HttpContent content); - Task PostAsync(string requestUri, HttpContent content, CancellationToken cancellationToken); - Task PostAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken); - Task PutAsync(string requestUri, HttpContent content); - Task PutAsync(Uri requestUri, HttpContent content); - Task PutAsync(string requestUri, HttpContent content, CancellationToken cancellationToken); - Task PutAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken); - Task SendAsync(HttpRequestMessage request); - Task SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption); - Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken); - Task SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken); - void Dispose(bool disposing); - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/RequestBuilder/IRequestBuilder.cs b/src/Ocelot.Library/Infrastructure/RequestBuilder/IRequestBuilder.cs index 5bb6e27d..482bf51a 100644 --- a/src/Ocelot.Library/Infrastructure/RequestBuilder/IRequestBuilder.cs +++ b/src/Ocelot.Library/Infrastructure/RequestBuilder/IRequestBuilder.cs @@ -1,17 +1,16 @@ -namespace Ocelot.Library.Infrastructure.RequestBuilder -{ - using System.IO; - using System.Net.Http; - using Microsoft.AspNetCore.Http; +using System.IO; +using Microsoft.AspNetCore.Http; +namespace Ocelot.Library.Infrastructure.RequestBuilder +{ public interface IRequestBuilder { - HttpRequestMessage Build(string httpMethod, + Request Build(string httpMethod, string downstreamUrl, Stream content, IHeaderDictionary headers, IRequestCookieCollection cookies, - IQueryCollection queryString, + string queryString, string contentType); } } diff --git a/src/Ocelot.Library/Infrastructure/RequestBuilder/Request.cs b/src/Ocelot.Library/Infrastructure/RequestBuilder/Request.cs new file mode 100644 index 00000000..b35abf32 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/RequestBuilder/Request.cs @@ -0,0 +1,17 @@ +using System.Net; +using System.Net.Http; + +namespace Ocelot.Library.Infrastructure.RequestBuilder +{ + public class Request + { + public Request(HttpRequestMessage httpRequestMessage, CookieContainer cookieContainer) + { + HttpRequestMessage = httpRequestMessage; + CookieContainer = cookieContainer; + } + + public HttpRequestMessage HttpRequestMessage { get; private set; } + public CookieContainer CookieContainer { get; private set; } + } +} diff --git a/src/Ocelot.Library/Infrastructure/RequestBuilder/RequestBuilder.cs b/src/Ocelot.Library/Infrastructure/RequestBuilder/RequestBuilder.cs index 578b60b5..653c263a 100644 --- a/src/Ocelot.Library/Infrastructure/RequestBuilder/RequestBuilder.cs +++ b/src/Ocelot.Library/Infrastructure/RequestBuilder/RequestBuilder.cs @@ -1,24 +1,27 @@ -namespace Ocelot.Library.Infrastructure.RequestBuilder -{ - using System; - using System.IO; - using System.Net.Http; - using System.Net.Http.Headers; - using Microsoft.AspNetCore.Http; +using System; +using System.IO; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using Microsoft.AspNetCore.Http; +namespace Ocelot.Library.Infrastructure.RequestBuilder +{ public class RequestBuilder : IRequestBuilder { - public HttpRequestMessage Build(string httpMethod, string downstreamUrl, Stream content, IHeaderDictionary headers, - IRequestCookieCollection cookies, IQueryCollection queryString, string contentType) + public Request Build(string httpMethod, string downstreamUrl, Stream content, IHeaderDictionary headers, + IRequestCookieCollection cookies, string queryString, string contentType) { var method = new HttpMethod(httpMethod); - var uri = new Uri(downstreamUrl + queryString); + var uri = new Uri(string.Format("{0}{1}", downstreamUrl, queryString)); - var httpRequestMessage = new HttpRequestMessage(method, uri) + var httpRequestMessage = new HttpRequestMessage(method, uri); + + if (content != null) { - Content = new StreamContent(content), - }; + httpRequestMessage.Content = new StreamContent(content); + } if (!string.IsNullOrEmpty(contentType)) { @@ -42,8 +45,19 @@ } } - return httpRequestMessage; + var cookieContainer = new CookieContainer(); + //todo get rid of if + if (cookies != null) + { + foreach (var cookie in cookies) + { + cookieContainer.Add(uri, new Cookie(cookie.Key, cookie.Value)); + } + } + + + return new Request(httpRequestMessage, cookieContainer); } } } \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs b/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs index b2a14c7e..c2b91523 100644 --- a/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs +++ b/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs @@ -1,22 +1,18 @@ using System.Net.Http; using System.Threading.Tasks; +using Ocelot.Library.Infrastructure.RequestBuilder; namespace Ocelot.Library.Infrastructure.Requester { - using HttpClient; - public class HttpClientHttpRequester : IHttpRequester { - private readonly IHttpClient _httpClient; - - public HttpClientHttpRequester(IHttpClient httpClient) + public async Task GetResponse(Request request) { - _httpClient = httpClient; - } - - public async Task GetResponse(HttpRequestMessage httpRequestMessage) - { - return await _httpClient.SendAsync(httpRequestMessage); + using (var handler = new HttpClientHandler { CookieContainer = request.CookieContainer }) + using (var httpClient = new HttpClient(handler)) + { + return await httpClient.SendAsync(request.HttpRequestMessage); + } } } } \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Requester/IHttpRequester.cs b/src/Ocelot.Library/Infrastructure/Requester/IHttpRequester.cs index 2a426d52..e8d3d33b 100644 --- a/src/Ocelot.Library/Infrastructure/Requester/IHttpRequester.cs +++ b/src/Ocelot.Library/Infrastructure/Requester/IHttpRequester.cs @@ -1,10 +1,11 @@ using System.Net.Http; using System.Threading.Tasks; +using Ocelot.Library.Infrastructure.RequestBuilder; namespace Ocelot.Library.Infrastructure.Requester { public interface IHttpRequester { - Task GetResponse(HttpRequestMessage httpRequestMessage); + Task GetResponse(Request request); } } diff --git a/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs b/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs index 4521e858..ed585924 100644 --- a/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs +++ b/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs @@ -41,7 +41,7 @@ namespace Ocelot.Library.Middleware var request = _requestBuilder .Build(context.Request.Method, downstreamUrl.Data, context.Request.Body, - context.Request.Headers, context.Request.Cookies, context.Request.Query, context.Request.ContentType); + context.Request.Headers, context.Request.Cookies, context.Request.QueryString.Value, context.Request.ContentType); var response = await _requester .GetResponse(request); diff --git a/src/Ocelot/Startup.cs b/src/Ocelot/Startup.cs index 71d329a5..0ff6b0e2 100644 --- a/src/Ocelot/Startup.cs +++ b/src/Ocelot/Startup.cs @@ -4,21 +4,18 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Ocelot.Library.Infrastructure.Configuration; using Ocelot.Library.Infrastructure.DownstreamRouteFinder; using Ocelot.Library.Infrastructure.Repository; +using Ocelot.Library.Infrastructure.RequestBuilder; using Ocelot.Library.Infrastructure.Requester; using Ocelot.Library.Infrastructure.Responder; +using Ocelot.Library.Infrastructure.UrlMatcher; +using Ocelot.Library.Infrastructure.UrlTemplateReplacer; using Ocelot.Library.Middleware; namespace Ocelot { - using System.Net.Http; - using Library.Infrastructure.Configuration; - using Library.Infrastructure.HttpClient; - using Library.Infrastructure.RequestBuilder; - using Library.Infrastructure.UrlMatcher; - using Library.Infrastructure.UrlTemplateReplacer; - public class Startup { public Startup(IHostingEnvironment env) @@ -47,8 +44,6 @@ namespace Ocelot services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); - services.AddTransient(); - services.AddTransient(); services.AddSingleton(); // see this for why we register this as singleton http://stackoverflow.com/questions/37371264/invalidoperationexception-unable-to-resolve-service-for-type-microsoft-aspnetc diff --git a/test/Ocelot.UnitTests/Configuration/Requester/RequesterTests.cs b/test/Ocelot.UnitTests/Configuration/Requester/RequesterTests.cs deleted file mode 100644 index 46708773..00000000 --- a/test/Ocelot.UnitTests/Configuration/Requester/RequesterTests.cs +++ /dev/null @@ -1,289 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; -using System.Net.Http; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Internal; -using Microsoft.Extensions.Primitives; -using Ocelot.Library.Infrastructure.Requester; -using Shouldly; -using TestStack.BDDfy; -using Xunit; - -namespace Ocelot.UnitTests.Requester -{ - using System; - using Library.Infrastructure.HttpClient; - using Moq; - - public class RequesterTests - { - private readonly IHttpRequester _httpRequester; - private string _httpMethod; - private string _downstreamUrl; - private HttpResponseMessage _result; - private HttpContent _content; - private IHeaderDictionary _headers; - private IRequestCookieCollection _cookies; - private IQueryCollection _query; - private string _contentType; - private Mock _httpClient; - - public RequesterTests() - { - _httpClient = new Mock(); - _httpRequester = new HttpClientHttpRequester(_httpClient.Object); - } - - [Fact] - public void should_call_downstream_url_correctly() - { - this.Given(x => x.GivenIHaveHttpMethod("GET")) - .And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk")) - .And(x => x.GivenTheDownstreamServerReturns(HttpStatusCode.OK)) - .When(x => x.WhenIMakeARequest()) - .Then(x => x.ThenTheFollowingIsReturned(HttpStatusCode.OK)) - .And(x => x.ThenTheDownstreamServerIsCalledCorrectly()) - .BDDfy(); - } - - [Fact] - public void should_obey_http_method() - { - this.Given(x => x.GivenIHaveHttpMethod("POST")) - .And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk")) - .And(x => x.GivenTheDownstreamServerReturns(HttpStatusCode.Created)) - .When(x => x.WhenIMakeARequest()) - .Then(x => x.ThenTheFollowingIsReturned(HttpStatusCode.Created)) - .And(x => x.ThenTheDownstreamServerIsCalledCorrectly()) - .And(x => x.ThenTheCorrectHttpMethodIsUsed(HttpMethod.Post)) - .BDDfy(); - } - - [Fact] - public void should_forward_http_content() - { - 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")) - .And(x => x.GivenTheDownstreamServerReturns(HttpStatusCode.Created)) - .When(x => x.WhenIMakeARequest()) - .Then(x => x.ThenTheFollowingIsReturned(HttpStatusCode.Created)) - .And(x => x.ThenTheDownstreamServerIsCalledCorrectly()) - .And(x => x.ThenTheCorrectHttpMethodIsUsed(HttpMethod.Post)) - .And(x => x.ThenTheCorrectContentIsUsed(new StringContent("Hi from Tom"))) - .BDDfy(); - } - - [Fact] - public void should_forward_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")) - .And(x => x.GivenTheDownstreamServerReturns(HttpStatusCode.Created)) - .When(x => x.WhenIMakeARequest()) - .Then(x => x.ThenTheFollowingIsReturned(HttpStatusCode.Created)) - .And(x => x.ThenTheDownstreamServerIsCalledCorrectly()) - .And(x => x.ThenTheCorrectHttpMethodIsUsed(HttpMethod.Post)) - .And(x => x.ThenTheCorrectContentIsUsed(new StringContent("Hi from Tom"))) - .And(x => x.ThenTheCorrectContentHeadersAreUsed(new HeaderDictionary - { - { - "Content-Type", "application/json" - } - })) - .BDDfy(); - } - - [Fact] - public void should_forward_headers() - { - this.Given(x => x.GivenIHaveHttpMethod("GET")) - .And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk")) - .And(x => x.GivenTheHttpHeadersAre(new HeaderDictionary - { - {"ChopSticks", "Bubbles" } - })) - .And(x => x.GivenTheDownstreamServerReturns(HttpStatusCode.OK)) - .When(x => x.WhenIMakeARequest()) - .Then(x => x.ThenTheFollowingIsReturned(HttpStatusCode.OK)) - .And(x => x.ThenTheDownstreamServerIsCalledCorrectly()) - .And(x => x.ThenTheCorrectHeadersAreUsed(new HeaderDictionary - { - {"ChopSticks", "Bubbles" } - })) - .BDDfy(); - } - - [Fact] - public void should_forward_cookies() - { - this.Given(x => x.GivenIHaveHttpMethod("GET")) - .And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk")) - .And(x => x.GivenTheCookiesAre(new RequestCookieCollection(new Dictionary - { - { "TheCookie","Monster" } - }))) - .And(x => x.GivenTheDownstreamServerReturns(HttpStatusCode.OK)) - .When(x => x.WhenIMakeARequest()) - .Then(x => x.ThenTheFollowingIsReturned(HttpStatusCode.OK)) - .And(x => x.ThenTheDownstreamServerIsCalledCorrectly()) - .And(x => x.ThenTheCorrectCookiesAreUsed(new RequestCookieCollection(new Dictionary - { - { "TheCookie","Monster" } - }))) - .BDDfy(); - } - - [Fact] - public void should_forward_query_string() - { - this.Given(x => x.GivenIHaveHttpMethod("POST")) - .And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk")) - .And(x => x.GivenTheQueryStringIs(new QueryCollection(new Dictionary - { - { "jeff", "1" }, - { "geoff", "2" } - }))) - .And(x => x.GivenTheDownstreamServerReturns(HttpStatusCode.Created)) - .When(x => x.WhenIMakeARequest()) - .Then(x => x.ThenTheFollowingIsReturned(HttpStatusCode.Created)) - .And(x => x.ThenTheDownstreamServerIsCalledCorrectly()) - .And(x => x.ThenTheCorrectQueryStringIsUsed("?jeff=1&geoff=2")) - .BDDfy(); - } - - private void GivenTheContentTypeIs(string contentType) - { - _contentType = contentType; - } - - private void ThenTheCorrectQueryStringIsUsed(string expected) - { - throw new NotImplementedException(); - //_httpTest.CallLog[0].Request.RequestUri.Query.ShouldBe(expected); - } - - private void GivenTheQueryStringIs(IQueryCollection query) - { - _query = query; - } - - private void ThenTheCorrectCookiesAreUsed(IRequestCookieCollection cookies) - { - throw new NotImplementedException(); - - /* var expectedCookies = cookies.Select(x => new KeyValuePair(x.Key, x.Value)); - - foreach (var expectedCookie in expectedCookies) - { - _httpTest - .CallLog[0] - .Request - .Headers - .ShouldContain(x => x.Key == "Cookie" && x.Value.First() == string.Format("{0}={1}", expectedCookie.Key, expectedCookie.Value)); - }*/ - } - - private void GivenTheCookiesAre(IRequestCookieCollection cookies) - { - _cookies = cookies; - } - - private void ThenTheCorrectHeadersAreUsed(IHeaderDictionary headers) - { - throw new NotImplementedException(); - - /*var expectedHeaders = headers.Select(x => new KeyValuePair(x.Key, x.Value)); - - foreach (var expectedHeader in expectedHeaders) - { - _httpTest.CallLog[0].Request.Headers.ShouldContain(x => x.Key == expectedHeader.Key && x.Value.First() == expectedHeader.Value[0]); - }*/ - } - - private void ThenTheCorrectContentHeadersAreUsed(IHeaderDictionary headers) - { - throw new NotImplementedException(); - - /*var expectedHeaders = headers.Select(x => new KeyValuePair(x.Key, x.Value)); - - foreach (var expectedHeader in expectedHeaders) - { - _httpTest.CallLog[0].Request.Content.Headers.ShouldContain(x => x.Key == expectedHeader.Key - && x.Value.First() == expectedHeader.Value[0] - ); - }*/ - } - - private void GivenTheHttpHeadersAre(IHeaderDictionary headers) - { - _headers = headers; - } - - private void GivenIHaveTheHttpContent(HttpContent content) - { - _content = content; - } - - private void GivenIHaveHttpMethod(string httpMethod) - { - _httpMethod = httpMethod; - } - - private void GivenIHaveDownstreamUrl(string downstreamUrl) - { - _downstreamUrl = downstreamUrl; - } - - private void GivenTheDownstreamServerReturns(HttpStatusCode statusCode) - { - _httpClient - .Setup(x => x.SendAsync(It.IsAny())) - .ReturnsAsync(new HttpResponseMessage() - { - StatusCode = statusCode, - Content = _content != null ? _content : null - - }); - /* _httpTest - .RespondWith(_content != null ? _content.ReadAsStringAsync().Result : string.Empty, (int)statusCode);*/ - } - - private void WhenIMakeARequest() - { - _result = _httpRequester - .GetResponse(new HttpRequestMessage()).Result; - } - - private void ThenTheFollowingIsReturned(HttpStatusCode expected) - { - _result.StatusCode.ShouldBe(expected); - } - - private void ThenTheDownstreamServerIsCalledCorrectly() - { - throw new NotImplementedException(); - - //_httpTest.ShouldHaveCalled(_downstreamUrl); - } - - private void ThenTheCorrectHttpMethodIsUsed(HttpMethod expected) - { - throw new NotImplementedException(); - - //_httpTest.CallLog[0].Request.Method.ShouldBe(expected); - } - - private void ThenTheCorrectContentIsUsed(HttpContent content) - { - throw new NotImplementedException(); - - //_httpTest.CallLog[0].Response.Content.ReadAsStringAsync().Result.ShouldBe(content.ReadAsStringAsync().Result); - } - } -} diff --git a/test/Ocelot.UnitTests/RequestBuilder/RequestBuilderTests.cs b/test/Ocelot.UnitTests/RequestBuilder/RequestBuilderTests.cs new file mode 100644 index 00000000..eb841306 --- /dev/null +++ b/test/Ocelot.UnitTests/RequestBuilder/RequestBuilderTests.cs @@ -0,0 +1,224 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Internal; +using Ocelot.Library.Infrastructure.RequestBuilder; +using Shouldly; +using TestStack.BDDfy; +using Xunit; + +namespace Ocelot.UnitTests.RequestBuilder +{ + public class RequestBuilderTests + { + private string _httpMethod; + private string _downstreamUrl; + private HttpContent _content; + private IHeaderDictionary _headers; + private IRequestCookieCollection _cookies; + private string _query; + private string _contentType; + private readonly IRequestBuilder _requestBuilder; + private Request _result; + + public RequestBuilderTests() + { + _content = new StringContent(string.Empty); + _requestBuilder = new Library.Infrastructure.RequestBuilder.RequestBuilder(); + } + + [Fact] + public void should_user_downstream_url() + { + this.Given(x => x.GivenIHaveHttpMethod("GET")) + .And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk")) + .When(x => x.WhenICreateARequest()) + .And(x => x.ThenTheCorrectDownstreamUrlIsUsed("http://www.bbc.co.uk/")) + .BDDfy(); + } + + [Fact] + public void should_use_http_method() + { + this.Given(x => x.GivenIHaveHttpMethod("POST")) + .And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk")) + .When(x => x.WhenICreateARequest()) + .And(x => x.ThenTheCorrectHttpMethodIsUsed(HttpMethod.Post)) + .BDDfy(); + } + + [Fact] + public void should_use_http_content() + { + 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")) + .When(x => x.WhenICreateARequest()) + .And(x => x.ThenTheCorrectContentIsUsed(new StringContent("Hi from Tom"))) + .BDDfy(); + } + + [Fact] + public void should_use_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")) + .When(x => x.WhenICreateARequest()) + .And(x => x.ThenTheCorrectContentIsUsed(new StringContent("Hi from Tom"))) + .And(x => x.ThenTheCorrectContentHeadersAreUsed(new HeaderDictionary + { + { + "Content-Type", "application/json" + } + })) + .BDDfy(); + } + + [Fact] + public void should_use_headers() + { + this.Given(x => x.GivenIHaveHttpMethod("GET")) + .And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk")) + .And(x => x.GivenTheHttpHeadersAre(new HeaderDictionary + { + {"ChopSticks", "Bubbles" } + })) + .When(x => x.WhenICreateARequest()) + .And(x => x.ThenTheCorrectHeadersAreUsed(new HeaderDictionary + { + {"ChopSticks", "Bubbles" } + })) + .BDDfy(); + } + + [Fact] + public void should_use_cookies() + { + this.Given(x => x.GivenIHaveHttpMethod("GET")) + .And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk")) + .And(x => x.GivenTheCookiesAre(new RequestCookieCollection(new Dictionary + { + { "TheCookie","Monster" } + }))) + .When(x => x.WhenICreateARequest()) + .And(x => x.ThenTheCorrectCookiesAreUsed(new RequestCookieCollection(new Dictionary + { + { "TheCookie","Monster" } + }))) + .BDDfy(); + } + + [Fact] + public void should_user_query_string() + { + this.Given(x => x.GivenIHaveHttpMethod("POST")) + .And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk")) + .And(x => x.GivenTheQueryStringIs("?jeff=1&geoff=2")) + .When(x => x.WhenICreateARequest()) + .And(x => x.ThenTheCorrectQueryStringIsUsed("?jeff=1&geoff=2")) + .BDDfy(); + } + + private void GivenTheContentTypeIs(string contentType) + { + _contentType = contentType; + } + + private void ThenTheCorrectQueryStringIsUsed(string expected) + { + _result.HttpRequestMessage.RequestUri.Query.ShouldBe(expected); + } + + private void GivenTheQueryStringIs(string query) + { + _query = query; + } + + private void ThenTheCorrectCookiesAreUsed(IRequestCookieCollection expected) + { + var resultCookies = _result.CookieContainer.GetCookies(new Uri(_downstreamUrl + _query)); + var resultDictionary = resultCookies.Cast().ToDictionary(cook => cook.Name, cook => cook.Value); + + foreach (var expectedCookie in expected) + { + var resultCookie = resultDictionary[expectedCookie.Key]; + resultCookie.ShouldBe(expectedCookie.Value); + } + } + + private void GivenTheCookiesAre(IRequestCookieCollection cookies) + { + _cookies = cookies; + } + + private void ThenTheCorrectHeadersAreUsed(IHeaderDictionary expected) + { + var expectedHeaders = expected.Select(x => new KeyValuePair(x.Key, x.Value)); + + foreach (var expectedHeader in expectedHeaders) + { + _result.HttpRequestMessage.Headers.ShouldContain(x => x.Key == expectedHeader.Key && x.Value.First() == expectedHeader.Value[0]); + } + } + + private void ThenTheCorrectContentHeadersAreUsed(IHeaderDictionary expected) + { + var expectedHeaders = expected.Select(x => new KeyValuePair(x.Key, x.Value)); + + foreach (var expectedHeader in expectedHeaders) + { + _result.HttpRequestMessage.Content.Headers.ShouldContain(x => x.Key == expectedHeader.Key + && x.Value.First() == expectedHeader.Value[0] + ); + } + } + + private void GivenTheHttpHeadersAre(IHeaderDictionary headers) + { + _headers = headers; + } + + private void GivenIHaveTheHttpContent(HttpContent content) + { + _content = content; + } + + private void GivenIHaveHttpMethod(string httpMethod) + { + _httpMethod = httpMethod; + } + + private void GivenIHaveDownstreamUrl(string downstreamUrl) + { + _downstreamUrl = downstreamUrl; + } + + private void WhenICreateARequest() + { + _result = _requestBuilder.Build(_httpMethod, _downstreamUrl, _content?.ReadAsStreamAsync().Result, _headers, + _cookies, _query, _contentType); + } + + + private void ThenTheCorrectDownstreamUrlIsUsed(string expected) + { + _result.HttpRequestMessage.RequestUri.AbsoluteUri.ShouldBe(expected); + } + + private void ThenTheCorrectHttpMethodIsUsed(HttpMethod expected) + { + _result.HttpRequestMessage.Method.Method.ShouldBe(expected.Method); + } + + private void ThenTheCorrectContentIsUsed(HttpContent expected) + { + _result.HttpRequestMessage.Content.ReadAsStringAsync().Result.ShouldBe(expected.ReadAsStringAsync().Result); + } + } +} From 3685efec0519320fcc453d31c0fbb163293e6b3d Mon Sep 17 00:00:00 2001 From: TomPallister Date: Fri, 7 Oct 2016 13:01:05 +0100 Subject: [PATCH 045/183] broke request builder and requester up into seperate middleware --- .../HttpRequestBuilderMiddleware.cs | 48 +++++++++++++++++++ .../HttpRequestBuilderMiddlewareExtensions.cs | 12 +++++ .../Middleware/HttpRequesterMiddleware.cs | 10 ++-- src/Ocelot/Startup.cs | 2 + 4 files changed, 65 insertions(+), 7 deletions(-) create mode 100644 src/Ocelot.Library/Middleware/HttpRequestBuilderMiddleware.cs create mode 100644 src/Ocelot.Library/Middleware/HttpRequestBuilderMiddlewareExtensions.cs diff --git a/src/Ocelot.Library/Middleware/HttpRequestBuilderMiddleware.cs b/src/Ocelot.Library/Middleware/HttpRequestBuilderMiddleware.cs new file mode 100644 index 00000000..1bb0d68a --- /dev/null +++ b/src/Ocelot.Library/Middleware/HttpRequestBuilderMiddleware.cs @@ -0,0 +1,48 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Ocelot.Library.Infrastructure.Repository; +using Ocelot.Library.Infrastructure.Requester; +using Ocelot.Library.Infrastructure.Responder; + +namespace Ocelot.Library.Middleware +{ + using Infrastructure.RequestBuilder; + + public class HttpRequestBuilderMiddleware + { + private readonly RequestDelegate _next; + private readonly IHttpResponder _responder; + private readonly IScopedRequestDataRepository _scopedRequestDataRepository; + private readonly IRequestBuilder _requestBuilder; + + public HttpRequestBuilderMiddleware(RequestDelegate next, + IHttpResponder responder, + IScopedRequestDataRepository scopedRequestDataRepository, + IRequestBuilder requestBuilder) + { + _next = next; + _responder = responder; + _scopedRequestDataRepository = scopedRequestDataRepository; + _requestBuilder = requestBuilder; + } + + public async Task Invoke(HttpContext context) + { + var downstreamUrl = _scopedRequestDataRepository.Get("DownstreamUrl"); + + if (downstreamUrl.IsError) + { + await _responder.CreateNotFoundResponse(context); + return; + } + + var request = _requestBuilder + .Build(context.Request.Method, downstreamUrl.Data, context.Request.Body, + context.Request.Headers, context.Request.Cookies, context.Request.QueryString.Value, context.Request.ContentType); + + _scopedRequestDataRepository.Add("Request", request); + + await _next.Invoke(context); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Middleware/HttpRequestBuilderMiddlewareExtensions.cs b/src/Ocelot.Library/Middleware/HttpRequestBuilderMiddlewareExtensions.cs new file mode 100644 index 00000000..0b51ccaa --- /dev/null +++ b/src/Ocelot.Library/Middleware/HttpRequestBuilderMiddlewareExtensions.cs @@ -0,0 +1,12 @@ +using Microsoft.AspNetCore.Builder; + +namespace Ocelot.Library.Middleware +{ + public static class HttpRequestBuilderMiddlewareExtensions + { + public static IApplicationBuilder UseHttpRequestBuilderMiddleware(this IApplicationBuilder builder) + { + return builder.UseMiddleware(); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs b/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs index ed585924..b5538df6 100644 --- a/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs +++ b/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs @@ -31,20 +31,16 @@ namespace Ocelot.Library.Middleware public async Task Invoke(HttpContext context) { - var downstreamUrl = _scopedRequestDataRepository.Get("DownstreamUrl"); + var request = _scopedRequestDataRepository.Get("Request"); - if (downstreamUrl.IsError) + if (request.IsError) { await _responder.CreateNotFoundResponse(context); return; } - var request = _requestBuilder - .Build(context.Request.Method, downstreamUrl.Data, context.Request.Body, - context.Request.Headers, context.Request.Cookies, context.Request.QueryString.Value, context.Request.ContentType); - var response = await _requester - .GetResponse(request); + .GetResponse(request.Data); await _responder.CreateResponse(context, response); diff --git a/src/Ocelot/Startup.cs b/src/Ocelot/Startup.cs index 0ff6b0e2..cb9e9e77 100644 --- a/src/Ocelot/Startup.cs +++ b/src/Ocelot/Startup.cs @@ -62,6 +62,8 @@ namespace Ocelot app.UserDownstreamUrlCreatorMiddleware(); + app.UseHttpRequestBuilderMiddleware(); + app.UseHttpRequesterMiddleware(); } } From a7a114382333ee40abbb38fc71fd5329fe694a59 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Sat, 8 Oct 2016 09:59:37 +0100 Subject: [PATCH 046/183] made a response middlware as terminating middleware... --- ...equestBuilder.cs => HttpRequestBuilder.cs} | 17 +++- .../RequestBuilder/IRequestBuilder.cs | 3 +- .../Requester/HttpClientHttpRequester.cs | 21 ++++- .../Requester/IHttpRequester.cs | 3 +- .../Requester/UnableToCompleteRequestError.cs | 13 +++ .../Responder/HttpContextResponder.cs | 13 ++- .../IUrlPathToUrlTemplateMatcher.cs | 2 +- .../UrlMatcher/UrlPathToUrlTemplateMatcher.cs | 19 +++-- .../HttpRequestBuilderMiddleware.cs | 2 +- .../Middleware/HttpRequesterMiddleware.cs | 10 +-- .../Middleware/HttpResponderMiddleware.cs | 34 ++++++++ .../HttpResponderMiddlewareExtensions.cs | 12 +++ src/Ocelot/Program.cs | 7 +- src/Ocelot/Startup.cs | 4 +- src/Ocelot/configuration.yaml | 2 +- .../RequestBuilder/RequestBuilderTests.cs | 5 +- .../UrlPathToUrlTemplateMatcherTests.cs | 84 ++++++++----------- 17 files changed, 165 insertions(+), 86 deletions(-) rename src/Ocelot.Library/Infrastructure/RequestBuilder/{RequestBuilder.cs => HttpRequestBuilder.cs} (69%) create mode 100644 src/Ocelot.Library/Infrastructure/Requester/UnableToCompleteRequestError.cs create mode 100644 src/Ocelot.Library/Middleware/HttpResponderMiddleware.cs create mode 100644 src/Ocelot.Library/Middleware/HttpResponderMiddlewareExtensions.cs diff --git a/src/Ocelot.Library/Infrastructure/RequestBuilder/RequestBuilder.cs b/src/Ocelot.Library/Infrastructure/RequestBuilder/HttpRequestBuilder.cs similarity index 69% rename from src/Ocelot.Library/Infrastructure/RequestBuilder/RequestBuilder.cs rename to src/Ocelot.Library/Infrastructure/RequestBuilder/HttpRequestBuilder.cs index 653c263a..6a0b7c8f 100644 --- a/src/Ocelot.Library/Infrastructure/RequestBuilder/RequestBuilder.cs +++ b/src/Ocelot.Library/Infrastructure/RequestBuilder/HttpRequestBuilder.cs @@ -3,13 +3,14 @@ using System.IO; using System.Net; using System.Net.Http; using System.Net.Http.Headers; +using System.Threading.Tasks; using Microsoft.AspNetCore.Http; namespace Ocelot.Library.Infrastructure.RequestBuilder { - public class RequestBuilder : IRequestBuilder + public class HttpRequestBuilder : IRequestBuilder { - public Request Build(string httpMethod, string downstreamUrl, Stream content, IHeaderDictionary headers, + public async Task Build(string httpMethod, string downstreamUrl, Stream content, IHeaderDictionary headers, IRequestCookieCollection cookies, string queryString, string contentType) { var method = new HttpMethod(httpMethod); @@ -20,7 +21,11 @@ namespace Ocelot.Library.Infrastructure.RequestBuilder if (content != null) { - httpRequestMessage.Content = new StreamContent(content); + using (var reader = new StreamReader(content)) + { + var body = await reader.ReadToEndAsync(); + httpRequestMessage.Content = new StringContent(body); + } } if (!string.IsNullOrEmpty(contentType)) @@ -41,7 +46,11 @@ namespace Ocelot.Library.Infrastructure.RequestBuilder { foreach (var header in headers) { - httpRequestMessage.Headers.Add(header.Key, header.Value.ToArray()); + //todo get rid of if.. + if (header.Key.ToLower() != "host") + { + httpRequestMessage.Headers.Add(header.Key, header.Value.ToArray()); + } } } diff --git a/src/Ocelot.Library/Infrastructure/RequestBuilder/IRequestBuilder.cs b/src/Ocelot.Library/Infrastructure/RequestBuilder/IRequestBuilder.cs index 482bf51a..cace3b70 100644 --- a/src/Ocelot.Library/Infrastructure/RequestBuilder/IRequestBuilder.cs +++ b/src/Ocelot.Library/Infrastructure/RequestBuilder/IRequestBuilder.cs @@ -1,11 +1,12 @@ using System.IO; +using System.Threading.Tasks; using Microsoft.AspNetCore.Http; namespace Ocelot.Library.Infrastructure.RequestBuilder { public interface IRequestBuilder { - Request Build(string httpMethod, + Task Build(string httpMethod, string downstreamUrl, Stream content, IHeaderDictionary headers, diff --git a/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs b/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs index c2b91523..260a6843 100644 --- a/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs +++ b/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs @@ -1,17 +1,32 @@ -using System.Net.Http; +using System; +using System.Collections.Generic; +using System.Net.Http; using System.Threading.Tasks; using Ocelot.Library.Infrastructure.RequestBuilder; +using Ocelot.Library.Infrastructure.Responses; namespace Ocelot.Library.Infrastructure.Requester { public class HttpClientHttpRequester : IHttpRequester { - public async Task GetResponse(Request request) + public async Task> GetResponse(Request request) { using (var handler = new HttpClientHandler { CookieContainer = request.CookieContainer }) using (var httpClient = new HttpClient(handler)) { - return await httpClient.SendAsync(request.HttpRequestMessage); + try + { + var response = await httpClient.SendAsync(request.HttpRequestMessage); + return new OkResponse(response); + } + catch (Exception exception) + { + return + new ErrorResponse(new List + { + new UnableToCompleteRequestError(exception) + }); + } } } } diff --git a/src/Ocelot.Library/Infrastructure/Requester/IHttpRequester.cs b/src/Ocelot.Library/Infrastructure/Requester/IHttpRequester.cs index e8d3d33b..eca3875e 100644 --- a/src/Ocelot.Library/Infrastructure/Requester/IHttpRequester.cs +++ b/src/Ocelot.Library/Infrastructure/Requester/IHttpRequester.cs @@ -1,11 +1,12 @@ using System.Net.Http; using System.Threading.Tasks; using Ocelot.Library.Infrastructure.RequestBuilder; +using Ocelot.Library.Infrastructure.Responses; namespace Ocelot.Library.Infrastructure.Requester { public interface IHttpRequester { - Task GetResponse(Request request); + Task> GetResponse(Request request); } } diff --git a/src/Ocelot.Library/Infrastructure/Requester/UnableToCompleteRequestError.cs b/src/Ocelot.Library/Infrastructure/Requester/UnableToCompleteRequestError.cs new file mode 100644 index 00000000..6e7a042c --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Requester/UnableToCompleteRequestError.cs @@ -0,0 +1,13 @@ +using System; +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.Requester +{ + public class UnableToCompleteRequestError : Error + { + public UnableToCompleteRequestError(Exception exception) + : base($"Error making http request, exception: {exception.Message}") + { + } + } +} diff --git a/src/Ocelot.Library/Infrastructure/Responder/HttpContextResponder.cs b/src/Ocelot.Library/Infrastructure/Responder/HttpContextResponder.cs index 1569e58a..5339ff92 100644 --- a/src/Ocelot.Library/Infrastructure/Responder/HttpContextResponder.cs +++ b/src/Ocelot.Library/Infrastructure/Responder/HttpContextResponder.cs @@ -11,7 +11,12 @@ namespace Ocelot.Library.Infrastructure.Responder { if (response.IsSuccessStatusCode) { - context.Response.StatusCode = (int)response.StatusCode; + context.Response.OnStarting(x => + { + context.Response.StatusCode = (int)response.StatusCode; + return Task.CompletedTask; + }, context); + await context.Response.WriteAsync(await response.Content.ReadAsStringAsync()); return context; } @@ -20,7 +25,11 @@ namespace Ocelot.Library.Infrastructure.Responder public async Task CreateNotFoundResponse(HttpContext context) { - context.Response.StatusCode = (int)HttpStatusCode.NotFound; + context.Response.OnStarting(x => + { + context.Response.StatusCode = (int)HttpStatusCode.NotFound; + return Task.CompletedTask; + }, context); return context; } } diff --git a/src/Ocelot.Library/Infrastructure/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs b/src/Ocelot.Library/Infrastructure/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs index 954e3fee..89e3e5a5 100644 --- a/src/Ocelot.Library/Infrastructure/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs +++ b/src/Ocelot.Library/Infrastructure/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs @@ -2,6 +2,6 @@ namespace Ocelot.Library.Infrastructure.UrlMatcher { public interface IUrlPathToUrlTemplateMatcher { - UrlMatch Match(string upstreamUrlPath, string upstreamUrlTemplate); + UrlMatch Match(string upstreamUrlPath, string upstreamUrlPathTemplate); } } \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlMatcher/UrlPathToUrlTemplateMatcher.cs b/src/Ocelot.Library/Infrastructure/UrlMatcher/UrlPathToUrlTemplateMatcher.cs index 0c396e32..4e5aed52 100644 --- a/src/Ocelot.Library/Infrastructure/UrlMatcher/UrlPathToUrlTemplateMatcher.cs +++ b/src/Ocelot.Library/Infrastructure/UrlMatcher/UrlPathToUrlTemplateMatcher.cs @@ -5,21 +5,26 @@ namespace Ocelot.Library.Infrastructure.UrlMatcher { public class UrlPathToUrlTemplateMatcher : IUrlPathToUrlTemplateMatcher { - public UrlMatch Match(string upstreamUrlPath, string upstreamUrlTemplate) + public UrlMatch Match(string upstreamUrlPath, string upstreamUrlPathTemplate) { - var urlPathTemplateCopy = upstreamUrlTemplate; + if (upstreamUrlPath.Length > upstreamUrlPathTemplate.Length) + { + return new UrlMatch(false, new List(), string.Empty); + } + + var urlPathTemplateCopy = upstreamUrlPathTemplate; var templateKeysAndValues = new List(); int counterForUrl = 0; - for (int counterForTemplate = 0; counterForTemplate < upstreamUrlTemplate.Length; counterForTemplate++) + for (int counterForTemplate = 0; counterForTemplate < upstreamUrlPathTemplate.Length; counterForTemplate++) { - if (CharactersDontMatch(upstreamUrlTemplate[counterForTemplate], upstreamUrlPath[counterForUrl]) && ContinueScanningUrl(counterForUrl,upstreamUrlPath.Length)) + if (CharactersDontMatch(upstreamUrlPathTemplate[counterForTemplate], upstreamUrlPath[counterForUrl]) && ContinueScanningUrl(counterForUrl,upstreamUrlPath.Length)) { - if (IsPlaceholder(upstreamUrlTemplate[counterForTemplate])) + if (IsPlaceholder(upstreamUrlPathTemplate[counterForTemplate])) { - var variableName = GetPlaceholderVariableName(upstreamUrlTemplate, counterForTemplate); + var variableName = GetPlaceholderVariableName(upstreamUrlPathTemplate, counterForTemplate); var variableValue = GetPlaceholderVariableValue(upstreamUrlPath, counterForUrl); @@ -27,7 +32,7 @@ namespace Ocelot.Library.Infrastructure.UrlMatcher templateKeysAndValues.Add(templateVariableNameAndValue); - counterForTemplate = GetNextCounterPosition(upstreamUrlTemplate, counterForTemplate, '}'); + counterForTemplate = GetNextCounterPosition(upstreamUrlPathTemplate, counterForTemplate, '}'); counterForUrl = GetNextCounterPosition(upstreamUrlPath, counterForUrl, '/'); diff --git a/src/Ocelot.Library/Middleware/HttpRequestBuilderMiddleware.cs b/src/Ocelot.Library/Middleware/HttpRequestBuilderMiddleware.cs index 1bb0d68a..e41b1417 100644 --- a/src/Ocelot.Library/Middleware/HttpRequestBuilderMiddleware.cs +++ b/src/Ocelot.Library/Middleware/HttpRequestBuilderMiddleware.cs @@ -36,7 +36,7 @@ namespace Ocelot.Library.Middleware return; } - var request = _requestBuilder + var request = await _requestBuilder .Build(context.Request.Method, downstreamUrl.Data, context.Request.Body, context.Request.Headers, context.Request.Cookies, context.Request.QueryString.Value, context.Request.ContentType); diff --git a/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs b/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs index b5538df6..e35121ca 100644 --- a/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs +++ b/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs @@ -1,3 +1,4 @@ +using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Ocelot.Library.Infrastructure.Repository; @@ -14,19 +15,16 @@ namespace Ocelot.Library.Middleware private readonly IHttpRequester _requester; private readonly IHttpResponder _responder; private readonly IScopedRequestDataRepository _scopedRequestDataRepository; - private readonly IRequestBuilder _requestBuilder; public HttpRequesterMiddleware(RequestDelegate next, IHttpRequester requester, IHttpResponder responder, - IScopedRequestDataRepository scopedRequestDataRepository, - IRequestBuilder requestBuilder) + IScopedRequestDataRepository scopedRequestDataRepository) { _next = next; _requester = requester; _responder = responder; _scopedRequestDataRepository = scopedRequestDataRepository; - _requestBuilder = requestBuilder; } public async Task Invoke(HttpContext context) @@ -42,8 +40,8 @@ namespace Ocelot.Library.Middleware var response = await _requester .GetResponse(request.Data); - await _responder.CreateResponse(context, response); - + _scopedRequestDataRepository.Add("Response", response.Data); + await _next.Invoke(context); } } diff --git a/src/Ocelot.Library/Middleware/HttpResponderMiddleware.cs b/src/Ocelot.Library/Middleware/HttpResponderMiddleware.cs new file mode 100644 index 00000000..09b31f70 --- /dev/null +++ b/src/Ocelot.Library/Middleware/HttpResponderMiddleware.cs @@ -0,0 +1,34 @@ +using System.Net.Http; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Ocelot.Library.Infrastructure.Repository; +using Ocelot.Library.Infrastructure.Responder; + +namespace Ocelot.Library.Middleware +{ + /// + /// Terminating middleware that is responsible for returning a http response to the client + /// + public class HttpResponderMiddleware + { + private readonly RequestDelegate _next; + private readonly IHttpResponder _responder; + private readonly IScopedRequestDataRepository _scopedRequestDataRepository; + + public HttpResponderMiddleware(RequestDelegate next, + IHttpResponder responder, + IScopedRequestDataRepository scopedRequestDataRepository) + { + _next = next; + _responder = responder; + _scopedRequestDataRepository = scopedRequestDataRepository; + } + + public async Task Invoke(HttpContext context) + { + var response = _scopedRequestDataRepository.Get("Response"); + + await _responder.CreateResponse(context, response.Data); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Middleware/HttpResponderMiddlewareExtensions.cs b/src/Ocelot.Library/Middleware/HttpResponderMiddlewareExtensions.cs new file mode 100644 index 00000000..4cec7fd0 --- /dev/null +++ b/src/Ocelot.Library/Middleware/HttpResponderMiddlewareExtensions.cs @@ -0,0 +1,12 @@ +using Microsoft.AspNetCore.Builder; + +namespace Ocelot.Library.Middleware +{ + public static class HttpResponderMiddlewareExtensions + { + public static IApplicationBuilder UseHttpResponderMiddleware(this IApplicationBuilder builder) + { + return builder.UseMiddleware(); + } + } +} \ No newline at end of file diff --git a/src/Ocelot/Program.cs b/src/Ocelot/Program.cs index e8777ea7..1fdd2ad8 100644 --- a/src/Ocelot/Program.cs +++ b/src/Ocelot/Program.cs @@ -1,10 +1,5 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading.Tasks; +using System.IO; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Builder; namespace Ocelot { diff --git a/src/Ocelot/Startup.cs b/src/Ocelot/Startup.cs index cb9e9e77..ed685d57 100644 --- a/src/Ocelot/Startup.cs +++ b/src/Ocelot/Startup.cs @@ -44,7 +44,7 @@ namespace Ocelot services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); // see this for why we register this as singleton http://stackoverflow.com/questions/37371264/invalidoperationexception-unable-to-resolve-service-for-type-microsoft-aspnetc services.AddSingleton(); @@ -65,6 +65,8 @@ namespace Ocelot app.UseHttpRequestBuilderMiddleware(); app.UseHttpRequesterMiddleware(); + + app.UseHttpResponderMiddleware(); } } } diff --git a/src/Ocelot/configuration.yaml b/src/Ocelot/configuration.yaml index 04ac7018..db7e74c5 100644 --- a/src/Ocelot/configuration.yaml +++ b/src/Ocelot/configuration.yaml @@ -1,4 +1,4 @@ ReRoutes: -- DownstreamTemplate: http://www.bbc.co.uk +- DownstreamTemplate: http://www.mattsite.dev/ UpstreamTemplate: / UpstreamHttpMethod: Get diff --git a/test/Ocelot.UnitTests/RequestBuilder/RequestBuilderTests.cs b/test/Ocelot.UnitTests/RequestBuilder/RequestBuilderTests.cs index eb841306..db6cf5e6 100644 --- a/test/Ocelot.UnitTests/RequestBuilder/RequestBuilderTests.cs +++ b/test/Ocelot.UnitTests/RequestBuilder/RequestBuilderTests.cs @@ -27,7 +27,7 @@ namespace Ocelot.UnitTests.RequestBuilder public RequestBuilderTests() { _content = new StringContent(string.Empty); - _requestBuilder = new Library.Infrastructure.RequestBuilder.RequestBuilder(); + _requestBuilder = new Library.Infrastructure.RequestBuilder.HttpRequestBuilder(); } [Fact] @@ -70,7 +70,6 @@ namespace Ocelot.UnitTests.RequestBuilder .And(x => x.GivenIHaveTheHttpContent(new StringContent("Hi from Tom"))) .And(x => x.GivenTheContentTypeIs("application/json")) .When(x => x.WhenICreateARequest()) - .And(x => x.ThenTheCorrectContentIsUsed(new StringContent("Hi from Tom"))) .And(x => x.ThenTheCorrectContentHeadersAreUsed(new HeaderDictionary { { @@ -202,7 +201,7 @@ namespace Ocelot.UnitTests.RequestBuilder private void WhenICreateARequest() { _result = _requestBuilder.Build(_httpMethod, _downstreamUrl, _content?.ReadAsStreamAsync().Result, _headers, - _cookies, _query, _contentType); + _cookies, _query, _contentType).Result; } diff --git a/test/Ocelot.UnitTests/UrlMatcher/UrlPathToUrlTemplateMatcherTests.cs b/test/Ocelot.UnitTests/UrlMatcher/UrlPathToUrlTemplateMatcherTests.cs index c2f64419..d196b479 100644 --- a/test/Ocelot.UnitTests/UrlMatcher/UrlPathToUrlTemplateMatcherTests.cs +++ b/test/Ocelot.UnitTests/UrlMatcher/UrlPathToUrlTemplateMatcherTests.cs @@ -18,11 +18,21 @@ namespace Ocelot.UnitTests.UrlMatcher _urlMatcher = new UrlPathToUrlTemplateMatcher(); } + [Fact] + public void should_not_find_match() + { + this.Given(x => x.GivenIHaveAUpstreamPath("/api/values")) + .And(x => x.GivenIHaveAnUpstreamUrlTemplate("/")) + .When(x => x.WhenIMatchThePaths()) + .And(x => x.ThenTheResultIsFalse()) + .BDDfy(); + } + [Fact] public void can_match_down_stream_url() { - this.Given(x => x.GivenIHaveADownstreamPath("")) - .And(x => x.GivenIHaveAnDownstreamUrlTemplate("")) + this.Given(x => x.GivenIHaveAUpstreamPath("")) + .And(x => x.GivenIHaveAnUpstreamUrlTemplate("")) .When(x => x.WhenIMatchThePaths()) .And(x => x.ThenTheResultIsTrue()) .And(x => x.ThenTheTemplatesVariablesAre(new List())) @@ -33,8 +43,8 @@ namespace Ocelot.UnitTests.UrlMatcher [Fact] public void can_match_down_stream_url_with_no_slash() { - this.Given(x => x.GivenIHaveADownstreamPath("api")) - .Given(x => x.GivenIHaveAnDownstreamUrlTemplate("api")) + this.Given(x => x.GivenIHaveAUpstreamPath("api")) + .Given(x => x.GivenIHaveAnUpstreamUrlTemplate("api")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsTrue()) .And(x => x.ThenTheTemplatesVariablesAre(new List())) @@ -45,8 +55,8 @@ namespace Ocelot.UnitTests.UrlMatcher [Fact] public void can_match_down_stream_url_with_one_slash() { - this.Given(x => x.GivenIHaveADownstreamPath("api/")) - .Given(x => x.GivenIHaveAnDownstreamUrlTemplate("api/")) + this.Given(x => x.GivenIHaveAUpstreamPath("api/")) + .Given(x => x.GivenIHaveAnUpstreamUrlTemplate("api/")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsTrue()) .And(x => x.ThenTheTemplatesVariablesAre(new List())) @@ -57,8 +67,8 @@ namespace Ocelot.UnitTests.UrlMatcher [Fact] public void can_match_down_stream_url_with_downstream_template() { - this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/")) - .Given(x => x.GivenIHaveAnDownstreamUrlTemplate("api/product/products/")) + this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/")) + .Given(x => x.GivenIHaveAnUpstreamUrlTemplate("api/product/products/")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsTrue()) .And(x => x.ThenTheTemplatesVariablesAre(new List())) @@ -66,35 +76,6 @@ namespace Ocelot.UnitTests.UrlMatcher .BDDfy(); } - [Fact] - public void can_match_down_stream_url_with_downstream_template_with_one_query_string_parameter() - { - this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/?soldout=false")) - .Given(x => x.GivenIHaveAnDownstreamUrlTemplate("api/product/products/")) - .When(x => x.WhenIMatchThePaths()) - .Then(x => x.ThenTheResultIsTrue()) - .And(x => x.ThenTheTemplatesVariablesAre(new List())) - .And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/")) - .BDDfy(); - } - - [Fact] - public void can_match_down_stream_url_with_downstream_template_with_one_query_string_parameter_and_one_template() - { - var expectedTemplates = new List - { - new TemplateVariableNameAndValue("{productId}", "1") - }; - - this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/1/variants/?soldout=false")) - .Given(x => x.GivenIHaveAnDownstreamUrlTemplate("api/product/products/{productId}/variants/")) - .When(x => x.WhenIMatchThePaths()) - .Then(x => x.ThenTheResultIsTrue()) - .And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates)) - .And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/{productId}/variants/")) - .BDDfy(); - } - [Fact] public void can_match_down_stream_url_with_downstream_template_with_one_place_holder() { @@ -103,8 +84,8 @@ namespace Ocelot.UnitTests.UrlMatcher new TemplateVariableNameAndValue("{productId}", "1") }; - this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/1")) - .Given(x => x.GivenIHaveAnDownstreamUrlTemplate("api/product/products/{productId}")) + this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1")) + .Given(x => x.GivenIHaveAnUpstreamUrlTemplate("api/product/products/{productId}")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsTrue()) .And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates)) @@ -121,8 +102,8 @@ namespace Ocelot.UnitTests.UrlMatcher new TemplateVariableNameAndValue("{categoryId}", "2") }; - this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/1/2")) - .Given(x => x.GivenIHaveAnDownstreamUrlTemplate("api/product/products/{productId}/{categoryId}")) + this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/2")) + .Given(x => x.GivenIHaveAnUpstreamUrlTemplate("api/product/products/{productId}/{categoryId}")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsTrue()) .And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates)) @@ -139,8 +120,8 @@ namespace Ocelot.UnitTests.UrlMatcher new TemplateVariableNameAndValue("{categoryId}", "2") }; - this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/1/categories/2")) - .And(x => x.GivenIHaveAnDownstreamUrlTemplate("api/product/products/{productId}/categories/{categoryId}")) + this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2")) + .And(x => x.GivenIHaveAnUpstreamUrlTemplate("api/product/products/{productId}/categories/{categoryId}")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsTrue()) .And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates)) @@ -158,8 +139,8 @@ namespace Ocelot.UnitTests.UrlMatcher new TemplateVariableNameAndValue("{variantId}", "123") }; - this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/1/categories/2/variant/123")) - .And(x => x.GivenIHaveAnDownstreamUrlTemplate("api/product/products/{productId}/categories/{categoryId}/variant/{variantId}")) + this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2/variant/123")) + .And(x => x.GivenIHaveAnUpstreamUrlTemplate("api/product/products/{productId}/categories/{categoryId}/variant/{variantId}")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsTrue()) .And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates)) @@ -176,8 +157,8 @@ namespace Ocelot.UnitTests.UrlMatcher new TemplateVariableNameAndValue("{categoryId}", "2") }; - this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/1/categories/2/variant/")) - .And(x => x.GivenIHaveAnDownstreamUrlTemplate("api/product/products/{productId}/categories/{categoryId}/variant/")) + this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2/variant/")) + .And(x => x.GivenIHaveAnUpstreamUrlTemplate("api/product/products/{productId}/categories/{categoryId}/variant/")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsTrue()) .And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates)) @@ -199,12 +180,12 @@ namespace Ocelot.UnitTests.UrlMatcher { _result.DownstreamUrlTemplate.ShouldBe(expectedDownstreamUrlTemplate); } - private void GivenIHaveADownstreamPath(string downstreamPath) + private void GivenIHaveAUpstreamPath(string downstreamPath) { _downstreamUrlPath = downstreamPath; } - private void GivenIHaveAnDownstreamUrlTemplate(string downstreamUrlTemplate) + private void GivenIHaveAnUpstreamUrlTemplate(string downstreamUrlTemplate) { _downstreamPathTemplate = downstreamUrlTemplate; } @@ -218,5 +199,10 @@ namespace Ocelot.UnitTests.UrlMatcher { _result.Match.ShouldBeTrue(); } + + private void ThenTheResultIsFalse() + { + _result.Match.ShouldBeFalse(); + } } } \ No newline at end of file From f8ea87c91b473e082cb3459b7a87cf43272bf24c Mon Sep 17 00:00:00 2001 From: TomPallister Date: Sat, 8 Oct 2016 10:01:11 +0100 Subject: [PATCH 047/183] added a failing test for the url matcher on a case i didnt pick up on...might be time to start thinking about regex for this.... --- .../UrlMatcher/UrlPathToUrlTemplateMatcherTests.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/Ocelot.UnitTests/UrlMatcher/UrlPathToUrlTemplateMatcherTests.cs b/test/Ocelot.UnitTests/UrlMatcher/UrlPathToUrlTemplateMatcherTests.cs index d196b479..d4502552 100644 --- a/test/Ocelot.UnitTests/UrlMatcher/UrlPathToUrlTemplateMatcherTests.cs +++ b/test/Ocelot.UnitTests/UrlMatcher/UrlPathToUrlTemplateMatcherTests.cs @@ -18,6 +18,16 @@ namespace Ocelot.UnitTests.UrlMatcher _urlMatcher = new UrlPathToUrlTemplateMatcher(); } + [Fact] + public void should_find_match_when_template_smaller_than_valid_path() + { + this.Given(x => x.GivenIHaveAUpstreamPath("/api/products/2354325435624623464235")) + .And(x => x.GivenIHaveAnUpstreamUrlTemplate("/api/products/{productId}")) + .When(x => x.WhenIMatchThePaths()) + .And(x => x.ThenTheResultIsTrue()) + .BDDfy(); + } + [Fact] public void should_not_find_match() { From 1fddcf0836b32563f325198eb35f40da90c72f4c Mon Sep 17 00:00:00 2001 From: TomPallister Date: Sun, 9 Oct 2016 15:40:13 +0100 Subject: [PATCH 048/183] regex for url match, means annoying constructor ocelot configuration object but cant work out a better way to do this at the moment --- .../Configuration/Configuration.cs | 14 -- .../DownstreamTemplateAlreadyUsedError.cs | 15 -- .../Configuration/IConfigurationValidator.cs | 13 -- .../Configuration/IOcelotConfiguration.cs | 9 + .../Configuration/OcelotConfiguration.cs | 57 +++++++ .../Infrastructure/Configuration/ReRoute.cs | 17 +- .../ConfigurationValidationResult.cs | 2 +- .../{ => Yaml}/ConfigurationValidator.cs | 4 +- .../DownstreamTemplateAlreadyUsedError.cs | 11 ++ .../Yaml/IConfigurationValidator.cs | 9 + .../Configuration/Yaml/YamlConfiguration.cs | 14 ++ .../Configuration/Yaml/YamlReRoute.cs | 9 + .../DownstreamRouteFinder.cs | 18 +- .../RequestBuilder/HttpRequestBuilder.cs | 8 +- .../RequestBuilder/IRequestBuilder.cs | 3 +- .../ITemplateVariableNameAndValueFinder.cs | 10 ++ .../IUrlPathToUrlTemplateMatcher.cs | 4 +- .../UrlMatcher/RegExUrlMatcher.cs | 17 ++ ... => TemplateVariableNameAndValueFinder.cs} | 26 +-- .../Infrastructure/UrlMatcher/UrlMatch.cs | 8 +- .../DownstreamUrlTemplateVariableReplacer.cs | 5 +- ...wnstreamUrlPathTemplateVariableReplacer.cs | 4 +- .../DownstreamRouteFinderMiddleware.cs | 11 +- .../DownstreamUrlCreatorMiddleware.cs | 18 +- .../HttpRequestBuilderMiddleware.cs | 21 +-- .../Middleware/HttpRequesterMiddleware.cs | 26 ++- .../Middleware/HttpResponderMiddleware.cs | 23 ++- .../Middleware/OcelotMiddleware.cs | 34 ++++ src/Ocelot.Library/project.json | 1 + src/Ocelot/Startup.cs | 19 ++- test/Ocelot.AcceptanceTests/OcelotTests.cs | 20 +-- .../ConfigurationValidationTests.cs | 24 +-- .../Configuration/OcelotConfigurationTests.cs | 142 ++++++++++++++++ .../DownstreamRouteFinderTests.cs | 85 ++++------ .../RequestBuilder/RequestBuilderTests.cs | 17 +- .../UrlMatcher/RegExUrlMatcherTests.cs | 156 ++++++++++++++++++ ...emplateVariableNameAndValueFinderTests.cs} | 84 ++-------- ...eamUrlPathTemplateVariableReplacerTests.cs | 5 +- 38 files changed, 675 insertions(+), 288 deletions(-) delete mode 100644 src/Ocelot.Library/Infrastructure/Configuration/Configuration.cs delete mode 100644 src/Ocelot.Library/Infrastructure/Configuration/DownstreamTemplateAlreadyUsedError.cs delete mode 100644 src/Ocelot.Library/Infrastructure/Configuration/IConfigurationValidator.cs create mode 100644 src/Ocelot.Library/Infrastructure/Configuration/IOcelotConfiguration.cs create mode 100644 src/Ocelot.Library/Infrastructure/Configuration/OcelotConfiguration.cs rename src/Ocelot.Library/Infrastructure/Configuration/{ => Yaml}/ConfigurationValidationResult.cs (90%) rename src/Ocelot.Library/Infrastructure/Configuration/{ => Yaml}/ConfigurationValidator.cs (88%) create mode 100644 src/Ocelot.Library/Infrastructure/Configuration/Yaml/DownstreamTemplateAlreadyUsedError.cs create mode 100644 src/Ocelot.Library/Infrastructure/Configuration/Yaml/IConfigurationValidator.cs create mode 100644 src/Ocelot.Library/Infrastructure/Configuration/Yaml/YamlConfiguration.cs create mode 100644 src/Ocelot.Library/Infrastructure/Configuration/Yaml/YamlReRoute.cs create mode 100644 src/Ocelot.Library/Infrastructure/UrlMatcher/ITemplateVariableNameAndValueFinder.cs create mode 100644 src/Ocelot.Library/Infrastructure/UrlMatcher/RegExUrlMatcher.cs rename src/Ocelot.Library/Infrastructure/UrlMatcher/{UrlPathToUrlTemplateMatcher.cs => TemplateVariableNameAndValueFinder.cs} (81%) create mode 100644 src/Ocelot.Library/Middleware/OcelotMiddleware.cs create mode 100644 test/Ocelot.UnitTests/Configuration/OcelotConfigurationTests.cs create mode 100644 test/Ocelot.UnitTests/UrlMatcher/RegExUrlMatcherTests.cs rename test/Ocelot.UnitTests/UrlMatcher/{UrlPathToUrlTemplateMatcherTests.cs => TemplateVariableNameAndValueFinderTests.cs} (64%) diff --git a/src/Ocelot.Library/Infrastructure/Configuration/Configuration.cs b/src/Ocelot.Library/Infrastructure/Configuration/Configuration.cs deleted file mode 100644 index f1cc9b90..00000000 --- a/src/Ocelot.Library/Infrastructure/Configuration/Configuration.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Collections.Generic; - -namespace Ocelot.Library.Infrastructure.Configuration -{ - public class Configuration - { - public Configuration() - { - ReRoutes = new List(); - } - - public List ReRoutes { get; set; } - } -} diff --git a/src/Ocelot.Library/Infrastructure/Configuration/DownstreamTemplateAlreadyUsedError.cs b/src/Ocelot.Library/Infrastructure/Configuration/DownstreamTemplateAlreadyUsedError.cs deleted file mode 100644 index 3992cb4e..00000000 --- a/src/Ocelot.Library/Infrastructure/Configuration/DownstreamTemplateAlreadyUsedError.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.Configuration -{ - public class DownstreamTemplateAlreadyUsedError : Error - { - public DownstreamTemplateAlreadyUsedError(string message) : base(message) - { - } - } -} diff --git a/src/Ocelot.Library/Infrastructure/Configuration/IConfigurationValidator.cs b/src/Ocelot.Library/Infrastructure/Configuration/IConfigurationValidator.cs deleted file mode 100644 index 595ea21f..00000000 --- a/src/Ocelot.Library/Infrastructure/Configuration/IConfigurationValidator.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.Configuration -{ - public interface IConfigurationValidator - { - Response IsValid(Configuration configuration); - } -} diff --git a/src/Ocelot.Library/Infrastructure/Configuration/IOcelotConfiguration.cs b/src/Ocelot.Library/Infrastructure/Configuration/IOcelotConfiguration.cs new file mode 100644 index 00000000..837edbaf --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Configuration/IOcelotConfiguration.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace Ocelot.Library.Infrastructure.Configuration +{ + public interface IOcelotConfiguration + { + List ReRoutes { get; } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Configuration/OcelotConfiguration.cs b/src/Ocelot.Library/Infrastructure/Configuration/OcelotConfiguration.cs new file mode 100644 index 00000000..be544d6a --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Configuration/OcelotConfiguration.cs @@ -0,0 +1,57 @@ +using System.Collections.Generic; +using Microsoft.Extensions.Options; +using Ocelot.Library.Infrastructure.Configuration.Yaml; + +namespace Ocelot.Library.Infrastructure.Configuration +{ + public class OcelotConfiguration : IOcelotConfiguration + { + private readonly IOptions _options; + private readonly List _reRoutes; + private const string RegExMatchEverything = ".*"; + private const string RegExMatchEndString = "$"; + + public OcelotConfiguration(IOptions options) + { + _options = options; + _reRoutes = new List(); + SetReRoutes(); + } + + private void SetReRoutes() + { + foreach(var reRoute in _options.Value.ReRoutes) + { + var upstreamTemplate = reRoute.UpstreamTemplate; + var placeholders = new List(); + + for (int i = 0; i < upstreamTemplate.Length; i++) + { + if (IsPlaceHolder(upstreamTemplate, i)) + { + var postitionOfPlaceHolderClosingBracket = upstreamTemplate.IndexOf('}', i); + var difference = postitionOfPlaceHolderClosingBracket - i + 1; + var variableName = upstreamTemplate.Substring(i, difference); + placeholders.Add(variableName); + } + } + + foreach (var placeholder in placeholders) + { + upstreamTemplate = upstreamTemplate.Replace(placeholder, RegExMatchEverything); + } + + upstreamTemplate = $"{upstreamTemplate}{RegExMatchEndString}"; + + _reRoutes.Add(new ReRoute(reRoute.DownstreamTemplate, reRoute.UpstreamTemplate, reRoute.UpstreamHttpMethod, upstreamTemplate)); + } + } + + private static bool IsPlaceHolder(string upstreamTemplate, int i) + { + return upstreamTemplate[i] == '{'; + } + + public List ReRoutes => _reRoutes; + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Configuration/ReRoute.cs b/src/Ocelot.Library/Infrastructure/Configuration/ReRoute.cs index 12698ed4..6d0f6497 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/ReRoute.cs +++ b/src/Ocelot.Library/Infrastructure/Configuration/ReRoute.cs @@ -2,8 +2,17 @@ { public class ReRoute { - public string DownstreamTemplate { get; set; } - public string UpstreamTemplate { get; set; } - public string UpstreamHttpMethod { get; set; } + public ReRoute(string downstreamTemplate, string upstreamTemplate, string upstreamHttpMethod, string upstreamTemplatePattern) + { + DownstreamTemplate = downstreamTemplate; + UpstreamTemplate = upstreamTemplate; + UpstreamHttpMethod = upstreamHttpMethod; + UpstreamTemplatePattern = upstreamTemplatePattern; + } + + public string DownstreamTemplate { get; private set; } + public string UpstreamTemplate { get; private set; } + public string UpstreamTemplatePattern { get; private set; } + public string UpstreamHttpMethod { get; private set; } } -} +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Configuration/ConfigurationValidationResult.cs b/src/Ocelot.Library/Infrastructure/Configuration/Yaml/ConfigurationValidationResult.cs similarity index 90% rename from src/Ocelot.Library/Infrastructure/Configuration/ConfigurationValidationResult.cs rename to src/Ocelot.Library/Infrastructure/Configuration/Yaml/ConfigurationValidationResult.cs index abbbcfae..aa3a0d00 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/ConfigurationValidationResult.cs +++ b/src/Ocelot.Library/Infrastructure/Configuration/Yaml/ConfigurationValidationResult.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using Ocelot.Library.Infrastructure.Responses; -namespace Ocelot.Library.Infrastructure.Configuration +namespace Ocelot.Library.Infrastructure.Configuration.Yaml { public class ConfigurationValidationResult { diff --git a/src/Ocelot.Library/Infrastructure/Configuration/ConfigurationValidator.cs b/src/Ocelot.Library/Infrastructure/Configuration/Yaml/ConfigurationValidator.cs similarity index 88% rename from src/Ocelot.Library/Infrastructure/Configuration/ConfigurationValidator.cs rename to src/Ocelot.Library/Infrastructure/Configuration/Yaml/ConfigurationValidator.cs index 5038baf3..777a6c84 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/ConfigurationValidator.cs +++ b/src/Ocelot.Library/Infrastructure/Configuration/Yaml/ConfigurationValidator.cs @@ -2,11 +2,11 @@ using System.Linq; using Ocelot.Library.Infrastructure.Responses; -namespace Ocelot.Library.Infrastructure.Configuration +namespace Ocelot.Library.Infrastructure.Configuration.Yaml { public class ConfigurationValidator : IConfigurationValidator { - public Response IsValid(Configuration configuration) + public Response IsValid(YamlConfiguration configuration) { var duplicateUpstreamTemplates = configuration.ReRoutes .Select(r => r.DownstreamTemplate) diff --git a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/DownstreamTemplateAlreadyUsedError.cs b/src/Ocelot.Library/Infrastructure/Configuration/Yaml/DownstreamTemplateAlreadyUsedError.cs new file mode 100644 index 00000000..5a256f91 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Configuration/Yaml/DownstreamTemplateAlreadyUsedError.cs @@ -0,0 +1,11 @@ +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.Configuration.Yaml +{ + public class DownstreamTemplateAlreadyUsedError : Error + { + public DownstreamTemplateAlreadyUsedError(string message) : base(message) + { + } + } +} diff --git a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/IConfigurationValidator.cs b/src/Ocelot.Library/Infrastructure/Configuration/Yaml/IConfigurationValidator.cs new file mode 100644 index 00000000..dd491928 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Configuration/Yaml/IConfigurationValidator.cs @@ -0,0 +1,9 @@ +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.Configuration.Yaml +{ + public interface IConfigurationValidator + { + Response IsValid(YamlConfiguration configuration); + } +} diff --git a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/YamlConfiguration.cs b/src/Ocelot.Library/Infrastructure/Configuration/Yaml/YamlConfiguration.cs new file mode 100644 index 00000000..69a7eb7a --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Configuration/Yaml/YamlConfiguration.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; + +namespace Ocelot.Library.Infrastructure.Configuration.Yaml +{ + public class YamlConfiguration + { + public YamlConfiguration() + { + ReRoutes = new List(); + } + + public List ReRoutes { get; set; } + } +} diff --git a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/YamlReRoute.cs b/src/Ocelot.Library/Infrastructure/Configuration/Yaml/YamlReRoute.cs new file mode 100644 index 00000000..b012d19a --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Configuration/Yaml/YamlReRoute.cs @@ -0,0 +1,9 @@ +namespace Ocelot.Library.Infrastructure.Configuration.Yaml +{ + public class YamlReRoute + { + public string DownstreamTemplate { get; set; } + public string UpstreamTemplate { get; set; } + public string UpstreamHttpMethod { get; set; } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRouteFinder.cs b/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRouteFinder.cs index f02000c3..d87b4ccd 100644 --- a/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRouteFinder.cs +++ b/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRouteFinder.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using Microsoft.Extensions.Options; +using Ocelot.Library.Infrastructure.Configuration; using Ocelot.Library.Infrastructure.Responses; using Ocelot.Library.Infrastructure.UrlMatcher; @@ -9,24 +10,29 @@ namespace Ocelot.Library.Infrastructure.DownstreamRouteFinder { public class DownstreamRouteFinder : IDownstreamRouteFinder { - private readonly IOptions _configuration; + private readonly IOcelotConfiguration _configuration; private readonly IUrlPathToUrlTemplateMatcher _urlMatcher; + private readonly ITemplateVariableNameAndValueFinder _templateVariableNameAndValueFinder; - public DownstreamRouteFinder(IOptions configuration, IUrlPathToUrlTemplateMatcher urlMatcher) + public DownstreamRouteFinder(IOcelotConfiguration configuration, IUrlPathToUrlTemplateMatcher urlMatcher, ITemplateVariableNameAndValueFinder templateVariableNameAndValueFinder) { _configuration = configuration; _urlMatcher = urlMatcher; + _templateVariableNameAndValueFinder = templateVariableNameAndValueFinder; } public Response FindDownstreamRoute(string upstreamUrlPath, string upstreamHttpMethod) { - foreach (var template in _configuration.Value.ReRoutes.Where(r => string.Equals(r.UpstreamHttpMethod, upstreamHttpMethod, StringComparison.CurrentCultureIgnoreCase))) + foreach (var template in _configuration.ReRoutes.Where(r => string.Equals(r.UpstreamHttpMethod, upstreamHttpMethod, StringComparison.CurrentCultureIgnoreCase))) { - var urlMatch = _urlMatcher.Match(upstreamUrlPath, template.UpstreamTemplate); + var urlMatch = _urlMatcher.Match(upstreamUrlPath, template.UpstreamTemplatePattern); - if (urlMatch.Match) + if (urlMatch.Data.Match) { - return new OkResponse(new DownstreamRoute(urlMatch.TemplateVariableNameAndValues, template.DownstreamTemplate)); + var templateVariableNameAndValues = _templateVariableNameAndValueFinder.Find(upstreamUrlPath, + template.UpstreamTemplate); + + return new OkResponse(new DownstreamRoute(templateVariableNameAndValues.Data, template.DownstreamTemplate)); } } diff --git a/src/Ocelot.Library/Infrastructure/RequestBuilder/HttpRequestBuilder.cs b/src/Ocelot.Library/Infrastructure/RequestBuilder/HttpRequestBuilder.cs index 6a0b7c8f..2aa6c9e2 100644 --- a/src/Ocelot.Library/Infrastructure/RequestBuilder/HttpRequestBuilder.cs +++ b/src/Ocelot.Library/Infrastructure/RequestBuilder/HttpRequestBuilder.cs @@ -5,12 +5,13 @@ using System.Net.Http; using System.Net.Http.Headers; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; +using Ocelot.Library.Infrastructure.Responses; namespace Ocelot.Library.Infrastructure.RequestBuilder { public class HttpRequestBuilder : IRequestBuilder { - public async Task Build(string httpMethod, string downstreamUrl, Stream content, IHeaderDictionary headers, + public async Task> Build(string httpMethod, string downstreamUrl, Stream content, IHeaderDictionary headers, IRequestCookieCollection cookies, string queryString, string contentType) { var method = new HttpMethod(httpMethod); @@ -64,9 +65,8 @@ namespace Ocelot.Library.Infrastructure.RequestBuilder cookieContainer.Add(uri, new Cookie(cookie.Key, cookie.Value)); } } - - - return new Request(httpRequestMessage, cookieContainer); + + return new OkResponse(new Request(httpRequestMessage, cookieContainer)); } } } \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/RequestBuilder/IRequestBuilder.cs b/src/Ocelot.Library/Infrastructure/RequestBuilder/IRequestBuilder.cs index cace3b70..296e4442 100644 --- a/src/Ocelot.Library/Infrastructure/RequestBuilder/IRequestBuilder.cs +++ b/src/Ocelot.Library/Infrastructure/RequestBuilder/IRequestBuilder.cs @@ -1,12 +1,13 @@ using System.IO; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; +using Ocelot.Library.Infrastructure.Responses; namespace Ocelot.Library.Infrastructure.RequestBuilder { public interface IRequestBuilder { - Task Build(string httpMethod, + Task> Build(string httpMethod, string downstreamUrl, Stream content, IHeaderDictionary headers, diff --git a/src/Ocelot.Library/Infrastructure/UrlMatcher/ITemplateVariableNameAndValueFinder.cs b/src/Ocelot.Library/Infrastructure/UrlMatcher/ITemplateVariableNameAndValueFinder.cs new file mode 100644 index 00000000..3cadce39 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/UrlMatcher/ITemplateVariableNameAndValueFinder.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.UrlMatcher +{ + public interface ITemplateVariableNameAndValueFinder + { + Response> Find(string upstreamUrlPath, string upstreamUrlPathTemplate); + } +} diff --git a/src/Ocelot.Library/Infrastructure/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs b/src/Ocelot.Library/Infrastructure/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs index 89e3e5a5..6be56a81 100644 --- a/src/Ocelot.Library/Infrastructure/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs +++ b/src/Ocelot.Library/Infrastructure/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs @@ -1,7 +1,9 @@ +using Ocelot.Library.Infrastructure.Responses; + namespace Ocelot.Library.Infrastructure.UrlMatcher { public interface IUrlPathToUrlTemplateMatcher { - UrlMatch Match(string upstreamUrlPath, string upstreamUrlPathTemplate); + Response Match(string upstreamUrlPath, string upstreamUrlPathTemplate); } } \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlMatcher/RegExUrlMatcher.cs b/src/Ocelot.Library/Infrastructure/UrlMatcher/RegExUrlMatcher.cs new file mode 100644 index 00000000..55855eca --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/UrlMatcher/RegExUrlMatcher.cs @@ -0,0 +1,17 @@ +using System.Text.RegularExpressions; +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.UrlMatcher +{ + public class RegExUrlMatcher : IUrlPathToUrlTemplateMatcher + { + public Response Match(string upstreamUrlPath, string upstreamUrlPathTemplate) + { + var regex = new Regex(upstreamUrlPathTemplate); + + return regex.IsMatch(upstreamUrlPath) + ? new OkResponse(new UrlMatch(true)) + : new OkResponse(new UrlMatch(false)); + } + } +} diff --git a/src/Ocelot.Library/Infrastructure/UrlMatcher/UrlPathToUrlTemplateMatcher.cs b/src/Ocelot.Library/Infrastructure/UrlMatcher/TemplateVariableNameAndValueFinder.cs similarity index 81% rename from src/Ocelot.Library/Infrastructure/UrlMatcher/UrlPathToUrlTemplateMatcher.cs rename to src/Ocelot.Library/Infrastructure/UrlMatcher/TemplateVariableNameAndValueFinder.cs index 4e5aed52..30658afc 100644 --- a/src/Ocelot.Library/Infrastructure/UrlMatcher/UrlPathToUrlTemplateMatcher.cs +++ b/src/Ocelot.Library/Infrastructure/UrlMatcher/TemplateVariableNameAndValueFinder.cs @@ -1,23 +1,16 @@ -using System; using System.Collections.Generic; +using Ocelot.Library.Infrastructure.Responses; namespace Ocelot.Library.Infrastructure.UrlMatcher { - public class UrlPathToUrlTemplateMatcher : IUrlPathToUrlTemplateMatcher + public class TemplateVariableNameAndValueFinder : ITemplateVariableNameAndValueFinder { - public UrlMatch Match(string upstreamUrlPath, string upstreamUrlPathTemplate) + public Response> Find(string upstreamUrlPath, string upstreamUrlPathTemplate) { - if (upstreamUrlPath.Length > upstreamUrlPathTemplate.Length) - { - return new UrlMatch(false, new List(), string.Empty); - } - - var urlPathTemplateCopy = upstreamUrlPathTemplate; - var templateKeysAndValues = new List(); int counterForUrl = 0; - + for (int counterForTemplate = 0; counterForTemplate < upstreamUrlPathTemplate.Length; counterForTemplate++) { if (CharactersDontMatch(upstreamUrlPathTemplate[counterForTemplate], upstreamUrlPath[counterForUrl]) && ContinueScanningUrl(counterForUrl,upstreamUrlPath.Length)) @@ -37,15 +30,14 @@ namespace Ocelot.Library.Infrastructure.UrlMatcher counterForUrl = GetNextCounterPosition(upstreamUrlPath, counterForUrl, '/'); continue; - } - else - { - return new UrlMatch(false, templateKeysAndValues, string.Empty); - } + } + + return new OkResponse>(templateKeysAndValues); } counterForUrl++; } - return new UrlMatch(true, templateKeysAndValues, urlPathTemplateCopy); + + return new OkResponse>(templateKeysAndValues); } private string GetPlaceholderVariableValue(string urlPath, int counterForUrl) diff --git a/src/Ocelot.Library/Infrastructure/UrlMatcher/UrlMatch.cs b/src/Ocelot.Library/Infrastructure/UrlMatcher/UrlMatch.cs index 0eb4cb47..db569d4a 100644 --- a/src/Ocelot.Library/Infrastructure/UrlMatcher/UrlMatch.cs +++ b/src/Ocelot.Library/Infrastructure/UrlMatcher/UrlMatch.cs @@ -1,17 +1,11 @@ -using System.Collections.Generic; - namespace Ocelot.Library.Infrastructure.UrlMatcher { public class UrlMatch { - public UrlMatch(bool match, List templateVariableNameAndValues, string downstreamUrlTemplate) + public UrlMatch(bool match) { Match = match; - TemplateVariableNameAndValues = templateVariableNameAndValues; - DownstreamUrlTemplate = downstreamUrlTemplate; } public bool Match {get;private set;} - public List TemplateVariableNameAndValues {get;private set;} - public string DownstreamUrlTemplate {get;private set;} } } \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs index 34987a8b..d9502341 100644 --- a/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs +++ b/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs @@ -1,11 +1,12 @@ using System.Text; using Ocelot.Library.Infrastructure.DownstreamRouteFinder; +using Ocelot.Library.Infrastructure.Responses; namespace Ocelot.Library.Infrastructure.UrlTemplateReplacer { public class DownstreamUrlTemplateVariableReplacer : IDownstreamUrlTemplateVariableReplacer { - public string ReplaceTemplateVariables(DownstreamRoute downstreamRoute) + public Response ReplaceTemplateVariables(DownstreamRoute downstreamRoute) { var upstreamUrl = new StringBuilder(); @@ -16,7 +17,7 @@ namespace Ocelot.Library.Infrastructure.UrlTemplateReplacer upstreamUrl.Replace(templateVarAndValue.TemplateVariableName, templateVarAndValue.TemplateVariableValue); } - return upstreamUrl.ToString(); + return new OkResponse(upstreamUrl.ToString()); } } } \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs index 9f27db84..3d76671b 100644 --- a/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs +++ b/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs @@ -1,10 +1,10 @@ using Ocelot.Library.Infrastructure.DownstreamRouteFinder; -using Ocelot.Library.Infrastructure.UrlMatcher; +using Ocelot.Library.Infrastructure.Responses; namespace Ocelot.Library.Infrastructure.UrlTemplateReplacer { public interface IDownstreamUrlTemplateVariableReplacer { - string ReplaceTemplateVariables(DownstreamRoute downstreamRoute); + Response ReplaceTemplateVariables(DownstreamRoute downstreamRoute); } } \ No newline at end of file diff --git a/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddleware.cs b/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddleware.cs index eff4b94e..598f953e 100644 --- a/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddleware.cs +++ b/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddleware.cs @@ -2,25 +2,22 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Ocelot.Library.Infrastructure.DownstreamRouteFinder; using Ocelot.Library.Infrastructure.Repository; -using Ocelot.Library.Infrastructure.Responder; namespace Ocelot.Library.Middleware { - public class DownstreamRouteFinderMiddleware + public class DownstreamRouteFinderMiddleware : OcelotMiddleware { private readonly RequestDelegate _next; private readonly IDownstreamRouteFinder _downstreamRouteFinder; - private readonly IHttpResponder _responder; private readonly IScopedRequestDataRepository _scopedRequestDataRepository; public DownstreamRouteFinderMiddleware(RequestDelegate next, IDownstreamRouteFinder downstreamRouteFinder, - IHttpResponder responder, IScopedRequestDataRepository scopedRequestDataRepository) + :base(scopedRequestDataRepository) { _next = next; _downstreamRouteFinder = downstreamRouteFinder; - _responder = responder; _scopedRequestDataRepository = scopedRequestDataRepository; } @@ -32,12 +29,12 @@ namespace Ocelot.Library.Middleware if (downstreamRoute.IsError) { - await _responder.CreateNotFoundResponse(context); + SetPipelineError(downstreamRoute.Errors); return; } _scopedRequestDataRepository.Add("DownstreamRoute", downstreamRoute.Data); - + await _next.Invoke(context); } } diff --git a/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddleware.cs b/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddleware.cs index ed0f330d..2627a722 100644 --- a/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddleware.cs +++ b/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddleware.cs @@ -7,22 +7,20 @@ using Ocelot.Library.Infrastructure.UrlTemplateReplacer; namespace Ocelot.Library.Middleware { - public class DownstreamUrlCreatorMiddleware + public class DownstreamUrlCreatorMiddleware : OcelotMiddleware { private readonly RequestDelegate _next; private readonly IDownstreamUrlTemplateVariableReplacer _urlReplacer; private readonly IScopedRequestDataRepository _scopedRequestDataRepository; - private readonly IHttpResponder _responder; public DownstreamUrlCreatorMiddleware(RequestDelegate next, IDownstreamUrlTemplateVariableReplacer urlReplacer, - IScopedRequestDataRepository scopedRequestDataRepository, - IHttpResponder responder) + IScopedRequestDataRepository scopedRequestDataRepository) + :base(scopedRequestDataRepository) { _next = next; _urlReplacer = urlReplacer; _scopedRequestDataRepository = scopedRequestDataRepository; - _responder = responder; } public async Task Invoke(HttpContext context) @@ -31,13 +29,19 @@ namespace Ocelot.Library.Middleware if (downstreamRoute.IsError) { - await _responder.CreateNotFoundResponse(context); + SetPipelineError(downstreamRoute.Errors); return; } var downstreamUrl = _urlReplacer.ReplaceTemplateVariables(downstreamRoute.Data); - _scopedRequestDataRepository.Add("DownstreamUrl", downstreamUrl); + if (downstreamUrl.IsError) + { + SetPipelineError(downstreamUrl.Errors); + return; + } + + _scopedRequestDataRepository.Add("DownstreamUrl", downstreamUrl.Data); await _next.Invoke(context); } diff --git a/src/Ocelot.Library/Middleware/HttpRequestBuilderMiddleware.cs b/src/Ocelot.Library/Middleware/HttpRequestBuilderMiddleware.cs index e41b1417..b800a3d7 100644 --- a/src/Ocelot.Library/Middleware/HttpRequestBuilderMiddleware.cs +++ b/src/Ocelot.Library/Middleware/HttpRequestBuilderMiddleware.cs @@ -1,27 +1,22 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Ocelot.Library.Infrastructure.Repository; -using Ocelot.Library.Infrastructure.Requester; -using Ocelot.Library.Infrastructure.Responder; +using Ocelot.Library.Infrastructure.RequestBuilder; namespace Ocelot.Library.Middleware { - using Infrastructure.RequestBuilder; - - public class HttpRequestBuilderMiddleware + public class HttpRequestBuilderMiddleware : OcelotMiddleware { private readonly RequestDelegate _next; - private readonly IHttpResponder _responder; private readonly IScopedRequestDataRepository _scopedRequestDataRepository; private readonly IRequestBuilder _requestBuilder; public HttpRequestBuilderMiddleware(RequestDelegate next, - IHttpResponder responder, IScopedRequestDataRepository scopedRequestDataRepository, IRequestBuilder requestBuilder) + :base(scopedRequestDataRepository) { _next = next; - _responder = responder; _scopedRequestDataRepository = scopedRequestDataRepository; _requestBuilder = requestBuilder; } @@ -32,7 +27,7 @@ namespace Ocelot.Library.Middleware if (downstreamUrl.IsError) { - await _responder.CreateNotFoundResponse(context); + SetPipelineError(downstreamUrl.Errors); return; } @@ -40,7 +35,13 @@ namespace Ocelot.Library.Middleware .Build(context.Request.Method, downstreamUrl.Data, context.Request.Body, context.Request.Headers, context.Request.Cookies, context.Request.QueryString.Value, context.Request.ContentType); - _scopedRequestDataRepository.Add("Request", request); + if (request.IsError) + { + SetPipelineError(request.Errors); + return; + } + + _scopedRequestDataRepository.Add("Request", request.Data); await _next.Invoke(context); } diff --git a/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs b/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs index e35121ca..7c2c4b9d 100644 --- a/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs +++ b/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs @@ -1,29 +1,24 @@ -using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Ocelot.Library.Infrastructure.Repository; +using Ocelot.Library.Infrastructure.RequestBuilder; using Ocelot.Library.Infrastructure.Requester; -using Ocelot.Library.Infrastructure.Responder; namespace Ocelot.Library.Middleware { - using Infrastructure.RequestBuilder; - - public class HttpRequesterMiddleware + public class HttpRequesterMiddleware : OcelotMiddleware { private readonly RequestDelegate _next; private readonly IHttpRequester _requester; - private readonly IHttpResponder _responder; private readonly IScopedRequestDataRepository _scopedRequestDataRepository; public HttpRequesterMiddleware(RequestDelegate next, IHttpRequester requester, - IHttpResponder responder, IScopedRequestDataRepository scopedRequestDataRepository) + :base(scopedRequestDataRepository) { _next = next; _requester = requester; - _responder = responder; _scopedRequestDataRepository = scopedRequestDataRepository; } @@ -33,16 +28,19 @@ namespace Ocelot.Library.Middleware if (request.IsError) { - await _responder.CreateNotFoundResponse(context); + SetPipelineError(request.Errors); return; } - var response = await _requester - .GetResponse(request.Data); + var response = await _requester.GetResponse(request.Data); - _scopedRequestDataRepository.Add("Response", response.Data); - - await _next.Invoke(context); + if (response.IsError) + { + SetPipelineError(response.Errors); + return; + } + + _scopedRequestDataRepository.Add("Response", response.Data); } } } \ No newline at end of file diff --git a/src/Ocelot.Library/Middleware/HttpResponderMiddleware.cs b/src/Ocelot.Library/Middleware/HttpResponderMiddleware.cs index 09b31f70..7974ad62 100644 --- a/src/Ocelot.Library/Middleware/HttpResponderMiddleware.cs +++ b/src/Ocelot.Library/Middleware/HttpResponderMiddleware.cs @@ -6,10 +6,7 @@ using Ocelot.Library.Infrastructure.Responder; namespace Ocelot.Library.Middleware { - /// - /// Terminating middleware that is responsible for returning a http response to the client - /// - public class HttpResponderMiddleware + public class HttpResponderMiddleware : OcelotMiddleware { private readonly RequestDelegate _next; private readonly IHttpResponder _responder; @@ -18,6 +15,7 @@ namespace Ocelot.Library.Middleware public HttpResponderMiddleware(RequestDelegate next, IHttpResponder responder, IScopedRequestDataRepository scopedRequestDataRepository) + :base(scopedRequestDataRepository) { _next = next; _responder = responder; @@ -26,9 +24,22 @@ namespace Ocelot.Library.Middleware public async Task Invoke(HttpContext context) { - var response = _scopedRequestDataRepository.Get("Response"); + await _next.Invoke(context); - await _responder.CreateResponse(context, response.Data); + if (PipelineError()) + { + //todo obviously this needs to be better...prob look at response errors + // and make a decision i guess + var errors = GetPipelineErrors(); + + await _responder.CreateNotFoundResponse(context); + } + else + { + var response = _scopedRequestDataRepository.Get("Response"); + + await _responder.CreateResponse(context, response.Data); + } } } } \ No newline at end of file diff --git a/src/Ocelot.Library/Middleware/OcelotMiddleware.cs b/src/Ocelot.Library/Middleware/OcelotMiddleware.cs new file mode 100644 index 00000000..f20daa96 --- /dev/null +++ b/src/Ocelot.Library/Middleware/OcelotMiddleware.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using Ocelot.Library.Infrastructure.Repository; +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Middleware +{ + public class OcelotMiddleware + { + private readonly IScopedRequestDataRepository _scopedRequestDataRepository; + + public OcelotMiddleware(IScopedRequestDataRepository scopedRequestDataRepository) + { + _scopedRequestDataRepository = scopedRequestDataRepository; + } + + public void SetPipelineError(List errors) + { + _scopedRequestDataRepository.Add("OcelotMiddlewareError", true); + _scopedRequestDataRepository.Add("OcelotMiddlewareErrors", errors); + } + + public bool PipelineError() + { + var response = _scopedRequestDataRepository.Get("OcelotMiddlewareError"); + return response.Data; + } + + public List GetPipelineErrors() + { + var response = _scopedRequestDataRepository.Get>("OcelotMiddlewareErrors"); + return response.Data; + } + } +} diff --git a/src/Ocelot.Library/project.json b/src/Ocelot.Library/project.json index b3d22c5c..e889d22f 100644 --- a/src/Ocelot.Library/project.json +++ b/src/Ocelot.Library/project.json @@ -17,6 +17,7 @@ "Microsoft.Extensions.Logging.Debug": "1.0.0", "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", "Microsoft.AspNetCore.Http": "1.0.0", + "System.Text.RegularExpressions": "4.1.0", "YamlDotNet": "3.9.0" }, diff --git a/src/Ocelot/Startup.cs b/src/Ocelot/Startup.cs index ed685d57..e2ecb505 100644 --- a/src/Ocelot/Startup.cs +++ b/src/Ocelot/Startup.cs @@ -1,10 +1,14 @@ -using Microsoft.AspNetCore.Builder; +using System.Collections.Generic; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration.Memory; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Ocelot.Library.Infrastructure.Configuration; +using Ocelot.Library.Infrastructure.Configuration.Yaml; using Ocelot.Library.Infrastructure.DownstreamRouteFinder; using Ocelot.Library.Infrastructure.Repository; using Ocelot.Library.Infrastructure.RequestBuilder; @@ -26,6 +30,7 @@ namespace Ocelot .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) .AddYamlFile("configuration.yaml") .AddEnvironmentVariables(); + Configuration = builder.Build(); } @@ -35,11 +40,13 @@ namespace Ocelot public void ConfigureServices(IServiceCollection services) { services.AddOptions(); - - services.Configure(Configuration); + + services.Configure(Configuration); // Add framework services. - services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); @@ -58,6 +65,8 @@ namespace Ocelot loggerFactory.AddDebug(); + app.UseHttpResponderMiddleware(); + app.UseDownstreamRouteFinderMiddleware(); app.UserDownstreamUrlCreatorMiddleware(); @@ -65,8 +74,6 @@ namespace Ocelot app.UseHttpRequestBuilderMiddleware(); app.UseHttpRequesterMiddleware(); - - app.UseHttpResponderMiddleware(); } } } diff --git a/test/Ocelot.AcceptanceTests/OcelotTests.cs b/test/Ocelot.AcceptanceTests/OcelotTests.cs index 4d57adf2..a4c3d5d5 100644 --- a/test/Ocelot.AcceptanceTests/OcelotTests.cs +++ b/test/Ocelot.AcceptanceTests/OcelotTests.cs @@ -6,7 +6,7 @@ using System.Net.Http; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Ocelot.AcceptanceTests.Fake; -using Ocelot.Library.Infrastructure.Configuration; +using Ocelot.Library.Infrastructure.Configuration.Yaml; using Shouldly; using TestStack.BDDfy; using Xunit; @@ -32,7 +32,7 @@ namespace Ocelot.AcceptanceTests [Fact] public void should_return_response_404() { - this.Given(x => x.GivenThereIsAConfiguration(new Configuration())) + this.Given(x => x.GivenThereIsAConfiguration(new YamlConfiguration())) .And(x => x.GivenTheApiGatewayIsRunning()) .When(x => x.WhenIGetUrlOnTheApiGateway("/")) .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound)) @@ -43,11 +43,11 @@ namespace Ocelot.AcceptanceTests public void should_return_response_200() { this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879")) - .And(x => x.GivenThereIsAConfiguration(new Configuration + .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration { - ReRoutes = new List + ReRoutes = new List { - new ReRoute + new YamlReRoute { DownstreamTemplate = "http://localhost:51879/", UpstreamTemplate = "/", @@ -66,11 +66,11 @@ namespace Ocelot.AcceptanceTests public void should_return_response_201() { this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879")) - .And(x => x.GivenThereIsAConfiguration(new Configuration + .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration { - ReRoutes = new List + ReRoutes = new List { - new ReRoute + new YamlReRoute { DownstreamTemplate = "http://localhost:51879/", UpstreamTemplate = "/", @@ -100,7 +100,7 @@ namespace Ocelot.AcceptanceTests _client = _server.CreateClient(); } - private void GivenThereIsAConfiguration(Configuration configuration) + private void GivenThereIsAConfiguration(YamlConfiguration yamlConfiguration) { var serializer = new Serializer(); @@ -111,7 +111,7 @@ namespace Ocelot.AcceptanceTests using (TextWriter writer = File.CreateText(_configurationPath)) { - serializer.Serialize(writer, configuration); + serializer.Serialize(writer, yamlConfiguration); } } diff --git a/test/Ocelot.UnitTests/Configuration/ConfigurationValidationTests.cs b/test/Ocelot.UnitTests/Configuration/ConfigurationValidationTests.cs index 3ddc8d38..3f3526e8 100644 --- a/test/Ocelot.UnitTests/Configuration/ConfigurationValidationTests.cs +++ b/test/Ocelot.UnitTests/Configuration/ConfigurationValidationTests.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using Ocelot.Library.Infrastructure.Configuration; +using Ocelot.Library.Infrastructure.Configuration.Yaml; using Ocelot.Library.Infrastructure.Responses; using Shouldly; using TestStack.BDDfy; @@ -9,7 +9,7 @@ namespace Ocelot.UnitTests.Configuration { public class ConfigurationValidationTests { - private Library.Infrastructure.Configuration.Configuration _configuration; + private YamlConfiguration _yamlConfiguration; private readonly IConfigurationValidator _configurationValidator; private Response _result; @@ -21,11 +21,11 @@ namespace Ocelot.UnitTests.Configuration [Fact] public void configuration_is_valid_with_one_reroute() { - this.Given(x => x.GivenAConfiguration(new Library.Infrastructure.Configuration.Configuration() + this.Given(x => x.GivenAConfiguration(new YamlConfiguration() { - ReRoutes = new List + ReRoutes = new List { - new ReRoute + new YamlReRoute { DownstreamTemplate = "http://www.bbc.co.uk", UpstreamTemplate = "http://asdf.com" @@ -40,16 +40,16 @@ namespace Ocelot.UnitTests.Configuration [Fact] public void configuration_is_not_valid_with_duplicate_reroutes() { - this.Given(x => x.GivenAConfiguration(new Library.Infrastructure.Configuration.Configuration() + this.Given(x => x.GivenAConfiguration(new YamlConfiguration() { - ReRoutes = new List + ReRoutes = new List { - new ReRoute + new YamlReRoute { DownstreamTemplate = "http://www.bbc.co.uk", UpstreamTemplate = "http://asdf.com" }, - new ReRoute + new YamlReRoute { DownstreamTemplate = "http://www.bbc.co.uk", UpstreamTemplate = "http://lol.com" @@ -62,14 +62,14 @@ namespace Ocelot.UnitTests.Configuration .BDDfy(); } - private void GivenAConfiguration(Library.Infrastructure.Configuration.Configuration configuration) + private void GivenAConfiguration(YamlConfiguration yamlConfiguration) { - _configuration = configuration; + _yamlConfiguration = yamlConfiguration; } private void WhenIValidateTheConfiguration() { - _result = _configurationValidator.IsValid(_configuration); + _result = _configurationValidator.IsValid(_yamlConfiguration); } private void ThenTheResultIsValid() diff --git a/test/Ocelot.UnitTests/Configuration/OcelotConfigurationTests.cs b/test/Ocelot.UnitTests/Configuration/OcelotConfigurationTests.cs new file mode 100644 index 00000000..1c030e6f --- /dev/null +++ b/test/Ocelot.UnitTests/Configuration/OcelotConfigurationTests.cs @@ -0,0 +1,142 @@ +using System.Collections.Generic; +using Microsoft.Extensions.Options; +using Moq; +using Ocelot.Library.Infrastructure.Configuration; +using Ocelot.Library.Infrastructure.Configuration.Yaml; +using Shouldly; +using TestStack.BDDfy; +using Xunit; + +namespace Ocelot.UnitTests.Configuration +{ + public class OcelotConfigurationTests + { + private readonly Mock> _yamlConfig; + private OcelotConfiguration _config; + private YamlConfiguration _yamlConfiguration; + + public OcelotConfigurationTests() + { + _yamlConfig = new Mock>(); + } + + [Fact] + public void should_create_template_pattern_that_matches_anything_to_end_of_string() + { + this.Given(x => x.GivenTheYamlConfigIs(new YamlConfiguration + { + ReRoutes = new List + { + new YamlReRoute + { + UpstreamTemplate = "/api/products/{productId}", + DownstreamTemplate = "/products/{productId}", + UpstreamHttpMethod = "Get" + } + } + })) + .When(x => x.WhenIInstanciateTheOcelotConfig()) + .Then(x => x.ThenTheReRoutesAre(new List + { + new ReRoute("/products/{productId}","/api/products/{productId}", "Get", "/api/products/.*$") + })) + .BDDfy(); + } + + [Fact] + public void should_create_template_pattern_that_matches_more_than_one_placeholder() + { + this.Given(x => x.GivenTheYamlConfigIs(new YamlConfiguration + { + ReRoutes = new List + { + new YamlReRoute + { + UpstreamTemplate = "/api/products/{productId}/variants/{variantId}", + DownstreamTemplate = "/products/{productId}", + UpstreamHttpMethod = "Get" + } + } + })) + .When(x => x.WhenIInstanciateTheOcelotConfig()) + .Then(x => x.ThenTheReRoutesAre(new List + { + new ReRoute("/products/{productId}","/api/products/{productId}/variants/{variantId}", "Get", "/api/products/.*/variants/.*$") + })) + .BDDfy(); + } + + [Fact] + public void should_create_template_pattern_that_matches_more_than_one_placeholder_with_trailing_slash() + { + this.Given(x => x.GivenTheYamlConfigIs(new YamlConfiguration + { + ReRoutes = new List + { + new YamlReRoute + { + UpstreamTemplate = "/api/products/{productId}/variants/{variantId}/", + DownstreamTemplate = "/products/{productId}", + UpstreamHttpMethod = "Get" + } + } + })) + .When(x => x.WhenIInstanciateTheOcelotConfig()) + .Then(x => x.ThenTheReRoutesAre(new List + { + new ReRoute("/products/{productId}","/api/products/{productId}/variants/{variantId}/", "Get", "/api/products/.*/variants/.*/$") + })) + .BDDfy(); + } + + [Fact] + public void should_create_template_pattern_that_matches_to_end_of_string() + { + this.Given(x => x.GivenTheYamlConfigIs(new YamlConfiguration + { + ReRoutes = new List + { + new YamlReRoute + { + UpstreamTemplate = "/", + DownstreamTemplate = "/api/products/", + UpstreamHttpMethod = "Get" + } + } + })) + .When(x => x.WhenIInstanciateTheOcelotConfig()) + .Then(x => x.ThenTheReRoutesAre(new List + { + new ReRoute("/api/products/","/", "Get", "/$") + })) + .BDDfy(); + } + + private void GivenTheYamlConfigIs(YamlConfiguration yamlConfiguration) + { + _yamlConfiguration = yamlConfiguration; + _yamlConfig + .Setup(x => x.Value) + .Returns(_yamlConfiguration); + } + + private void WhenIInstanciateTheOcelotConfig() + { + _config = new OcelotConfiguration(_yamlConfig.Object); + } + + private void ThenTheReRoutesAre(List expectedReRoutes) + { + for (int i = 0; i < _config.ReRoutes.Count; i++) + { + var result = _config.ReRoutes[i]; + var expected = expectedReRoutes[i]; + + result.DownstreamTemplate.ShouldBe(expected.DownstreamTemplate); + result.UpstreamHttpMethod.ShouldBe(expected.UpstreamHttpMethod); + result.UpstreamTemplate.ShouldBe(expected.UpstreamTemplate); + result.UpstreamTemplatePattern.ShouldBe(expected.UpstreamTemplatePattern); + } + } + } +} diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs index a1c23bee..ee35836b 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using Microsoft.Extensions.Options; using Moq; using Ocelot.Library.Infrastructure.Configuration; using Ocelot.Library.Infrastructure.DownstreamRouteFinder; @@ -14,38 +13,35 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder public class DownstreamRouteFinderTests { private readonly IDownstreamRouteFinder _downstreamRouteFinder; - private readonly Mock> _mockConfig; + private readonly Mock _mockConfig; private readonly Mock _mockMatcher; + private readonly Mock _finder; private string _upstreamUrlPath; private Response _result; private Response _response; - private Library.Infrastructure.Configuration.Configuration _configuration; - private UrlMatch _match; + private List _reRoutesConfig; + private Response _match; private string _upstreamHttpMethod; public DownstreamRouteFinderTests() { - _mockConfig = new Mock>(); + _mockConfig = new Mock(); _mockMatcher = new Mock(); - _downstreamRouteFinder = new Library.Infrastructure.DownstreamRouteFinder.DownstreamRouteFinder(_mockConfig.Object, _mockMatcher.Object); + _finder = new Mock(); + _downstreamRouteFinder = new Library.Infrastructure.DownstreamRouteFinder.DownstreamRouteFinder(_mockConfig.Object, _mockMatcher.Object, _finder.Object); } [Fact] public void should_return_route() { this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath")) - .And(x => x.GivenTheConfigurationIs(new Library.Infrastructure.Configuration.Configuration { - ReRoutes = new List + .And(x => x.GivenTheTemplateVariableAndNameFinderReturns(new OkResponse>(new List()))) + .And(x => x.GivenTheConfigurationIs(new List { - new ReRoute() - { - UpstreamTemplate = "someUpstreamPath", - DownstreamTemplate = "someDownstreamPath", - UpstreamHttpMethod = "Get" - } + new ReRoute("someDownstreamPath","someUpstreamPath", "Get", "someUpstreamPath") } - })) - .And(x => x.GivenTheUrlMatcherReturns(new UrlMatch(true, new List(), "someDownstreamPath"))) + )) + .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true)))) .And(x => x.GivenTheUpstreamHttpMethodIs("Get")) .When(x => x.WhenICallTheFinder()) .Then( @@ -58,25 +54,14 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder public void should_return_correct_route_for_http_verb() { this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath")) - .And(x => x.GivenTheConfigurationIs(new Library.Infrastructure.Configuration.Configuration - { - ReRoutes = new List + .And(x => x.GivenTheTemplateVariableAndNameFinderReturns(new OkResponse>(new List()))) + .And(x => x.GivenTheConfigurationIs(new List { - new ReRoute() - { - UpstreamTemplate = "someUpstreamPath", - DownstreamTemplate = "someDownstreamPath", - UpstreamHttpMethod = "Get" - }, - new ReRoute() - { - UpstreamTemplate = "someUpstreamPath", - DownstreamTemplate = "someDownstreamPathForAPost", - UpstreamHttpMethod = "Post" - } + new ReRoute("someDownstreamPath", "someUpstreamPath", "Get", string.Empty), + new ReRoute("someDownstreamPathForAPost", "someUpstreamPath", "Post", string.Empty) } - })) - .And(x => x.GivenTheUrlMatcherReturns(new UrlMatch(true, new List(), "someDownstreamPathForAPost"))) + )) + .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true)))) .And(x => x.GivenTheUpstreamHttpMethodIs("Post")) .When(x => x.WhenICallTheFinder()) .Then( @@ -88,19 +73,12 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder public void should_not_return_route() { this.Given(x => x.GivenThereIsAnUpstreamUrlPath("somePath")) - .And(x => x.GivenTheConfigurationIs(new Library.Infrastructure.Configuration.Configuration - { - ReRoutes = new List + .And(x => x.GivenTheConfigurationIs(new List { - new ReRoute() - { - UpstreamTemplate = "somePath", - DownstreamTemplate = "somPath", - UpstreamHttpMethod = "Get" - } + new ReRoute("somPath", "somePath", "Get", "somePath") } - })) - .And(x => x.GivenTheUrlMatcherReturns(new UrlMatch(false, new List(), null))) + )) + .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(false)))) .And(x => x.GivenTheUpstreamHttpMethodIs("Get")) .When(x => x.WhenICallTheFinder()) .Then( @@ -109,6 +87,13 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .BDDfy(); } + private void GivenTheTemplateVariableAndNameFinderReturns(Response> response) + { + _finder + .Setup(x => x.Find(It.IsAny(), It.IsAny())) + .Returns(response); + } + private void GivenTheUpstreamHttpMethodIs(string upstreamHttpMethod) { _upstreamHttpMethod = upstreamHttpMethod; @@ -122,10 +107,10 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder private void ThenTheUrlMatcherIsCalledCorrectly() { _mockMatcher - .Verify(x => x.Match(_upstreamUrlPath, _configuration.ReRoutes[0].UpstreamTemplate), Times.Once); + .Verify(x => x.Match(_upstreamUrlPath, _reRoutesConfig[0].UpstreamTemplate), Times.Once); } - private void GivenTheUrlMatcherReturns(UrlMatch match) + private void GivenTheUrlMatcherReturns(Response match) { _match = match; _mockMatcher @@ -133,12 +118,12 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .Returns(_match); } - private void GivenTheConfigurationIs(Library.Infrastructure.Configuration.Configuration configuration) + private void GivenTheConfigurationIs(List reRoutesConfig) { - _configuration = configuration; + _reRoutesConfig = reRoutesConfig; _mockConfig - .Setup(x => x.Value) - .Returns(_configuration); + .Setup(x => x.ReRoutes) + .Returns(_reRoutesConfig); } private void GivenThereIsAnUpstreamUrlPath(string upstreamUrlPath) diff --git a/test/Ocelot.UnitTests/RequestBuilder/RequestBuilderTests.cs b/test/Ocelot.UnitTests/RequestBuilder/RequestBuilderTests.cs index db6cf5e6..ad11ae2a 100644 --- a/test/Ocelot.UnitTests/RequestBuilder/RequestBuilderTests.cs +++ b/test/Ocelot.UnitTests/RequestBuilder/RequestBuilderTests.cs @@ -6,6 +6,7 @@ using System.Net.Http; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Internal; using Ocelot.Library.Infrastructure.RequestBuilder; +using Ocelot.Library.Infrastructure.Responses; using Shouldly; using TestStack.BDDfy; using Xunit; @@ -22,7 +23,7 @@ namespace Ocelot.UnitTests.RequestBuilder private string _query; private string _contentType; private readonly IRequestBuilder _requestBuilder; - private Request _result; + private Response _result; public RequestBuilderTests() { @@ -131,7 +132,7 @@ namespace Ocelot.UnitTests.RequestBuilder private void ThenTheCorrectQueryStringIsUsed(string expected) { - _result.HttpRequestMessage.RequestUri.Query.ShouldBe(expected); + _result.Data.HttpRequestMessage.RequestUri.Query.ShouldBe(expected); } private void GivenTheQueryStringIs(string query) @@ -141,7 +142,7 @@ namespace Ocelot.UnitTests.RequestBuilder private void ThenTheCorrectCookiesAreUsed(IRequestCookieCollection expected) { - var resultCookies = _result.CookieContainer.GetCookies(new Uri(_downstreamUrl + _query)); + var resultCookies = _result.Data.CookieContainer.GetCookies(new Uri(_downstreamUrl + _query)); var resultDictionary = resultCookies.Cast().ToDictionary(cook => cook.Name, cook => cook.Value); foreach (var expectedCookie in expected) @@ -162,7 +163,7 @@ namespace Ocelot.UnitTests.RequestBuilder foreach (var expectedHeader in expectedHeaders) { - _result.HttpRequestMessage.Headers.ShouldContain(x => x.Key == expectedHeader.Key && x.Value.First() == expectedHeader.Value[0]); + _result.Data.HttpRequestMessage.Headers.ShouldContain(x => x.Key == expectedHeader.Key && x.Value.First() == expectedHeader.Value[0]); } } @@ -172,7 +173,7 @@ namespace Ocelot.UnitTests.RequestBuilder foreach (var expectedHeader in expectedHeaders) { - _result.HttpRequestMessage.Content.Headers.ShouldContain(x => x.Key == expectedHeader.Key + _result.Data.HttpRequestMessage.Content.Headers.ShouldContain(x => x.Key == expectedHeader.Key && x.Value.First() == expectedHeader.Value[0] ); } @@ -207,17 +208,17 @@ namespace Ocelot.UnitTests.RequestBuilder private void ThenTheCorrectDownstreamUrlIsUsed(string expected) { - _result.HttpRequestMessage.RequestUri.AbsoluteUri.ShouldBe(expected); + _result.Data.HttpRequestMessage.RequestUri.AbsoluteUri.ShouldBe(expected); } private void ThenTheCorrectHttpMethodIsUsed(HttpMethod expected) { - _result.HttpRequestMessage.Method.Method.ShouldBe(expected.Method); + _result.Data.HttpRequestMessage.Method.Method.ShouldBe(expected.Method); } private void ThenTheCorrectContentIsUsed(HttpContent expected) { - _result.HttpRequestMessage.Content.ReadAsStringAsync().Result.ShouldBe(expected.ReadAsStringAsync().Result); + _result.Data.HttpRequestMessage.Content.ReadAsStringAsync().Result.ShouldBe(expected.ReadAsStringAsync().Result); } } } diff --git a/test/Ocelot.UnitTests/UrlMatcher/RegExUrlMatcherTests.cs b/test/Ocelot.UnitTests/UrlMatcher/RegExUrlMatcherTests.cs new file mode 100644 index 00000000..5774c573 --- /dev/null +++ b/test/Ocelot.UnitTests/UrlMatcher/RegExUrlMatcherTests.cs @@ -0,0 +1,156 @@ +using Ocelot.Library.Infrastructure.Responses; +using Ocelot.Library.Infrastructure.UrlMatcher; +using Shouldly; +using TestStack.BDDfy; +using Xunit; + +namespace Ocelot.UnitTests.UrlMatcher +{ + public class RegExUrlMatcherTests + { + private readonly IUrlPathToUrlTemplateMatcher _urlMatcher; + private string _downstreamUrlPath; + private string _downstreamPathTemplate; + private Response _result; + + public RegExUrlMatcherTests() + { + _urlMatcher = new RegExUrlMatcher(); + } + + [Fact] + public void should_find_match_when_template_smaller_than_valid_path() + { + this.Given(x => x.GivenIHaveAUpstreamPath("/api/products/2354325435624623464235")) + .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("/api/products/.*$")) + .When(x => x.WhenIMatchThePaths()) + .And(x => x.ThenTheResultIsTrue()) + .BDDfy(); + } + + [Fact] + public void should_not_find_match() + { + this.Given(x => x.GivenIHaveAUpstreamPath("/api/values")) + .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("/$")) + .When(x => x.WhenIMatchThePaths()) + .And(x => x.ThenTheResultIsFalse()) + .BDDfy(); + } + + [Fact] + public void can_match_down_stream_url() + { + this.Given(x => x.GivenIHaveAUpstreamPath("")) + .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("$")) + .When(x => x.WhenIMatchThePaths()) + .And(x => x.ThenTheResultIsTrue()) + .BDDfy(); + } + + [Fact] + public void can_match_down_stream_url_with_no_slash() + { + this.Given(x => x.GivenIHaveAUpstreamPath("api")) + .Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("api$")) + .When(x => x.WhenIMatchThePaths()) + .Then(x => x.ThenTheResultIsTrue()) + .BDDfy(); + } + + [Fact] + public void can_match_down_stream_url_with_one_slash() + { + this.Given(x => x.GivenIHaveAUpstreamPath("api/")) + .Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("api/$")) + .When(x => x.WhenIMatchThePaths()) + .Then(x => x.ThenTheResultIsTrue()) + .BDDfy(); + } + + [Fact] + public void can_match_down_stream_url_with_downstream_template() + { + this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/")) + .Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("api/product/products/$")) + .When(x => x.WhenIMatchThePaths()) + .Then(x => x.ThenTheResultIsTrue()) + .BDDfy(); + } + + [Fact] + public void can_match_down_stream_url_with_downstream_template_with_one_place_holder() + { + this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1")) + .Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("api/product/products/.*$")) + .When(x => x.WhenIMatchThePaths()) + .Then(x => x.ThenTheResultIsTrue()) + .BDDfy(); + } + + [Fact] + public void can_match_down_stream_url_with_downstream_template_with_two_place_holders() + { + this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/2")) + .Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("api/product/products/.*/.*$")) + .When(x => x.WhenIMatchThePaths()) + .Then(x => x.ThenTheResultIsTrue()) + .BDDfy(); + } + + [Fact] + public void can_match_down_stream_url_with_downstream_template_with_two_place_holders_seperated_by_something() + { + this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2")) + .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("api/product/products/.*/categories/.*$")) + .When(x => x.WhenIMatchThePaths()) + .Then(x => x.ThenTheResultIsTrue()) + .BDDfy(); + } + + [Fact] + public void can_match_down_stream_url_with_downstream_template_with_three_place_holders_seperated_by_something() + { + this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2/variant/123")) + .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("api/product/products/.*/categories/.*/variant/.*$")) + .When(x => x.WhenIMatchThePaths()) + .Then(x => x.ThenTheResultIsTrue()) + .BDDfy(); + } + + [Fact] + public void can_match_down_stream_url_with_downstream_template_with_three_place_holders() + { + this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2/variant/")) + .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("api/product/products/.*/categories/.*/variant/$")) + .When(x => x.WhenIMatchThePaths()) + .Then(x => x.ThenTheResultIsTrue()) + .BDDfy(); + } + + private void GivenIHaveAUpstreamPath(string downstreamPath) + { + _downstreamUrlPath = downstreamPath; + } + + private void GivenIHaveAnUpstreamUrlTemplatePattern(string downstreamUrlTemplate) + { + _downstreamPathTemplate = downstreamUrlTemplate; + } + + private void WhenIMatchThePaths() + { + _result = _urlMatcher.Match(_downstreamUrlPath, _downstreamPathTemplate); + } + + private void ThenTheResultIsTrue() + { + _result.Data.Match.ShouldBeTrue(); + } + + private void ThenTheResultIsFalse() + { + _result.Data.Match.ShouldBeFalse(); + } + } +} \ No newline at end of file diff --git a/test/Ocelot.UnitTests/UrlMatcher/UrlPathToUrlTemplateMatcherTests.cs b/test/Ocelot.UnitTests/UrlMatcher/TemplateVariableNameAndValueFinderTests.cs similarity index 64% rename from test/Ocelot.UnitTests/UrlMatcher/UrlPathToUrlTemplateMatcherTests.cs rename to test/Ocelot.UnitTests/UrlMatcher/TemplateVariableNameAndValueFinderTests.cs index d4502552..6f7f4d7f 100644 --- a/test/Ocelot.UnitTests/UrlMatcher/UrlPathToUrlTemplateMatcherTests.cs +++ b/test/Ocelot.UnitTests/UrlMatcher/TemplateVariableNameAndValueFinderTests.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq; +using Ocelot.Library.Infrastructure.Responses; using Ocelot.Library.Infrastructure.UrlMatcher; using Shouldly; using TestStack.BDDfy; @@ -9,33 +10,14 @@ namespace Ocelot.UnitTests.UrlMatcher { public class UrlPathToUrlTemplateMatcherTests { - private readonly IUrlPathToUrlTemplateMatcher _urlMatcher; + private readonly ITemplateVariableNameAndValueFinder _finder; private string _downstreamUrlPath; private string _downstreamPathTemplate; - private UrlMatch _result; + private Response> _result; + public UrlPathToUrlTemplateMatcherTests() { - _urlMatcher = new UrlPathToUrlTemplateMatcher(); - } - - [Fact] - public void should_find_match_when_template_smaller_than_valid_path() - { - this.Given(x => x.GivenIHaveAUpstreamPath("/api/products/2354325435624623464235")) - .And(x => x.GivenIHaveAnUpstreamUrlTemplate("/api/products/{productId}")) - .When(x => x.WhenIMatchThePaths()) - .And(x => x.ThenTheResultIsTrue()) - .BDDfy(); - } - - [Fact] - public void should_not_find_match() - { - this.Given(x => x.GivenIHaveAUpstreamPath("/api/values")) - .And(x => x.GivenIHaveAnUpstreamUrlTemplate("/")) - .When(x => x.WhenIMatchThePaths()) - .And(x => x.ThenTheResultIsFalse()) - .BDDfy(); + _finder = new TemplateVariableNameAndValueFinder(); } [Fact] @@ -43,10 +25,8 @@ namespace Ocelot.UnitTests.UrlMatcher { this.Given(x => x.GivenIHaveAUpstreamPath("")) .And(x => x.GivenIHaveAnUpstreamUrlTemplate("")) - .When(x => x.WhenIMatchThePaths()) - .And(x => x.ThenTheResultIsTrue()) + .When(x => x.WhenIFindTheUrlVariableNamesAndValues()) .And(x => x.ThenTheTemplatesVariablesAre(new List())) - .And(x => x.ThenTheDownstreamUrlTemplateIs("")) .BDDfy(); } @@ -55,10 +35,8 @@ namespace Ocelot.UnitTests.UrlMatcher { this.Given(x => x.GivenIHaveAUpstreamPath("api")) .Given(x => x.GivenIHaveAnUpstreamUrlTemplate("api")) - .When(x => x.WhenIMatchThePaths()) - .Then(x => x.ThenTheResultIsTrue()) + .When(x => x.WhenIFindTheUrlVariableNamesAndValues()) .And(x => x.ThenTheTemplatesVariablesAre(new List())) - .And(x => x.ThenTheDownstreamUrlTemplateIs("api")) .BDDfy(); } @@ -67,10 +45,8 @@ namespace Ocelot.UnitTests.UrlMatcher { this.Given(x => x.GivenIHaveAUpstreamPath("api/")) .Given(x => x.GivenIHaveAnUpstreamUrlTemplate("api/")) - .When(x => x.WhenIMatchThePaths()) - .Then(x => x.ThenTheResultIsTrue()) + .When(x => x.WhenIFindTheUrlVariableNamesAndValues()) .And(x => x.ThenTheTemplatesVariablesAre(new List())) - .And(x => x.ThenTheDownstreamUrlTemplateIs("api/")) .BDDfy(); } @@ -79,10 +55,8 @@ namespace Ocelot.UnitTests.UrlMatcher { this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/")) .Given(x => x.GivenIHaveAnUpstreamUrlTemplate("api/product/products/")) - .When(x => x.WhenIMatchThePaths()) - .Then(x => x.ThenTheResultIsTrue()) + .When(x => x.WhenIFindTheUrlVariableNamesAndValues()) .And(x => x.ThenTheTemplatesVariablesAre(new List())) - .And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/")) .BDDfy(); } @@ -96,10 +70,8 @@ namespace Ocelot.UnitTests.UrlMatcher this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1")) .Given(x => x.GivenIHaveAnUpstreamUrlTemplate("api/product/products/{productId}")) - .When(x => x.WhenIMatchThePaths()) - .Then(x => x.ThenTheResultIsTrue()) + .When(x => x.WhenIFindTheUrlVariableNamesAndValues()) .And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates)) - .And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/{productId}")) .BDDfy(); } @@ -114,10 +86,8 @@ namespace Ocelot.UnitTests.UrlMatcher this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/2")) .Given(x => x.GivenIHaveAnUpstreamUrlTemplate("api/product/products/{productId}/{categoryId}")) - .When(x => x.WhenIMatchThePaths()) - .Then(x => x.ThenTheResultIsTrue()) + .When(x => x.WhenIFindTheUrlVariableNamesAndValues()) .And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates)) - .And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/{productId}/{categoryId}")) .BDDfy(); } @@ -132,10 +102,8 @@ namespace Ocelot.UnitTests.UrlMatcher this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2")) .And(x => x.GivenIHaveAnUpstreamUrlTemplate("api/product/products/{productId}/categories/{categoryId}")) - .When(x => x.WhenIMatchThePaths()) - .Then(x => x.ThenTheResultIsTrue()) + .When(x => x.WhenIFindTheUrlVariableNamesAndValues()) .And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates)) - .And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/{productId}/categories/{categoryId}")) .BDDfy(); } @@ -151,10 +119,8 @@ namespace Ocelot.UnitTests.UrlMatcher this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2/variant/123")) .And(x => x.GivenIHaveAnUpstreamUrlTemplate("api/product/products/{productId}/categories/{categoryId}/variant/{variantId}")) - .When(x => x.WhenIMatchThePaths()) - .Then(x => x.ThenTheResultIsTrue()) + .When(x => x.WhenIFindTheUrlVariableNamesAndValues()) .And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates)) - .And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/{productId}/categories/{categoryId}/variant/{variantId}")) .BDDfy(); } @@ -169,10 +135,8 @@ namespace Ocelot.UnitTests.UrlMatcher this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2/variant/")) .And(x => x.GivenIHaveAnUpstreamUrlTemplate("api/product/products/{productId}/categories/{categoryId}/variant/")) - .When(x => x.WhenIMatchThePaths()) - .Then(x => x.ThenTheResultIsTrue()) + .When(x => x.WhenIFindTheUrlVariableNamesAndValues()) .And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates)) - .And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/{productId}/categories/{categoryId}/variant/")) .BDDfy(); } @@ -180,16 +144,12 @@ namespace Ocelot.UnitTests.UrlMatcher { foreach (var expectedResult in expectedResults) { - var result = _result.TemplateVariableNameAndValues + var result = _result.Data .First(t => t.TemplateVariableName == expectedResult.TemplateVariableName); result.TemplateVariableValue.ShouldBe(expectedResult.TemplateVariableValue); } } - private void ThenTheDownstreamUrlTemplateIs(string expectedDownstreamUrlTemplate) - { - _result.DownstreamUrlTemplate.ShouldBe(expectedDownstreamUrlTemplate); - } private void GivenIHaveAUpstreamPath(string downstreamPath) { _downstreamUrlPath = downstreamPath; @@ -200,19 +160,9 @@ namespace Ocelot.UnitTests.UrlMatcher _downstreamPathTemplate = downstreamUrlTemplate; } - private void WhenIMatchThePaths() + private void WhenIFindTheUrlVariableNamesAndValues() { - _result = _urlMatcher.Match(_downstreamUrlPath, _downstreamPathTemplate); - } - - private void ThenTheResultIsTrue() - { - _result.Match.ShouldBeTrue(); - } - - private void ThenTheResultIsFalse() - { - _result.Match.ShouldBeFalse(); + _result = _finder.Find(_downstreamUrlPath, _downstreamPathTemplate); } } } \ No newline at end of file diff --git a/test/Ocelot.UnitTests/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs b/test/Ocelot.UnitTests/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs index ef03aa70..597c7d74 100644 --- a/test/Ocelot.UnitTests/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs +++ b/test/Ocelot.UnitTests/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using Ocelot.Library.Infrastructure.DownstreamRouteFinder; +using Ocelot.Library.Infrastructure.Responses; using Ocelot.Library.Infrastructure.UrlMatcher; using Ocelot.Library.Infrastructure.UrlTemplateReplacer; using Shouldly; @@ -11,7 +12,7 @@ namespace Ocelot.UnitTests.UrlTemplateReplacer public class UpstreamUrlPathTemplateVariableReplacerTests { private DownstreamRoute _downstreamRoute; - private string _result; + private Response _result; private readonly IDownstreamUrlTemplateVariableReplacer _downstreamUrlPathReplacer; public UpstreamUrlPathTemplateVariableReplacerTests() @@ -135,7 +136,7 @@ namespace Ocelot.UnitTests.UrlTemplateReplacer private void ThenTheDownstreamUrlPathIsReturned(string expected) { - _result.ShouldBe(expected); + _result.Data.ShouldBe(expected); } } From 58393f07ec48f0ab98292eb6673957350606f7ff Mon Sep 17 00:00:00 2001 From: "tom.pallister" Date: Wed, 12 Oct 2016 13:40:46 +0100 Subject: [PATCH 049/183] started adding authentication stack, thing that decides if we should be authenticated is in --- .../CouldNotFindConfigurationError.cs | 11 +++ .../IRouteRequiresAuthentication.cs | 10 ++ .../RouteRequiresAuthentication.cs | 35 +++++++ .../Configuration/OcelotConfiguration.cs | 4 +- .../Infrastructure/Configuration/ReRoute.cs | 4 +- .../Configuration/Yaml/YamlReRoute.cs | 1 + .../Middleware/AuthenticationMiddleware.cs | 54 +++++++++++ ...nticationMiddlewareMiddlewareExtensions.cs | 12 +++ .../DownstreamUrlCreatorMiddleware.cs | 1 - ...ownstreamUrlCreatorMiddlewareExtensions.cs | 2 +- src/Ocelot/Startup.cs | 7 +- .../Ocelot.AcceptanceTests/configuration.yaml | 1 + .../RequiresAuthenticationTests.cs | 96 +++++++++++++++++++ .../Configuration/OcelotConfigurationTests.cs | 8 +- .../DownstreamRouteFinderTests.cs | 8 +- 15 files changed, 241 insertions(+), 13 deletions(-) create mode 100644 src/Ocelot.Library/Infrastructure/Authentication/CouldNotFindConfigurationError.cs create mode 100644 src/Ocelot.Library/Infrastructure/Authentication/IRouteRequiresAuthentication.cs create mode 100644 src/Ocelot.Library/Infrastructure/Authentication/RouteRequiresAuthentication.cs create mode 100644 src/Ocelot.Library/Middleware/AuthenticationMiddleware.cs create mode 100644 src/Ocelot.Library/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs create mode 100644 test/Ocelot.UnitTests/Authentication/RequiresAuthenticationTests.cs diff --git a/src/Ocelot.Library/Infrastructure/Authentication/CouldNotFindConfigurationError.cs b/src/Ocelot.Library/Infrastructure/Authentication/CouldNotFindConfigurationError.cs new file mode 100644 index 00000000..5b30c463 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Authentication/CouldNotFindConfigurationError.cs @@ -0,0 +1,11 @@ +namespace Ocelot.Library.Infrastructure.Authentication +{ + using Responses; + public class CouldNotFindConfigurationError : Error + { + public CouldNotFindConfigurationError(string message) + : base(message) + { + } + } +} diff --git a/src/Ocelot.Library/Infrastructure/Authentication/IRouteRequiresAuthentication.cs b/src/Ocelot.Library/Infrastructure/Authentication/IRouteRequiresAuthentication.cs new file mode 100644 index 00000000..0a3f9858 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Authentication/IRouteRequiresAuthentication.cs @@ -0,0 +1,10 @@ +namespace Ocelot.Library.Infrastructure.Authentication +{ + using DownstreamRouteFinder; + using Responses; + + public interface IRouteRequiresAuthentication + { + Response IsAuthenticated(DownstreamRoute downstreamRoute, string httpMethod); + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Authentication/RouteRequiresAuthentication.cs b/src/Ocelot.Library/Infrastructure/Authentication/RouteRequiresAuthentication.cs new file mode 100644 index 00000000..988959e4 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Authentication/RouteRequiresAuthentication.cs @@ -0,0 +1,35 @@ +namespace Ocelot.Library.Infrastructure.Authentication +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Configuration; + using DownstreamRouteFinder; + using Responses; + + public class RouteRequiresAuthentication : IRouteRequiresAuthentication + { + private readonly IOcelotConfiguration _configuration; + + public RouteRequiresAuthentication(IOcelotConfiguration configuration) + { + _configuration = configuration; + } + + public Response IsAuthenticated(DownstreamRoute downstreamRoute, string httpMethod) + { + var reRoute = + _configuration.ReRoutes.FirstOrDefault( + x => + x.DownstreamTemplate == downstreamRoute.DownstreamUrlTemplate && + string.Equals(x.UpstreamHttpMethod, httpMethod, StringComparison.CurrentCultureIgnoreCase)); + + if (reRoute == null) + { + return new ErrorResponse(new List {new CouldNotFindConfigurationError($"Could not find configuration for {downstreamRoute.DownstreamUrlTemplate} using method {httpMethod}")}); + } + + return new OkResponse(reRoute.IsAuthenticated); + } + } +} diff --git a/src/Ocelot.Library/Infrastructure/Configuration/OcelotConfiguration.cs b/src/Ocelot.Library/Infrastructure/Configuration/OcelotConfiguration.cs index be544d6a..7ac93b3c 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/OcelotConfiguration.cs +++ b/src/Ocelot.Library/Infrastructure/Configuration/OcelotConfiguration.cs @@ -43,7 +43,9 @@ namespace Ocelot.Library.Infrastructure.Configuration upstreamTemplate = $"{upstreamTemplate}{RegExMatchEndString}"; - _reRoutes.Add(new ReRoute(reRoute.DownstreamTemplate, reRoute.UpstreamTemplate, reRoute.UpstreamHttpMethod, upstreamTemplate)); + var isAuthenticated = !string.IsNullOrEmpty(reRoute.Authentication); + + _reRoutes.Add(new ReRoute(reRoute.DownstreamTemplate, reRoute.UpstreamTemplate, reRoute.UpstreamHttpMethod, upstreamTemplate, isAuthenticated)); } } diff --git a/src/Ocelot.Library/Infrastructure/Configuration/ReRoute.cs b/src/Ocelot.Library/Infrastructure/Configuration/ReRoute.cs index 6d0f6497..9c5edf0f 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/ReRoute.cs +++ b/src/Ocelot.Library/Infrastructure/Configuration/ReRoute.cs @@ -2,17 +2,19 @@ { public class ReRoute { - public ReRoute(string downstreamTemplate, string upstreamTemplate, string upstreamHttpMethod, string upstreamTemplatePattern) + public ReRoute(string downstreamTemplate, string upstreamTemplate, string upstreamHttpMethod, string upstreamTemplatePattern, bool isAuthenticated) { DownstreamTemplate = downstreamTemplate; UpstreamTemplate = upstreamTemplate; UpstreamHttpMethod = upstreamHttpMethod; UpstreamTemplatePattern = upstreamTemplatePattern; + IsAuthenticated = isAuthenticated; } public string DownstreamTemplate { get; private set; } public string UpstreamTemplate { get; private set; } public string UpstreamTemplatePattern { get; private set; } public string UpstreamHttpMethod { get; private set; } + public bool IsAuthenticated { get; private set; } } } \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/YamlReRoute.cs b/src/Ocelot.Library/Infrastructure/Configuration/Yaml/YamlReRoute.cs index b012d19a..0c1e1e12 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/YamlReRoute.cs +++ b/src/Ocelot.Library/Infrastructure/Configuration/Yaml/YamlReRoute.cs @@ -5,5 +5,6 @@ public string DownstreamTemplate { get; set; } public string UpstreamTemplate { get; set; } public string UpstreamHttpMethod { get; set; } + public string Authentication { get; set; } } } \ No newline at end of file diff --git a/src/Ocelot.Library/Middleware/AuthenticationMiddleware.cs b/src/Ocelot.Library/Middleware/AuthenticationMiddleware.cs new file mode 100644 index 00000000..21f680eb --- /dev/null +++ b/src/Ocelot.Library/Middleware/AuthenticationMiddleware.cs @@ -0,0 +1,54 @@ +namespace Ocelot.Library.Middleware +{ + using System.Threading.Tasks; + using Infrastructure.Authentication; + using Infrastructure.DownstreamRouteFinder; + using Infrastructure.Repository; + using Infrastructure.Responses; + using Microsoft.AspNetCore.Http; + + public class AuthenticationMiddleware : OcelotMiddleware + { + private readonly RequestDelegate _next; + private readonly IScopedRequestDataRepository _scopedRequestDataRepository; + private readonly IRouteRequiresAuthentication _requiresAuthentication; + public AuthenticationMiddleware(RequestDelegate next, + IScopedRequestDataRepository scopedRequestDataRepository, + IRouteRequiresAuthentication requiresAuthentication) + : base(scopedRequestDataRepository) + { + _next = next; + _scopedRequestDataRepository = scopedRequestDataRepository; + _requiresAuthentication = requiresAuthentication; + } + + public async Task Invoke(HttpContext context) + { + var downstreamRoute = _scopedRequestDataRepository.Get("DownstreamRoute"); + + var isAuthenticated = _requiresAuthentication.IsAuthenticated(downstreamRoute.Data, context.Request.Method); + + if (isAuthenticated.IsError) + { + SetPipelineError(downstreamRoute.Errors); + return; + } + + if (IsAuthenticatedRoute(isAuthenticated)) + { + //todo - build auth pipeline and then call normal pipeline if all good? + await _next.Invoke(context); + } + else + { + await _next.Invoke(context); + } + + } + + private static bool IsAuthenticatedRoute(Response isAuthenticated) + { + return isAuthenticated.Data; + } + } +} diff --git a/src/Ocelot.Library/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs b/src/Ocelot.Library/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs new file mode 100644 index 00000000..3655e470 --- /dev/null +++ b/src/Ocelot.Library/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs @@ -0,0 +1,12 @@ +using Microsoft.AspNetCore.Builder; + +namespace Ocelot.Library.Middleware +{ + public static class AuthenticationMiddlewareMiddlewareExtensions + { + public static IApplicationBuilder UseAuthenticationMiddleware(this IApplicationBuilder builder) + { + return builder.UseMiddleware(); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddleware.cs b/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddleware.cs index 2627a722..00d5d76b 100644 --- a/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddleware.cs +++ b/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddleware.cs @@ -2,7 +2,6 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Ocelot.Library.Infrastructure.DownstreamRouteFinder; using Ocelot.Library.Infrastructure.Repository; -using Ocelot.Library.Infrastructure.Responder; using Ocelot.Library.Infrastructure.UrlTemplateReplacer; namespace Ocelot.Library.Middleware diff --git a/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs b/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs index 0ba3e58c..325a7454 100644 --- a/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs +++ b/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs @@ -4,7 +4,7 @@ namespace Ocelot.Library.Middleware { public static class DownstreamUrlCreatorMiddlewareExtensions { - public static IApplicationBuilder UserDownstreamUrlCreatorMiddleware(this IApplicationBuilder builder) + public static IApplicationBuilder UseDownstreamUrlCreatorMiddleware(this IApplicationBuilder builder) { return builder.UseMiddleware(); } diff --git a/src/Ocelot/Startup.cs b/src/Ocelot/Startup.cs index e2ecb505..9056daf9 100644 --- a/src/Ocelot/Startup.cs +++ b/src/Ocelot/Startup.cs @@ -20,6 +20,8 @@ using Ocelot.Library.Middleware; namespace Ocelot { + using Library.Infrastructure.Authentication; + public class Startup { public Startup(IHostingEnvironment env) @@ -52,6 +54,7 @@ namespace Ocelot services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); // see this for why we register this as singleton http://stackoverflow.com/questions/37371264/invalidoperationexception-unable-to-resolve-service-for-type-microsoft-aspnetc services.AddSingleton(); @@ -69,7 +72,9 @@ namespace Ocelot app.UseDownstreamRouteFinderMiddleware(); - app.UserDownstreamUrlCreatorMiddleware(); + app.UseAuthenticationMiddleware(); + + app.UseDownstreamUrlCreatorMiddleware(); app.UseHttpRequestBuilderMiddleware(); diff --git a/test/Ocelot.AcceptanceTests/configuration.yaml b/test/Ocelot.AcceptanceTests/configuration.yaml index 7a2db711..42e7ab07 100644 --- a/test/Ocelot.AcceptanceTests/configuration.yaml +++ b/test/Ocelot.AcceptanceTests/configuration.yaml @@ -2,3 +2,4 @@ ReRoutes: - DownstreamTemplate: http://localhost:51879/ UpstreamTemplate: / UpstreamHttpMethod: Get + Authentication: IdentityServer diff --git a/test/Ocelot.UnitTests/Authentication/RequiresAuthenticationTests.cs b/test/Ocelot.UnitTests/Authentication/RequiresAuthenticationTests.cs new file mode 100644 index 00000000..5747c963 --- /dev/null +++ b/test/Ocelot.UnitTests/Authentication/RequiresAuthenticationTests.cs @@ -0,0 +1,96 @@ +namespace Ocelot.UnitTests.Authentication +{ + using System.Collections.Generic; + using Library.Infrastructure.Authentication; + using Library.Infrastructure.Configuration; + using Library.Infrastructure.DownstreamRouteFinder; + using Library.Infrastructure.Responses; + using Library.Infrastructure.UrlMatcher; + using Moq; + using Shouldly; + using TestStack.BDDfy; + using Xunit; + + public class RequiresAuthenticationTests + { + private readonly RouteRequiresAuthentication _routeRequiresAuthentication; + private string _url; + private readonly Mock _config; + private Response _result; + private string _httpMethod; + + public RequiresAuthenticationTests() + { + _config = new Mock(); + _routeRequiresAuthentication = new RouteRequiresAuthentication(_config.Object); + } + + [Fact] + public void should_return_true_if_route_requires_authentication() + { + this.Given(x => x.GivenIHaveADownstreamUrl("http://www.bbc.co.uk")) + .And( + x => + x.GivenTheConfigurationForTheRouteIs(new ReRoute("http://www.bbc.co.uk", "/api/poo", "get", + "/api/poo$", true))) + .When(x => x.WhenICheckToSeeIfTheRouteShouldBeAuthenticated()) + .Then(x => x.ThenTheResultIs(true)) + .BDDfy(); + } + + [Fact] + public void should_return_false_if_route_requires_authentication() + { + this.Given(x => x.GivenIHaveADownstreamUrl("http://www.bbc.co.uk")) + .And( + x => + x.GivenTheConfigurationForTheRouteIs(new ReRoute("http://www.bbc.co.uk", "/api/poo", "get", + "/api/poo$", false))) + .When(x => x.WhenICheckToSeeIfTheRouteShouldBeAuthenticated()) + .Then(x => x.ThenTheResultIs(false)) + .BDDfy(); + } + + [Fact] + public void should_return_error_if_no_matching_config() + { + this.Given(x => x.GivenIHaveADownstreamUrl("http://www.bbc.co.uk")) + .And(x => x.GivenTheConfigurationForTheRouteIs(new ReRoute(string.Empty, string.Empty, string.Empty, string.Empty,false))) + .When(x => x.WhenICheckToSeeIfTheRouteShouldBeAuthenticated()) + .Then(x => x.ThenAnErrorIsReturned()) + .BDDfy(); + } + + private void ThenAnErrorIsReturned() + { + _result.IsError.ShouldBeTrue(); + } + + public void GivenIHaveADownstreamUrl(string url) + { + _url = url; + } + + private void GivenTheConfigurationForTheRouteIs(ReRoute reRoute) + { + _httpMethod = reRoute.UpstreamHttpMethod; + + _config + .Setup(x => x.ReRoutes) + .Returns(new List + { + reRoute + }); + } + + private void WhenICheckToSeeIfTheRouteShouldBeAuthenticated() + { + _result = _routeRequiresAuthentication.IsAuthenticated(new DownstreamRoute(new List(), _url), _httpMethod); + } + + private void ThenTheResultIs(bool expected) + { + _result.Data.ShouldBe(expected); + } + } +} diff --git a/test/Ocelot.UnitTests/Configuration/OcelotConfigurationTests.cs b/test/Ocelot.UnitTests/Configuration/OcelotConfigurationTests.cs index 1c030e6f..56ee89b8 100644 --- a/test/Ocelot.UnitTests/Configuration/OcelotConfigurationTests.cs +++ b/test/Ocelot.UnitTests/Configuration/OcelotConfigurationTests.cs @@ -38,7 +38,7 @@ namespace Ocelot.UnitTests.Configuration .When(x => x.WhenIInstanciateTheOcelotConfig()) .Then(x => x.ThenTheReRoutesAre(new List { - new ReRoute("/products/{productId}","/api/products/{productId}", "Get", "/api/products/.*$") + new ReRoute("/products/{productId}","/api/products/{productId}", "Get", "/api/products/.*$", false) })) .BDDfy(); } @@ -61,7 +61,7 @@ namespace Ocelot.UnitTests.Configuration .When(x => x.WhenIInstanciateTheOcelotConfig()) .Then(x => x.ThenTheReRoutesAre(new List { - new ReRoute("/products/{productId}","/api/products/{productId}/variants/{variantId}", "Get", "/api/products/.*/variants/.*$") + new ReRoute("/products/{productId}","/api/products/{productId}/variants/{variantId}", "Get", "/api/products/.*/variants/.*$", false) })) .BDDfy(); } @@ -84,7 +84,7 @@ namespace Ocelot.UnitTests.Configuration .When(x => x.WhenIInstanciateTheOcelotConfig()) .Then(x => x.ThenTheReRoutesAre(new List { - new ReRoute("/products/{productId}","/api/products/{productId}/variants/{variantId}/", "Get", "/api/products/.*/variants/.*/$") + new ReRoute("/products/{productId}","/api/products/{productId}/variants/{variantId}/", "Get", "/api/products/.*/variants/.*/$", false) })) .BDDfy(); } @@ -107,7 +107,7 @@ namespace Ocelot.UnitTests.Configuration .When(x => x.WhenIInstanciateTheOcelotConfig()) .Then(x => x.ThenTheReRoutesAre(new List { - new ReRoute("/api/products/","/", "Get", "/$") + new ReRoute("/api/products/","/", "Get", "/$", false) })) .BDDfy(); } diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs index ee35836b..3675459a 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs @@ -38,7 +38,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .And(x => x.GivenTheTemplateVariableAndNameFinderReturns(new OkResponse>(new List()))) .And(x => x.GivenTheConfigurationIs(new List { - new ReRoute("someDownstreamPath","someUpstreamPath", "Get", "someUpstreamPath") + new ReRoute("someDownstreamPath","someUpstreamPath", "Get", "someUpstreamPath", false) } )) .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true)))) @@ -57,8 +57,8 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .And(x => x.GivenTheTemplateVariableAndNameFinderReturns(new OkResponse>(new List()))) .And(x => x.GivenTheConfigurationIs(new List { - new ReRoute("someDownstreamPath", "someUpstreamPath", "Get", string.Empty), - new ReRoute("someDownstreamPathForAPost", "someUpstreamPath", "Post", string.Empty) + new ReRoute("someDownstreamPath", "someUpstreamPath", "Get", string.Empty, false), + new ReRoute("someDownstreamPathForAPost", "someUpstreamPath", "Post", string.Empty, false) } )) .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true)))) @@ -75,7 +75,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder this.Given(x => x.GivenThereIsAnUpstreamUrlPath("somePath")) .And(x => x.GivenTheConfigurationIs(new List { - new ReRoute("somPath", "somePath", "Get", "somePath") + new ReRoute("somPath", "somePath", "Get", "somePath", false) } )) .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(false)))) From cff130196f09516efacbd31035acb6ebc4a2d1a2 Mon Sep 17 00:00:00 2001 From: "tom.pallister" Date: Wed, 12 Oct 2016 14:00:13 +0100 Subject: [PATCH 050/183] Removed the fake woop --- .../Fake/FakeService.cs | 34 ----------- .../Fake/FakeStartup.cs | 47 --------------- test/Ocelot.AcceptanceTests/OcelotTests.cs | 60 +++++++++++++------ .../DownstreamRouteFinderTests.cs | 1 - 4 files changed, 41 insertions(+), 101 deletions(-) delete mode 100644 test/Ocelot.AcceptanceTests/Fake/FakeService.cs delete mode 100644 test/Ocelot.AcceptanceTests/Fake/FakeStartup.cs diff --git a/test/Ocelot.AcceptanceTests/Fake/FakeService.cs b/test/Ocelot.AcceptanceTests/Fake/FakeService.cs deleted file mode 100644 index 56f97ce5..00000000 --- a/test/Ocelot.AcceptanceTests/Fake/FakeService.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.IO; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Hosting; - -namespace Ocelot.AcceptanceTests.Fake -{ - public class FakeService - { - private Task _handler; - private IWebHost _webHostBuilder; - - public void Start(string url) - { - _webHostBuilder = new WebHostBuilder() - .UseKestrel() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() - .UseUrls(url) - .UseStartup() - .Build(); - - _handler = Task.Run(() => _webHostBuilder.Run()); - } - - public void Stop() - { - if(_webHostBuilder != null) - { - _webHostBuilder.Dispose(); - _handler.Wait(); - } - } - } -} \ No newline at end of file diff --git a/test/Ocelot.AcceptanceTests/Fake/FakeStartup.cs b/test/Ocelot.AcceptanceTests/Fake/FakeStartup.cs deleted file mode 100644 index 7f8ceaea..00000000 --- a/test/Ocelot.AcceptanceTests/Fake/FakeStartup.cs +++ /dev/null @@ -1,47 +0,0 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; - -namespace Ocelot.AcceptanceTests.Fake -{ - public class FakeStartup - { - public FakeStartup(IHostingEnvironment env) - { - var builder = new ConfigurationBuilder() - .SetBasePath(env.ContentRootPath) - .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) - .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) - .AddEnvironmentVariables(); - Configuration = builder.Build(); - } - - public IConfigurationRoot Configuration { get; } - - // This method gets called by the runtime. Use this method to add services to the container. - public void ConfigureServices(IServiceCollection services) - { - // Add framework services. - - } - - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) - { - app.Run(async context => - { - if (context.Request.Method.ToLower() == "get") - { - await context.Response.WriteAsync("Hello from Laura"); - } - else - { - context.Response.StatusCode = 201; - } - }); - } - } -} diff --git a/test/Ocelot.AcceptanceTests/OcelotTests.cs b/test/Ocelot.AcceptanceTests/OcelotTests.cs index a4c3d5d5..f327d586 100644 --- a/test/Ocelot.AcceptanceTests/OcelotTests.cs +++ b/test/Ocelot.AcceptanceTests/OcelotTests.cs @@ -1,32 +1,33 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Net; -using System.Net.Http; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.TestHost; -using Ocelot.AcceptanceTests.Fake; -using Ocelot.Library.Infrastructure.Configuration.Yaml; -using Shouldly; -using TestStack.BDDfy; -using Xunit; -using YamlDotNet.Serialization; - namespace Ocelot.AcceptanceTests { + using System; + using System.Collections.Generic; + using System.IO; + using System.Net; + using System.Net.Http; + using Microsoft.AspNetCore.Hosting; + using Microsoft.AspNetCore.TestHost; + using Ocelot.Library.Infrastructure.Configuration.Yaml; + using Shouldly; + using TestStack.BDDfy; + using Xunit; + using YamlDotNet.Serialization; + using System.Threading.Tasks; + using Microsoft.AspNetCore.Builder; + using Microsoft.AspNetCore.Http; + public class OcelotTests : IDisposable { - private readonly FakeService _fakeService; private TestServer _server; private HttpClient _client; private HttpResponseMessage _response; private readonly string _configurationPath; private StringContent _postContent; + private Task _fake; public OcelotTests() { _configurationPath = "./bin/Debug/netcoreapp1.0/configuration.yaml"; - _fakeService = new FakeService(); } [Fact] @@ -117,7 +118,29 @@ namespace Ocelot.AcceptanceTests private void GivenThereIsAServiceRunningOn(string url) { - _fakeService.Start(url); + var builder = new WebHostBuilder() + .Configure(app => + { + app.Run(async context => + { + if (context.Request.Method.ToLower() == "get") + { + await context.Response.WriteAsync("Hello from Laura"); + } + else + { + context.Response.StatusCode = 201; + } + }); + }) + .UseUrls(url) + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseUrls(url) + .Build(); + + _fake = Task.Run(() => builder.Run()); } private void WhenIGetUrlOnTheApiGateway(string url) @@ -141,8 +164,7 @@ namespace Ocelot.AcceptanceTests } public void Dispose() - { - _fakeService.Stop(); + { _client.Dispose(); _server.Dispose(); } diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs index 3675459a..791a6aa2 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs @@ -18,7 +18,6 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder private readonly Mock _finder; private string _upstreamUrlPath; private Response _result; - private Response _response; private List _reRoutesConfig; private Response _match; private string _upstreamHttpMethod; From cdeb97731e7ac1db87c1afc628d46d7f9de8f765 Mon Sep 17 00:00:00 2001 From: "tom.pallister" Date: Wed, 12 Oct 2016 19:34:47 +0100 Subject: [PATCH 051/183] tempoary commit while refactoring tests sorry bisect nazis --- test/Ocelot.AcceptanceTests/OcelotTests.cs | 32 ++++++++++++++++++---- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/test/Ocelot.AcceptanceTests/OcelotTests.cs b/test/Ocelot.AcceptanceTests/OcelotTests.cs index f327d586..4253083e 100644 --- a/test/Ocelot.AcceptanceTests/OcelotTests.cs +++ b/test/Ocelot.AcceptanceTests/OcelotTests.cs @@ -5,6 +5,7 @@ namespace Ocelot.AcceptanceTests using System.IO; using System.Net; using System.Net.Http; + using System.Text; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Ocelot.Library.Infrastructure.Configuration.Yaml; @@ -43,7 +44,12 @@ namespace Ocelot.AcceptanceTests [Fact] public void should_return_response_200() { - this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879")) + var serviceResponse = new DefaultHttpContext(); + serviceResponse.Request.Method = "get"; + serviceResponse.Response.Body = GenerateStreamFromString("Hello from Laura"); + serviceResponse.Response.StatusCode = 200; + + this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", serviceResponse)) .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration { ReRoutes = new List @@ -66,7 +72,11 @@ namespace Ocelot.AcceptanceTests [Fact] public void should_return_response_201() { - this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879")) + var serviceResponse = new DefaultHttpContext(); + serviceResponse.Request.Method = "post"; + serviceResponse.Response.StatusCode = 201; + + this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", serviceResponse)) .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration { ReRoutes = new List @@ -90,6 +100,15 @@ namespace Ocelot.AcceptanceTests _postContent = new StringContent(postcontent); } + public Stream GenerateStreamFromString(string s) + { + var stream = new MemoryStream(); + var writer = new StreamWriter(stream); + writer.Write(s); + writer.Flush(); + stream.Position = 0; + return stream; + } /// /// This is annoying cos it should be in the constructor but we need to set up the yaml file before calling startup so its a step. /// @@ -116,21 +135,24 @@ namespace Ocelot.AcceptanceTests } } - private void GivenThereIsAServiceRunningOn(string url) + private void GivenThereIsAServiceRunningOn(string url, HttpContext httpContext) { var builder = new WebHostBuilder() .Configure(app => { app.Run(async context => { - if (context.Request.Method.ToLower() == "get") + context.Response.Body = httpContext.Response.Body; + context.Response.StatusCode = httpContext.Response.StatusCode; + + /* if (context.Request.Method.ToLower() == "get") { await context.Response.WriteAsync("Hello from Laura"); } else { context.Response.StatusCode = 201; - } + }*/ }); }) .UseUrls(url) From 581c9d01b9f056aac33d5c8df63a93074116d969 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Wed, 12 Oct 2016 20:38:29 +0100 Subject: [PATCH 052/183] finished removing fake, all tests now working --- test/Ocelot.AcceptanceTests/OcelotTests.cs | 92 ++++++++-------------- 1 file changed, 34 insertions(+), 58 deletions(-) diff --git a/test/Ocelot.AcceptanceTests/OcelotTests.cs b/test/Ocelot.AcceptanceTests/OcelotTests.cs index 4253083e..91c0def8 100644 --- a/test/Ocelot.AcceptanceTests/OcelotTests.cs +++ b/test/Ocelot.AcceptanceTests/OcelotTests.cs @@ -1,22 +1,21 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Http; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.TestHost; +using Ocelot.Library.Infrastructure.Configuration.Yaml; +using Shouldly; +using TestStack.BDDfy; +using Xunit; +using YamlDotNet.Serialization; + +[assembly: CollectionBehavior(DisableTestParallelization = true)] namespace Ocelot.AcceptanceTests { - using System; - using System.Collections.Generic; - using System.IO; - using System.Net; - using System.Net.Http; - using System.Text; - using Microsoft.AspNetCore.Hosting; - using Microsoft.AspNetCore.TestHost; - using Ocelot.Library.Infrastructure.Configuration.Yaml; - using Shouldly; - using TestStack.BDDfy; - using Xunit; - using YamlDotNet.Serialization; - using System.Threading.Tasks; - using Microsoft.AspNetCore.Builder; - using Microsoft.AspNetCore.Http; - public class OcelotTests : IDisposable { private TestServer _server; @@ -24,7 +23,7 @@ namespace Ocelot.AcceptanceTests private HttpResponseMessage _response; private readonly string _configurationPath; private StringContent _postContent; - private Task _fake; + private IWebHost _builder; public OcelotTests() { @@ -44,12 +43,7 @@ namespace Ocelot.AcceptanceTests [Fact] public void should_return_response_200() { - var serviceResponse = new DefaultHttpContext(); - serviceResponse.Request.Method = "get"; - serviceResponse.Response.Body = GenerateStreamFromString("Hello from Laura"); - serviceResponse.Response.StatusCode = 200; - - this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", serviceResponse)) + this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", 200, "Hello from Laura")) .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration { ReRoutes = new List @@ -72,11 +66,7 @@ namespace Ocelot.AcceptanceTests [Fact] public void should_return_response_201() { - var serviceResponse = new DefaultHttpContext(); - serviceResponse.Request.Method = "post"; - serviceResponse.Response.StatusCode = 201; - - this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", serviceResponse)) + this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", 201, string.Empty)) .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration { ReRoutes = new List @@ -100,15 +90,6 @@ namespace Ocelot.AcceptanceTests _postContent = new StringContent(postcontent); } - public Stream GenerateStreamFromString(string s) - { - var stream = new MemoryStream(); - var writer = new StreamWriter(stream); - writer.Write(s); - writer.Flush(); - stream.Position = 0; - return stream; - } /// /// This is annoying cos it should be in the constructor but we need to set up the yaml file before calling startup so its a step. /// @@ -135,34 +116,25 @@ namespace Ocelot.AcceptanceTests } } - private void GivenThereIsAServiceRunningOn(string url, HttpContext httpContext) + private void GivenThereIsAServiceRunningOn(string url, int statusCode, string responseBody) { - var builder = new WebHostBuilder() - .Configure(app => - { - app.Run(async context => - { - context.Response.Body = httpContext.Response.Body; - context.Response.StatusCode = httpContext.Response.StatusCode; - - /* if (context.Request.Method.ToLower() == "get") - { - await context.Response.WriteAsync("Hello from Laura"); - } - else - { - context.Response.StatusCode = 201; - }*/ - }); - }) + _builder = new WebHostBuilder() .UseUrls(url) .UseKestrel() .UseContentRoot(Directory.GetCurrentDirectory()) .UseIISIntegration() .UseUrls(url) + .Configure(app => + { + app.Run(async context => + { + context.Response.StatusCode = statusCode; + await context.Response.WriteAsync(responseBody); + }); + }) .Build(); - _fake = Task.Run(() => builder.Run()); + _builder.Start(); } private void WhenIGetUrlOnTheApiGateway(string url) @@ -187,6 +159,10 @@ namespace Ocelot.AcceptanceTests public void Dispose() { + if (_builder != null) + { + _builder.Dispose(); + } _client.Dispose(); _server.Dispose(); } From 5492b70c87eca6280e1b1459d58a75340a0be26f Mon Sep 17 00:00:00 2001 From: TomPallister Date: Wed, 12 Oct 2016 20:42:43 +0100 Subject: [PATCH 053/183] Acceptance test for complex url combo...cant believe it acually worked --- test/Ocelot.AcceptanceTests/OcelotTests.cs | 30 +++++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/test/Ocelot.AcceptanceTests/OcelotTests.cs b/test/Ocelot.AcceptanceTests/OcelotTests.cs index 91c0def8..99219ac7 100644 --- a/test/Ocelot.AcceptanceTests/OcelotTests.cs +++ b/test/Ocelot.AcceptanceTests/OcelotTests.cs @@ -13,7 +13,6 @@ using TestStack.BDDfy; using Xunit; using YamlDotNet.Serialization; -[assembly: CollectionBehavior(DisableTestParallelization = true)] namespace Ocelot.AcceptanceTests { public class OcelotTests : IDisposable @@ -31,7 +30,7 @@ namespace Ocelot.AcceptanceTests } [Fact] - public void should_return_response_404() + public void should_return_response_404_when_no_configuration_at_all() { this.Given(x => x.GivenThereIsAConfiguration(new YamlConfiguration())) .And(x => x.GivenTheApiGatewayIsRunning()) @@ -41,7 +40,7 @@ namespace Ocelot.AcceptanceTests } [Fact] - public void should_return_response_200() + public void should_return_response_200_with_simple_url() { this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", 200, "Hello from Laura")) .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration @@ -64,7 +63,30 @@ namespace Ocelot.AcceptanceTests } [Fact] - public void should_return_response_201() + public void should_return_response_200_with_complex_url() + { + this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879/api/products/1", 200, "Some Product")) + .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration + { + ReRoutes = new List + { + new YamlReRoute + { + DownstreamTemplate = "http://localhost:51879/api/products/{productId}", + UpstreamTemplate = "/products/{productId}", + UpstreamHttpMethod = "Get" + } + } + })) + .And(x => x.GivenTheApiGatewayIsRunning()) + .When(x => x.WhenIGetUrlOnTheApiGateway("/products/1")) + .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + .And(x => x.ThenTheResponseBodyShouldBe("Some Product")) + .BDDfy(); + } + + [Fact] + public void should_return_response_201_with_simple_url() { this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", 201, string.Empty)) .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration From d80c4e2de24c2efac1df23d697358f4cc05732b7 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Wed, 12 Oct 2016 20:45:29 +0100 Subject: [PATCH 054/183] apveyor yaml --- appveyor.yml | 3 +++ src/Ocelot.Library/Middleware/AuthenticationMiddleware.cs | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 appveyor.yml diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 00000000..efa27b50 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,3 @@ +version: 1.0.{build} +build: + verbosity: minimal \ No newline at end of file diff --git a/src/Ocelot.Library/Middleware/AuthenticationMiddleware.cs b/src/Ocelot.Library/Middleware/AuthenticationMiddleware.cs index 21f680eb..67f11815 100644 --- a/src/Ocelot.Library/Middleware/AuthenticationMiddleware.cs +++ b/src/Ocelot.Library/Middleware/AuthenticationMiddleware.cs @@ -43,7 +43,6 @@ { await _next.Invoke(context); } - } private static bool IsAuthenticatedRoute(Response isAuthenticated) From 3b4123099a55b7957e623622382078b20fb65e3e Mon Sep 17 00:00:00 2001 From: TomPallister Date: Wed, 12 Oct 2016 20:47:56 +0100 Subject: [PATCH 055/183] trying to get working in CI --- appveyor.yml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index efa27b50..a7409bbe 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,3 +1,14 @@ version: 1.0.{build} -build: - verbosity: minimal \ No newline at end of file +configuration: +- Debug +- Release +platform: Any CPU +environment: + # Don't report back to the mothership + DOTNET_CLI_TELEMETRY_OPTOUT: 1 +init: +- ps: $Env:LABEL = "CI" + $Env:APPVEYOR_BUILD_NUMBER.PadLeft(5, "0") +before_build: +- appveyor-retry dotnet restore -v Minimal +build_script: +- build.sh From 244aa69022e8bfa9aa20687099643109f9a815b7 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Wed, 12 Oct 2016 20:50:29 +0100 Subject: [PATCH 056/183] apveyor yaml --- Ocelot.sln | 1 + appveyor.yml | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Ocelot.sln b/Ocelot.sln index 73df0502..27a97cfc 100644 --- a/Ocelot.sln +++ b/Ocelot.sln @@ -7,6 +7,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{5CFB79B7-C9D EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3FA7C349-DBE8-4904-A2CE-015B8869CE6C}" ProjectSection(SolutionItems) = preProject + appveyor.yml = appveyor.yml build.sh = build.sh global.json = global.json LICENSE.md = LICENSE.md diff --git a/appveyor.yml b/appveyor.yml index a7409bbe..46f42d5a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -8,7 +8,5 @@ environment: DOTNET_CLI_TELEMETRY_OPTOUT: 1 init: - ps: $Env:LABEL = "CI" + $Env:APPVEYOR_BUILD_NUMBER.PadLeft(5, "0") -before_build: -- appveyor-retry dotnet restore -v Minimal build_script: - build.sh From 276d5b9e4b8f0d52cc0b3a9e54c563d10df2cd6c Mon Sep 17 00:00:00 2001 From: TomPallister Date: Wed, 12 Oct 2016 20:54:31 +0100 Subject: [PATCH 057/183] apveyor yaml --- appveyor.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 46f42d5a..a5776074 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,12 +1,7 @@ version: 1.0.{build} configuration: -- Debug - Release platform: Any CPU environment: - # Don't report back to the mothership - DOTNET_CLI_TELEMETRY_OPTOUT: 1 -init: -- ps: $Env:LABEL = "CI" + $Env:APPVEYOR_BUILD_NUMBER.PadLeft(5, "0") build_script: - build.sh From 3665347f833ea554010b4a8bff7cdfbdcf148e4b Mon Sep 17 00:00:00 2001 From: TomPallister Date: Wed, 12 Oct 2016 20:58:20 +0100 Subject: [PATCH 058/183] artifacts for CI --- appveyor.yml | 4 ++++ build.sh | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index a5776074..294eeb49 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -5,3 +5,7 @@ platform: Any CPU environment: build_script: - build.sh +artifacts: +- path: artifacts\**\*.* +cache: +- '%USERPROFILE%\.nuget\packages' \ No newline at end of file diff --git a/build.sh b/build.sh index 1f04f561..c0ff2d8a 100755 --- a/build.sh +++ b/build.sh @@ -17,6 +17,6 @@ echo Building Ocelot dotnet restore src/Ocelot dotnet build src/Ocelot -dotnet publish src/Ocelot +dotnet publish src/Ocelot -o artifacts/Ocelot From d987e66369ec94f523bcbd30bd39ab04b95a31d7 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Wed, 12 Oct 2016 20:59:00 +0100 Subject: [PATCH 059/183] removed environment section --- appveyor.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 294eeb49..60a782f9 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,7 +2,6 @@ version: 1.0.{build} configuration: - Release platform: Any CPU -environment: build_script: - build.sh artifacts: From d78dc2847ec55ba5194a8d9f8054930eccf9948d Mon Sep 17 00:00:00 2001 From: TomPallister Date: Wed, 12 Oct 2016 21:04:35 +0100 Subject: [PATCH 060/183] tests --- appveyor.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index 60a782f9..5dede7d4 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -4,6 +4,8 @@ configuration: platform: Any CPU build_script: - build.sh +test_script: +- run-tests.sh artifacts: - path: artifacts\**\*.* cache: From 1fcc0c20d3f78709a82a455601cbc87b817fca05 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Wed, 12 Oct 2016 21:08:06 +0100 Subject: [PATCH 061/183] bat --- appveyor.yml | 4 ++-- build.sh => build.bat | 0 run-benchmarks.sh => run-benchmarks.bat | 0 run-tests.sh | 15 --------------- 4 files changed, 2 insertions(+), 17 deletions(-) rename build.sh => build.bat (100%) mode change 100755 => 100644 rename run-benchmarks.sh => run-benchmarks.bat (100%) mode change 100755 => 100644 delete mode 100755 run-tests.sh diff --git a/appveyor.yml b/appveyor.yml index 5dede7d4..410c858e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -3,9 +3,9 @@ configuration: - Release platform: Any CPU build_script: -- build.sh +- build.bat test_script: -- run-tests.sh +- run-tests.bat artifacts: - path: artifacts\**\*.* cache: diff --git a/build.sh b/build.bat old mode 100755 new mode 100644 similarity index 100% rename from build.sh rename to build.bat diff --git a/run-benchmarks.sh b/run-benchmarks.bat old mode 100755 new mode 100644 similarity index 100% rename from run-benchmarks.sh rename to run-benchmarks.bat diff --git a/run-tests.sh b/run-tests.sh deleted file mode 100755 index c2a65fc7..00000000 --- a/run-tests.sh +++ /dev/null @@ -1,15 +0,0 @@ - #!/bin/bash -echo ------------------------- - -echo Running Ocelot.UnitTests - -dotnet restore test/Ocelot.UnitTests/ -dotnet test test/Ocelot.UnitTests/ - -echo Running Ocelot.AcceptanceTests - -cd test/Ocelot.AcceptanceTests/ -dotnet restore -dotnet test -cd ../../ - From 9d89c6c1ab43eaab768bc0c1a66737bef9f512fb Mon Sep 17 00:00:00 2001 From: TomPallister Date: Wed, 12 Oct 2016 21:40:42 +0100 Subject: [PATCH 062/183] updated scripts --- run-benchmarks.bat | 1 - run-tests.bat | 13 +++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 run-tests.bat diff --git a/run-benchmarks.bat b/run-benchmarks.bat index 9ebef371..1376f17a 100644 --- a/run-benchmarks.bat +++ b/run-benchmarks.bat @@ -1,4 +1,3 @@ - #!/bin/bash echo ------------------------- echo Running Ocelot.Benchmarks diff --git a/run-tests.bat b/run-tests.bat new file mode 100644 index 00000000..f25a9cbf --- /dev/null +++ b/run-tests.bat @@ -0,0 +1,13 @@ +echo ------------------------- + +echo Running Ocelot.UnitTests + +dotnet restore test/Ocelot.UnitTests/ +dotnet test test/Ocelot.UnitTests/ + +echo Running Ocelot.AcceptanceTests + +cd test/Ocelot.AcceptanceTests/ +dotnet restore +dotnet test +cd ../../ \ No newline at end of file From 6b01ab1ac1981c71f1502d187c6d5fdf0fc83afb Mon Sep 17 00:00:00 2001 From: TomPallister Date: Wed, 12 Oct 2016 21:41:07 +0100 Subject: [PATCH 063/183] sln updates --- Ocelot.sln | 6 +++--- build.bat | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Ocelot.sln b/Ocelot.sln index 27a97cfc..1f3e50cb 100644 --- a/Ocelot.sln +++ b/Ocelot.sln @@ -8,12 +8,12 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3FA7C349-DBE8-4904-A2CE-015B8869CE6C}" ProjectSection(SolutionItems) = preProject appveyor.yml = appveyor.yml - build.sh = build.sh + build.bat = build.bat global.json = global.json LICENSE.md = LICENSE.md README.md = README.md - run-benchmarks.sh = run-benchmarks.sh - run-tests.sh = run-tests.sh + run-benchmarks.bat = run-benchmarks.bat + run-tests.bat = run-tests.bat EndProjectSection EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Ocelot", "src\Ocelot\Ocelot.xproj", "{AEC8FB40-B370-48A6-9B38-78E560041F01}" diff --git a/build.bat b/build.bat index c0ff2d8a..c444f952 100644 --- a/build.bat +++ b/build.bat @@ -1,4 +1,3 @@ - #!/bin/bash echo ------------------------- echo Running Ocelot.UnitTests From ff59eb9f3d85b433e4766aac9caf8d94bcb2b7a1 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Wed, 12 Oct 2016 21:42:45 +0100 Subject: [PATCH 064/183] update for appveyor --- build.bat | 1 + 1 file changed, 1 insertion(+) diff --git a/build.bat b/build.bat index c444f952..4406d204 100644 --- a/build.bat +++ b/build.bat @@ -15,6 +15,7 @@ cd ../../ echo Building Ocelot dotnet restore src/Ocelot +dotnet restore src/Ocelot.Library dotnet build src/Ocelot dotnet publish src/Ocelot -o artifacts/Ocelot From 7b785b25233f3362612ed5a4e8fb19a3003083ff Mon Sep 17 00:00:00 2001 From: Tom Pallister Date: Thu, 13 Oct 2016 08:44:38 +0100 Subject: [PATCH 065/183] added appveyor badge woot --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8494c6ff..fbc3bc33 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,8 @@ +![Build status](https://ci.appveyor.com/api/projects/status/github/TomPallister/Ocelot?svg=true) + + + + # Ocelot Attempt at a .NET Api Gateway @@ -29,4 +34,4 @@ Priorities ## How to use -TBC.... \ No newline at end of file +TBC.... From 20181ab4ee5fec2cc06b6f434160770ab78a4f7a Mon Sep 17 00:00:00 2001 From: Tom Pallister Date: Thu, 13 Oct 2016 12:29:05 +0100 Subject: [PATCH 066/183] Update README.md --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index fbc3bc33..63dc4976 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -![Build status](https://ci.appveyor.com/api/projects/status/github/TomPallister/Ocelot?svg=true) - +[![Build status](https://ci.appveyor.com/api/projects/status/roahbe4nl526ysya?svg=true)](https://ci.appveyor.com/project/TomPallister/ocelot) From 52ba77f4d5e025ba38b2458793eddb9ba57f031b Mon Sep 17 00:00:00 2001 From: "tom.pallister" Date: Thu, 13 Oct 2016 19:10:11 +0100 Subject: [PATCH 067/183] adding midleware tests --- .../DownstreamRouteFinderMiddlewareTests.cs | 89 +++++++++++++++ .../DownstreamUrlCreatorMiddlewareTests.cs | 100 +++++++++++++++++ .../HttpRequestBuilderMiddlewareTests.cs | 102 ++++++++++++++++++ 3 files changed, 291 insertions(+) create mode 100644 test/Ocelot.UnitTests/Middleware/DownstreamRouteFinderMiddlewareTests.cs create mode 100644 test/Ocelot.UnitTests/Middleware/DownstreamUrlCreatorMiddlewareTests.cs create mode 100644 test/Ocelot.UnitTests/Middleware/HttpRequestBuilderMiddlewareTests.cs diff --git a/test/Ocelot.UnitTests/Middleware/DownstreamRouteFinderMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/DownstreamRouteFinderMiddlewareTests.cs new file mode 100644 index 00000000..e3264653 --- /dev/null +++ b/test/Ocelot.UnitTests/Middleware/DownstreamRouteFinderMiddlewareTests.cs @@ -0,0 +1,89 @@ +namespace Ocelot.UnitTests.Middleware +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Net.Http; + using Library.Infrastructure.DownstreamRouteFinder; + using Library.Infrastructure.Repository; + using Library.Infrastructure.Responses; + using Library.Infrastructure.UrlMatcher; + using Library.Middleware; + using Microsoft.AspNetCore.Hosting; + using Microsoft.AspNetCore.TestHost; + using Microsoft.Extensions.DependencyInjection; + using Moq; + using TestStack.BDDfy; + using Xunit; + + public class DownstreamRouteFinderMiddlewareTests : IDisposable + { + private readonly Mock _downstreamRouteFinder; + private readonly Mock _scopedRepository; + private readonly string _url; + private readonly TestServer _server; + private readonly HttpClient _client; + private Response _downstreamRoute; + private HttpResponseMessage _result; + + public DownstreamRouteFinderMiddlewareTests() + { + _url = "http://localhost:51879"; + _downstreamRouteFinder = new Mock(); + _scopedRepository = new Mock(); + + var builder = new WebHostBuilder() + .ConfigureServices(x => + { + x.AddSingleton(_downstreamRouteFinder.Object); + x.AddSingleton(_scopedRepository.Object); + }) + .UseUrls(_url) + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseUrls(_url) + .Configure(app => + { + app.UseDownstreamRouteFinderMiddleware(); + }); + + _server = new TestServer(builder); + _client = _server.CreateClient(); + } + + [Fact] + public void happy_path() + { + this.Given(x => x.GivenTheDownStreamRouteFinderReturns(new DownstreamRoute(new List(), "any old string"))) + .When(x => x.WhenICallTheMiddleware()) + .Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly()) + .BDDfy(); + } + + private void ThenTheScopedDataRepositoryIsCalledCorrectly() + { + _scopedRepository + .Verify(x => x.Add("DownstreamRoute", _downstreamRoute.Data), Times.Once()); + } + + private void WhenICallTheMiddleware() + { + _result = _client.GetAsync(_url).Result; + } + + private void GivenTheDownStreamRouteFinderReturns(DownstreamRoute downstreamRoute) + { + _downstreamRoute = new OkResponse(downstreamRoute); + _downstreamRouteFinder + .Setup(x => x.FindDownstreamRoute(It.IsAny(), It.IsAny())) + .Returns(_downstreamRoute); + } + + public void Dispose() + { + _client.Dispose(); + _server.Dispose(); + } + } +} diff --git a/test/Ocelot.UnitTests/Middleware/DownstreamUrlCreatorMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/DownstreamUrlCreatorMiddlewareTests.cs new file mode 100644 index 00000000..b607cea7 --- /dev/null +++ b/test/Ocelot.UnitTests/Middleware/DownstreamUrlCreatorMiddlewareTests.cs @@ -0,0 +1,100 @@ +namespace Ocelot.UnitTests.Middleware +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Net.Http; + using Library.Infrastructure.DownstreamRouteFinder; + using Library.Infrastructure.Repository; + using Library.Infrastructure.Responses; + using Library.Infrastructure.UrlMatcher; + using Library.Infrastructure.UrlTemplateReplacer; + using Library.Middleware; + using Microsoft.AspNetCore.Hosting; + using Microsoft.AspNetCore.TestHost; + using Microsoft.Extensions.DependencyInjection; + using Moq; + using TestStack.BDDfy; + using Xunit; + + public class DownstreamUrlCreatorMiddlewareTests : IDisposable + { + 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; + + public DownstreamUrlCreatorMiddlewareTests() + { + _url = "http://localhost:51879"; + _downstreamUrlTemplateVariableReplacer = new Mock(); + _scopedRepository = new Mock(); + + var builder = new WebHostBuilder() + .ConfigureServices(x => + { + x.AddSingleton(_downstreamUrlTemplateVariableReplacer.Object); + x.AddSingleton(_scopedRepository.Object); + }) + .UseUrls(_url) + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseUrls(_url) + .Configure(app => + { + app.UseDownstreamUrlCreatorMiddleware(); + }); + + _server = new TestServer(builder); + _client = _server.CreateClient(); + } + + [Fact] + public void happy_path() + { + this.Given(x => x.GivenTheDownStreamRouteIs(new DownstreamRoute(new List(), "any old string"))) + .And(x => x.TheUrlReplacerReturns("any old string")) + .When(x => x.WhenICallTheMiddleware()) + .Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly()) + .BDDfy(); + } + + private void TheUrlReplacerReturns(string downstreamUrl) + { + _downstreamUrl = new OkResponse(downstreamUrl); + _downstreamUrlTemplateVariableReplacer + .Setup(x => x.ReplaceTemplateVariables(It.IsAny())) + .Returns(_downstreamUrl); + } + + private void ThenTheScopedDataRepositoryIsCalledCorrectly() + { + _scopedRepository + .Verify(x => x.Add("DownstreamUrl", _downstreamUrl.Data), Times.Once()); + } + + private void WhenICallTheMiddleware() + { + _result = _client.GetAsync(_url).Result; + } + + private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute) + { + _downstreamRoute = new OkResponse(downstreamRoute); + _scopedRepository + .Setup(x => x.Get(It.IsAny())) + .Returns(_downstreamRoute); + } + + public void Dispose() + { + _client.Dispose(); + _server.Dispose(); + } + } +} diff --git a/test/Ocelot.UnitTests/Middleware/HttpRequestBuilderMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/HttpRequestBuilderMiddlewareTests.cs new file mode 100644 index 00000000..1f38238b --- /dev/null +++ b/test/Ocelot.UnitTests/Middleware/HttpRequestBuilderMiddlewareTests.cs @@ -0,0 +1,102 @@ +/* +namespace Ocelot.UnitTests.Middleware +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Net.Http; + using Library.Infrastructure.DownstreamRouteFinder; + using Library.Infrastructure.Repository; + using Library.Infrastructure.RequestBuilder; + using Library.Infrastructure.Responses; + using Library.Infrastructure.UrlMatcher; + using Library.Infrastructure.UrlTemplateReplacer; + using Library.Middleware; + using Microsoft.AspNetCore.Hosting; + using Microsoft.AspNetCore.TestHost; + using Microsoft.Extensions.DependencyInjection; + using Moq; + using TestStack.BDDfy; + using Xunit; + + public class HttpRequestBuilderMiddlewareTests : IDisposable + { + private readonly Mock _requestBuilder; + private readonly Mock _scopedRepository; + private readonly string _url; + private readonly TestServer _server; + private readonly HttpClient _client; + private HttpResponseMessage _result; + private OkResponse _downstreamUrl; + + public HttpRequestBuilderMiddlewareTests() + { + _url = "http://localhost:51879"; + _requestBuilder = new Mock(); + _scopedRepository = new Mock(); + + var builder = new WebHostBuilder() + .ConfigureServices(x => + { + x.AddSingleton(_requestBuilder.Object); + x.AddSingleton(_scopedRepository.Object); + }) + .UseUrls(_url) + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseUrls(_url) + .Configure(app => + { + app.UseHttpRequestBuilderMiddleware(); + }); + + _server = new TestServer(builder); + _client = _server.CreateClient(); + } + + [Fact] + public void happy_path() + { + this.Given(x => x.GivenTheDownStreamUrlIs(new DownstreamRoute(new List(), "any old string"))) + .And(x => x.GivenTheRequestBuilderReturns("any old string")) + .When(x => x.WhenICallTheMiddleware()) + .Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly()) + .BDDfy(); + } + + private void GivenTheRequestBuilderReturns(Response request) + { + _downstreamUrl = new OkResponse(downstreamUrl); + _downstreamUrlTemplateVariableReplacer + .Setup(x => x.ReplaceTemplateVariables(It.IsAny())) + .Returns(_downstreamUrl); + } + + private void ThenTheScopedDataRepositoryIsCalledCorrectly() + { + _scopedRepository + .Verify(x => x.Add("DownstreamUrl", _downstreamUrl.Data), Times.Once()); + } + + private void WhenICallTheMiddleware() + { + _result = _client.GetAsync(_url).Result; + } + + private void GivenTheDownStreamUrlIs(string downstreamRoute) + { + _downstreamUrl = new OkResponse(downstreamRoute); + _scopedRepository + .Setup(x => x.Get(It.IsAny())) + .Returns(_downstreamUrl); + } + + public void Dispose() + { + _client.Dispose(); + _server.Dispose(); + } + } +} +*/ From 7ae35f4ce365915934bac001f8f37357abc94628 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Thu, 13 Oct 2016 19:59:12 +0100 Subject: [PATCH 068/183] added happy path tests for more middlewares --- .../Middleware/AuthenticationMiddleware.cs | 1 + .../Middleware/OcelotMiddleware.cs | 4 +- .../Middleware/RequestLoggerExtensions.cs | 12 --- .../Middleware/RequestLoggerMiddleware.cs | 25 ----- .../AuthenticationMiddlewareTests.cs | 98 ++++++++++++++++++ .../HttpRequestBuilderMiddlewareTests.cs | 58 ++++++----- .../HttpRequesterMiddlewareTests.cs | 99 +++++++++++++++++++ .../HttpResponderMiddlewareTests.cs | 96 ++++++++++++++++++ 8 files changed, 324 insertions(+), 69 deletions(-) delete mode 100644 src/Ocelot.Library/Middleware/RequestLoggerExtensions.cs delete mode 100644 src/Ocelot.Library/Middleware/RequestLoggerMiddleware.cs create mode 100644 test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs create mode 100644 test/Ocelot.UnitTests/Middleware/HttpRequesterMiddlewareTests.cs create mode 100644 test/Ocelot.UnitTests/Middleware/HttpResponderMiddlewareTests.cs diff --git a/src/Ocelot.Library/Middleware/AuthenticationMiddleware.cs b/src/Ocelot.Library/Middleware/AuthenticationMiddleware.cs index 67f11815..1d745c1c 100644 --- a/src/Ocelot.Library/Middleware/AuthenticationMiddleware.cs +++ b/src/Ocelot.Library/Middleware/AuthenticationMiddleware.cs @@ -12,6 +12,7 @@ private readonly RequestDelegate _next; private readonly IScopedRequestDataRepository _scopedRequestDataRepository; private readonly IRouteRequiresAuthentication _requiresAuthentication; + public AuthenticationMiddleware(RequestDelegate next, IScopedRequestDataRepository scopedRequestDataRepository, IRouteRequiresAuthentication requiresAuthentication) diff --git a/src/Ocelot.Library/Middleware/OcelotMiddleware.cs b/src/Ocelot.Library/Middleware/OcelotMiddleware.cs index f20daa96..dda41207 100644 --- a/src/Ocelot.Library/Middleware/OcelotMiddleware.cs +++ b/src/Ocelot.Library/Middleware/OcelotMiddleware.cs @@ -4,11 +4,11 @@ using Ocelot.Library.Infrastructure.Responses; namespace Ocelot.Library.Middleware { - public class OcelotMiddleware + public abstract class OcelotMiddleware { private readonly IScopedRequestDataRepository _scopedRequestDataRepository; - public OcelotMiddleware(IScopedRequestDataRepository scopedRequestDataRepository) + protected OcelotMiddleware(IScopedRequestDataRepository scopedRequestDataRepository) { _scopedRequestDataRepository = scopedRequestDataRepository; } diff --git a/src/Ocelot.Library/Middleware/RequestLoggerExtensions.cs b/src/Ocelot.Library/Middleware/RequestLoggerExtensions.cs deleted file mode 100644 index 0d1a0027..00000000 --- a/src/Ocelot.Library/Middleware/RequestLoggerExtensions.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Microsoft.AspNetCore.Builder; - -namespace Ocelot.Library.Middleware -{ - public static class RequestLoggerExtensions - { - public static IApplicationBuilder UseRequestLogger(this IApplicationBuilder builder) - { - return builder.UseMiddleware(); - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Middleware/RequestLoggerMiddleware.cs b/src/Ocelot.Library/Middleware/RequestLoggerMiddleware.cs deleted file mode 100644 index 554433b2..00000000 --- a/src/Ocelot.Library/Middleware/RequestLoggerMiddleware.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Logging; - -namespace Ocelot.Library.Middleware -{ - public class RequestLoggerMiddleware - { - private readonly RequestDelegate _next; - private readonly ILogger _logger; - - public RequestLoggerMiddleware(RequestDelegate next, ILoggerFactory loggerFactory) - { - _next = next; - _logger = loggerFactory.CreateLogger(); - } - - public async Task Invoke(HttpContext context) - { - _logger.LogInformation("Handling request: " + context.Request.Path); - await _next.Invoke(context); - _logger.LogInformation("Finished handling request."); - } - } -} \ No newline at end of file diff --git a/test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs new file mode 100644 index 00000000..4b1d2e07 --- /dev/null +++ b/test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net.Http; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using Moq; +using Ocelot.Library.Infrastructure.Authentication; +using Ocelot.Library.Infrastructure.DownstreamRouteFinder; +using Ocelot.Library.Infrastructure.Repository; +using Ocelot.Library.Infrastructure.Responses; +using Ocelot.Library.Infrastructure.UrlMatcher; +using Ocelot.Library.Middleware; +using TestStack.BDDfy; +using Xunit; + +namespace Ocelot.UnitTests.Middleware +{ + public class AuthenticationMiddlewareTests : IDisposable + { + private readonly Mock _requiresAuth; + private readonly Mock _scopedRepository; + private readonly string _url; + private readonly TestServer _server; + private readonly HttpClient _client; + private HttpResponseMessage _result; + private OkResponse _downstreamRoute; + + public AuthenticationMiddlewareTests() + { + _url = "http://localhost:51879"; + _requiresAuth = new Mock(); + _scopedRepository = new Mock(); + + var builder = new WebHostBuilder() + .ConfigureServices(x => + { + x.AddSingleton(_requiresAuth.Object); + x.AddSingleton(_scopedRepository.Object); + }) + .UseUrls(_url) + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseUrls(_url) + .Configure(app => + { + app.UseAuthenticationMiddleware(); + }); + + _server = new TestServer(builder); + _client = _server.CreateClient(); + } + + [Fact] + public void happy_path() + { + this.Given(x => x.GivenTheDownStreamRouteIs(new DownstreamRoute(new List(), "any old string"))) + .And(x => x.GivenTheRouteIsNotAuthenticated()) + .When(x => x.WhenICallTheMiddleware()) + .Then(x => x.ThenNoExceptionsAreThrown()) + .BDDfy(); + } + + private void ThenNoExceptionsAreThrown() + { + //todo not suck + } + + private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute) + { + _downstreamRoute = new OkResponse(downstreamRoute); + _scopedRepository + .Setup(x => x.Get(It.IsAny())) + .Returns(_downstreamRoute); + } + + private void GivenTheRouteIsNotAuthenticated() + { + _requiresAuth + .Setup(x => x.IsAuthenticated(It.IsAny(), It.IsAny())) + .Returns(new OkResponse(false)); + } + + private void WhenICallTheMiddleware() + { + _result = _client.GetAsync(_url).Result; + } + + + public void Dispose() + { + _client.Dispose(); + _server.Dispose(); + } + } +} diff --git a/test/Ocelot.UnitTests/Middleware/HttpRequestBuilderMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/HttpRequestBuilderMiddlewareTests.cs index 1f38238b..56142b70 100644 --- a/test/Ocelot.UnitTests/Middleware/HttpRequestBuilderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Middleware/HttpRequestBuilderMiddlewareTests.cs @@ -1,24 +1,21 @@ -/* +using System; +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; +using Ocelot.Library.Infrastructure.Repository; +using Ocelot.Library.Infrastructure.RequestBuilder; +using Ocelot.Library.Infrastructure.Responses; +using Ocelot.Library.Middleware; +using TestStack.BDDfy; +using Xunit; + namespace Ocelot.UnitTests.Middleware { - using System; - using System.Collections.Generic; - using System.IO; - using System.Net.Http; - using Library.Infrastructure.DownstreamRouteFinder; - using Library.Infrastructure.Repository; - using Library.Infrastructure.RequestBuilder; - using Library.Infrastructure.Responses; - using Library.Infrastructure.UrlMatcher; - using Library.Infrastructure.UrlTemplateReplacer; - using Library.Middleware; - using Microsoft.AspNetCore.Hosting; - using Microsoft.AspNetCore.TestHost; - using Microsoft.Extensions.DependencyInjection; - using Moq; - using TestStack.BDDfy; - using Xunit; - public class HttpRequestBuilderMiddlewareTests : IDisposable { private readonly Mock _requestBuilder; @@ -27,6 +24,7 @@ namespace Ocelot.UnitTests.Middleware private readonly TestServer _server; private readonly HttpClient _client; private HttpResponseMessage _result; + private OkResponse _request; private OkResponse _downstreamUrl; public HttpRequestBuilderMiddlewareTests() @@ -58,25 +56,26 @@ namespace Ocelot.UnitTests.Middleware [Fact] public void happy_path() { - this.Given(x => x.GivenTheDownStreamUrlIs(new DownstreamRoute(new List(), "any old string"))) - .And(x => x.GivenTheRequestBuilderReturns("any old string")) + this.Given(x => x.GivenTheDownStreamUrlIs("any old string")) + .And(x => x.GivenTheRequestBuilderReturns(new Request(new HttpRequestMessage(), new CookieContainer()))) .When(x => x.WhenICallTheMiddleware()) .Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly()) .BDDfy(); } - private void GivenTheRequestBuilderReturns(Response request) + private void GivenTheRequestBuilderReturns(Request request) { - _downstreamUrl = new OkResponse(downstreamUrl); - _downstreamUrlTemplateVariableReplacer - .Setup(x => x.ReplaceTemplateVariables(It.IsAny())) - .Returns(_downstreamUrl); + _request = new OkResponse(request); + _requestBuilder + .Setup(x => x.Build(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), + It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(_request); } private void ThenTheScopedDataRepositoryIsCalledCorrectly() { _scopedRepository - .Verify(x => x.Add("DownstreamUrl", _downstreamUrl.Data), Times.Once()); + .Verify(x => x.Add("Request", _request.Data), Times.Once()); } private void WhenICallTheMiddleware() @@ -84,9 +83,9 @@ namespace Ocelot.UnitTests.Middleware _result = _client.GetAsync(_url).Result; } - private void GivenTheDownStreamUrlIs(string downstreamRoute) + private void GivenTheDownStreamUrlIs(string downstreamUrl) { - _downstreamUrl = new OkResponse(downstreamRoute); + _downstreamUrl = new OkResponse(downstreamUrl); _scopedRepository .Setup(x => x.Get(It.IsAny())) .Returns(_downstreamUrl); @@ -99,4 +98,3 @@ namespace Ocelot.UnitTests.Middleware } } } -*/ diff --git a/test/Ocelot.UnitTests/Middleware/HttpRequesterMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/HttpRequesterMiddlewareTests.cs new file mode 100644 index 00000000..ecb62b19 --- /dev/null +++ b/test/Ocelot.UnitTests/Middleware/HttpRequesterMiddlewareTests.cs @@ -0,0 +1,99 @@ +using System; +using System.IO; +using System.Net; +using System.Net.Http; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using Moq; +using Ocelot.Library.Infrastructure.Repository; +using Ocelot.Library.Infrastructure.RequestBuilder; +using Ocelot.Library.Infrastructure.Requester; +using Ocelot.Library.Infrastructure.Responses; +using Ocelot.Library.Middleware; +using TestStack.BDDfy; +using Xunit; + +namespace Ocelot.UnitTests.Middleware +{ + public class HttpRequesterMiddlewareTests : IDisposable + { + private readonly Mock _requester; + private readonly Mock _scopedRepository; + private readonly string _url; + private readonly TestServer _server; + private readonly HttpClient _client; + private HttpResponseMessage _result; + private OkResponse _response; + private OkResponse _request; + + public HttpRequesterMiddlewareTests() + { + _url = "http://localhost:51879"; + _requester = new Mock(); + _scopedRepository = new Mock(); + + var builder = new WebHostBuilder() + .ConfigureServices(x => + { + x.AddSingleton(_requester.Object); + x.AddSingleton(_scopedRepository.Object); + }) + .UseUrls(_url) + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseUrls(_url) + .Configure(app => + { + app.UseHttpRequesterMiddleware(); + }); + + _server = new TestServer(builder); + _client = _server.CreateClient(); + } + + [Fact] + public void happy_path() + { + this.Given(x => x.GivenTheRequestIs(new Request(new HttpRequestMessage(),new CookieContainer()))) + .And(x => x.GivenTheRequesterReturns(new HttpResponseMessage())) + .When(x => x.WhenICallTheMiddleware()) + .Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly()) + .BDDfy(); + } + + private void GivenTheRequesterReturns(HttpResponseMessage response) + { + _response = new OkResponse(response); + _requester + .Setup(x => x.GetResponse(It.IsAny())) + .ReturnsAsync(_response); + } + + private void ThenTheScopedDataRepositoryIsCalledCorrectly() + { + _scopedRepository + .Verify(x => x.Add("Response", _response.Data), Times.Once()); + } + + private void WhenICallTheMiddleware() + { + _result = _client.GetAsync(_url).Result; + } + + private void GivenTheRequestIs(Request request) + { + _request = new OkResponse(request); + _scopedRepository + .Setup(x => x.Get(It.IsAny())) + .Returns(_request); + } + + public void Dispose() + { + _client.Dispose(); + _server.Dispose(); + } + } +} diff --git a/test/Ocelot.UnitTests/Middleware/HttpResponderMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/HttpResponderMiddlewareTests.cs new file mode 100644 index 00000000..d565dbf8 --- /dev/null +++ b/test/Ocelot.UnitTests/Middleware/HttpResponderMiddlewareTests.cs @@ -0,0 +1,96 @@ +using System; +using System.IO; +using System.Net.Http; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using Moq; +using Ocelot.Library.Infrastructure.Repository; +using Ocelot.Library.Infrastructure.Responder; +using Ocelot.Library.Infrastructure.Responses; +using Ocelot.Library.Middleware; +using TestStack.BDDfy; +using Xunit; + +namespace Ocelot.UnitTests.Middleware +{ + public class HttpResponderMiddlewareTests : IDisposable + { + private readonly Mock _responder; + private readonly Mock _scopedRepository; + private readonly string _url; + private readonly TestServer _server; + private readonly HttpClient _client; + private HttpResponseMessage _result; + private OkResponse _response; + + public HttpResponderMiddlewareTests() + { + _url = "http://localhost:51879"; + _responder = new Mock(); + _scopedRepository = new Mock(); + + var builder = new WebHostBuilder() + .ConfigureServices(x => + { + x.AddSingleton(_responder.Object); + x.AddSingleton(_scopedRepository.Object); + }) + .UseUrls(_url) + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseUrls(_url) + .Configure(app => + { + app.UseHttpResponderMiddleware(); + }); + + _server = new TestServer(builder); + _client = _server.CreateClient(); + } + + [Fact] + public void happy_path() + { + this.Given(x => x.GivenTheHttpResponseMessageIs(new HttpResponseMessage())) + .And(x => x.GivenThereAreNoPipelineErrors()) + .When(x => x.WhenICallTheMiddleware()) + .Then(x => x.TheResponderIsCalledCorrectly()) + .BDDfy(); + } + + private void GivenThereAreNoPipelineErrors() + { + _scopedRepository + .Setup(x => x.Get(It.IsAny())) + .Returns(new OkResponse(false)); + } + + private void TheResponderIsCalledCorrectly() + { + _responder + .Verify(x => x.CreateResponse(It.IsAny(), _response.Data), Times.Once); + } + + private void WhenICallTheMiddleware() + { + _result = _client.GetAsync(_url).Result; + } + + private void GivenTheHttpResponseMessageIs(HttpResponseMessage response) + { + _response = new OkResponse(response); + _scopedRepository + .Setup(x => x.Get(It.IsAny())) + .Returns(_response); + } + + public void Dispose() + { + _client.Dispose(); + _server.Dispose(); + } + } +} From 17b24d3da505fc6dd652e10a50c5a0a309e97902 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Thu, 13 Oct 2016 20:40:03 +0100 Subject: [PATCH 069/183] changes to get ftp deploy working from appveyor --- .gitignore | 1 + appveyor.yml | 2 +- build.bat | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 7639ba0d..1acefa83 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,7 @@ results/ .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ +site/wwwroot/ # MSTest test Results [Tt]est[Rr]esult*/ diff --git a/appveyor.yml b/appveyor.yml index 410c858e..d2b5d90c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,6 +7,6 @@ build_script: test_script: - run-tests.bat artifacts: -- path: artifacts\**\*.* +- path: site\wwwroot\*.* cache: - '%USERPROFILE%\.nuget\packages' \ No newline at end of file diff --git a/build.bat b/build.bat index 4406d204..4b064953 100644 --- a/build.bat +++ b/build.bat @@ -17,6 +17,6 @@ echo Building Ocelot dotnet restore src/Ocelot dotnet restore src/Ocelot.Library dotnet build src/Ocelot -dotnet publish src/Ocelot -o artifacts/Ocelot +dotnet publish src/Ocelot -o site/wwwroot From 2e9d2b3c8c830b3b859bd389c3252d3a9fb54edd Mon Sep 17 00:00:00 2001 From: TomPallister Date: Thu, 13 Oct 2016 20:53:17 +0100 Subject: [PATCH 070/183] try copy all artifacts for appveyor --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index d2b5d90c..09d281a0 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,6 +7,6 @@ build_script: test_script: - run-tests.bat artifacts: -- path: site\wwwroot\*.* +- path: site\wwwroot\**\*.* cache: - '%USERPROFILE%\.nuget\packages' \ No newline at end of file From dcea887059ee842fb50cec6e31b29ecfb056bf59 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Thu, 13 Oct 2016 20:54:43 +0100 Subject: [PATCH 071/183] for testing on azure --- src/Ocelot/configuration.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Ocelot/configuration.yaml b/src/Ocelot/configuration.yaml index db7e74c5..04ac7018 100644 --- a/src/Ocelot/configuration.yaml +++ b/src/Ocelot/configuration.yaml @@ -1,4 +1,4 @@ ReRoutes: -- DownstreamTemplate: http://www.mattsite.dev/ +- DownstreamTemplate: http://www.bbc.co.uk UpstreamTemplate: / UpstreamHttpMethod: Get From 19970a1bac035817c811da0b857cadc839268d7b Mon Sep 17 00:00:00 2001 From: The Gitter Badger Date: Thu, 13 Oct 2016 19:57:24 +0000 Subject: [PATCH 072/183] Add Gitter badge --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 63dc4976..dada1069 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ # Ocelot +[![Join the chat at https://gitter.im/Ocelotey/Lobby](https://badges.gitter.im/Ocelotey/Lobby.svg)](https://gitter.im/Ocelotey/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + Attempt at a .NET Api Gateway This project is aimed at people using .NET running From 06173a00352c4942ba59448fdaf384c545c7d281 Mon Sep 17 00:00:00 2001 From: Tom Pallister Date: Thu, 13 Oct 2016 21:00:24 +0100 Subject: [PATCH 073/183] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 63dc4976..3326518a 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ [![Build status](https://ci.appveyor.com/api/projects/status/roahbe4nl526ysya?svg=true)](https://ci.appveyor.com/project/TomPallister/ocelot) +[![Gitter](https://img.shields.io/gitter/room/nwjs/nw.js.svg?maxAge=2592000)](https://gitter.im/Ocelotey/Lobby#) + # Ocelot From 63ed89c1a0b3f3b3dc3f98083dab3f1040a14d9d Mon Sep 17 00:00:00 2001 From: Tom Pallister Date: Thu, 13 Oct 2016 21:03:02 +0100 Subject: [PATCH 074/183] Update README.md --- README.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 0c2ed613..39e5fc35 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,7 @@ -[![Build status](https://ci.appveyor.com/api/projects/status/roahbe4nl526ysya?svg=true)](https://ci.appveyor.com/project/TomPallister/ocelot) - -[![Gitter](https://img.shields.io/gitter/room/nwjs/nw.js.svg?maxAge=2592000)](https://gitter.im/Ocelotey/Lobby#) - - - # Ocelot +[![Build status](https://ci.appveyor.com/api/projects/status/roahbe4nl526ysya?svg=true)](https://ci.appveyor.com/project/TomPallister/ocelot) + [![Join the chat at https://gitter.im/Ocelotey/Lobby](https://badges.gitter.im/Ocelotey/Lobby.svg)](https://gitter.im/Ocelotey/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) Attempt at a .NET Api Gateway From 3f4e908798da55e6bee6a34c5a3d7028a691e07c Mon Sep 17 00:00:00 2001 From: TomPallister Date: Thu, 13 Oct 2016 21:16:17 +0100 Subject: [PATCH 075/183] gitingore --- Ocelot.sln | 1 + 1 file changed, 1 insertion(+) diff --git a/Ocelot.sln b/Ocelot.sln index 1f3e50cb..dc86cfdd 100644 --- a/Ocelot.sln +++ b/Ocelot.sln @@ -7,6 +7,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{5CFB79B7-C9D EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3FA7C349-DBE8-4904-A2CE-015B8869CE6C}" ProjectSection(SolutionItems) = preProject + .gitignore = .gitignore appveyor.yml = appveyor.yml build.bat = build.bat global.json = global.json From 16801ec016e297da75b07b4ffaafa61e9394e83a Mon Sep 17 00:00:00 2001 From: TomPallister Date: Thu, 13 Oct 2016 21:49:11 +0100 Subject: [PATCH 076/183] upgrade --- global.json | 6 +++--- src/Ocelot/Ocelot.xproj | 7 ++++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/global.json b/global.json index 0d315988..ff8d898e 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@  { "projects": [ "src", "test" ], - "sdk": { - "version": "1.0.0-preview2-003121" - } + "sdk": { + "version": "1.0.0-preview2-003133" + } } diff --git a/src/Ocelot/Ocelot.xproj b/src/Ocelot/Ocelot.xproj index 86842479..ec987923 100644 --- a/src/Ocelot/Ocelot.xproj +++ b/src/Ocelot/Ocelot.xproj @@ -16,4 +16,9 @@ 2.0 - + + + + + + \ No newline at end of file From 35fa32c090b84ebb4d621ce5accb55c09ac9e596 Mon Sep 17 00:00:00 2001 From: "tom.pallister" Date: Fri, 14 Oct 2016 08:26:51 +0100 Subject: [PATCH 077/183] updated build scripts --- build-and-run-tests.bat | 2 ++ build.bat | 13 +------------ run-tests.bat | 8 ++++++-- 3 files changed, 9 insertions(+), 14 deletions(-) create mode 100644 build-and-run-tests.bat diff --git a/build-and-run-tests.bat b/build-and-run-tests.bat new file mode 100644 index 00000000..764682b6 --- /dev/null +++ b/build-and-run-tests.bat @@ -0,0 +1,2 @@ +./run-tests.bat +./build.bat \ No newline at end of file diff --git a/build.bat b/build.bat index 4b064953..6c89e8e6 100644 --- a/build.bat +++ b/build.bat @@ -1,22 +1,11 @@ echo ------------------------- -echo Running Ocelot.UnitTests - -dotnet restore test/Ocelot.UnitTests/ -dotnet test test/Ocelot.UnitTests/ - -echo Running Ocelot.AcceptanceTests - -cd test/Ocelot.AcceptanceTests/ -dotnet restore -dotnet test -cd ../../ - echo Building Ocelot dotnet restore src/Ocelot dotnet restore src/Ocelot.Library dotnet build src/Ocelot +dotnet pack src/Ocelot/project.json --no-build --output nupkgs dotnet publish src/Ocelot -o site/wwwroot diff --git a/run-tests.bat b/run-tests.bat index f25a9cbf..853ea538 100644 --- a/run-tests.bat +++ b/run-tests.bat @@ -1,12 +1,16 @@ echo ------------------------- -echo Running Ocelot.UnitTests +echo Restoring Ocelot +dotnet restore src/Ocelot +echo Restoring Ocelot +dotnet restore src/Ocelot.Library + +echo Running Ocelot.UnitTests dotnet restore test/Ocelot.UnitTests/ dotnet test test/Ocelot.UnitTests/ echo Running Ocelot.AcceptanceTests - cd test/Ocelot.AcceptanceTests/ dotnet restore dotnet test From aabfe62cebd02a890edf7e066aa7397b87a30783 Mon Sep 17 00:00:00 2001 From: "tom.pallister" Date: Fri, 14 Oct 2016 08:29:28 +0100 Subject: [PATCH 078/183] updated sln --- Ocelot.sln | 1 + 1 file changed, 1 insertion(+) diff --git a/Ocelot.sln b/Ocelot.sln index dc86cfdd..f06eb7cf 100644 --- a/Ocelot.sln +++ b/Ocelot.sln @@ -9,6 +9,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution ProjectSection(SolutionItems) = preProject .gitignore = .gitignore appveyor.yml = appveyor.yml + build-and-run-tests.bat = build-and-run-tests.bat build.bat = build.bat global.json = global.json LICENSE.md = LICENSE.md From 6e61161406f3d3ff6880cdbbd310aad1c1b3f478 Mon Sep 17 00:00:00 2001 From: "tom.pallister" Date: Fri, 14 Oct 2016 13:22:02 +0100 Subject: [PATCH 079/183] updated to netstandard 1.4 and added authentication packages --- src/Ocelot.Library/project.json | 47 ++++++++++++++---------- src/Ocelot/project.json | 2 +- test/Ocelot.AcceptanceTests/project.json | 2 +- test/Ocelot.UnitTests/project.json | 2 +- 4 files changed, 31 insertions(+), 22 deletions(-) diff --git a/src/Ocelot.Library/project.json b/src/Ocelot.Library/project.json index e889d22f..24790da9 100644 --- a/src/Ocelot.Library/project.json +++ b/src/Ocelot.Library/project.json @@ -1,28 +1,37 @@ { "version": "1.0.0-*", - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.0.0", - "type": "platform" - }, - "Microsoft.AspNetCore.Mvc": "1.0.0", - "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", - "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", - "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", - "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0", - "Microsoft.Extensions.Configuration.Json": "1.0.0", - "Microsoft.Extensions.Logging": "1.0.0", - "Microsoft.Extensions.Logging.Console": "1.0.0", - "Microsoft.Extensions.Logging.Debug": "1.0.0", - "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", - "Microsoft.AspNetCore.Http": "1.0.0", - "System.Text.RegularExpressions": "4.1.0", - "YamlDotNet": "3.9.0" + "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.0.0", + "type": "platform" }, + "Microsoft.AspNetCore.Mvc": "1.0.0", + "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", + "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", + "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0", + "Microsoft.Extensions.Configuration.Json": "1.0.0", + "Microsoft.Extensions.Logging": "1.0.0", + "Microsoft.Extensions.Logging.Console": "1.0.0", + "Microsoft.Extensions.Logging.Debug": "1.0.0", + "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", + "Microsoft.AspNetCore.Http": "1.0.0", + "System.Text.RegularExpressions": "4.1.0", + "YamlDotNet": "3.9.0", + "Microsoft.AspNetCore.Authentication.OAuth": "1.0.0", + "Microsoft.AspNetCore.Authentication.JwtBearer": "1.0.0", + "Microsoft.AspNetCore.Authentication.OpenIdConnect": "1.0.0", + "Microsoft.AspNetCore.Authentication.Cookies": "1.0.0", + "Microsoft.AspNetCore.Authentication.Google": "1.0.0", + "Microsoft.AspNetCore.Authentication.Facebook": "1.0.0", + "Microsoft.AspNetCore.Authentication.Twitter": "1.0.0", + "Microsoft.AspNetCore.Authentication.MicrosoftAccount": "1.0.0", + "Microsoft.AspNetCore.Authentication": "1.0.0" + }, "frameworks": { - "netcoreapp1.0": { + "netcoreapp1.4": { "imports": [ "dotnet5.6", "portable-net45+win8" diff --git a/src/Ocelot/project.json b/src/Ocelot/project.json index 5a1d73de..98c5d1e5 100644 --- a/src/Ocelot/project.json +++ b/src/Ocelot/project.json @@ -26,7 +26,7 @@ }, "frameworks": { - "netcoreapp1.0": { + "netcoreapp1.4": { "imports": [ "dotnet5.6", "portable-net45+win8" diff --git a/test/Ocelot.AcceptanceTests/project.json b/test/Ocelot.AcceptanceTests/project.json index c672997c..ba6d6162 100644 --- a/test/Ocelot.AcceptanceTests/project.json +++ b/test/Ocelot.AcceptanceTests/project.json @@ -38,7 +38,7 @@ }, "frameworks": { - "netcoreapp1.0": { + "netcoreapp1.4": { "imports": [ "dotnet5.6", "portable-net45+win8" diff --git a/test/Ocelot.UnitTests/project.json b/test/Ocelot.UnitTests/project.json index 6e5a6811..4c8f0f4f 100644 --- a/test/Ocelot.UnitTests/project.json +++ b/test/Ocelot.UnitTests/project.json @@ -30,7 +30,7 @@ }, "frameworks": { - "netcoreapp1.0": { + "netcoreapp1.4": { "imports": [ "dotnet5.6", "portable-net45+win8" From 8c194a365bc6db3675ca7c7e3609a0b9c1f42240 Mon Sep 17 00:00:00 2001 From: "tom.pallister" Date: Fri, 14 Oct 2016 13:30:34 +0100 Subject: [PATCH 080/183] fixed failing tests after upgrade --- test/Ocelot.AcceptanceTests/OcelotTests.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/Ocelot.AcceptanceTests/OcelotTests.cs b/test/Ocelot.AcceptanceTests/OcelotTests.cs index 99219ac7..299f67bf 100644 --- a/test/Ocelot.AcceptanceTests/OcelotTests.cs +++ b/test/Ocelot.AcceptanceTests/OcelotTests.cs @@ -24,9 +24,12 @@ namespace Ocelot.AcceptanceTests private StringContent _postContent; private IWebHost _builder; + // Sadly we need to change this when we update the netcoreapp version to make the test update the config correctly + private double _netCoreAppVersion = 1.4; + public OcelotTests() { - _configurationPath = "./bin/Debug/netcoreapp1.0/configuration.yaml"; + _configurationPath = $"./bin/Debug/netcoreapp{_netCoreAppVersion}/configuration.yaml"; } [Fact] From f545ba86206460bef87694708d3a6de65a81bf69 Mon Sep 17 00:00:00 2001 From: "tom.pallister" Date: Fri, 14 Oct 2016 20:08:09 +0100 Subject: [PATCH 081/183] removed thing that checks if route is authorised cos we dont need it --- .../CouldNotFindConfigurationError.cs | 11 --- .../IRouteRequiresAuthentication.cs | 10 -- .../RouteRequiresAuthentication.cs | 35 ------- .../Infrastructure/Builder/ReRouteBuilder.cs | 47 +++++++++ .../Configuration/OcelotConfiguration.cs | 2 +- .../Infrastructure/Configuration/ReRoute.cs | 4 +- .../DownstreamRouteFinder/DownstreamRoute.cs | 8 +- .../DownstreamRouteFinder.cs | 2 +- .../DownstreamUrlTemplateVariableReplacer.cs | 2 +- .../Middleware/AuthenticationMiddleware.cs | 18 ++-- src/Ocelot/Startup.cs | 3 - .../RequiresAuthenticationTests.cs | 96 ------------------- .../Configuration/OcelotConfigurationTests.cs | 8 +- .../DownstreamRouteFinderTests.cs | 14 +-- .../AuthenticationMiddlewareTests.cs | 16 +--- .../DownstreamRouteFinderMiddlewareTests.cs | 3 +- .../DownstreamUrlCreatorMiddlewareTests.cs | 3 +- ...eamUrlPathTemplateVariableReplacerTests.cs | 21 ++-- 18 files changed, 93 insertions(+), 210 deletions(-) delete mode 100644 src/Ocelot.Library/Infrastructure/Authentication/CouldNotFindConfigurationError.cs delete mode 100644 src/Ocelot.Library/Infrastructure/Authentication/IRouteRequiresAuthentication.cs delete mode 100644 src/Ocelot.Library/Infrastructure/Authentication/RouteRequiresAuthentication.cs create mode 100644 src/Ocelot.Library/Infrastructure/Builder/ReRouteBuilder.cs delete mode 100644 test/Ocelot.UnitTests/Authentication/RequiresAuthenticationTests.cs diff --git a/src/Ocelot.Library/Infrastructure/Authentication/CouldNotFindConfigurationError.cs b/src/Ocelot.Library/Infrastructure/Authentication/CouldNotFindConfigurationError.cs deleted file mode 100644 index 5b30c463..00000000 --- a/src/Ocelot.Library/Infrastructure/Authentication/CouldNotFindConfigurationError.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Ocelot.Library.Infrastructure.Authentication -{ - using Responses; - public class CouldNotFindConfigurationError : Error - { - public CouldNotFindConfigurationError(string message) - : base(message) - { - } - } -} diff --git a/src/Ocelot.Library/Infrastructure/Authentication/IRouteRequiresAuthentication.cs b/src/Ocelot.Library/Infrastructure/Authentication/IRouteRequiresAuthentication.cs deleted file mode 100644 index 0a3f9858..00000000 --- a/src/Ocelot.Library/Infrastructure/Authentication/IRouteRequiresAuthentication.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ocelot.Library.Infrastructure.Authentication -{ - using DownstreamRouteFinder; - using Responses; - - public interface IRouteRequiresAuthentication - { - Response IsAuthenticated(DownstreamRoute downstreamRoute, string httpMethod); - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Authentication/RouteRequiresAuthentication.cs b/src/Ocelot.Library/Infrastructure/Authentication/RouteRequiresAuthentication.cs deleted file mode 100644 index 988959e4..00000000 --- a/src/Ocelot.Library/Infrastructure/Authentication/RouteRequiresAuthentication.cs +++ /dev/null @@ -1,35 +0,0 @@ -namespace Ocelot.Library.Infrastructure.Authentication -{ - using System; - using System.Collections.Generic; - using System.Linq; - using Configuration; - using DownstreamRouteFinder; - using Responses; - - public class RouteRequiresAuthentication : IRouteRequiresAuthentication - { - private readonly IOcelotConfiguration _configuration; - - public RouteRequiresAuthentication(IOcelotConfiguration configuration) - { - _configuration = configuration; - } - - public Response IsAuthenticated(DownstreamRoute downstreamRoute, string httpMethod) - { - var reRoute = - _configuration.ReRoutes.FirstOrDefault( - x => - x.DownstreamTemplate == downstreamRoute.DownstreamUrlTemplate && - string.Equals(x.UpstreamHttpMethod, httpMethod, StringComparison.CurrentCultureIgnoreCase)); - - if (reRoute == null) - { - return new ErrorResponse(new List {new CouldNotFindConfigurationError($"Could not find configuration for {downstreamRoute.DownstreamUrlTemplate} using method {httpMethod}")}); - } - - return new OkResponse(reRoute.IsAuthenticated); - } - } -} diff --git a/src/Ocelot.Library/Infrastructure/Builder/ReRouteBuilder.cs b/src/Ocelot.Library/Infrastructure/Builder/ReRouteBuilder.cs new file mode 100644 index 00000000..3966ae7c --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Builder/ReRouteBuilder.cs @@ -0,0 +1,47 @@ +namespace Ocelot.Library.Infrastructure.Builder +{ + using Configuration; + + public class ReRouteBuilder + { + private string _downstreamTemplate; + private string _upstreamTemplate; + private string _upstreamTemplatePattern; + private string _upstreamHttpMethod; + private bool _isAuthenticated; + private string _authenticationProvider; + + public void WithDownstreamTemplate(string input) + { + _downstreamTemplate = input; + } + + public void WithUpstreamTemplate(string input) + { + _upstreamTemplate = input; + } + + public void WithUpstreamTemplatePattern(string input) + { + _upstreamTemplatePattern = input; + } + public void WithUpstreamHttpMethod(string input) + { + _upstreamHttpMethod = input; + } + public void WithIsAuthenticated(bool input) + { + _isAuthenticated = input; + + } + public void WithAuthenticationProvider(string input) + { + _authenticationProvider = input; + } + + public ReRoute Build() + { + return new ReRoute(_downstreamTemplate, _upstreamTemplate, _upstreamHttpMethod, _upstreamTemplatePattern, _isAuthenticated, _authenticationProvider); + } + } +} diff --git a/src/Ocelot.Library/Infrastructure/Configuration/OcelotConfiguration.cs b/src/Ocelot.Library/Infrastructure/Configuration/OcelotConfiguration.cs index 7ac93b3c..1b93447a 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/OcelotConfiguration.cs +++ b/src/Ocelot.Library/Infrastructure/Configuration/OcelotConfiguration.cs @@ -45,7 +45,7 @@ namespace Ocelot.Library.Infrastructure.Configuration var isAuthenticated = !string.IsNullOrEmpty(reRoute.Authentication); - _reRoutes.Add(new ReRoute(reRoute.DownstreamTemplate, reRoute.UpstreamTemplate, reRoute.UpstreamHttpMethod, upstreamTemplate, isAuthenticated)); + _reRoutes.Add(new ReRoute(reRoute.DownstreamTemplate, reRoute.UpstreamTemplate, reRoute.UpstreamHttpMethod, upstreamTemplate, isAuthenticated, reRoute.Authentication)); } } diff --git a/src/Ocelot.Library/Infrastructure/Configuration/ReRoute.cs b/src/Ocelot.Library/Infrastructure/Configuration/ReRoute.cs index 9c5edf0f..5d000511 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/ReRoute.cs +++ b/src/Ocelot.Library/Infrastructure/Configuration/ReRoute.cs @@ -2,13 +2,14 @@ { public class ReRoute { - public ReRoute(string downstreamTemplate, string upstreamTemplate, string upstreamHttpMethod, string upstreamTemplatePattern, bool isAuthenticated) + public ReRoute(string downstreamTemplate, string upstreamTemplate, string upstreamHttpMethod, string upstreamTemplatePattern, bool isAuthenticated, string authenticationProvider) { DownstreamTemplate = downstreamTemplate; UpstreamTemplate = upstreamTemplate; UpstreamHttpMethod = upstreamHttpMethod; UpstreamTemplatePattern = upstreamTemplatePattern; IsAuthenticated = isAuthenticated; + AuthenticationProvider = authenticationProvider; } public string DownstreamTemplate { get; private set; } @@ -16,5 +17,6 @@ public string UpstreamTemplatePattern { get; private set; } public string UpstreamHttpMethod { get; private set; } public bool IsAuthenticated { get; private set; } + public string AuthenticationProvider { get; private set; } } } \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRoute.cs b/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRoute.cs index b88f0063..8d8cd074 100644 --- a/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRoute.cs +++ b/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRoute.cs @@ -3,14 +3,16 @@ using Ocelot.Library.Infrastructure.UrlMatcher; namespace Ocelot.Library.Infrastructure.DownstreamRouteFinder { + using Configuration; + public class DownstreamRoute { - public DownstreamRoute(List templateVariableNameAndValues, string downstreamUrlTemplate) + public DownstreamRoute(List templateVariableNameAndValues, ReRoute reRoute) { TemplateVariableNameAndValues = templateVariableNameAndValues; - DownstreamUrlTemplate = downstreamUrlTemplate; + ReRoute = reRoute; } public List TemplateVariableNameAndValues { get; private set; } - public string DownstreamUrlTemplate { get; private set; } + public ReRoute ReRoute { get; private set; } } } \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRouteFinder.cs b/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRouteFinder.cs index d87b4ccd..3063cf76 100644 --- a/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRouteFinder.cs +++ b/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRouteFinder.cs @@ -32,7 +32,7 @@ namespace Ocelot.Library.Infrastructure.DownstreamRouteFinder var templateVariableNameAndValues = _templateVariableNameAndValueFinder.Find(upstreamUrlPath, template.UpstreamTemplate); - return new OkResponse(new DownstreamRoute(templateVariableNameAndValues.Data, template.DownstreamTemplate)); + return new OkResponse(new DownstreamRoute(templateVariableNameAndValues.Data, template)); } } diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs index d9502341..65f8a759 100644 --- a/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs +++ b/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs @@ -10,7 +10,7 @@ namespace Ocelot.Library.Infrastructure.UrlTemplateReplacer { var upstreamUrl = new StringBuilder(); - upstreamUrl.Append(downstreamRoute.DownstreamUrlTemplate); + upstreamUrl.Append(downstreamRoute.ReRoute.DownstreamTemplate); foreach (var templateVarAndValue in downstreamRoute.TemplateVariableNameAndValues) { diff --git a/src/Ocelot.Library/Middleware/AuthenticationMiddleware.cs b/src/Ocelot.Library/Middleware/AuthenticationMiddleware.cs index 1d745c1c..6fc73817 100644 --- a/src/Ocelot.Library/Middleware/AuthenticationMiddleware.cs +++ b/src/Ocelot.Library/Middleware/AuthenticationMiddleware.cs @@ -1,41 +1,35 @@ namespace Ocelot.Library.Middleware { using System.Threading.Tasks; - using Infrastructure.Authentication; + using Infrastructure.Configuration; using Infrastructure.DownstreamRouteFinder; using Infrastructure.Repository; - using Infrastructure.Responses; using Microsoft.AspNetCore.Http; public class AuthenticationMiddleware : OcelotMiddleware { private readonly RequestDelegate _next; private readonly IScopedRequestDataRepository _scopedRequestDataRepository; - private readonly IRouteRequiresAuthentication _requiresAuthentication; public AuthenticationMiddleware(RequestDelegate next, - IScopedRequestDataRepository scopedRequestDataRepository, - IRouteRequiresAuthentication requiresAuthentication) + IScopedRequestDataRepository scopedRequestDataRepository) : base(scopedRequestDataRepository) { _next = next; _scopedRequestDataRepository = scopedRequestDataRepository; - _requiresAuthentication = requiresAuthentication; } public async Task Invoke(HttpContext context) { var downstreamRoute = _scopedRequestDataRepository.Get("DownstreamRoute"); - var isAuthenticated = _requiresAuthentication.IsAuthenticated(downstreamRoute.Data, context.Request.Method); - - if (isAuthenticated.IsError) + if (downstreamRoute.IsError) { SetPipelineError(downstreamRoute.Errors); return; } - if (IsAuthenticatedRoute(isAuthenticated)) + if (IsAuthenticatedRoute(downstreamRoute.Data.ReRoute)) { //todo - build auth pipeline and then call normal pipeline if all good? await _next.Invoke(context); @@ -46,9 +40,9 @@ } } - private static bool IsAuthenticatedRoute(Response isAuthenticated) + private static bool IsAuthenticatedRoute(ReRoute reRoute) { - return isAuthenticated.Data; + return reRoute.IsAuthenticated; } } } diff --git a/src/Ocelot/Startup.cs b/src/Ocelot/Startup.cs index 9056daf9..b9298d0a 100644 --- a/src/Ocelot/Startup.cs +++ b/src/Ocelot/Startup.cs @@ -20,8 +20,6 @@ using Ocelot.Library.Middleware; namespace Ocelot { - using Library.Infrastructure.Authentication; - public class Startup { public Startup(IHostingEnvironment env) @@ -54,7 +52,6 @@ namespace Ocelot services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); // see this for why we register this as singleton http://stackoverflow.com/questions/37371264/invalidoperationexception-unable-to-resolve-service-for-type-microsoft-aspnetc services.AddSingleton(); diff --git a/test/Ocelot.UnitTests/Authentication/RequiresAuthenticationTests.cs b/test/Ocelot.UnitTests/Authentication/RequiresAuthenticationTests.cs deleted file mode 100644 index 5747c963..00000000 --- a/test/Ocelot.UnitTests/Authentication/RequiresAuthenticationTests.cs +++ /dev/null @@ -1,96 +0,0 @@ -namespace Ocelot.UnitTests.Authentication -{ - using System.Collections.Generic; - using Library.Infrastructure.Authentication; - using Library.Infrastructure.Configuration; - using Library.Infrastructure.DownstreamRouteFinder; - using Library.Infrastructure.Responses; - using Library.Infrastructure.UrlMatcher; - using Moq; - using Shouldly; - using TestStack.BDDfy; - using Xunit; - - public class RequiresAuthenticationTests - { - private readonly RouteRequiresAuthentication _routeRequiresAuthentication; - private string _url; - private readonly Mock _config; - private Response _result; - private string _httpMethod; - - public RequiresAuthenticationTests() - { - _config = new Mock(); - _routeRequiresAuthentication = new RouteRequiresAuthentication(_config.Object); - } - - [Fact] - public void should_return_true_if_route_requires_authentication() - { - this.Given(x => x.GivenIHaveADownstreamUrl("http://www.bbc.co.uk")) - .And( - x => - x.GivenTheConfigurationForTheRouteIs(new ReRoute("http://www.bbc.co.uk", "/api/poo", "get", - "/api/poo$", true))) - .When(x => x.WhenICheckToSeeIfTheRouteShouldBeAuthenticated()) - .Then(x => x.ThenTheResultIs(true)) - .BDDfy(); - } - - [Fact] - public void should_return_false_if_route_requires_authentication() - { - this.Given(x => x.GivenIHaveADownstreamUrl("http://www.bbc.co.uk")) - .And( - x => - x.GivenTheConfigurationForTheRouteIs(new ReRoute("http://www.bbc.co.uk", "/api/poo", "get", - "/api/poo$", false))) - .When(x => x.WhenICheckToSeeIfTheRouteShouldBeAuthenticated()) - .Then(x => x.ThenTheResultIs(false)) - .BDDfy(); - } - - [Fact] - public void should_return_error_if_no_matching_config() - { - this.Given(x => x.GivenIHaveADownstreamUrl("http://www.bbc.co.uk")) - .And(x => x.GivenTheConfigurationForTheRouteIs(new ReRoute(string.Empty, string.Empty, string.Empty, string.Empty,false))) - .When(x => x.WhenICheckToSeeIfTheRouteShouldBeAuthenticated()) - .Then(x => x.ThenAnErrorIsReturned()) - .BDDfy(); - } - - private void ThenAnErrorIsReturned() - { - _result.IsError.ShouldBeTrue(); - } - - public void GivenIHaveADownstreamUrl(string url) - { - _url = url; - } - - private void GivenTheConfigurationForTheRouteIs(ReRoute reRoute) - { - _httpMethod = reRoute.UpstreamHttpMethod; - - _config - .Setup(x => x.ReRoutes) - .Returns(new List - { - reRoute - }); - } - - private void WhenICheckToSeeIfTheRouteShouldBeAuthenticated() - { - _result = _routeRequiresAuthentication.IsAuthenticated(new DownstreamRoute(new List(), _url), _httpMethod); - } - - private void ThenTheResultIs(bool expected) - { - _result.Data.ShouldBe(expected); - } - } -} diff --git a/test/Ocelot.UnitTests/Configuration/OcelotConfigurationTests.cs b/test/Ocelot.UnitTests/Configuration/OcelotConfigurationTests.cs index 56ee89b8..2977f54f 100644 --- a/test/Ocelot.UnitTests/Configuration/OcelotConfigurationTests.cs +++ b/test/Ocelot.UnitTests/Configuration/OcelotConfigurationTests.cs @@ -38,7 +38,7 @@ namespace Ocelot.UnitTests.Configuration .When(x => x.WhenIInstanciateTheOcelotConfig()) .Then(x => x.ThenTheReRoutesAre(new List { - new ReRoute("/products/{productId}","/api/products/{productId}", "Get", "/api/products/.*$", false) + new ReRoute("/products/{productId}","/api/products/{productId}", "Get", "/api/products/.*$", false, "") })) .BDDfy(); } @@ -61,7 +61,7 @@ namespace Ocelot.UnitTests.Configuration .When(x => x.WhenIInstanciateTheOcelotConfig()) .Then(x => x.ThenTheReRoutesAre(new List { - new ReRoute("/products/{productId}","/api/products/{productId}/variants/{variantId}", "Get", "/api/products/.*/variants/.*$", false) + new ReRoute("/products/{productId}","/api/products/{productId}/variants/{variantId}", "Get", "/api/products/.*/variants/.*$", false, "") })) .BDDfy(); } @@ -84,7 +84,7 @@ namespace Ocelot.UnitTests.Configuration .When(x => x.WhenIInstanciateTheOcelotConfig()) .Then(x => x.ThenTheReRoutesAre(new List { - new ReRoute("/products/{productId}","/api/products/{productId}/variants/{variantId}/", "Get", "/api/products/.*/variants/.*/$", false) + new ReRoute("/products/{productId}","/api/products/{productId}/variants/{variantId}/", "Get", "/api/products/.*/variants/.*/$", false, "") })) .BDDfy(); } @@ -107,7 +107,7 @@ namespace Ocelot.UnitTests.Configuration .When(x => x.WhenIInstanciateTheOcelotConfig()) .Then(x => x.ThenTheReRoutesAre(new List { - new ReRoute("/api/products/","/", "Get", "/$", false) + new ReRoute("/api/products/","/", "Get", "/$", false, "") })) .BDDfy(); } diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs index 791a6aa2..127ec7d8 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs @@ -37,14 +37,14 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .And(x => x.GivenTheTemplateVariableAndNameFinderReturns(new OkResponse>(new List()))) .And(x => x.GivenTheConfigurationIs(new List { - new ReRoute("someDownstreamPath","someUpstreamPath", "Get", "someUpstreamPath", false) + new ReRoute("someDownstreamPath","someUpstreamPath", "Get", "someUpstreamPath", false, "") } )) .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true)))) .And(x => x.GivenTheUpstreamHttpMethodIs("Get")) .When(x => x.WhenICallTheFinder()) .Then( - x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List(), "someDownstreamPath"))) + x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List(), new ReRoute("someDownstreamPath","","","",false, "")))) .And(x => x.ThenTheUrlMatcherIsCalledCorrectly()) .BDDfy(); } @@ -56,15 +56,15 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .And(x => x.GivenTheTemplateVariableAndNameFinderReturns(new OkResponse>(new List()))) .And(x => x.GivenTheConfigurationIs(new List { - new ReRoute("someDownstreamPath", "someUpstreamPath", "Get", string.Empty, false), - new ReRoute("someDownstreamPathForAPost", "someUpstreamPath", "Post", string.Empty, false) + new ReRoute("someDownstreamPath", "someUpstreamPath", "Get", string.Empty, false, ""), + new ReRoute("someDownstreamPathForAPost", "someUpstreamPath", "Post", string.Empty, false, "") } )) .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true)))) .And(x => x.GivenTheUpstreamHttpMethodIs("Post")) .When(x => x.WhenICallTheFinder()) .Then( - x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List(), "someDownstreamPathForAPost"))) + x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List(), new ReRoute("someDownstreamPathForAPost", "","","",false, "")))) .BDDfy(); } @@ -74,7 +74,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder this.Given(x => x.GivenThereIsAnUpstreamUrlPath("somePath")) .And(x => x.GivenTheConfigurationIs(new List { - new ReRoute("somPath", "somePath", "Get", "somePath", false) + new ReRoute("somPath", "somePath", "Get", "somePath", false, "") } )) .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(false)))) @@ -137,7 +137,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder private void ThenTheFollowingIsReturned(DownstreamRoute expected) { - _result.Data.DownstreamUrlTemplate.ShouldBe(expected.DownstreamUrlTemplate); + _result.Data.ReRoute.DownstreamTemplate.ShouldBe(expected.ReRoute.DownstreamTemplate); for (int i = 0; i < _result.Data.TemplateVariableNameAndValues.Count; i++) { diff --git a/test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs index 4b1d2e07..f5cc37f5 100644 --- a/test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs @@ -6,7 +6,6 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Moq; -using Ocelot.Library.Infrastructure.Authentication; using Ocelot.Library.Infrastructure.DownstreamRouteFinder; using Ocelot.Library.Infrastructure.Repository; using Ocelot.Library.Infrastructure.Responses; @@ -17,9 +16,10 @@ using Xunit; namespace Ocelot.UnitTests.Middleware { + using Library.Infrastructure.Configuration; + public class AuthenticationMiddlewareTests : IDisposable { - private readonly Mock _requiresAuth; private readonly Mock _scopedRepository; private readonly string _url; private readonly TestServer _server; @@ -30,13 +30,11 @@ namespace Ocelot.UnitTests.Middleware public AuthenticationMiddlewareTests() { _url = "http://localhost:51879"; - _requiresAuth = new Mock(); _scopedRepository = new Mock(); var builder = new WebHostBuilder() .ConfigureServices(x => { - x.AddSingleton(_requiresAuth.Object); x.AddSingleton(_scopedRepository.Object); }) .UseUrls(_url) @@ -56,8 +54,7 @@ namespace Ocelot.UnitTests.Middleware [Fact] public void happy_path() { - this.Given(x => x.GivenTheDownStreamRouteIs(new DownstreamRoute(new List(), "any old string"))) - .And(x => x.GivenTheRouteIsNotAuthenticated()) + this.Given(x => x.GivenTheDownStreamRouteIs(new DownstreamRoute(new List(), new ReRoute("","","","",false, "")))) .When(x => x.WhenICallTheMiddleware()) .Then(x => x.ThenNoExceptionsAreThrown()) .BDDfy(); @@ -76,13 +73,6 @@ namespace Ocelot.UnitTests.Middleware .Returns(_downstreamRoute); } - private void GivenTheRouteIsNotAuthenticated() - { - _requiresAuth - .Setup(x => x.IsAuthenticated(It.IsAny(), It.IsAny())) - .Returns(new OkResponse(false)); - } - private void WhenICallTheMiddleware() { _result = _client.GetAsync(_url).Result; diff --git a/test/Ocelot.UnitTests/Middleware/DownstreamRouteFinderMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/DownstreamRouteFinderMiddlewareTests.cs index e3264653..b960e399 100644 --- a/test/Ocelot.UnitTests/Middleware/DownstreamRouteFinderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Middleware/DownstreamRouteFinderMiddlewareTests.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.IO; using System.Net.Http; + using Library.Infrastructure.Configuration; using Library.Infrastructure.DownstreamRouteFinder; using Library.Infrastructure.Repository; using Library.Infrastructure.Responses; @@ -55,7 +56,7 @@ [Fact] public void happy_path() { - this.Given(x => x.GivenTheDownStreamRouteFinderReturns(new DownstreamRoute(new List(), "any old string"))) + this.Given(x => x.GivenTheDownStreamRouteFinderReturns(new DownstreamRoute(new List(), new ReRoute("any old string", "", "", "",false, "")))) .When(x => x.WhenICallTheMiddleware()) .Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly()) .BDDfy(); diff --git a/test/Ocelot.UnitTests/Middleware/DownstreamUrlCreatorMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/DownstreamUrlCreatorMiddlewareTests.cs index b607cea7..df9260c8 100644 --- a/test/Ocelot.UnitTests/Middleware/DownstreamUrlCreatorMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Middleware/DownstreamUrlCreatorMiddlewareTests.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.IO; using System.Net.Http; + using Library.Infrastructure.Configuration; using Library.Infrastructure.DownstreamRouteFinder; using Library.Infrastructure.Repository; using Library.Infrastructure.Responses; @@ -57,7 +58,7 @@ [Fact] public void happy_path() { - this.Given(x => x.GivenTheDownStreamRouteIs(new DownstreamRoute(new List(), "any old string"))) + this.Given(x => x.GivenTheDownStreamRouteIs(new DownstreamRoute(new List(), new ReRoute("any old string", "", "", "", false, "")))) .And(x => x.TheUrlReplacerReturns("any old string")) .When(x => x.WhenICallTheMiddleware()) .Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly()) diff --git a/test/Ocelot.UnitTests/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs b/test/Ocelot.UnitTests/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs index 597c7d74..18bf22d8 100644 --- a/test/Ocelot.UnitTests/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs +++ b/test/Ocelot.UnitTests/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs @@ -9,6 +9,8 @@ using Xunit; namespace Ocelot.UnitTests.UrlTemplateReplacer { + using Library.Infrastructure.Configuration; + public class UpstreamUrlPathTemplateVariableReplacerTests { private DownstreamRoute _downstreamRoute; @@ -23,7 +25,7 @@ namespace Ocelot.UnitTests.UrlTemplateReplacer [Fact] public void can_replace_no_template_variables() { - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), ""))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), new ReRoute("", "", "", "", false, "")))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("")) .BDDfy(); @@ -32,7 +34,7 @@ namespace Ocelot.UnitTests.UrlTemplateReplacer [Fact] public void can_replace_no_template_variables_with_slash() { - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), "/"))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), new ReRoute("/", "", "", "", false, "")))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("/")) .BDDfy(); @@ -41,7 +43,7 @@ namespace Ocelot.UnitTests.UrlTemplateReplacer [Fact] public void can_replace_url_no_slash() { - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), "api"))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), new ReRoute("api", "", "", "", false, "")))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api")) .BDDfy(); @@ -50,7 +52,7 @@ namespace Ocelot.UnitTests.UrlTemplateReplacer [Fact] public void can_replace_url_one_slash() { - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), "api/"))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), new ReRoute("api/", "", "", "", false, "")))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api/")) .BDDfy(); @@ -59,7 +61,7 @@ namespace Ocelot.UnitTests.UrlTemplateReplacer [Fact] public void can_replace_url_multiple_slash() { - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), "api/product/products/"))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), new ReRoute("api/product/products/", "", "", "", false, "")))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api/product/products/")) .BDDfy(); @@ -73,7 +75,7 @@ namespace Ocelot.UnitTests.UrlTemplateReplacer new TemplateVariableNameAndValue("{productId}", "1") }; - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, "productservice/products/{productId}/"))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, new ReRoute("productservice/products/{productId}/", "", "", "", false, "")))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/")) .BDDfy(); @@ -87,7 +89,7 @@ namespace Ocelot.UnitTests.UrlTemplateReplacer new TemplateVariableNameAndValue("{productId}", "1") }; - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, "productservice/products/{productId}/variants"))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, new ReRoute("productservice/products/{productId}/variants", "", "", "", false, "")))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/variants")) .BDDfy(); @@ -102,7 +104,7 @@ namespace Ocelot.UnitTests.UrlTemplateReplacer new TemplateVariableNameAndValue("{variantId}", "12") }; - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, "productservice/products/{productId}/variants/{variantId}"))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, new ReRoute("productservice/products/{productId}/variants/{variantId}", "", "", "", false, "")))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/variants/12")) .BDDfy(); @@ -118,7 +120,7 @@ namespace Ocelot.UnitTests.UrlTemplateReplacer new TemplateVariableNameAndValue("{categoryId}", "34") }; - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, "productservice/category/{categoryId}/products/{productId}/variants/{variantId}"))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, new ReRoute("productservice/category/{categoryId}/products/{productId}/variants/{variantId}", "", "", "", false, "")))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/category/34/products/1/variants/12")) .BDDfy(); @@ -138,6 +140,5 @@ namespace Ocelot.UnitTests.UrlTemplateReplacer { _result.Data.ShouldBe(expected); } - } } From 67af8841b20e836ceed9ca22ddb6798790f9fe69 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Fri, 14 Oct 2016 20:20:03 +0100 Subject: [PATCH 082/183] updated build scriptos --- appveyor.yml | 2 +- build.bat | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 09d281a0..410c858e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,6 +7,6 @@ build_script: test_script: - run-tests.bat artifacts: -- path: site\wwwroot\**\*.* +- path: artifacts\**\*.* cache: - '%USERPROFILE%\.nuget\packages' \ No newline at end of file diff --git a/build.bat b/build.bat index 6c89e8e6..03856cfb 100644 --- a/build.bat +++ b/build.bat @@ -5,7 +5,6 @@ echo Building Ocelot dotnet restore src/Ocelot dotnet restore src/Ocelot.Library dotnet build src/Ocelot -dotnet pack src/Ocelot/project.json --no-build --output nupkgs -dotnet publish src/Ocelot -o site/wwwroot +dotnet publish src/Ocelot -o artifacts/ From 34bac7e0d4fa16b490162d1bce929a47cb485c7d Mon Sep 17 00:00:00 2001 From: TomPallister Date: Sat, 15 Oct 2016 11:17:18 +0100 Subject: [PATCH 083/183] Added first authentiction code..we have a test that makes sure we are unauthenticed but i havent been able to get authenticated to work yet due to identity server usual madness when calling with their SDK! --- build.bat | 1 - .../Yaml/ConfigurationValidationResult.cs | 1 + .../Yaml/ConfigurationValidator.cs | 1 + .../DownstreamTemplateAlreadyUsedError.cs | 5 +- .../DownstreamRouteFinder.cs | 1 + .../UnableToFindDownstreamRouteError.cs | 3 +- .../Infrastructure/Errors/Error.cs | 14 ++ .../Infrastructure/Errors/OcelotErrorCode.cs | 13 ++ .../Middleware/AuthenticationMiddleware.cs | 80 +++++++ ...nticationMiddlewareMiddlewareExtensions.cs | 4 +- .../DownstreamRouteFinderMiddleware.cs | 2 +- ...wnstreamRouteFinderMiddlewareExtensions.cs | 2 +- .../DownstreamUrlCreatorMiddleware.cs | 2 +- ...ownstreamUrlCreatorMiddlewareExtensions.cs | 2 +- .../HttpRequestBuilderMiddleware.cs | 2 +- .../HttpRequestBuilderMiddlewareExtensions.cs | 2 +- .../Middleware/HttpRequesterMiddleware.cs | 2 +- .../HttpRequesterMiddlewareExtensions.cs | 2 +- .../Middleware/HttpResponderMiddleware.cs | 21 +- .../HttpResponderMiddlewareExtensions.cs | 2 +- .../Middleware/OcelotMiddleware.cs | 3 +- .../Middleware/UnauthenticatedError.cs | 11 + .../Repository/CannotAddDataError.cs | 5 +- .../Repository/CannotFindDataError.cs | 5 +- .../Repository/ScopedRequestDataRepository.cs | 1 + .../Requester/HttpClientHttpRequester.cs | 1 + .../Requester/UnableToCompleteRequestError.cs | 3 +- .../Responder/ErrorsToHttpStatusCodeMapper.cs | 20 ++ .../Responder/HttpContextResponder.cs | 7 +- .../IErrorsToHttpStatusCodeMapper.cs | 11 + .../Responder/IHttpResponder.cs | 3 +- .../Infrastructure/Responses/Error.cs | 12 -- .../Infrastructure/Responses/ErrorResponse.cs | 1 + .../Responses/ErrorResponseGeneric.cs | 1 + .../Infrastructure/Responses/Response.cs | 1 + .../Responses/ResponseGeneric.cs | 1 + .../Middleware/AuthenticationMiddleware.cs | 48 ----- src/Ocelot/Controllers/HomeController.cs | 22 ++ src/Ocelot/Startup.cs | 7 +- .../AuthenticationTests.cs | 202 ++++++++++++++++++ test/Ocelot.AcceptanceTests/OcelotTests.cs | 6 +- test/Ocelot.AcceptanceTests/project.json | 49 ++--- .../AuthenticationMiddlewareTests.cs | 2 +- .../DownstreamRouteFinderMiddlewareTests.cs | 5 +- .../DownstreamUrlCreatorMiddlewareTests.cs | 5 +- .../HttpRequestBuilderMiddlewareTests.cs | 2 +- .../HttpRequesterMiddlewareTests.cs | 2 +- .../HttpResponderMiddlewareTests.cs | 5 +- .../ErrorsToHttpStatusCodeMapperTests.cs | 72 +++++++ .../Responder/ResponderTests.cs | 14 -- 50 files changed, 545 insertions(+), 144 deletions(-) create mode 100644 src/Ocelot.Library/Infrastructure/Errors/Error.cs create mode 100644 src/Ocelot.Library/Infrastructure/Errors/OcelotErrorCode.cs create mode 100644 src/Ocelot.Library/Infrastructure/Middleware/AuthenticationMiddleware.cs rename src/Ocelot.Library/{ => Infrastructure}/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs (82%) rename src/Ocelot.Library/{ => Infrastructure}/Middleware/DownstreamRouteFinderMiddleware.cs (96%) rename src/Ocelot.Library/{ => Infrastructure}/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs (86%) rename src/Ocelot.Library/{ => Infrastructure}/Middleware/DownstreamUrlCreatorMiddleware.cs (96%) rename src/Ocelot.Library/{ => Infrastructure}/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs (86%) rename src/Ocelot.Library/{ => Infrastructure}/Middleware/HttpRequestBuilderMiddleware.cs (97%) rename src/Ocelot.Library/{ => Infrastructure}/Middleware/HttpRequestBuilderMiddlewareExtensions.cs (86%) rename src/Ocelot.Library/{ => Infrastructure}/Middleware/HttpRequesterMiddleware.cs (96%) rename src/Ocelot.Library/{ => Infrastructure}/Middleware/HttpRequesterMiddlewareExtensions.cs (85%) rename src/Ocelot.Library/{ => Infrastructure}/Middleware/HttpResponderMiddleware.cs (68%) rename src/Ocelot.Library/{ => Infrastructure}/Middleware/HttpResponderMiddlewareExtensions.cs (85%) rename src/Ocelot.Library/{ => Infrastructure}/Middleware/OcelotMiddleware.cs (91%) create mode 100644 src/Ocelot.Library/Infrastructure/Middleware/UnauthenticatedError.cs create mode 100644 src/Ocelot.Library/Infrastructure/Responder/ErrorsToHttpStatusCodeMapper.cs create mode 100644 src/Ocelot.Library/Infrastructure/Responder/IErrorsToHttpStatusCodeMapper.cs delete mode 100644 src/Ocelot.Library/Infrastructure/Responses/Error.cs delete mode 100644 src/Ocelot.Library/Middleware/AuthenticationMiddleware.cs create mode 100644 src/Ocelot/Controllers/HomeController.cs create mode 100644 test/Ocelot.AcceptanceTests/AuthenticationTests.cs create mode 100644 test/Ocelot.UnitTests/Responder/ErrorsToHttpStatusCodeMapperTests.cs delete mode 100644 test/Ocelot.UnitTests/Responder/ResponderTests.cs diff --git a/build.bat b/build.bat index 03856cfb..e1de8546 100644 --- a/build.bat +++ b/build.bat @@ -1,7 +1,6 @@ echo ------------------------- echo Building Ocelot - dotnet restore src/Ocelot dotnet restore src/Ocelot.Library dotnet build src/Ocelot diff --git a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/ConfigurationValidationResult.cs b/src/Ocelot.Library/Infrastructure/Configuration/Yaml/ConfigurationValidationResult.cs index aa3a0d00..577fe18c 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/ConfigurationValidationResult.cs +++ b/src/Ocelot.Library/Infrastructure/Configuration/Yaml/ConfigurationValidationResult.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Ocelot.Library.Infrastructure.Errors; using Ocelot.Library.Infrastructure.Responses; namespace Ocelot.Library.Infrastructure.Configuration.Yaml diff --git a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/ConfigurationValidator.cs b/src/Ocelot.Library/Infrastructure/Configuration/Yaml/ConfigurationValidator.cs index 777a6c84..64b72929 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/ConfigurationValidator.cs +++ b/src/Ocelot.Library/Infrastructure/Configuration/Yaml/ConfigurationValidator.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq; +using Ocelot.Library.Infrastructure.Errors; using Ocelot.Library.Infrastructure.Responses; namespace Ocelot.Library.Infrastructure.Configuration.Yaml diff --git a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/DownstreamTemplateAlreadyUsedError.cs b/src/Ocelot.Library/Infrastructure/Configuration/Yaml/DownstreamTemplateAlreadyUsedError.cs index 5a256f91..533f1bb3 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/DownstreamTemplateAlreadyUsedError.cs +++ b/src/Ocelot.Library/Infrastructure/Configuration/Yaml/DownstreamTemplateAlreadyUsedError.cs @@ -1,10 +1,11 @@ -using Ocelot.Library.Infrastructure.Responses; +using Ocelot.Library.Infrastructure.Errors; +using Ocelot.Library.Infrastructure.Responses; namespace Ocelot.Library.Infrastructure.Configuration.Yaml { public class DownstreamTemplateAlreadyUsedError : Error { - public DownstreamTemplateAlreadyUsedError(string message) : base(message) + public DownstreamTemplateAlreadyUsedError(string message) : base(message, OcelotErrorCode.DownstreamTemplateAlreadyUsedError) { } } diff --git a/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRouteFinder.cs b/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRouteFinder.cs index 3063cf76..4d58b549 100644 --- a/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRouteFinder.cs +++ b/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRouteFinder.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using Microsoft.Extensions.Options; using Ocelot.Library.Infrastructure.Configuration; +using Ocelot.Library.Infrastructure.Errors; using Ocelot.Library.Infrastructure.Responses; using Ocelot.Library.Infrastructure.UrlMatcher; diff --git a/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/UnableToFindDownstreamRouteError.cs b/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/UnableToFindDownstreamRouteError.cs index 62618951..e0f8d26a 100644 --- a/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/UnableToFindDownstreamRouteError.cs +++ b/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/UnableToFindDownstreamRouteError.cs @@ -2,13 +2,14 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Ocelot.Library.Infrastructure.Errors; using Ocelot.Library.Infrastructure.Responses; namespace Ocelot.Library.Infrastructure.DownstreamRouteFinder { public class UnableToFindDownstreamRouteError : Error { - public UnableToFindDownstreamRouteError() : base("UnableToFindDownstreamRouteError") + public UnableToFindDownstreamRouteError() : base("UnableToFindDownstreamRouteError", OcelotErrorCode.UnableToFindDownstreamRouteError) { } } diff --git a/src/Ocelot.Library/Infrastructure/Errors/Error.cs b/src/Ocelot.Library/Infrastructure/Errors/Error.cs new file mode 100644 index 00000000..50b27354 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Errors/Error.cs @@ -0,0 +1,14 @@ +namespace Ocelot.Library.Infrastructure.Errors +{ + public abstract class Error + { + protected Error(string message, OcelotErrorCode code) + { + Message = message; + Code = code; + } + + public string Message { get; private set; } + public OcelotErrorCode Code { get; private set; } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Errors/OcelotErrorCode.cs b/src/Ocelot.Library/Infrastructure/Errors/OcelotErrorCode.cs new file mode 100644 index 00000000..e746de55 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Errors/OcelotErrorCode.cs @@ -0,0 +1,13 @@ +namespace Ocelot.Library.Infrastructure.Errors +{ + public enum OcelotErrorCode + { + UnauthenticatedError, + UnknownError, + DownstreamTemplateAlreadyUsedError, + UnableToFindDownstreamRouteError, + CannotAddDataError, + CannotFindDataError, + UnableToCompleteRequestError + } +} diff --git a/src/Ocelot.Library/Infrastructure/Middleware/AuthenticationMiddleware.cs b/src/Ocelot.Library/Infrastructure/Middleware/AuthenticationMiddleware.cs new file mode 100644 index 00000000..4a72d412 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Middleware/AuthenticationMiddleware.cs @@ -0,0 +1,80 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Ocelot.Library.Infrastructure.Configuration; +using Ocelot.Library.Infrastructure.DownstreamRouteFinder; +using Ocelot.Library.Infrastructure.Errors; +using Ocelot.Library.Infrastructure.Repository; +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.Middleware +{ + public class AuthenticationMiddleware : OcelotMiddleware + { + private readonly RequestDelegate _next; + private RequestDelegate _authenticationNext; + private readonly IScopedRequestDataRepository _scopedRequestDataRepository; + private readonly IApplicationBuilder _app; + + public AuthenticationMiddleware(RequestDelegate next, IApplicationBuilder app, + IScopedRequestDataRepository scopedRequestDataRepository) + : base(scopedRequestDataRepository) + { + _next = next; + _scopedRequestDataRepository = scopedRequestDataRepository; + _app = app; + } + + public async Task Invoke(HttpContext context) + { + var downstreamRoute = _scopedRequestDataRepository.Get("DownstreamRoute"); + + if (downstreamRoute.IsError) + { + SetPipelineError(downstreamRoute.Errors); + return; + } + + if (IsAuthenticatedRoute(downstreamRoute.Data.ReRoute)) + { + //todo - build auth pipeline and then call normal pipeline if all good? + //create new app builder + var builder = _app.New(); + //set up any options for the authentication + var jwtBearerOptions = new JwtBearerOptions + { + AutomaticAuthenticate = true, + AutomaticChallenge = true, + RequireHttpsMetadata = false, + }; + //set the authentication middleware + builder.UseJwtBearerAuthentication(jwtBearerOptions); + //use mvc so we hit the catch all authorised controller + builder.UseMvc(); + //then build it + _authenticationNext = builder.Build(); + //then call it + await _authenticationNext(context); + //check if the user is authenticated + if (context.User.Identity.IsAuthenticated) + { + await _next.Invoke(context); + } + else + { + SetPipelineError(new List {new UnauthenticatedError($"Request for authenticated route {context.Request.Path} by {context.User.Identity.Name} was unauthenticated")}); + } + } + else + { + await _next.Invoke(context); + } + } + + private static bool IsAuthenticatedRoute(ReRoute reRoute) + { + return reRoute.IsAuthenticated; + } + } +} diff --git a/src/Ocelot.Library/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs b/src/Ocelot.Library/Infrastructure/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs similarity index 82% rename from src/Ocelot.Library/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs rename to src/Ocelot.Library/Infrastructure/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs index 3655e470..43b90856 100644 --- a/src/Ocelot.Library/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs +++ b/src/Ocelot.Library/Infrastructure/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs @@ -1,12 +1,12 @@ using Microsoft.AspNetCore.Builder; -namespace Ocelot.Library.Middleware +namespace Ocelot.Library.Infrastructure.Middleware { public static class AuthenticationMiddlewareMiddlewareExtensions { public static IApplicationBuilder UseAuthenticationMiddleware(this IApplicationBuilder builder) { - return builder.UseMiddleware(); + return builder.UseMiddleware(builder); } } } \ No newline at end of file diff --git a/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddleware.cs b/src/Ocelot.Library/Infrastructure/Middleware/DownstreamRouteFinderMiddleware.cs similarity index 96% rename from src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddleware.cs rename to src/Ocelot.Library/Infrastructure/Middleware/DownstreamRouteFinderMiddleware.cs index 598f953e..1537ab45 100644 --- a/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddleware.cs +++ b/src/Ocelot.Library/Infrastructure/Middleware/DownstreamRouteFinderMiddleware.cs @@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Http; using Ocelot.Library.Infrastructure.DownstreamRouteFinder; using Ocelot.Library.Infrastructure.Repository; -namespace Ocelot.Library.Middleware +namespace Ocelot.Library.Infrastructure.Middleware { public class DownstreamRouteFinderMiddleware : OcelotMiddleware { diff --git a/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs b/src/Ocelot.Library/Infrastructure/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs similarity index 86% rename from src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs rename to src/Ocelot.Library/Infrastructure/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs index ec454bf4..7f23d1de 100644 --- a/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs +++ b/src/Ocelot.Library/Infrastructure/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs @@ -1,6 +1,6 @@ using Microsoft.AspNetCore.Builder; -namespace Ocelot.Library.Middleware +namespace Ocelot.Library.Infrastructure.Middleware { public static class DownstreamRouteFinderMiddlewareExtensions { diff --git a/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddleware.cs b/src/Ocelot.Library/Infrastructure/Middleware/DownstreamUrlCreatorMiddleware.cs similarity index 96% rename from src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddleware.cs rename to src/Ocelot.Library/Infrastructure/Middleware/DownstreamUrlCreatorMiddleware.cs index 00d5d76b..955e983a 100644 --- a/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddleware.cs +++ b/src/Ocelot.Library/Infrastructure/Middleware/DownstreamUrlCreatorMiddleware.cs @@ -4,7 +4,7 @@ using Ocelot.Library.Infrastructure.DownstreamRouteFinder; using Ocelot.Library.Infrastructure.Repository; using Ocelot.Library.Infrastructure.UrlTemplateReplacer; -namespace Ocelot.Library.Middleware +namespace Ocelot.Library.Infrastructure.Middleware { public class DownstreamUrlCreatorMiddleware : OcelotMiddleware { diff --git a/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs b/src/Ocelot.Library/Infrastructure/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs similarity index 86% rename from src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs rename to src/Ocelot.Library/Infrastructure/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs index 325a7454..b0997b7b 100644 --- a/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs +++ b/src/Ocelot.Library/Infrastructure/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs @@ -1,6 +1,6 @@ using Microsoft.AspNetCore.Builder; -namespace Ocelot.Library.Middleware +namespace Ocelot.Library.Infrastructure.Middleware { public static class DownstreamUrlCreatorMiddlewareExtensions { diff --git a/src/Ocelot.Library/Middleware/HttpRequestBuilderMiddleware.cs b/src/Ocelot.Library/Infrastructure/Middleware/HttpRequestBuilderMiddleware.cs similarity index 97% rename from src/Ocelot.Library/Middleware/HttpRequestBuilderMiddleware.cs rename to src/Ocelot.Library/Infrastructure/Middleware/HttpRequestBuilderMiddleware.cs index b800a3d7..aa2c4017 100644 --- a/src/Ocelot.Library/Middleware/HttpRequestBuilderMiddleware.cs +++ b/src/Ocelot.Library/Infrastructure/Middleware/HttpRequestBuilderMiddleware.cs @@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Http; using Ocelot.Library.Infrastructure.Repository; using Ocelot.Library.Infrastructure.RequestBuilder; -namespace Ocelot.Library.Middleware +namespace Ocelot.Library.Infrastructure.Middleware { public class HttpRequestBuilderMiddleware : OcelotMiddleware { diff --git a/src/Ocelot.Library/Middleware/HttpRequestBuilderMiddlewareExtensions.cs b/src/Ocelot.Library/Infrastructure/Middleware/HttpRequestBuilderMiddlewareExtensions.cs similarity index 86% rename from src/Ocelot.Library/Middleware/HttpRequestBuilderMiddlewareExtensions.cs rename to src/Ocelot.Library/Infrastructure/Middleware/HttpRequestBuilderMiddlewareExtensions.cs index 0b51ccaa..fa36ce01 100644 --- a/src/Ocelot.Library/Middleware/HttpRequestBuilderMiddlewareExtensions.cs +++ b/src/Ocelot.Library/Infrastructure/Middleware/HttpRequestBuilderMiddlewareExtensions.cs @@ -1,6 +1,6 @@ using Microsoft.AspNetCore.Builder; -namespace Ocelot.Library.Middleware +namespace Ocelot.Library.Infrastructure.Middleware { public static class HttpRequestBuilderMiddlewareExtensions { diff --git a/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs b/src/Ocelot.Library/Infrastructure/Middleware/HttpRequesterMiddleware.cs similarity index 96% rename from src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs rename to src/Ocelot.Library/Infrastructure/Middleware/HttpRequesterMiddleware.cs index 7c2c4b9d..3cf988e4 100644 --- a/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs +++ b/src/Ocelot.Library/Infrastructure/Middleware/HttpRequesterMiddleware.cs @@ -4,7 +4,7 @@ using Ocelot.Library.Infrastructure.Repository; using Ocelot.Library.Infrastructure.RequestBuilder; using Ocelot.Library.Infrastructure.Requester; -namespace Ocelot.Library.Middleware +namespace Ocelot.Library.Infrastructure.Middleware { public class HttpRequesterMiddleware : OcelotMiddleware { diff --git a/src/Ocelot.Library/Middleware/HttpRequesterMiddlewareExtensions.cs b/src/Ocelot.Library/Infrastructure/Middleware/HttpRequesterMiddlewareExtensions.cs similarity index 85% rename from src/Ocelot.Library/Middleware/HttpRequesterMiddlewareExtensions.cs rename to src/Ocelot.Library/Infrastructure/Middleware/HttpRequesterMiddlewareExtensions.cs index 8aead7bc..b8b31f40 100644 --- a/src/Ocelot.Library/Middleware/HttpRequesterMiddlewareExtensions.cs +++ b/src/Ocelot.Library/Infrastructure/Middleware/HttpRequesterMiddlewareExtensions.cs @@ -1,6 +1,6 @@ using Microsoft.AspNetCore.Builder; -namespace Ocelot.Library.Middleware +namespace Ocelot.Library.Infrastructure.Middleware { public static class HttpRequesterMiddlewareExtensions { diff --git a/src/Ocelot.Library/Middleware/HttpResponderMiddleware.cs b/src/Ocelot.Library/Infrastructure/Middleware/HttpResponderMiddleware.cs similarity index 68% rename from src/Ocelot.Library/Middleware/HttpResponderMiddleware.cs rename to src/Ocelot.Library/Infrastructure/Middleware/HttpResponderMiddleware.cs index 7974ad62..3f268a62 100644 --- a/src/Ocelot.Library/Middleware/HttpResponderMiddleware.cs +++ b/src/Ocelot.Library/Infrastructure/Middleware/HttpResponderMiddleware.cs @@ -4,22 +4,25 @@ using Microsoft.AspNetCore.Http; using Ocelot.Library.Infrastructure.Repository; using Ocelot.Library.Infrastructure.Responder; -namespace Ocelot.Library.Middleware +namespace Ocelot.Library.Infrastructure.Middleware { public class HttpResponderMiddleware : OcelotMiddleware { private readonly RequestDelegate _next; private readonly IHttpResponder _responder; private readonly IScopedRequestDataRepository _scopedRequestDataRepository; + private readonly IErrorsToHttpStatusCodeMapper _codeMapper; public HttpResponderMiddleware(RequestDelegate next, IHttpResponder responder, - IScopedRequestDataRepository scopedRequestDataRepository) + IScopedRequestDataRepository scopedRequestDataRepository, + IErrorsToHttpStatusCodeMapper codeMapper) :base(scopedRequestDataRepository) { _next = next; _responder = responder; _scopedRequestDataRepository = scopedRequestDataRepository; + _codeMapper = codeMapper; } public async Task Invoke(HttpContext context) @@ -28,11 +31,19 @@ namespace Ocelot.Library.Middleware if (PipelineError()) { - //todo obviously this needs to be better...prob look at response errors - // and make a decision i guess var errors = GetPipelineErrors(); + + var statusCode = _codeMapper.Map(errors); + + if (!statusCode.IsError) + { + await _responder.CreateErrorResponse(context, statusCode.Data); + } + else + { + await _responder.CreateErrorResponse(context, 500); + } - await _responder.CreateNotFoundResponse(context); } else { diff --git a/src/Ocelot.Library/Middleware/HttpResponderMiddlewareExtensions.cs b/src/Ocelot.Library/Infrastructure/Middleware/HttpResponderMiddlewareExtensions.cs similarity index 85% rename from src/Ocelot.Library/Middleware/HttpResponderMiddlewareExtensions.cs rename to src/Ocelot.Library/Infrastructure/Middleware/HttpResponderMiddlewareExtensions.cs index 4cec7fd0..30d69ae7 100644 --- a/src/Ocelot.Library/Middleware/HttpResponderMiddlewareExtensions.cs +++ b/src/Ocelot.Library/Infrastructure/Middleware/HttpResponderMiddlewareExtensions.cs @@ -1,6 +1,6 @@ using Microsoft.AspNetCore.Builder; -namespace Ocelot.Library.Middleware +namespace Ocelot.Library.Infrastructure.Middleware { public static class HttpResponderMiddlewareExtensions { diff --git a/src/Ocelot.Library/Middleware/OcelotMiddleware.cs b/src/Ocelot.Library/Infrastructure/Middleware/OcelotMiddleware.cs similarity index 91% rename from src/Ocelot.Library/Middleware/OcelotMiddleware.cs rename to src/Ocelot.Library/Infrastructure/Middleware/OcelotMiddleware.cs index dda41207..7af593e0 100644 --- a/src/Ocelot.Library/Middleware/OcelotMiddleware.cs +++ b/src/Ocelot.Library/Infrastructure/Middleware/OcelotMiddleware.cs @@ -1,8 +1,9 @@ using System.Collections.Generic; +using Ocelot.Library.Infrastructure.Errors; using Ocelot.Library.Infrastructure.Repository; using Ocelot.Library.Infrastructure.Responses; -namespace Ocelot.Library.Middleware +namespace Ocelot.Library.Infrastructure.Middleware { public abstract class OcelotMiddleware { diff --git a/src/Ocelot.Library/Infrastructure/Middleware/UnauthenticatedError.cs b/src/Ocelot.Library/Infrastructure/Middleware/UnauthenticatedError.cs new file mode 100644 index 00000000..3a7c3ec6 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Middleware/UnauthenticatedError.cs @@ -0,0 +1,11 @@ +using Ocelot.Library.Infrastructure.Errors; + +namespace Ocelot.Library.Infrastructure.Middleware +{ + public class UnauthenticatedError : Error + { + public UnauthenticatedError(string message) : base(message, OcelotErrorCode.UnauthenticatedError) + { + } + } +} diff --git a/src/Ocelot.Library/Infrastructure/Repository/CannotAddDataError.cs b/src/Ocelot.Library/Infrastructure/Repository/CannotAddDataError.cs index ea9d9b75..1bc0f26a 100644 --- a/src/Ocelot.Library/Infrastructure/Repository/CannotAddDataError.cs +++ b/src/Ocelot.Library/Infrastructure/Repository/CannotAddDataError.cs @@ -1,10 +1,11 @@ -using Ocelot.Library.Infrastructure.Responses; +using Ocelot.Library.Infrastructure.Errors; +using Ocelot.Library.Infrastructure.Responses; namespace Ocelot.Library.Infrastructure.Repository { public class CannotAddDataError : Error { - public CannotAddDataError(string message) : base(message) + public CannotAddDataError(string message) : base(message, OcelotErrorCode.CannotAddDataError) { } } diff --git a/src/Ocelot.Library/Infrastructure/Repository/CannotFindDataError.cs b/src/Ocelot.Library/Infrastructure/Repository/CannotFindDataError.cs index 41699f12..08a814f4 100644 --- a/src/Ocelot.Library/Infrastructure/Repository/CannotFindDataError.cs +++ b/src/Ocelot.Library/Infrastructure/Repository/CannotFindDataError.cs @@ -1,10 +1,11 @@ -using Ocelot.Library.Infrastructure.Responses; +using Ocelot.Library.Infrastructure.Errors; +using Ocelot.Library.Infrastructure.Responses; namespace Ocelot.Library.Infrastructure.Repository { public class CannotFindDataError : Error { - public CannotFindDataError(string message) : base(message) + public CannotFindDataError(string message) : base(message, OcelotErrorCode.CannotFindDataError) { } } diff --git a/src/Ocelot.Library/Infrastructure/Repository/ScopedRequestDataRepository.cs b/src/Ocelot.Library/Infrastructure/Repository/ScopedRequestDataRepository.cs index f49de35b..9b41d655 100644 --- a/src/Ocelot.Library/Infrastructure/Repository/ScopedRequestDataRepository.cs +++ b/src/Ocelot.Library/Infrastructure/Repository/ScopedRequestDataRepository.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using Microsoft.AspNetCore.Http; +using Ocelot.Library.Infrastructure.Errors; using Ocelot.Library.Infrastructure.Responses; namespace Ocelot.Library.Infrastructure.Repository diff --git a/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs b/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs index 260a6843..912d7bff 100644 --- a/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs +++ b/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Net.Http; using System.Threading.Tasks; +using Ocelot.Library.Infrastructure.Errors; using Ocelot.Library.Infrastructure.RequestBuilder; using Ocelot.Library.Infrastructure.Responses; diff --git a/src/Ocelot.Library/Infrastructure/Requester/UnableToCompleteRequestError.cs b/src/Ocelot.Library/Infrastructure/Requester/UnableToCompleteRequestError.cs index 6e7a042c..003e84e7 100644 --- a/src/Ocelot.Library/Infrastructure/Requester/UnableToCompleteRequestError.cs +++ b/src/Ocelot.Library/Infrastructure/Requester/UnableToCompleteRequestError.cs @@ -1,4 +1,5 @@ using System; +using Ocelot.Library.Infrastructure.Errors; using Ocelot.Library.Infrastructure.Responses; namespace Ocelot.Library.Infrastructure.Requester @@ -6,7 +7,7 @@ namespace Ocelot.Library.Infrastructure.Requester public class UnableToCompleteRequestError : Error { public UnableToCompleteRequestError(Exception exception) - : base($"Error making http request, exception: {exception.Message}") + : base($"Error making http request, exception: {exception.Message}", OcelotErrorCode.UnableToCompleteRequestError) { } } diff --git a/src/Ocelot.Library/Infrastructure/Responder/ErrorsToHttpStatusCodeMapper.cs b/src/Ocelot.Library/Infrastructure/Responder/ErrorsToHttpStatusCodeMapper.cs new file mode 100644 index 00000000..4798343e --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Responder/ErrorsToHttpStatusCodeMapper.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using System.Linq; +using Ocelot.Library.Infrastructure.Errors; +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.Responder +{ + public class ErrorsToHttpStatusCodeMapper : IErrorsToHttpStatusCodeMapper + { + public Response Map(List errors) + { + if (errors.Any(e => e.Code == OcelotErrorCode.UnauthenticatedError)) + { + return new OkResponse(401); + } + + return new OkResponse(404); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Responder/HttpContextResponder.cs b/src/Ocelot.Library/Infrastructure/Responder/HttpContextResponder.cs index 5339ff92..e1cfa8a1 100644 --- a/src/Ocelot.Library/Infrastructure/Responder/HttpContextResponder.cs +++ b/src/Ocelot.Library/Infrastructure/Responder/HttpContextResponder.cs @@ -1,5 +1,4 @@ -using System.Net; -using System.Net.Http; +using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; @@ -23,11 +22,11 @@ namespace Ocelot.Library.Infrastructure.Responder return context; } - public async Task CreateNotFoundResponse(HttpContext context) + public async Task CreateErrorResponse(HttpContext context, int statusCode) { context.Response.OnStarting(x => { - context.Response.StatusCode = (int)HttpStatusCode.NotFound; + context.Response.StatusCode = statusCode; return Task.CompletedTask; }, context); return context; diff --git a/src/Ocelot.Library/Infrastructure/Responder/IErrorsToHttpStatusCodeMapper.cs b/src/Ocelot.Library/Infrastructure/Responder/IErrorsToHttpStatusCodeMapper.cs new file mode 100644 index 00000000..21932bdf --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Responder/IErrorsToHttpStatusCodeMapper.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using Ocelot.Library.Infrastructure.Errors; +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.Responder +{ + public interface IErrorsToHttpStatusCodeMapper + { + Response Map(List errors); + } +} diff --git a/src/Ocelot.Library/Infrastructure/Responder/IHttpResponder.cs b/src/Ocelot.Library/Infrastructure/Responder/IHttpResponder.cs index 97bb4995..9e18647b 100644 --- a/src/Ocelot.Library/Infrastructure/Responder/IHttpResponder.cs +++ b/src/Ocelot.Library/Infrastructure/Responder/IHttpResponder.cs @@ -7,7 +7,6 @@ namespace Ocelot.Library.Infrastructure.Responder public interface IHttpResponder { Task CreateResponse(HttpContext context, HttpResponseMessage response); - Task CreateNotFoundResponse(HttpContext context); - + Task CreateErrorResponse(HttpContext context, int statusCode); } } diff --git a/src/Ocelot.Library/Infrastructure/Responses/Error.cs b/src/Ocelot.Library/Infrastructure/Responses/Error.cs deleted file mode 100644 index 57684854..00000000 --- a/src/Ocelot.Library/Infrastructure/Responses/Error.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ocelot.Library.Infrastructure.Responses -{ - public abstract class Error - { - public Error(string message) - { - Message = message; - } - - public string Message { get; private set; } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Responses/ErrorResponse.cs b/src/Ocelot.Library/Infrastructure/Responses/ErrorResponse.cs index 5233f358..2ceb83a2 100644 --- a/src/Ocelot.Library/Infrastructure/Responses/ErrorResponse.cs +++ b/src/Ocelot.Library/Infrastructure/Responses/ErrorResponse.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Ocelot.Library.Infrastructure.Errors; namespace Ocelot.Library.Infrastructure.Responses { diff --git a/src/Ocelot.Library/Infrastructure/Responses/ErrorResponseGeneric.cs b/src/Ocelot.Library/Infrastructure/Responses/ErrorResponseGeneric.cs index 95bda1b7..86d884c1 100644 --- a/src/Ocelot.Library/Infrastructure/Responses/ErrorResponseGeneric.cs +++ b/src/Ocelot.Library/Infrastructure/Responses/ErrorResponseGeneric.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Ocelot.Library.Infrastructure.Errors; namespace Ocelot.Library.Infrastructure.Responses { diff --git a/src/Ocelot.Library/Infrastructure/Responses/Response.cs b/src/Ocelot.Library/Infrastructure/Responses/Response.cs index ead3141c..9818df78 100644 --- a/src/Ocelot.Library/Infrastructure/Responses/Response.cs +++ b/src/Ocelot.Library/Infrastructure/Responses/Response.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Ocelot.Library.Infrastructure.Errors; namespace Ocelot.Library.Infrastructure.Responses { diff --git a/src/Ocelot.Library/Infrastructure/Responses/ResponseGeneric.cs b/src/Ocelot.Library/Infrastructure/Responses/ResponseGeneric.cs index ed020292..790fe5c1 100644 --- a/src/Ocelot.Library/Infrastructure/Responses/ResponseGeneric.cs +++ b/src/Ocelot.Library/Infrastructure/Responses/ResponseGeneric.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Ocelot.Library.Infrastructure.Errors; namespace Ocelot.Library.Infrastructure.Responses { diff --git a/src/Ocelot.Library/Middleware/AuthenticationMiddleware.cs b/src/Ocelot.Library/Middleware/AuthenticationMiddleware.cs deleted file mode 100644 index 6fc73817..00000000 --- a/src/Ocelot.Library/Middleware/AuthenticationMiddleware.cs +++ /dev/null @@ -1,48 +0,0 @@ -namespace Ocelot.Library.Middleware -{ - using System.Threading.Tasks; - using Infrastructure.Configuration; - using Infrastructure.DownstreamRouteFinder; - using Infrastructure.Repository; - using Microsoft.AspNetCore.Http; - - public class AuthenticationMiddleware : OcelotMiddleware - { - private readonly RequestDelegate _next; - private readonly IScopedRequestDataRepository _scopedRequestDataRepository; - - public AuthenticationMiddleware(RequestDelegate next, - IScopedRequestDataRepository scopedRequestDataRepository) - : base(scopedRequestDataRepository) - { - _next = next; - _scopedRequestDataRepository = scopedRequestDataRepository; - } - - public async Task Invoke(HttpContext context) - { - var downstreamRoute = _scopedRequestDataRepository.Get("DownstreamRoute"); - - if (downstreamRoute.IsError) - { - SetPipelineError(downstreamRoute.Errors); - return; - } - - if (IsAuthenticatedRoute(downstreamRoute.Data.ReRoute)) - { - //todo - build auth pipeline and then call normal pipeline if all good? - await _next.Invoke(context); - } - else - { - await _next.Invoke(context); - } - } - - private static bool IsAuthenticatedRoute(ReRoute reRoute) - { - return reRoute.IsAuthenticated; - } - } -} diff --git a/src/Ocelot/Controllers/HomeController.cs b/src/Ocelot/Controllers/HomeController.cs new file mode 100644 index 00000000..c6dbe9d2 --- /dev/null +++ b/src/Ocelot/Controllers/HomeController.cs @@ -0,0 +1,22 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace Ocelot.Controllers +{ + /// + /// This controller is a catch all for requests so that if we build it into a pipeline + /// the requests get authorised. + /// + public class HomeController : Controller + { + //[Authorize] + [Route("{*url}")] + public void Index() + { + if (true == true) + { + + } + } + } +} diff --git a/src/Ocelot/Startup.cs b/src/Ocelot/Startup.cs index b9298d0a..5c9e44e6 100644 --- a/src/Ocelot/Startup.cs +++ b/src/Ocelot/Startup.cs @@ -10,13 +10,13 @@ using Microsoft.Extensions.Options; using Ocelot.Library.Infrastructure.Configuration; using Ocelot.Library.Infrastructure.Configuration.Yaml; using Ocelot.Library.Infrastructure.DownstreamRouteFinder; +using Ocelot.Library.Infrastructure.Middleware; using Ocelot.Library.Infrastructure.Repository; using Ocelot.Library.Infrastructure.RequestBuilder; using Ocelot.Library.Infrastructure.Requester; using Ocelot.Library.Infrastructure.Responder; using Ocelot.Library.Infrastructure.UrlMatcher; using Ocelot.Library.Infrastructure.UrlTemplateReplacer; -using Ocelot.Library.Middleware; namespace Ocelot { @@ -40,8 +40,10 @@ namespace Ocelot public void ConfigureServices(IServiceCollection services) { services.AddOptions(); - + services.AddMvc(); + services.Configure(Configuration); + services.AddAuthentication(); // Add framework services. services.AddSingleton(); @@ -52,6 +54,7 @@ namespace Ocelot services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); // see this for why we register this as singleton http://stackoverflow.com/questions/37371264/invalidoperationexception-unable-to-resolve-service-for-type-microsoft-aspnetc services.AddSingleton(); diff --git a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs new file mode 100644 index 00000000..6b7ca01c --- /dev/null +++ b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs @@ -0,0 +1,202 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Http; +using System.Text.Encodings.Web; +using IdentityServer4.Models; +using IdentityServer4.Services.InMemory; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using Ocelot.Library.Infrastructure.Configuration.Yaml; +using Shouldly; +using TestStack.BDDfy; +using Xunit; +using YamlDotNet.Serialization; + +namespace Ocelot.AcceptanceTests +{ + public class AuthenticationTests : IDisposable + { + private TestServer _server; + private HttpClient _client; + private HttpResponseMessage _response; + private readonly string _configurationPath; + private StringContent _postContent; + private IWebHost _builder; + + // Sadly we need to change this when we update the netcoreapp version to make the test update the config correctly + private double _netCoreAppVersion = 1.4; + private HttpClient _idServerClient; + private TestServer _idServer; + + public AuthenticationTests() + { + _configurationPath = $"./bin/Debug/netcoreapp{_netCoreAppVersion}/configuration.yaml"; + } + + [Fact] + public void should_return_401_using_jwt() + { + this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888")) + .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 201, string.Empty)) + .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration + { + ReRoutes = new List + { + new YamlReRoute + { + DownstreamTemplate = "http://localhost:51876/", + UpstreamTemplate = "/", + UpstreamHttpMethod = "Post", + Authentication = "JwtBearerAuthentication" + } + } + })) + .And(x => x.GivenTheApiGatewayIsRunning()) + .And(x => x.GivenThePostHasContent("postContent")) + .When(x => x.WhenIPostUrlOnTheApiGateway("/")) + .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.Unauthorized)) + .BDDfy(); + } + + private void GivenThePostHasContent(string postcontent) + { + _postContent = new StringContent(postcontent); + } + + /// + /// This is annoying cos it should be in the constructor but we need to set up the yaml file before calling startup so its a step. + /// + private void GivenTheApiGatewayIsRunning() + { + _server = new TestServer(new WebHostBuilder() + .UseStartup()); + + _client = _server.CreateClient(); + } + + private void GivenThereIsAConfiguration(YamlConfiguration yamlConfiguration) + { + var serializer = new Serializer(); + + if (File.Exists(_configurationPath)) + { + File.Delete(_configurationPath); + } + + using (TextWriter writer = File.CreateText(_configurationPath)) + { + serializer.Serialize(writer, yamlConfiguration); + } + } + + private void GivenThereIsAServiceRunningOn(string url, int statusCode, string responseBody) + { + _builder = new WebHostBuilder() + .UseUrls(url) + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseUrls(url) + .Configure(app => + { + app.Run(async context => + { + context.Response.StatusCode = statusCode; + await context.Response.WriteAsync(responseBody); + }); + }) + .Build(); + + _builder.Start(); + } + + private void GivenThereIsAnIdentityServerOn(string url) + { + var builder = new WebHostBuilder() + .UseUrls(url) + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseUrls(url) + .ConfigureServices(services => + { + services.AddDeveloperIdentityServer() + .AddInMemoryClients(new List { + new Client + { + ClientId = "test", + AllowedGrantTypes = GrantTypes.ResourceOwnerPassword, + ClientSecrets = new List { new Secret("test".Sha256()) }, + AllowedScopes = new List { "api1" }, + AllowAccessToAllScopes = true, + AccessTokenType = AccessTokenType.Jwt, + Enabled = true + + } }) + .AddInMemoryScopes(new List { new Scope + { + Name = "api1", + Description = "My API", + Enabled = true + + }}) + .AddInMemoryUsers(new List { new InMemoryUser + { + Username = "test", Password = "test", Enabled = true, Subject = "asdads" + }}); + }) + .Configure(app => + { + app.UseIdentityServer(); + }); + + _idServer = new TestServer(builder); + _idServerClient = _idServer.CreateClient(); + + var response = _idServerClient.GetAsync($"{url}/.well-known/openid-configuration").Result; + response.EnsureSuccessStatusCode(); + var content = response.Content.ReadAsStringAsync().Result; + } + + private void GivenIHaveAToken(string url) + { + var tokenUrl = $"{url}/connect/token"; + var formData = new List> + { + new KeyValuePair("client_id", "test"), + new KeyValuePair("client_secret", "test".Sha256()), + new KeyValuePair("scope", "api1"), + new KeyValuePair("username", "test"), + new KeyValuePair("password", "test"), + new KeyValuePair("grant_type", "password") + }; + var content = new FormUrlEncodedContent(formData); + var response = _idServerClient.PostAsync(tokenUrl, content).Result; + var responseContent = response.Content.ReadAsStringAsync().Result; + } + + private void WhenIPostUrlOnTheApiGateway(string url) + { + _response = _client.PostAsync(url, _postContent).Result; + } + + private void ThenTheStatusCodeShouldBe(HttpStatusCode expectedHttpStatusCode) + { + _response.StatusCode.ShouldBe(expectedHttpStatusCode); + } + + public void Dispose() + { + _idServerClient?.Dispose(); + _idServer?.Dispose(); + _builder?.Dispose(); + _client.Dispose(); + _server.Dispose(); + } + } +} diff --git a/test/Ocelot.AcceptanceTests/OcelotTests.cs b/test/Ocelot.AcceptanceTests/OcelotTests.cs index 299f67bf..2f4fb53b 100644 --- a/test/Ocelot.AcceptanceTests/OcelotTests.cs +++ b/test/Ocelot.AcceptanceTests/OcelotTests.cs @@ -110,6 +110,7 @@ namespace Ocelot.AcceptanceTests .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.Created)) .BDDfy(); } + private void GivenThePostHasContent(string postcontent) { _postContent = new StringContent(postcontent); @@ -184,10 +185,7 @@ namespace Ocelot.AcceptanceTests public void Dispose() { - if (_builder != null) - { - _builder.Dispose(); - } + _builder?.Dispose(); _client.Dispose(); _server.Dispose(); } diff --git a/test/Ocelot.AcceptanceTests/project.json b/test/Ocelot.AcceptanceTests/project.json index ba6d6162..722e58e4 100644 --- a/test/Ocelot.AcceptanceTests/project.json +++ b/test/Ocelot.AcceptanceTests/project.json @@ -11,31 +11,32 @@ "testRunner": "xunit", - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.0.0", - "type": "platform" + "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.0.0", + "type": "platform" + }, + "Microsoft.AspNetCore.Mvc": "1.0.0", + "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", + "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", + "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0", + "Microsoft.Extensions.Configuration.Json": "1.0.0", + "Microsoft.Extensions.Logging": "1.0.0", + "Microsoft.Extensions.Logging.Console": "1.0.0", + "Microsoft.Extensions.Logging.Debug": "1.0.0", + "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", + "Microsoft.AspNetCore.Http": "1.0.0", + "Ocelot.Library": "1.0.0-*", + "xunit": "2.1.0", + "dotnet-test-xunit": "2.2.0-preview2-build1029", + "Shouldly": "2.8.0", + "Ocelot": "1.0.0-*", + "Microsoft.AspNetCore.TestHost": "1.0.0", + "TestStack.BDDfy": "4.3.1", + "YamlDotNet": "3.9.0", + "IdentityServer4": "1.0.0-rc2" }, - "Microsoft.AspNetCore.Mvc": "1.0.0", - "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", - "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", - "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", - "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0", - "Microsoft.Extensions.Configuration.Json": "1.0.0", - "Microsoft.Extensions.Logging": "1.0.0", - "Microsoft.Extensions.Logging.Console": "1.0.0", - "Microsoft.Extensions.Logging.Debug": "1.0.0", - "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", - "Microsoft.AspNetCore.Http": "1.0.0", - "Ocelot.Library": "1.0.0-*", - "xunit": "2.1.0", - "dotnet-test-xunit": "2.2.0-preview2-build1029", - "Shouldly": "2.8.0", - "Ocelot": "1.0.0-*", - "Microsoft.AspNetCore.TestHost": "1.0.0", - "TestStack.BDDfy": "4.3.1", - "YamlDotNet": "3.9.0" - }, "frameworks": { "netcoreapp1.4": { diff --git a/test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs index f5cc37f5..fb4e2d32 100644 --- a/test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs @@ -7,10 +7,10 @@ using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Moq; using Ocelot.Library.Infrastructure.DownstreamRouteFinder; +using Ocelot.Library.Infrastructure.Middleware; using Ocelot.Library.Infrastructure.Repository; using Ocelot.Library.Infrastructure.Responses; using Ocelot.Library.Infrastructure.UrlMatcher; -using Ocelot.Library.Middleware; using TestStack.BDDfy; using Xunit; diff --git a/test/Ocelot.UnitTests/Middleware/DownstreamRouteFinderMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/DownstreamRouteFinderMiddlewareTests.cs index b960e399..ec48f886 100644 --- a/test/Ocelot.UnitTests/Middleware/DownstreamRouteFinderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Middleware/DownstreamRouteFinderMiddlewareTests.cs @@ -1,4 +1,6 @@ -namespace Ocelot.UnitTests.Middleware +using Ocelot.Library.Infrastructure.Middleware; + +namespace Ocelot.UnitTests.Middleware { using System; using System.Collections.Generic; @@ -9,7 +11,6 @@ using Library.Infrastructure.Repository; using Library.Infrastructure.Responses; using Library.Infrastructure.UrlMatcher; - using Library.Middleware; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; diff --git a/test/Ocelot.UnitTests/Middleware/DownstreamUrlCreatorMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/DownstreamUrlCreatorMiddlewareTests.cs index df9260c8..d9545f2f 100644 --- a/test/Ocelot.UnitTests/Middleware/DownstreamUrlCreatorMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Middleware/DownstreamUrlCreatorMiddlewareTests.cs @@ -1,4 +1,6 @@ -namespace Ocelot.UnitTests.Middleware +using Ocelot.Library.Infrastructure.Middleware; + +namespace Ocelot.UnitTests.Middleware { using System; using System.Collections.Generic; @@ -10,7 +12,6 @@ using Library.Infrastructure.Responses; using Library.Infrastructure.UrlMatcher; using Library.Infrastructure.UrlTemplateReplacer; - using Library.Middleware; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; diff --git a/test/Ocelot.UnitTests/Middleware/HttpRequestBuilderMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/HttpRequestBuilderMiddlewareTests.cs index 56142b70..2a483330 100644 --- a/test/Ocelot.UnitTests/Middleware/HttpRequestBuilderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Middleware/HttpRequestBuilderMiddlewareTests.cs @@ -7,10 +7,10 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Moq; +using Ocelot.Library.Infrastructure.Middleware; using Ocelot.Library.Infrastructure.Repository; using Ocelot.Library.Infrastructure.RequestBuilder; using Ocelot.Library.Infrastructure.Responses; -using Ocelot.Library.Middleware; using TestStack.BDDfy; using Xunit; diff --git a/test/Ocelot.UnitTests/Middleware/HttpRequesterMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/HttpRequesterMiddlewareTests.cs index ecb62b19..a2e24133 100644 --- a/test/Ocelot.UnitTests/Middleware/HttpRequesterMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Middleware/HttpRequesterMiddlewareTests.cs @@ -6,11 +6,11 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Moq; +using Ocelot.Library.Infrastructure.Middleware; using Ocelot.Library.Infrastructure.Repository; using Ocelot.Library.Infrastructure.RequestBuilder; using Ocelot.Library.Infrastructure.Requester; using Ocelot.Library.Infrastructure.Responses; -using Ocelot.Library.Middleware; using TestStack.BDDfy; using Xunit; diff --git a/test/Ocelot.UnitTests/Middleware/HttpResponderMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/HttpResponderMiddlewareTests.cs index d565dbf8..e8f6ef10 100644 --- a/test/Ocelot.UnitTests/Middleware/HttpResponderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Middleware/HttpResponderMiddlewareTests.cs @@ -6,10 +6,10 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Moq; +using Ocelot.Library.Infrastructure.Middleware; using Ocelot.Library.Infrastructure.Repository; using Ocelot.Library.Infrastructure.Responder; using Ocelot.Library.Infrastructure.Responses; -using Ocelot.Library.Middleware; using TestStack.BDDfy; using Xunit; @@ -19,6 +19,7 @@ namespace Ocelot.UnitTests.Middleware { private readonly Mock _responder; private readonly Mock _scopedRepository; + private readonly Mock _codeMapper; private readonly string _url; private readonly TestServer _server; private readonly HttpClient _client; @@ -30,10 +31,12 @@ namespace Ocelot.UnitTests.Middleware _url = "http://localhost:51879"; _responder = new Mock(); _scopedRepository = new Mock(); + _codeMapper = new Mock(); var builder = new WebHostBuilder() .ConfigureServices(x => { + x.AddSingleton(_codeMapper.Object); x.AddSingleton(_responder.Object); x.AddSingleton(_scopedRepository.Object); }) diff --git a/test/Ocelot.UnitTests/Responder/ErrorsToHttpStatusCodeMapperTests.cs b/test/Ocelot.UnitTests/Responder/ErrorsToHttpStatusCodeMapperTests.cs new file mode 100644 index 00000000..cc976b6d --- /dev/null +++ b/test/Ocelot.UnitTests/Responder/ErrorsToHttpStatusCodeMapperTests.cs @@ -0,0 +1,72 @@ +using System.Collections.Generic; +using System.IO; +using System.Net.Http; +using Microsoft.AspNetCore.Http; +using Ocelot.Library.Infrastructure.Errors; +using Ocelot.Library.Infrastructure.Middleware; +using Ocelot.Library.Infrastructure.Responder; +using Ocelot.Library.Infrastructure.Responses; +using Shouldly; +using TestStack.BDDfy; +using Xunit; + +namespace Ocelot.UnitTests.Responder +{ + public class ErrorsToHttpStatusCodeMapperTests + { + private readonly IErrorsToHttpStatusCodeMapper _codeMapper; + private Response _result; + private List _errors; + + public ErrorsToHttpStatusCodeMapperTests() + { + _codeMapper = new ErrorsToHttpStatusCodeMapper(); + } + + [Fact] + public void should_create_unauthenticated_response_code() + { + this.Given(x => x.GivenThereAreErrors(new List + { + new UnauthenticatedError("no matter") + })) + .When(x => x.WhenIGetErrorStatusCode()) + .Then(x => x.ThenTheResponseIsStatusCodeIs(401)) + .BDDfy(); + } + + [Fact] + public void should_create_not_found_response_response_code() + { + this.Given(x => x.GivenThereAreErrors(new List + { + new AnyError() + })) + .When(x => x.WhenIGetErrorStatusCode()) + .Then(x => x.ThenTheResponseIsStatusCodeIs(404)) + .BDDfy(); + } + + class AnyError : Error + { + public AnyError() : base("blahh", OcelotErrorCode.UnknownError) + { + } + } + + private void GivenThereAreErrors(List errors) + { + _errors = errors; + } + + private void WhenIGetErrorStatusCode() + { + _result = _codeMapper.Map(_errors); + } + + private void ThenTheResponseIsStatusCodeIs(int expectedCode) + { + _result.Data.ShouldBe(expectedCode); + } + } +} diff --git a/test/Ocelot.UnitTests/Responder/ResponderTests.cs b/test/Ocelot.UnitTests/Responder/ResponderTests.cs deleted file mode 100644 index 60a20153..00000000 --- a/test/Ocelot.UnitTests/Responder/ResponderTests.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Microsoft.AspNetCore.Http; -using Xunit; - -namespace Ocelot.UnitTests.Responder -{ - public class ResponderTests - { - [Fact] - public void should_do_something() - { - - } - } -} From 320b442526eba88dac3684a48fcfcce2b8f52d90 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Sat, 15 Oct 2016 13:50:43 +0100 Subject: [PATCH 084/183] got identity server access token acceptance test working, created factory for choosing auth handlers, a creator for making the auth handlers, some general refactoring...next step is injecting the config for the auth handler creator in some way or just passing it in --- .../Authentication/AuthenticationHandler.cs | 16 ++ .../AuthenticationHandlerCreator.cs | 32 ++++ .../AuthenticationProviderFactory.cs | 32 ++++ .../IAuthenticationHandlerCreator.cs | 11 ++ .../IAuthenticationProviderFactory.cs | 10 ++ ...nableToCreateAuthenticationHandlerError.cs | 12 ++ .../Infrastructure/Errors/OcelotErrorCode.cs | 3 +- .../Middleware/AuthenticationMiddleware.cs | 38 ++--- .../Middleware/HttpResponderMiddleware.cs | 1 - .../Responder/HttpContextResponder.cs | 6 +- src/Ocelot.Library/project.json | 55 +++---- src/Ocelot/Startup.cs | 6 +- .../AuthenticationTests.cs | 147 +++++++++++++----- .../Ocelot.AcceptanceTests/configuration.yaml | 2 +- .../AuthenticationProviderFactoryTests.cs | 88 +++++++++++ .../AuthenticationMiddlewareTests.cs | 5 +- 16 files changed, 369 insertions(+), 95 deletions(-) create mode 100644 src/Ocelot.Library/Infrastructure/Authentication/AuthenticationHandler.cs create mode 100644 src/Ocelot.Library/Infrastructure/Authentication/AuthenticationHandlerCreator.cs create mode 100644 src/Ocelot.Library/Infrastructure/Authentication/AuthenticationProviderFactory.cs create mode 100644 src/Ocelot.Library/Infrastructure/Authentication/IAuthenticationHandlerCreator.cs create mode 100644 src/Ocelot.Library/Infrastructure/Authentication/IAuthenticationProviderFactory.cs create mode 100644 src/Ocelot.Library/Infrastructure/Authentication/UnableToCreateAuthenticationHandlerError.cs create mode 100644 test/Ocelot.UnitTests/Authentication/AuthenticationProviderFactoryTests.cs diff --git a/src/Ocelot.Library/Infrastructure/Authentication/AuthenticationHandler.cs b/src/Ocelot.Library/Infrastructure/Authentication/AuthenticationHandler.cs new file mode 100644 index 00000000..3830e33a --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Authentication/AuthenticationHandler.cs @@ -0,0 +1,16 @@ +using Microsoft.AspNetCore.Http; + +namespace Ocelot.Library.Infrastructure.Authentication +{ + public class AuthenticationHandler + { + public AuthenticationHandler(string provider, RequestDelegate handler) + { + Provider = provider; + Handler = handler; + } + + public string Provider { get; private set; } + public RequestDelegate Handler { get; private set; } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Authentication/AuthenticationHandlerCreator.cs b/src/Ocelot.Library/Infrastructure/Authentication/AuthenticationHandlerCreator.cs new file mode 100644 index 00000000..1428f239 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Authentication/AuthenticationHandlerCreator.cs @@ -0,0 +1,32 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.Authentication +{ + /// + /// Cannot unit test things in this class due to use of extension methods + /// + public class AuthenticationHandlerCreator : IAuthenticationHandlerCreator + { + public Response CreateIdentityServerAuthenticationHandler(IApplicationBuilder app) + { + var builder = app.New(); + + builder.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions + { + //todo sort these options out + Authority = "http://localhost:51888", + ScopeName = "api", + + RequireHttpsMetadata = false + }); + + builder.UseMvc(); + + var authenticationNext = builder.Build(); + + return new OkResponse(authenticationNext); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Authentication/AuthenticationProviderFactory.cs b/src/Ocelot.Library/Infrastructure/Authentication/AuthenticationProviderFactory.cs new file mode 100644 index 00000000..770462ca --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Authentication/AuthenticationProviderFactory.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using Microsoft.AspNetCore.Builder; +using Ocelot.Library.Infrastructure.Errors; +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.Authentication +{ + public class AuthenticationProviderFactory : IAuthenticationProviderFactory + { + private readonly IAuthenticationHandlerCreator _creator; + + public AuthenticationProviderFactory(IAuthenticationHandlerCreator creator) + { + _creator = creator; + } + + public Response Get(string provider, IApplicationBuilder app) + { + var handler = _creator.CreateIdentityServerAuthenticationHandler(app); + + if (!handler.IsError) + { + return new OkResponse(new AuthenticationHandler(provider, handler.Data)); + } + + return new ErrorResponse(new List + { + new UnableToCreateAuthenticationHandlerError($"Unable to create authentication handler for {provider}") + }); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Authentication/IAuthenticationHandlerCreator.cs b/src/Ocelot.Library/Infrastructure/Authentication/IAuthenticationHandlerCreator.cs new file mode 100644 index 00000000..cb1b2a91 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Authentication/IAuthenticationHandlerCreator.cs @@ -0,0 +1,11 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.Authentication +{ + public interface IAuthenticationHandlerCreator + { + Response CreateIdentityServerAuthenticationHandler(IApplicationBuilder app); + } +} diff --git a/src/Ocelot.Library/Infrastructure/Authentication/IAuthenticationProviderFactory.cs b/src/Ocelot.Library/Infrastructure/Authentication/IAuthenticationProviderFactory.cs new file mode 100644 index 00000000..e9a25a54 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Authentication/IAuthenticationProviderFactory.cs @@ -0,0 +1,10 @@ +using Microsoft.AspNetCore.Builder; +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.Authentication +{ + public interface IAuthenticationProviderFactory + { + Response Get(string provider, IApplicationBuilder app); + } +} diff --git a/src/Ocelot.Library/Infrastructure/Authentication/UnableToCreateAuthenticationHandlerError.cs b/src/Ocelot.Library/Infrastructure/Authentication/UnableToCreateAuthenticationHandlerError.cs new file mode 100644 index 00000000..5637ef73 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Authentication/UnableToCreateAuthenticationHandlerError.cs @@ -0,0 +1,12 @@ +using Ocelot.Library.Infrastructure.Errors; + +namespace Ocelot.Library.Infrastructure.Authentication +{ + public class UnableToCreateAuthenticationHandlerError : Error + { + public UnableToCreateAuthenticationHandlerError(string message) + : base(message, OcelotErrorCode.UnableToCreateAuthenticationHandlerError) + { + } + } +} diff --git a/src/Ocelot.Library/Infrastructure/Errors/OcelotErrorCode.cs b/src/Ocelot.Library/Infrastructure/Errors/OcelotErrorCode.cs index e746de55..4f7a1fd7 100644 --- a/src/Ocelot.Library/Infrastructure/Errors/OcelotErrorCode.cs +++ b/src/Ocelot.Library/Infrastructure/Errors/OcelotErrorCode.cs @@ -8,6 +8,7 @@ UnableToFindDownstreamRouteError, CannotAddDataError, CannotFindDataError, - UnableToCompleteRequestError + UnableToCompleteRequestError, + UnableToCreateAuthenticationHandlerError } } diff --git a/src/Ocelot.Library/Infrastructure/Middleware/AuthenticationMiddleware.cs b/src/Ocelot.Library/Infrastructure/Middleware/AuthenticationMiddleware.cs index 4a72d412..be8f54be 100644 --- a/src/Ocelot.Library/Infrastructure/Middleware/AuthenticationMiddleware.cs +++ b/src/Ocelot.Library/Infrastructure/Middleware/AuthenticationMiddleware.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.IdentityModel.Tokens.Jwt; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; @@ -7,6 +8,11 @@ using Ocelot.Library.Infrastructure.DownstreamRouteFinder; using Ocelot.Library.Infrastructure.Errors; using Ocelot.Library.Infrastructure.Repository; using Ocelot.Library.Infrastructure.Responses; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Ocelot.Library.Infrastructure.Authentication; namespace Ocelot.Library.Infrastructure.Middleware { @@ -16,13 +22,15 @@ namespace Ocelot.Library.Infrastructure.Middleware private RequestDelegate _authenticationNext; private readonly IScopedRequestDataRepository _scopedRequestDataRepository; private readonly IApplicationBuilder _app; + private readonly IAuthenticationProviderFactory _authProviderFactory; public AuthenticationMiddleware(RequestDelegate next, IApplicationBuilder app, - IScopedRequestDataRepository scopedRequestDataRepository) + IScopedRequestDataRepository scopedRequestDataRepository, IAuthenticationProviderFactory authProviderFactory) : base(scopedRequestDataRepository) { _next = next; _scopedRequestDataRepository = scopedRequestDataRepository; + _authProviderFactory = authProviderFactory; _app = app; } @@ -38,25 +46,17 @@ namespace Ocelot.Library.Infrastructure.Middleware if (IsAuthenticatedRoute(downstreamRoute.Data.ReRoute)) { - //todo - build auth pipeline and then call normal pipeline if all good? - //create new app builder - var builder = _app.New(); - //set up any options for the authentication - var jwtBearerOptions = new JwtBearerOptions + var authenticationNext = _authProviderFactory.Get(downstreamRoute.Data.ReRoute.AuthenticationProvider, _app); + + if (!authenticationNext.IsError) { - AutomaticAuthenticate = true, - AutomaticChallenge = true, - RequireHttpsMetadata = false, - }; - //set the authentication middleware - builder.UseJwtBearerAuthentication(jwtBearerOptions); - //use mvc so we hit the catch all authorised controller - builder.UseMvc(); - //then build it - _authenticationNext = builder.Build(); - //then call it - await _authenticationNext(context); - //check if the user is authenticated + await authenticationNext.Data.Handler.Invoke(context); + } + else + { + SetPipelineError(authenticationNext.Errors); + } + if (context.User.Identity.IsAuthenticated) { await _next.Invoke(context); diff --git a/src/Ocelot.Library/Infrastructure/Middleware/HttpResponderMiddleware.cs b/src/Ocelot.Library/Infrastructure/Middleware/HttpResponderMiddleware.cs index 3f268a62..0c8fba3c 100644 --- a/src/Ocelot.Library/Infrastructure/Middleware/HttpResponderMiddleware.cs +++ b/src/Ocelot.Library/Infrastructure/Middleware/HttpResponderMiddleware.cs @@ -43,7 +43,6 @@ namespace Ocelot.Library.Infrastructure.Middleware { await _responder.CreateErrorResponse(context, 500); } - } else { diff --git a/src/Ocelot.Library/Infrastructure/Responder/HttpContextResponder.cs b/src/Ocelot.Library/Infrastructure/Responder/HttpContextResponder.cs index e1cfa8a1..e5e31fe4 100644 --- a/src/Ocelot.Library/Infrastructure/Responder/HttpContextResponder.cs +++ b/src/Ocelot.Library/Infrastructure/Responder/HttpContextResponder.cs @@ -3,7 +3,11 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; namespace Ocelot.Library.Infrastructure.Responder -{ +{ + /// + /// Cannot unit test things in this class due to methods not being implemented + /// on .net concretes used for testing + /// public class HttpContextResponder : IHttpResponder { public async Task CreateResponse(HttpContext context, HttpResponseMessage response) diff --git a/src/Ocelot.Library/project.json b/src/Ocelot.Library/project.json index 24790da9..f57d8566 100644 --- a/src/Ocelot.Library/project.json +++ b/src/Ocelot.Library/project.json @@ -1,34 +1,35 @@ { "version": "1.0.0-*", - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.0.0", - "type": "platform" + "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.0.0", + "type": "platform" + }, + "Microsoft.AspNetCore.Mvc": "1.0.0", + "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", + "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", + "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0", + "Microsoft.Extensions.Configuration.Json": "1.0.0", + "Microsoft.Extensions.Logging": "1.0.0", + "Microsoft.Extensions.Logging.Console": "1.0.0", + "Microsoft.Extensions.Logging.Debug": "1.0.0", + "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", + "Microsoft.AspNetCore.Http": "1.0.0", + "System.Text.RegularExpressions": "4.1.0", + "YamlDotNet": "3.9.0", + "Microsoft.AspNetCore.Authentication.OAuth": "1.0.0", + "Microsoft.AspNetCore.Authentication.JwtBearer": "1.0.0", + "Microsoft.AspNetCore.Authentication.OpenIdConnect": "1.0.0", + "Microsoft.AspNetCore.Authentication.Cookies": "1.0.0", + "Microsoft.AspNetCore.Authentication.Google": "1.0.0", + "Microsoft.AspNetCore.Authentication.Facebook": "1.0.0", + "Microsoft.AspNetCore.Authentication.Twitter": "1.0.0", + "Microsoft.AspNetCore.Authentication.MicrosoftAccount": "1.0.0", + "Microsoft.AspNetCore.Authentication": "1.0.0", + "IdentityServer4.AccessTokenValidation": "1.0.1-rc2" }, - "Microsoft.AspNetCore.Mvc": "1.0.0", - "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", - "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", - "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", - "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0", - "Microsoft.Extensions.Configuration.Json": "1.0.0", - "Microsoft.Extensions.Logging": "1.0.0", - "Microsoft.Extensions.Logging.Console": "1.0.0", - "Microsoft.Extensions.Logging.Debug": "1.0.0", - "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", - "Microsoft.AspNetCore.Http": "1.0.0", - "System.Text.RegularExpressions": "4.1.0", - "YamlDotNet": "3.9.0", - "Microsoft.AspNetCore.Authentication.OAuth": "1.0.0", - "Microsoft.AspNetCore.Authentication.JwtBearer": "1.0.0", - "Microsoft.AspNetCore.Authentication.OpenIdConnect": "1.0.0", - "Microsoft.AspNetCore.Authentication.Cookies": "1.0.0", - "Microsoft.AspNetCore.Authentication.Google": "1.0.0", - "Microsoft.AspNetCore.Authentication.Facebook": "1.0.0", - "Microsoft.AspNetCore.Authentication.Twitter": "1.0.0", - "Microsoft.AspNetCore.Authentication.MicrosoftAccount": "1.0.0", - "Microsoft.AspNetCore.Authentication": "1.0.0" - }, "frameworks": { "netcoreapp1.4": { diff --git a/src/Ocelot/Startup.cs b/src/Ocelot/Startup.cs index 5c9e44e6..35934de3 100644 --- a/src/Ocelot/Startup.cs +++ b/src/Ocelot/Startup.cs @@ -7,6 +7,7 @@ using Microsoft.Extensions.Configuration.Memory; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Ocelot.Library.Infrastructure.Authentication; using Ocelot.Library.Infrastructure.Configuration; using Ocelot.Library.Infrastructure.Configuration.Yaml; using Ocelot.Library.Infrastructure.DownstreamRouteFinder; @@ -41,7 +42,8 @@ namespace Ocelot { services.AddOptions(); services.AddMvc(); - + services.AddMvcCore().AddAuthorization().AddJsonFormatters(); + services.Configure(Configuration); services.AddAuthentication(); @@ -55,6 +57,8 @@ namespace Ocelot services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); // see this for why we register this as singleton http://stackoverflow.com/questions/37371264/invalidoperationexception-unable-to-resolve-service-for-type-microsoft-aspnetc services.AddSingleton(); diff --git a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs index 6b7ca01c..bfefdc7f 100644 --- a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs +++ b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Net; using System.Net.Http; +using System.Net.Http.Headers; using System.Text.Encodings.Web; using IdentityServer4.Models; using IdentityServer4.Services.InMemory; @@ -11,6 +12,7 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; +using Newtonsoft.Json; using Ocelot.Library.Infrastructure.Configuration.Yaml; using Shouldly; using TestStack.BDDfy; @@ -21,17 +23,17 @@ namespace Ocelot.AcceptanceTests { public class AuthenticationTests : IDisposable { - private TestServer _server; - private HttpClient _client; + private TestServer _ocelotServer; + private HttpClient _ocelotClient; private HttpResponseMessage _response; private readonly string _configurationPath; private StringContent _postContent; - private IWebHost _builder; + private IWebHost _ocelotBbuilder; // Sadly we need to change this when we update the netcoreapp version to make the test update the config correctly private double _netCoreAppVersion = 1.4; - private HttpClient _idServerClient; - private TestServer _idServer; + private BearerToken _token; + private IWebHost _identityServerBuilder; public AuthenticationTests() { @@ -39,7 +41,7 @@ namespace Ocelot.AcceptanceTests } [Fact] - public void should_return_401_using_jwt() + public void should_return_401_using_identity_server_access_token() { this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888")) .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 201, string.Empty)) @@ -63,6 +65,33 @@ namespace Ocelot.AcceptanceTests .BDDfy(); } + [Fact] + public void should_return_201_using_identity_server_access_token() + { + this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888")) + .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 201, string.Empty)) + .And(x => x.GivenIHaveAToken("http://localhost:51888")) + .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration + { + ReRoutes = new List + { + new YamlReRoute + { + DownstreamTemplate = "http://localhost:51876/", + UpstreamTemplate = "/", + UpstreamHttpMethod = "Post", + Authentication = "JwtBearerAuthentication" + } + } + })) + .And(x => x.GivenTheApiGatewayIsRunning()) + .And(x => x.GivenIHaveAddedATokenToMyRequest()) + .And(x => x.GivenThePostHasContent("postContent")) + .When(x => x.WhenIPostUrlOnTheApiGateway("/")) + .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.Created)) + .BDDfy(); + } + private void GivenThePostHasContent(string postcontent) { _postContent = new StringContent(postcontent); @@ -73,10 +102,10 @@ namespace Ocelot.AcceptanceTests /// private void GivenTheApiGatewayIsRunning() { - _server = new TestServer(new WebHostBuilder() + _ocelotServer = new TestServer(new WebHostBuilder() .UseStartup()); - _client = _server.CreateClient(); + _ocelotClient = _ocelotServer.CreateClient(); } private void GivenThereIsAConfiguration(YamlConfiguration yamlConfiguration) @@ -96,7 +125,7 @@ namespace Ocelot.AcceptanceTests private void GivenThereIsAServiceRunningOn(string url, int statusCode, string responseBody) { - _builder = new WebHostBuilder() + _ocelotBbuilder = new WebHostBuilder() .UseUrls(url) .UseKestrel() .UseContentRoot(Directory.GetCurrentDirectory()) @@ -112,12 +141,12 @@ namespace Ocelot.AcceptanceTests }) .Build(); - _builder.Start(); + _ocelotBbuilder.Start(); } private void GivenThereIsAnIdentityServerOn(string url) { - var builder = new WebHostBuilder() + _identityServerBuilder = new WebHostBuilder() .UseUrls(url) .UseKestrel() .UseContentRoot(Directory.GetCurrentDirectory()) @@ -126,41 +155,51 @@ namespace Ocelot.AcceptanceTests .ConfigureServices(services => { services.AddDeveloperIdentityServer() - .AddInMemoryClients(new List { - new Client - { - ClientId = "test", - AllowedGrantTypes = GrantTypes.ResourceOwnerPassword, - ClientSecrets = new List { new Secret("test".Sha256()) }, - AllowedScopes = new List { "api1" }, - AllowAccessToAllScopes = true, - AccessTokenType = AccessTokenType.Jwt, - Enabled = true - - } }) .AddInMemoryScopes(new List { new Scope { - Name = "api1", + Name = "api", Description = "My API", Enabled = true }}) + .AddInMemoryClients(new List { + new Client + { + ClientId = "client", + AllowedGrantTypes = GrantTypes.ResourceOwnerPassword, + ClientSecrets = new List { new Secret("secret".Sha256()) }, + AllowedScopes = new List { "api" }, + AccessTokenType = AccessTokenType.Jwt, + Enabled = true, + RequireClientSecret = false + } }) .AddInMemoryUsers(new List { new InMemoryUser { - Username = "test", Password = "test", Enabled = true, Subject = "asdads" + Username = "test", + Password = "test", + Enabled = true, + Subject = "asdads" }}); }) .Configure(app => { app.UseIdentityServer(); - }); - - _idServer = new TestServer(builder); - _idServerClient = _idServer.CreateClient(); + }) + .Build(); - var response = _idServerClient.GetAsync($"{url}/.well-known/openid-configuration").Result; - response.EnsureSuccessStatusCode(); - var content = response.Content.ReadAsStringAsync().Result; + _identityServerBuilder.Start(); + + VerifyIdentiryServerStarted(url); + + } + + private void VerifyIdentiryServerStarted(string url) + { + using (var httpClient = new HttpClient()) + { + var response = httpClient.GetAsync($"{url}/.well-known/openid-configuration").Result; + response.EnsureSuccessStatusCode(); + } } private void GivenIHaveAToken(string url) @@ -168,21 +207,32 @@ namespace Ocelot.AcceptanceTests var tokenUrl = $"{url}/connect/token"; var formData = new List> { - new KeyValuePair("client_id", "test"), - new KeyValuePair("client_secret", "test".Sha256()), - new KeyValuePair("scope", "api1"), + new KeyValuePair("client_id", "client"), + new KeyValuePair("client_secret", "secret"), + new KeyValuePair("scope", "api"), new KeyValuePair("username", "test"), new KeyValuePair("password", "test"), new KeyValuePair("grant_type", "password") }; var content = new FormUrlEncodedContent(formData); - var response = _idServerClient.PostAsync(tokenUrl, content).Result; - var responseContent = response.Content.ReadAsStringAsync().Result; + + using (var httpClient = new HttpClient()) + { + var response = httpClient.PostAsync(tokenUrl, content).Result; + response.EnsureSuccessStatusCode(); + var responseContent = response.Content.ReadAsStringAsync().Result; + _token = JsonConvert.DeserializeObject(responseContent); + } + } + + private void GivenIHaveAddedATokenToMyRequest() + { + _ocelotClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _token.AccessToken); } private void WhenIPostUrlOnTheApiGateway(string url) { - _response = _client.PostAsync(url, _postContent).Result; + _response = _ocelotClient.PostAsync(url, _postContent).Result; } private void ThenTheStatusCodeShouldBe(HttpStatusCode expectedHttpStatusCode) @@ -192,11 +242,22 @@ namespace Ocelot.AcceptanceTests public void Dispose() { - _idServerClient?.Dispose(); - _idServer?.Dispose(); - _builder?.Dispose(); - _client.Dispose(); - _server.Dispose(); + _ocelotBbuilder?.Dispose(); + _ocelotClient?.Dispose(); + _ocelotServer?.Dispose(); + _identityServerBuilder?.Dispose(); + } + + class BearerToken + { + [JsonProperty("access_token")] + public string AccessToken { get; set; } + + [JsonProperty("expires_in")] + public int ExpiresIn { get; set; } + + [JsonProperty("token_type")] + public string TokenType { get; set; } } } } diff --git a/test/Ocelot.AcceptanceTests/configuration.yaml b/test/Ocelot.AcceptanceTests/configuration.yaml index 42e7ab07..c438428b 100644 --- a/test/Ocelot.AcceptanceTests/configuration.yaml +++ b/test/Ocelot.AcceptanceTests/configuration.yaml @@ -2,4 +2,4 @@ ReRoutes: - DownstreamTemplate: http://localhost:51879/ UpstreamTemplate: / UpstreamHttpMethod: Get - Authentication: IdentityServer + Authentication: IdentityServer.AccessToken diff --git a/test/Ocelot.UnitTests/Authentication/AuthenticationProviderFactoryTests.cs b/test/Ocelot.UnitTests/Authentication/AuthenticationProviderFactoryTests.cs new file mode 100644 index 00000000..752aca0b --- /dev/null +++ b/test/Ocelot.UnitTests/Authentication/AuthenticationProviderFactoryTests.cs @@ -0,0 +1,88 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Moq; +using Ocelot.Library.Infrastructure.Authentication; +using Ocelot.Library.Infrastructure.Errors; +using Ocelot.Library.Infrastructure.Responses; +using Shouldly; +using TestStack.BDDfy; +using Xunit; + +namespace Ocelot.UnitTests.Authentication +{ + public class AuthenticationProviderFactoryTests + { + private readonly IAuthenticationProviderFactory _authenticationProviderFactory; + private readonly Mock _app; + private readonly Mock _creator; + + private string _provider; + private Response _result; + + public AuthenticationProviderFactoryTests() + { + _app = new Mock(); + _creator = new Mock(); + _authenticationProviderFactory = new AuthenticationProviderFactory(_creator.Object); + } + + [Fact] + public void should_return_identity_server_access_token_provider() + { + this.Given(x => x.GivenTheProviderIs("IdentityServer.AccessToken")) + .And(x => x.GivenTheCreatorReturns()) + .When(x => x.WhenIGetFromTheFactory()) + .Then(x => x.ThenTheHandlerIsReturned("IdentityServer.AccessToken")) + .BDDfy(); + } + + [Fact] + public void should_return_error_if_cannot_create_handler() + { + this.Given(x => x.GivenTheProviderIs("IdentityServer.AccessToken")) + .And(x => x.GivenTheCreatorReturnsAnError()) + .When(x => x.WhenIGetFromTheFactory()) + .Then(x => x.ThenAnErrorResponseIsReturned()) + .BDDfy(); + } + + private void GivenTheCreatorReturnsAnError() + { + _creator + .Setup(x => x.CreateIdentityServerAuthenticationHandler(It.IsAny())) + .Returns(new ErrorResponse(new List + { + new UnableToCreateAuthenticationHandlerError($"Unable to create authentication handler for xxx") + })); + } + + private void GivenTheCreatorReturns() + { + _creator + .Setup(x => x.CreateIdentityServerAuthenticationHandler(It.IsAny())) + .Returns(new OkResponse(x => Task.CompletedTask)); + } + + private void GivenTheProviderIs(string provider) + { + _provider = provider; + } + + private void WhenIGetFromTheFactory() + { + _result = _authenticationProviderFactory.Get(_provider, _app.Object); + } + + private void ThenTheHandlerIsReturned(string expected) + { + _result.Data.Provider.ShouldBe(expected); + } + + private void ThenAnErrorResponseIsReturned() + { + _result.IsError.ShouldBeTrue(); + } + } +} diff --git a/test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs index fb4e2d32..6c82b0fe 100644 --- a/test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs @@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Moq; +using Ocelot.Library.Infrastructure.Authentication; using Ocelot.Library.Infrastructure.DownstreamRouteFinder; using Ocelot.Library.Infrastructure.Middleware; using Ocelot.Library.Infrastructure.Repository; @@ -21,6 +22,7 @@ namespace Ocelot.UnitTests.Middleware public class AuthenticationMiddlewareTests : IDisposable { private readonly Mock _scopedRepository; + private readonly Mock _authFactory; private readonly string _url; private readonly TestServer _server; private readonly HttpClient _client; @@ -31,10 +33,11 @@ namespace Ocelot.UnitTests.Middleware { _url = "http://localhost:51879"; _scopedRepository = new Mock(); - + _authFactory = new Mock(); var builder = new WebHostBuilder() .ConfigureServices(x => { + x.AddSingleton(_authFactory.Object); x.AddSingleton(_scopedRepository.Object); }) .UseUrls(_url) From 7289cd803b94f82cc465209ba436f528f01e2659 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Sun, 16 Oct 2016 16:47:08 +0100 Subject: [PATCH 085/183] renamed provider to handler --- ...derFactory.cs => AuthenticationHandlerFactory.cs} | 4 ++-- ...erFactory.cs => IAuthenticationHandlerFactory.cs} | 2 +- .../Middleware/AuthenticationMiddleware.cs | 8 ++++---- src/Ocelot/Startup.cs | 2 +- ...Tests.cs => AuthenticationHandlerFactoryTests.cs} | 12 ++++++------ .../Middleware/AuthenticationMiddlewareTests.cs | 4 ++-- 6 files changed, 16 insertions(+), 16 deletions(-) rename src/Ocelot.Library/Infrastructure/Authentication/{AuthenticationProviderFactory.cs => AuthenticationHandlerFactory.cs} (85%) rename src/Ocelot.Library/Infrastructure/Authentication/{IAuthenticationProviderFactory.cs => IAuthenticationHandlerFactory.cs} (82%) rename test/Ocelot.UnitTests/Authentication/{AuthenticationProviderFactoryTests.cs => AuthenticationHandlerFactoryTests.cs} (85%) diff --git a/src/Ocelot.Library/Infrastructure/Authentication/AuthenticationProviderFactory.cs b/src/Ocelot.Library/Infrastructure/Authentication/AuthenticationHandlerFactory.cs similarity index 85% rename from src/Ocelot.Library/Infrastructure/Authentication/AuthenticationProviderFactory.cs rename to src/Ocelot.Library/Infrastructure/Authentication/AuthenticationHandlerFactory.cs index 770462ca..eaa8837b 100644 --- a/src/Ocelot.Library/Infrastructure/Authentication/AuthenticationProviderFactory.cs +++ b/src/Ocelot.Library/Infrastructure/Authentication/AuthenticationHandlerFactory.cs @@ -5,11 +5,11 @@ using Ocelot.Library.Infrastructure.Responses; namespace Ocelot.Library.Infrastructure.Authentication { - public class AuthenticationProviderFactory : IAuthenticationProviderFactory + public class AuthenticationHandlerFactory : IAuthenticationHandlerFactory { private readonly IAuthenticationHandlerCreator _creator; - public AuthenticationProviderFactory(IAuthenticationHandlerCreator creator) + public AuthenticationHandlerFactory(IAuthenticationHandlerCreator creator) { _creator = creator; } diff --git a/src/Ocelot.Library/Infrastructure/Authentication/IAuthenticationProviderFactory.cs b/src/Ocelot.Library/Infrastructure/Authentication/IAuthenticationHandlerFactory.cs similarity index 82% rename from src/Ocelot.Library/Infrastructure/Authentication/IAuthenticationProviderFactory.cs rename to src/Ocelot.Library/Infrastructure/Authentication/IAuthenticationHandlerFactory.cs index e9a25a54..6fc2af29 100644 --- a/src/Ocelot.Library/Infrastructure/Authentication/IAuthenticationProviderFactory.cs +++ b/src/Ocelot.Library/Infrastructure/Authentication/IAuthenticationHandlerFactory.cs @@ -3,7 +3,7 @@ using Ocelot.Library.Infrastructure.Responses; namespace Ocelot.Library.Infrastructure.Authentication { - public interface IAuthenticationProviderFactory + public interface IAuthenticationHandlerFactory { Response Get(string provider, IApplicationBuilder app); } diff --git a/src/Ocelot.Library/Infrastructure/Middleware/AuthenticationMiddleware.cs b/src/Ocelot.Library/Infrastructure/Middleware/AuthenticationMiddleware.cs index be8f54be..896d1be3 100644 --- a/src/Ocelot.Library/Infrastructure/Middleware/AuthenticationMiddleware.cs +++ b/src/Ocelot.Library/Infrastructure/Middleware/AuthenticationMiddleware.cs @@ -22,15 +22,15 @@ namespace Ocelot.Library.Infrastructure.Middleware private RequestDelegate _authenticationNext; private readonly IScopedRequestDataRepository _scopedRequestDataRepository; private readonly IApplicationBuilder _app; - private readonly IAuthenticationProviderFactory _authProviderFactory; + private readonly IAuthenticationHandlerFactory _authHandlerFactory; public AuthenticationMiddleware(RequestDelegate next, IApplicationBuilder app, - IScopedRequestDataRepository scopedRequestDataRepository, IAuthenticationProviderFactory authProviderFactory) + IScopedRequestDataRepository scopedRequestDataRepository, IAuthenticationHandlerFactory authHandlerFactory) : base(scopedRequestDataRepository) { _next = next; _scopedRequestDataRepository = scopedRequestDataRepository; - _authProviderFactory = authProviderFactory; + _authHandlerFactory = authHandlerFactory; _app = app; } @@ -46,7 +46,7 @@ namespace Ocelot.Library.Infrastructure.Middleware if (IsAuthenticatedRoute(downstreamRoute.Data.ReRoute)) { - var authenticationNext = _authProviderFactory.Get(downstreamRoute.Data.ReRoute.AuthenticationProvider, _app); + var authenticationNext = _authHandlerFactory.Get(downstreamRoute.Data.ReRoute.AuthenticationProvider, _app); if (!authenticationNext.IsError) { diff --git a/src/Ocelot/Startup.cs b/src/Ocelot/Startup.cs index 35934de3..fc8a9d0f 100644 --- a/src/Ocelot/Startup.cs +++ b/src/Ocelot/Startup.cs @@ -57,7 +57,7 @@ namespace Ocelot services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); // see this for why we register this as singleton http://stackoverflow.com/questions/37371264/invalidoperationexception-unable-to-resolve-service-for-type-microsoft-aspnetc diff --git a/test/Ocelot.UnitTests/Authentication/AuthenticationProviderFactoryTests.cs b/test/Ocelot.UnitTests/Authentication/AuthenticationHandlerFactoryTests.cs similarity index 85% rename from test/Ocelot.UnitTests/Authentication/AuthenticationProviderFactoryTests.cs rename to test/Ocelot.UnitTests/Authentication/AuthenticationHandlerFactoryTests.cs index 752aca0b..028d07d9 100644 --- a/test/Ocelot.UnitTests/Authentication/AuthenticationProviderFactoryTests.cs +++ b/test/Ocelot.UnitTests/Authentication/AuthenticationHandlerFactoryTests.cs @@ -12,24 +12,24 @@ using Xunit; namespace Ocelot.UnitTests.Authentication { - public class AuthenticationProviderFactoryTests + public class AuthenticationHandlerFactoryTests { - private readonly IAuthenticationProviderFactory _authenticationProviderFactory; + private readonly IAuthenticationHandlerFactory _authenticationHandlerFactory; private readonly Mock _app; private readonly Mock _creator; private string _provider; private Response _result; - public AuthenticationProviderFactoryTests() + public AuthenticationHandlerFactoryTests() { _app = new Mock(); _creator = new Mock(); - _authenticationProviderFactory = new AuthenticationProviderFactory(_creator.Object); + _authenticationHandlerFactory = new AuthenticationHandlerFactory(_creator.Object); } [Fact] - public void should_return_identity_server_access_token_provider() + public void should_return_identity_server_access_token_handler() { this.Given(x => x.GivenTheProviderIs("IdentityServer.AccessToken")) .And(x => x.GivenTheCreatorReturns()) @@ -72,7 +72,7 @@ namespace Ocelot.UnitTests.Authentication private void WhenIGetFromTheFactory() { - _result = _authenticationProviderFactory.Get(_provider, _app.Object); + _result = _authenticationHandlerFactory.Get(_provider, _app.Object); } private void ThenTheHandlerIsReturned(string expected) diff --git a/test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs index 6c82b0fe..793bd66a 100644 --- a/test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs @@ -22,7 +22,7 @@ namespace Ocelot.UnitTests.Middleware public class AuthenticationMiddlewareTests : IDisposable { private readonly Mock _scopedRepository; - private readonly Mock _authFactory; + private readonly Mock _authFactory; private readonly string _url; private readonly TestServer _server; private readonly HttpClient _client; @@ -33,7 +33,7 @@ namespace Ocelot.UnitTests.Middleware { _url = "http://localhost:51879"; _scopedRepository = new Mock(); - _authFactory = new Mock(); + _authFactory = new Mock(); var builder = new WebHostBuilder() .ConfigureServices(x => { From ce84ad4fc2440854c90e64e00b6a36545601dfb3 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Sun, 16 Oct 2016 20:28:23 +0100 Subject: [PATCH 086/183] Added tests for identity server reference tokens, general refactoring and come config validation --- README.md | 17 ++- .../AuthenticationHandlerCreator.cs | 15 ++- .../AuthenticationHandlerFactory.cs | 9 +- .../IAuthenticationHandlerCreator.cs | 3 +- .../IAuthenticationHandlerFactory.cs | 3 +- .../SupportAuthenticationProviders.cs | 7 ++ .../Infrastructure/Builder/ReRouteBuilder.cs | 64 ++++++++-- .../Configuration/AuthenticationOptions.cs | 25 ++++ .../Configuration/OcelotConfiguration.cs | 88 +++++++++----- .../Infrastructure/Configuration/ReRoute.cs | 6 +- .../Yaml/ConfigurationValidator.cs | 75 ++++++++++-- .../UnsupportedAuthenticationProviderError.cs | 12 ++ .../Yaml/YamlAuthenticationOptions.cs | 14 +++ .../Configuration/Yaml/YamlReRoute.cs | 2 +- .../Infrastructure/Errors/OcelotErrorCode.cs | 3 +- .../Middleware/AuthenticationMiddleware.cs | 11 +- src/Ocelot/Startup.cs | 4 +- .../AuthenticationTests.cs | 115 ++++++++++++++++-- .../AuthenticationHandlerFactoryTests.cs | 25 ++-- .../ConfigurationValidationTests.cs | 47 +++++++ .../Configuration/OcelotConfigurationTests.cs | 45 ++++++- .../DownstreamRouteFinderTests.cs | 63 +++++++--- .../AuthenticationMiddlewareTests.cs | 3 +- .../DownstreamRouteFinderMiddlewareTests.cs | 35 +++--- .../DownstreamUrlCreatorMiddlewareTests.cs | 5 +- ...eamUrlPathTemplateVariableReplacerTests.cs | 19 +-- 26 files changed, 565 insertions(+), 150 deletions(-) create mode 100644 src/Ocelot.Library/Infrastructure/Authentication/SupportAuthenticationProviders.cs create mode 100644 src/Ocelot.Library/Infrastructure/Configuration/AuthenticationOptions.cs create mode 100644 src/Ocelot.Library/Infrastructure/Configuration/Yaml/UnsupportedAuthenticationProviderError.cs create mode 100644 src/Ocelot.Library/Infrastructure/Configuration/Yaml/YamlAuthenticationOptions.cs diff --git a/README.md b/README.md index 39e5fc35..9bbaf309 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,19 @@ Priorities - Rate Limiting - Then a big list of cool things... -## How to use +# How to use -TBC.... +# Configuration + +TBC really but example configuration for a route below. + +ReRoutes: +- DownstreamTemplate: http://localhost:51876/ + UpstreamTemplate: / + UpstreamHttpMethod: Post + AuthenticationOptions: + Provider: IdentityServer.AccessToken + ProviderRootUrl: http://localhost:51888 + ScopeName: api + AdditionalScopes: [] + ScopeSecret: secret diff --git a/src/Ocelot.Library/Infrastructure/Authentication/AuthenticationHandlerCreator.cs b/src/Ocelot.Library/Infrastructure/Authentication/AuthenticationHandlerCreator.cs index 1428f239..ef0f9722 100644 --- a/src/Ocelot.Library/Infrastructure/Authentication/AuthenticationHandlerCreator.cs +++ b/src/Ocelot.Library/Infrastructure/Authentication/AuthenticationHandlerCreator.cs @@ -1,6 +1,8 @@ +using IdentityServer4.AccessTokenValidation; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Ocelot.Library.Infrastructure.Responses; +using AuthenticationOptions = Ocelot.Library.Infrastructure.Configuration.AuthenticationOptions; namespace Ocelot.Library.Infrastructure.Authentication { @@ -9,17 +11,18 @@ namespace Ocelot.Library.Infrastructure.Authentication /// public class AuthenticationHandlerCreator : IAuthenticationHandlerCreator { - public Response CreateIdentityServerAuthenticationHandler(IApplicationBuilder app) + public Response CreateIdentityServerAuthenticationHandler(IApplicationBuilder app, AuthenticationOptions authOptions) { var builder = app.New(); builder.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions { - //todo sort these options out - Authority = "http://localhost:51888", - ScopeName = "api", - - RequireHttpsMetadata = false + Authority = authOptions.ProviderRootUrl, + ScopeName = authOptions.ScopeName, + RequireHttpsMetadata = authOptions.RequireHttps, + AdditionalScopes = authOptions.AdditionalScopes, + SupportedTokens = SupportedTokens.Both, + ScopeSecret = authOptions.ScopeSecret }); builder.UseMvc(); diff --git a/src/Ocelot.Library/Infrastructure/Authentication/AuthenticationHandlerFactory.cs b/src/Ocelot.Library/Infrastructure/Authentication/AuthenticationHandlerFactory.cs index eaa8837b..1f606938 100644 --- a/src/Ocelot.Library/Infrastructure/Authentication/AuthenticationHandlerFactory.cs +++ b/src/Ocelot.Library/Infrastructure/Authentication/AuthenticationHandlerFactory.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using Microsoft.AspNetCore.Builder; using Ocelot.Library.Infrastructure.Errors; using Ocelot.Library.Infrastructure.Responses; +using AuthenticationOptions = Ocelot.Library.Infrastructure.Configuration.AuthenticationOptions; namespace Ocelot.Library.Infrastructure.Authentication { @@ -14,18 +15,18 @@ namespace Ocelot.Library.Infrastructure.Authentication _creator = creator; } - public Response Get(string provider, IApplicationBuilder app) + public Response Get(IApplicationBuilder app, AuthenticationOptions authOptions) { - var handler = _creator.CreateIdentityServerAuthenticationHandler(app); + var handler = _creator.CreateIdentityServerAuthenticationHandler(app, authOptions); if (!handler.IsError) { - return new OkResponse(new AuthenticationHandler(provider, handler.Data)); + return new OkResponse(new AuthenticationHandler(authOptions.Provider, handler.Data)); } return new ErrorResponse(new List { - new UnableToCreateAuthenticationHandlerError($"Unable to create authentication handler for {provider}") + new UnableToCreateAuthenticationHandlerError($"Unable to create authentication handler for {authOptions.Provider}") }); } } diff --git a/src/Ocelot.Library/Infrastructure/Authentication/IAuthenticationHandlerCreator.cs b/src/Ocelot.Library/Infrastructure/Authentication/IAuthenticationHandlerCreator.cs index cb1b2a91..553386d7 100644 --- a/src/Ocelot.Library/Infrastructure/Authentication/IAuthenticationHandlerCreator.cs +++ b/src/Ocelot.Library/Infrastructure/Authentication/IAuthenticationHandlerCreator.cs @@ -1,11 +1,12 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Ocelot.Library.Infrastructure.Responses; +using AuthenticationOptions = Ocelot.Library.Infrastructure.Configuration.AuthenticationOptions; namespace Ocelot.Library.Infrastructure.Authentication { public interface IAuthenticationHandlerCreator { - Response CreateIdentityServerAuthenticationHandler(IApplicationBuilder app); + Response CreateIdentityServerAuthenticationHandler(IApplicationBuilder app, AuthenticationOptions authOptions); } } diff --git a/src/Ocelot.Library/Infrastructure/Authentication/IAuthenticationHandlerFactory.cs b/src/Ocelot.Library/Infrastructure/Authentication/IAuthenticationHandlerFactory.cs index 6fc2af29..87f62346 100644 --- a/src/Ocelot.Library/Infrastructure/Authentication/IAuthenticationHandlerFactory.cs +++ b/src/Ocelot.Library/Infrastructure/Authentication/IAuthenticationHandlerFactory.cs @@ -1,10 +1,11 @@ using Microsoft.AspNetCore.Builder; using Ocelot.Library.Infrastructure.Responses; +using AuthenticationOptions = Ocelot.Library.Infrastructure.Configuration.AuthenticationOptions; namespace Ocelot.Library.Infrastructure.Authentication { public interface IAuthenticationHandlerFactory { - Response Get(string provider, IApplicationBuilder app); + Response Get(IApplicationBuilder app, AuthenticationOptions authOptions); } } diff --git a/src/Ocelot.Library/Infrastructure/Authentication/SupportAuthenticationProviders.cs b/src/Ocelot.Library/Infrastructure/Authentication/SupportAuthenticationProviders.cs new file mode 100644 index 00000000..01ff98d0 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Authentication/SupportAuthenticationProviders.cs @@ -0,0 +1,7 @@ +namespace Ocelot.Library.Infrastructure.Authentication +{ + public enum SupportAuthenticationProviders + { + IdentityServer + } +} diff --git a/src/Ocelot.Library/Infrastructure/Builder/ReRouteBuilder.cs b/src/Ocelot.Library/Infrastructure/Builder/ReRouteBuilder.cs index 3966ae7c..ee01b7d6 100644 --- a/src/Ocelot.Library/Infrastructure/Builder/ReRouteBuilder.cs +++ b/src/Ocelot.Library/Infrastructure/Builder/ReRouteBuilder.cs @@ -1,4 +1,6 @@ -namespace Ocelot.Library.Infrastructure.Builder +using System.Collections.Generic; + +namespace Ocelot.Library.Infrastructure.Builder { using Configuration; @@ -10,38 +12,84 @@ private string _upstreamHttpMethod; private bool _isAuthenticated; private string _authenticationProvider; + private string _authenticationProviderUrl; + private string _scopeName; + private List _additionalScopes; + private bool _requireHttps; + private string _scopeSecret; - public void WithDownstreamTemplate(string input) + public ReRouteBuilder() + { + _additionalScopes = new List(); + } + + public ReRouteBuilder WithDownstreamTemplate(string input) { _downstreamTemplate = input; + return this; } - public void WithUpstreamTemplate(string input) + public ReRouteBuilder WithUpstreamTemplate(string input) { _upstreamTemplate = input; + return this; } - public void WithUpstreamTemplatePattern(string input) + public ReRouteBuilder WithUpstreamTemplatePattern(string input) { _upstreamTemplatePattern = input; + return this; } - public void WithUpstreamHttpMethod(string input) + public ReRouteBuilder WithUpstreamHttpMethod(string input) { _upstreamHttpMethod = input; + return this; } - public void WithIsAuthenticated(bool input) + public ReRouteBuilder WithIsAuthenticated(bool input) { _isAuthenticated = input; + return this; } - public void WithAuthenticationProvider(string input) + public ReRouteBuilder WithAuthenticationProvider(string input) { _authenticationProvider = input; + return this; + } + + public ReRouteBuilder WithAuthenticationProviderUrl(string input) + { + _authenticationProviderUrl = input; + return this; + } + + public ReRouteBuilder WithAuthenticationProviderScopeName(string input) + { + _scopeName = input; + return this; + } + + public ReRouteBuilder WithAuthenticationProviderAdditionalScopes(List input) + { + _additionalScopes = input; + return this; + } + + public ReRouteBuilder WithRequireHttps(bool input) + { + _requireHttps = input; + return this; + } + + public ReRouteBuilder WithScopeSecret(string input) + { + _scopeSecret = input; + return this; } public ReRoute Build() { - return new ReRoute(_downstreamTemplate, _upstreamTemplate, _upstreamHttpMethod, _upstreamTemplatePattern, _isAuthenticated, _authenticationProvider); + return new ReRoute(_downstreamTemplate, _upstreamTemplate, _upstreamHttpMethod, _upstreamTemplatePattern, _isAuthenticated, new AuthenticationOptions(_authenticationProvider, _authenticationProviderUrl, _scopeName, _requireHttps, _additionalScopes, _scopeSecret)); } } } diff --git a/src/Ocelot.Library/Infrastructure/Configuration/AuthenticationOptions.cs b/src/Ocelot.Library/Infrastructure/Configuration/AuthenticationOptions.cs new file mode 100644 index 00000000..9cda2672 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Configuration/AuthenticationOptions.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; + +namespace Ocelot.Library.Infrastructure.Configuration +{ + public class AuthenticationOptions + { + public AuthenticationOptions(string provider, string providerRootUrl, string scopeName, bool requireHttps, List additionalScopes, string scopeSecret) + { + Provider = provider; + ProviderRootUrl = providerRootUrl; + ScopeName = scopeName; + RequireHttps = requireHttps; + AdditionalScopes = additionalScopes; + ScopeSecret = scopeSecret; + } + + public string Provider { get; private set; } + public string ProviderRootUrl { get; private set; } + public string ScopeName { get; private set; } + public string ScopeSecret { get; private set; } + public bool RequireHttps { get; private set; } + public List AdditionalScopes { get; private set; } + + } +} diff --git a/src/Ocelot.Library/Infrastructure/Configuration/OcelotConfiguration.cs b/src/Ocelot.Library/Infrastructure/Configuration/OcelotConfiguration.cs index 1b93447a..afa768d2 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/OcelotConfiguration.cs +++ b/src/Ocelot.Library/Infrastructure/Configuration/OcelotConfiguration.cs @@ -7,49 +7,81 @@ namespace Ocelot.Library.Infrastructure.Configuration public class OcelotConfiguration : IOcelotConfiguration { private readonly IOptions _options; + private readonly IConfigurationValidator _configurationValidator; private readonly List _reRoutes; private const string RegExMatchEverything = ".*"; private const string RegExMatchEndString = "$"; - public OcelotConfiguration(IOptions options) + public OcelotConfiguration(IOptions options, IConfigurationValidator configurationValidator) { _options = options; + _configurationValidator = configurationValidator; _reRoutes = new List(); - SetReRoutes(); + SetUpConfiguration(); } - private void SetReRoutes() + /// + /// This method is meant to be tempoary to convert a yaml config to an ocelot config...probably wont keep this but we will see + /// will need a refactor at some point as its crap + /// + private void SetUpConfiguration() { - foreach(var reRoute in _options.Value.ReRoutes) + var response = _configurationValidator.IsValid(_options.Value); + + if (!response.IsError && !response.Data.IsError) { - var upstreamTemplate = reRoute.UpstreamTemplate; - var placeholders = new List(); - - for (int i = 0; i < upstreamTemplate.Length; i++) + foreach (var reRoute in _options.Value.ReRoutes) { - if (IsPlaceHolder(upstreamTemplate, i)) - { - var postitionOfPlaceHolderClosingBracket = upstreamTemplate.IndexOf('}', i); - var difference = postitionOfPlaceHolderClosingBracket - i + 1; - var variableName = upstreamTemplate.Substring(i, difference); - placeholders.Add(variableName); - } + SetUpReRoute(reRoute); } - - foreach (var placeholder in placeholders) - { - upstreamTemplate = upstreamTemplate.Replace(placeholder, RegExMatchEverything); - } - - upstreamTemplate = $"{upstreamTemplate}{RegExMatchEndString}"; - - var isAuthenticated = !string.IsNullOrEmpty(reRoute.Authentication); - - _reRoutes.Add(new ReRoute(reRoute.DownstreamTemplate, reRoute.UpstreamTemplate, reRoute.UpstreamHttpMethod, upstreamTemplate, isAuthenticated, reRoute.Authentication)); - } + } } - private static bool IsPlaceHolder(string upstreamTemplate, int i) + private void SetUpReRoute(YamlReRoute reRoute) + { + var upstreamTemplate = reRoute.UpstreamTemplate; + + var placeholders = new List(); + + for (int i = 0; i < upstreamTemplate.Length; i++) + { + if (IsPlaceHolder(upstreamTemplate, i)) + { + var postitionOfPlaceHolderClosingBracket = upstreamTemplate.IndexOf('}', i); + var difference = postitionOfPlaceHolderClosingBracket - i + 1; + var variableName = upstreamTemplate.Substring(i, difference); + placeholders.Add(variableName); + } + } + + foreach (var placeholder in placeholders) + { + upstreamTemplate = upstreamTemplate.Replace(placeholder, RegExMatchEverything); + } + + upstreamTemplate = $"{upstreamTemplate}{RegExMatchEndString}"; + + var isAuthenticated = !string.IsNullOrEmpty(reRoute.AuthenticationOptions?.Provider); + + if (isAuthenticated) + { + var authOptionsForRoute = new AuthenticationOptions(reRoute.AuthenticationOptions.Provider, + reRoute.AuthenticationOptions.ProviderRootUrl, reRoute.AuthenticationOptions.ScopeName, + reRoute.AuthenticationOptions.RequireHttps, reRoute.AuthenticationOptions.AdditionalScopes, + reRoute.AuthenticationOptions.ScopeSecret); + + _reRoutes.Add(new ReRoute(reRoute.DownstreamTemplate, reRoute.UpstreamTemplate, + reRoute.UpstreamHttpMethod, upstreamTemplate, isAuthenticated, authOptionsForRoute + )); + } + else + { + _reRoutes.Add(new ReRoute(reRoute.DownstreamTemplate, reRoute.UpstreamTemplate, reRoute.UpstreamHttpMethod, + upstreamTemplate, isAuthenticated, null)); + } + } + + private bool IsPlaceHolder(string upstreamTemplate, int i) { return upstreamTemplate[i] == '{'; } diff --git a/src/Ocelot.Library/Infrastructure/Configuration/ReRoute.cs b/src/Ocelot.Library/Infrastructure/Configuration/ReRoute.cs index 5d000511..12dfd1b2 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/ReRoute.cs +++ b/src/Ocelot.Library/Infrastructure/Configuration/ReRoute.cs @@ -2,14 +2,14 @@ { public class ReRoute { - public ReRoute(string downstreamTemplate, string upstreamTemplate, string upstreamHttpMethod, string upstreamTemplatePattern, bool isAuthenticated, string authenticationProvider) + public ReRoute(string downstreamTemplate, string upstreamTemplate, string upstreamHttpMethod, string upstreamTemplatePattern, bool isAuthenticated, AuthenticationOptions authenticationOptions) { DownstreamTemplate = downstreamTemplate; UpstreamTemplate = upstreamTemplate; UpstreamHttpMethod = upstreamHttpMethod; UpstreamTemplatePattern = upstreamTemplatePattern; IsAuthenticated = isAuthenticated; - AuthenticationProvider = authenticationProvider; + AuthenticationOptions = authenticationOptions; } public string DownstreamTemplate { get; private set; } @@ -17,6 +17,6 @@ public string UpstreamTemplatePattern { get; private set; } public string UpstreamHttpMethod { get; private set; } public bool IsAuthenticated { get; private set; } - public string AuthenticationProvider { get; private set; } + public AuthenticationOptions AuthenticationOptions { get; private set; } } } \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/ConfigurationValidator.cs b/src/Ocelot.Library/Infrastructure/Configuration/Yaml/ConfigurationValidator.cs index 64b72929..6c7aee98 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/ConfigurationValidator.cs +++ b/src/Ocelot.Library/Infrastructure/Configuration/Yaml/ConfigurationValidator.cs @@ -1,5 +1,7 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; +using Ocelot.Library.Infrastructure.Authentication; using Ocelot.Library.Infrastructure.Errors; using Ocelot.Library.Infrastructure.Responses; @@ -8,6 +10,59 @@ namespace Ocelot.Library.Infrastructure.Configuration.Yaml public class ConfigurationValidator : IConfigurationValidator { public Response IsValid(YamlConfiguration configuration) + { + var result = CheckForDupliateReRoutes(configuration); + + if (result.IsError) + { + return new OkResponse(result); + } + + result = CheckForUnsupportedAuthenticationProviders(configuration); + + if (result.IsError) + { + return new OkResponse(result); + } + + return new OkResponse(result); + } + + private ConfigurationValidationResult CheckForUnsupportedAuthenticationProviders(YamlConfiguration configuration) + { + var errors = new List(); + + foreach (var yamlReRoute in configuration.ReRoutes) + { + var isAuthenticated = !string.IsNullOrEmpty(yamlReRoute.AuthenticationOptions?.Provider); + + if (!isAuthenticated) + { + continue; + } + + if (IsSupportedAuthenticationProvider(yamlReRoute.AuthenticationOptions?.Provider)) + { + continue; + } + + var error = new UnsupportedAuthenticationProviderError($"{yamlReRoute.AuthenticationOptions?.Provider} is unsupported authentication provider, upstream template is {yamlReRoute.UpstreamTemplate}, upstream method is {yamlReRoute.UpstreamHttpMethod}"); + errors.Add(error); + } + + return errors.Count > 0 + ? new ConfigurationValidationResult(true, errors) + : new ConfigurationValidationResult(false); + } + + private bool IsSupportedAuthenticationProvider(string provider) + { + SupportAuthenticationProviders supportedProvider; + + return Enum.TryParse(provider, true, out supportedProvider); + } + + private ConfigurationValidationResult CheckForDupliateReRoutes(YamlConfiguration configuration) { var duplicateUpstreamTemplates = configuration.ReRoutes .Select(r => r.DownstreamTemplate) @@ -18,19 +73,15 @@ namespace Ocelot.Library.Infrastructure.Configuration.Yaml if (duplicateUpstreamTemplates.Count <= 0) { - return new OkResponse(new ConfigurationValidationResult(false)); - } - - var errors = new List(); - - foreach (var duplicateUpstreamTemplate in duplicateUpstreamTemplates) - { - var error = new DownstreamTemplateAlreadyUsedError(string.Format("Duplicate DownstreamTemplate: {0}", - duplicateUpstreamTemplate)); - errors.Add(error); + return new ConfigurationValidationResult(false); } - return new OkResponse(new ConfigurationValidationResult(true, errors)); + var errors = duplicateUpstreamTemplates + .Select(duplicateUpstreamTemplate => new DownstreamTemplateAlreadyUsedError(string.Format("Duplicate DownstreamTemplate: {0}", duplicateUpstreamTemplate))) + .Cast() + .ToList(); + + return new ConfigurationValidationResult(true, errors); } } } diff --git a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/UnsupportedAuthenticationProviderError.cs b/src/Ocelot.Library/Infrastructure/Configuration/Yaml/UnsupportedAuthenticationProviderError.cs new file mode 100644 index 00000000..1964ef80 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Configuration/Yaml/UnsupportedAuthenticationProviderError.cs @@ -0,0 +1,12 @@ +using Ocelot.Library.Infrastructure.Errors; + +namespace Ocelot.Library.Infrastructure.Configuration.Yaml +{ + public class UnsupportedAuthenticationProviderError : Error + { + public UnsupportedAuthenticationProviderError(string message) + : base(message, OcelotErrorCode.UnsupportedAuthenticationProviderError) + { + } + } +} diff --git a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/YamlAuthenticationOptions.cs b/src/Ocelot.Library/Infrastructure/Configuration/Yaml/YamlAuthenticationOptions.cs new file mode 100644 index 00000000..463a75f5 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Configuration/Yaml/YamlAuthenticationOptions.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; + +namespace Ocelot.Library.Infrastructure.Configuration.Yaml +{ + public class YamlAuthenticationOptions + { + public string Provider { get; set; } + public string ProviderRootUrl { get; set; } + public string ScopeName { get; set; } + public bool RequireHttps { get; set; } + public List AdditionalScopes { get; set; } + public string ScopeSecret { get; set; } + } +} diff --git a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/YamlReRoute.cs b/src/Ocelot.Library/Infrastructure/Configuration/Yaml/YamlReRoute.cs index 0c1e1e12..26c1569b 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/YamlReRoute.cs +++ b/src/Ocelot.Library/Infrastructure/Configuration/Yaml/YamlReRoute.cs @@ -5,6 +5,6 @@ public string DownstreamTemplate { get; set; } public string UpstreamTemplate { get; set; } public string UpstreamHttpMethod { get; set; } - public string Authentication { get; set; } + public YamlAuthenticationOptions AuthenticationOptions { get; set; } } } \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Errors/OcelotErrorCode.cs b/src/Ocelot.Library/Infrastructure/Errors/OcelotErrorCode.cs index 4f7a1fd7..01ddfa39 100644 --- a/src/Ocelot.Library/Infrastructure/Errors/OcelotErrorCode.cs +++ b/src/Ocelot.Library/Infrastructure/Errors/OcelotErrorCode.cs @@ -9,6 +9,7 @@ CannotAddDataError, CannotFindDataError, UnableToCompleteRequestError, - UnableToCreateAuthenticationHandlerError + UnableToCreateAuthenticationHandlerError, + UnsupportedAuthenticationProviderError } } diff --git a/src/Ocelot.Library/Infrastructure/Middleware/AuthenticationMiddleware.cs b/src/Ocelot.Library/Infrastructure/Middleware/AuthenticationMiddleware.cs index 896d1be3..89bdd875 100644 --- a/src/Ocelot.Library/Infrastructure/Middleware/AuthenticationMiddleware.cs +++ b/src/Ocelot.Library/Infrastructure/Middleware/AuthenticationMiddleware.cs @@ -1,25 +1,18 @@ using System.Collections.Generic; -using System.IdentityModel.Tokens.Jwt; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; +using Ocelot.Library.Infrastructure.Authentication; using Ocelot.Library.Infrastructure.Configuration; using Ocelot.Library.Infrastructure.DownstreamRouteFinder; using Ocelot.Library.Infrastructure.Errors; using Ocelot.Library.Infrastructure.Repository; -using Ocelot.Library.Infrastructure.Responses; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Ocelot.Library.Infrastructure.Authentication; namespace Ocelot.Library.Infrastructure.Middleware { public class AuthenticationMiddleware : OcelotMiddleware { private readonly RequestDelegate _next; - private RequestDelegate _authenticationNext; private readonly IScopedRequestDataRepository _scopedRequestDataRepository; private readonly IApplicationBuilder _app; private readonly IAuthenticationHandlerFactory _authHandlerFactory; @@ -46,7 +39,7 @@ namespace Ocelot.Library.Infrastructure.Middleware if (IsAuthenticatedRoute(downstreamRoute.Data.ReRoute)) { - var authenticationNext = _authHandlerFactory.Get(downstreamRoute.Data.ReRoute.AuthenticationProvider, _app); + var authenticationNext = _authHandlerFactory.Get(_app, downstreamRoute.Data.ReRoute.AuthenticationOptions); if (!authenticationNext.IsError) { diff --git a/src/Ocelot/Startup.cs b/src/Ocelot/Startup.cs index fc8a9d0f..1ea234e3 100644 --- a/src/Ocelot/Startup.cs +++ b/src/Ocelot/Startup.cs @@ -43,11 +43,13 @@ namespace Ocelot services.AddOptions(); services.AddMvc(); services.AddMvcCore().AddAuthorization().AddJsonFormatters(); + services.AddAuthentication(); + services.AddLogging(); services.Configure(Configuration); - services.AddAuthentication(); // Add framework services. + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs index bfefdc7f..b38b70a7 100644 --- a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs +++ b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs @@ -43,7 +43,7 @@ namespace Ocelot.AcceptanceTests [Fact] public void should_return_401_using_identity_server_access_token() { - this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888")) + this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Jwt)) .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 201, string.Empty)) .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration { @@ -54,7 +54,48 @@ namespace Ocelot.AcceptanceTests DownstreamTemplate = "http://localhost:51876/", UpstreamTemplate = "/", UpstreamHttpMethod = "Post", - Authentication = "JwtBearerAuthentication" + AuthenticationOptions = new YamlAuthenticationOptions + { + AdditionalScopes = new List(), + Provider = "IdentityServer", + ProviderRootUrl = "http://localhost:51888", + RequireHttps = false, + ScopeName = "api", + ScopeSecret = "secret" + } + } + } + })) + .And(x => x.GivenTheApiGatewayIsRunning()) + .And(x => x.GivenThePostHasContent("postContent")) + .When(x => x.WhenIPostUrlOnTheApiGateway("/")) + .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.Unauthorized)) + .BDDfy(); + } + + [Fact] + public void should_return_401_using_identity_server_reference_token() + { + this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Reference)) + .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 201, string.Empty)) + .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration + { + ReRoutes = new List + { + new YamlReRoute + { + DownstreamTemplate = "http://localhost:51876/", + UpstreamTemplate = "/", + UpstreamHttpMethod = "Post", + AuthenticationOptions = new YamlAuthenticationOptions + { + AdditionalScopes = new List(), + Provider = "IdentityServer", + ProviderRootUrl = "http://localhost:51888", + RequireHttps = false, + ScopeName = "api", + ScopeSecret = "secret" + } } } })) @@ -68,7 +109,7 @@ namespace Ocelot.AcceptanceTests [Fact] public void should_return_201_using_identity_server_access_token() { - this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888")) + this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Jwt)) .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 201, string.Empty)) .And(x => x.GivenIHaveAToken("http://localhost:51888")) .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration @@ -80,7 +121,50 @@ namespace Ocelot.AcceptanceTests DownstreamTemplate = "http://localhost:51876/", UpstreamTemplate = "/", UpstreamHttpMethod = "Post", - Authentication = "JwtBearerAuthentication" + AuthenticationOptions = new YamlAuthenticationOptions + { + AdditionalScopes = new List(), + Provider = "IdentityServer", + ProviderRootUrl = "http://localhost:51888", + RequireHttps = false, + ScopeName = "api", + ScopeSecret = "secret" + } + } + } + })) + .And(x => x.GivenTheApiGatewayIsRunning()) + .And(x => x.GivenIHaveAddedATokenToMyRequest()) + .And(x => x.GivenThePostHasContent("postContent")) + .When(x => x.WhenIPostUrlOnTheApiGateway("/")) + .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.Created)) + .BDDfy(); + } + + [Fact] + public void should_return_201_using_identity_server_reference_token() + { + this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Reference)) + .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 201, string.Empty)) + .And(x => x.GivenIHaveAToken("http://localhost:51888")) + .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration + { + ReRoutes = new List + { + new YamlReRoute + { + DownstreamTemplate = "http://localhost:51876/", + UpstreamTemplate = "/", + UpstreamHttpMethod = "Post", + AuthenticationOptions = new YamlAuthenticationOptions + { + AdditionalScopes = new List(), + Provider = "IdentityServer", + ProviderRootUrl = "http://localhost:51888", + RequireHttps = false, + ScopeName = "api", + ScopeSecret = "secret" + } } } })) @@ -144,7 +228,7 @@ namespace Ocelot.AcceptanceTests _ocelotBbuilder.Start(); } - private void GivenThereIsAnIdentityServerOn(string url) + private void GivenThereIsAnIdentityServerOn(string url, string scopeName, AccessTokenType tokenType) { _identityServerBuilder = new WebHostBuilder() .UseUrls(url) @@ -154,13 +238,21 @@ namespace Ocelot.AcceptanceTests .UseUrls(url) .ConfigureServices(services => { + services.AddLogging(); services.AddDeveloperIdentityServer() .AddInMemoryScopes(new List { new Scope { - Name = "api", + Name = scopeName, Description = "My API", - Enabled = true - + Enabled = true, + AllowUnrestrictedIntrospection = true, + ScopeSecrets = new List() + { + new Secret + { + Value = "secret".Sha256() + } + } }}) .AddInMemoryClients(new List { new Client @@ -168,8 +260,8 @@ namespace Ocelot.AcceptanceTests ClientId = "client", AllowedGrantTypes = GrantTypes.ResourceOwnerPassword, ClientSecrets = new List { new Secret("secret".Sha256()) }, - AllowedScopes = new List { "api" }, - AccessTokenType = AccessTokenType.Jwt, + AllowedScopes = new List { scopeName }, + AccessTokenType = tokenType, Enabled = true, RequireClientSecret = false } }) @@ -182,7 +274,7 @@ namespace Ocelot.AcceptanceTests }}); }) .Configure(app => - { + { app.UseIdentityServer(); }) .Build(); @@ -248,6 +340,7 @@ namespace Ocelot.AcceptanceTests _identityServerBuilder?.Dispose(); } + // ReSharper disable once ClassNeverInstantiated.Local class BearerToken { [JsonProperty("access_token")] diff --git a/test/Ocelot.UnitTests/Authentication/AuthenticationHandlerFactoryTests.cs b/test/Ocelot.UnitTests/Authentication/AuthenticationHandlerFactoryTests.cs index 028d07d9..1e2f6d42 100644 --- a/test/Ocelot.UnitTests/Authentication/AuthenticationHandlerFactoryTests.cs +++ b/test/Ocelot.UnitTests/Authentication/AuthenticationHandlerFactoryTests.cs @@ -17,8 +17,7 @@ namespace Ocelot.UnitTests.Authentication private readonly IAuthenticationHandlerFactory _authenticationHandlerFactory; private readonly Mock _app; private readonly Mock _creator; - - private string _provider; + private Library.Infrastructure.Configuration.AuthenticationOptions _authenticationOptions; private Response _result; public AuthenticationHandlerFactoryTests() @@ -31,27 +30,32 @@ namespace Ocelot.UnitTests.Authentication [Fact] public void should_return_identity_server_access_token_handler() { - this.Given(x => x.GivenTheProviderIs("IdentityServer.AccessToken")) + this.Given(x => x.GivenTheAuthenticationOptionsAre(new Library.Infrastructure.Configuration.AuthenticationOptions("IdentityServer", "","",false, new List(), ""))) .And(x => x.GivenTheCreatorReturns()) .When(x => x.WhenIGetFromTheFactory()) - .Then(x => x.ThenTheHandlerIsReturned("IdentityServer.AccessToken")) + .Then(x => x.ThenTheHandlerIsReturned("IdentityServer")) .BDDfy(); } [Fact] public void should_return_error_if_cannot_create_handler() { - this.Given(x => x.GivenTheProviderIs("IdentityServer.AccessToken")) + this.Given(x => x.GivenTheAuthenticationOptionsAre(new Library.Infrastructure.Configuration.AuthenticationOptions("IdentityServer", "", "", false, new List(), ""))) .And(x => x.GivenTheCreatorReturnsAnError()) .When(x => x.WhenIGetFromTheFactory()) .Then(x => x.ThenAnErrorResponseIsReturned()) .BDDfy(); } + private void GivenTheAuthenticationOptionsAre(Library.Infrastructure.Configuration.AuthenticationOptions authenticationOptions) + { + _authenticationOptions = authenticationOptions; + } + private void GivenTheCreatorReturnsAnError() { _creator - .Setup(x => x.CreateIdentityServerAuthenticationHandler(It.IsAny())) + .Setup(x => x.CreateIdentityServerAuthenticationHandler(It.IsAny(), It.IsAny())) .Returns(new ErrorResponse(new List { new UnableToCreateAuthenticationHandlerError($"Unable to create authentication handler for xxx") @@ -61,18 +65,13 @@ namespace Ocelot.UnitTests.Authentication private void GivenTheCreatorReturns() { _creator - .Setup(x => x.CreateIdentityServerAuthenticationHandler(It.IsAny())) + .Setup(x => x.CreateIdentityServerAuthenticationHandler(It.IsAny(), It.IsAny())) .Returns(new OkResponse(x => Task.CompletedTask)); } - private void GivenTheProviderIs(string provider) - { - _provider = provider; - } - private void WhenIGetFromTheFactory() { - _result = _authenticationHandlerFactory.Get(_provider, _app.Object); + _result = _authenticationHandlerFactory.Get(_app.Object, _authenticationOptions); } private void ThenTheHandlerIsReturned(string expected) diff --git a/test/Ocelot.UnitTests/Configuration/ConfigurationValidationTests.cs b/test/Ocelot.UnitTests/Configuration/ConfigurationValidationTests.cs index 3f3526e8..b797a9bf 100644 --- a/test/Ocelot.UnitTests/Configuration/ConfigurationValidationTests.cs +++ b/test/Ocelot.UnitTests/Configuration/ConfigurationValidationTests.cs @@ -37,6 +37,53 @@ namespace Ocelot.UnitTests.Configuration .BDDfy(); } + [Fact] + public void configuration_is_valid_with_valid_authentication_provider() + { + this.Given(x => x.GivenAConfiguration(new YamlConfiguration() + { + ReRoutes = new List + { + new YamlReRoute + { + DownstreamTemplate = "http://www.bbc.co.uk", + UpstreamTemplate = "http://asdf.com", + AuthenticationOptions = new YamlAuthenticationOptions + { + Provider = "IdentityServer" + } + } + } + })) + .When(x => x.WhenIValidateTheConfiguration()) + .Then(x => x.ThenTheResultIsValid()) + .BDDfy(); + } + + [Fact] + public void configuration_is_invalid_with_invalid_authentication_provider() + { + this.Given(x => x.GivenAConfiguration(new YamlConfiguration() + { + ReRoutes = new List + { + new YamlReRoute + { + DownstreamTemplate = "http://www.bbc.co.uk", + UpstreamTemplate = "http://asdf.com", + AuthenticationOptions = new YamlAuthenticationOptions + { + Provider = "BootyBootyBottyRockinEverywhere" + } + } + } + })) + .When(x => x.WhenIValidateTheConfiguration()) + .Then(x => x.ThenTheResultIsNotValid()) + .And(x => x.ThenTheErrorIs()) + .BDDfy(); + } + [Fact] public void configuration_is_not_valid_with_duplicate_reroutes() { diff --git a/test/Ocelot.UnitTests/Configuration/OcelotConfigurationTests.cs b/test/Ocelot.UnitTests/Configuration/OcelotConfigurationTests.cs index 2977f54f..bfbeee98 100644 --- a/test/Ocelot.UnitTests/Configuration/OcelotConfigurationTests.cs +++ b/test/Ocelot.UnitTests/Configuration/OcelotConfigurationTests.cs @@ -1,8 +1,10 @@ using System.Collections.Generic; using Microsoft.Extensions.Options; using Moq; +using Ocelot.Library.Infrastructure.Builder; using Ocelot.Library.Infrastructure.Configuration; using Ocelot.Library.Infrastructure.Configuration.Yaml; +using Ocelot.Library.Infrastructure.Responses; using Shouldly; using TestStack.BDDfy; using Xunit; @@ -12,11 +14,13 @@ namespace Ocelot.UnitTests.Configuration public class OcelotConfigurationTests { private readonly Mock> _yamlConfig; + private readonly Mock _validator; private OcelotConfiguration _config; private YamlConfiguration _yamlConfiguration; public OcelotConfigurationTests() { + _validator = new Mock(); _yamlConfig = new Mock>(); } @@ -35,10 +39,16 @@ namespace Ocelot.UnitTests.Configuration } } })) + .And(x => x.GivenTheYamlConfigIsValid()) .When(x => x.WhenIInstanciateTheOcelotConfig()) .Then(x => x.ThenTheReRoutesAre(new List { - new ReRoute("/products/{productId}","/api/products/{productId}", "Get", "/api/products/.*$", false, "") + new ReRouteBuilder() + .WithDownstreamTemplate("/products/{productId}") + .WithUpstreamTemplate("/api/products/{productId}") + .WithUpstreamHttpMethod("Get") + .WithUpstreamTemplatePattern("/api/products/.*$") + .Build() })) .BDDfy(); } @@ -58,10 +68,16 @@ namespace Ocelot.UnitTests.Configuration } } })) + .And(x => x.GivenTheYamlConfigIsValid()) .When(x => x.WhenIInstanciateTheOcelotConfig()) .Then(x => x.ThenTheReRoutesAre(new List { - new ReRoute("/products/{productId}","/api/products/{productId}/variants/{variantId}", "Get", "/api/products/.*/variants/.*$", false, "") + new ReRouteBuilder() + .WithDownstreamTemplate("/products/{productId}") + .WithUpstreamTemplate("/api/products/{productId}/variants/{variantId}") + .WithUpstreamHttpMethod("Get") + .WithUpstreamTemplatePattern("/api/products/.*/variants/.*$") + .Build() })) .BDDfy(); } @@ -81,10 +97,16 @@ namespace Ocelot.UnitTests.Configuration } } })) + .And(x => x.GivenTheYamlConfigIsValid()) .When(x => x.WhenIInstanciateTheOcelotConfig()) .Then(x => x.ThenTheReRoutesAre(new List { - new ReRoute("/products/{productId}","/api/products/{productId}/variants/{variantId}/", "Get", "/api/products/.*/variants/.*/$", false, "") + new ReRouteBuilder() + .WithDownstreamTemplate("/products/{productId}") + .WithUpstreamTemplate("/api/products/{productId}/variants/{variantId}/") + .WithUpstreamHttpMethod("Get") + .WithUpstreamTemplatePattern("/api/products/.*/variants/.*/$") + .Build() })) .BDDfy(); } @@ -104,14 +126,27 @@ namespace Ocelot.UnitTests.Configuration } } })) + .And(x => x.GivenTheYamlConfigIsValid()) .When(x => x.WhenIInstanciateTheOcelotConfig()) .Then(x => x.ThenTheReRoutesAre(new List { - new ReRoute("/api/products/","/", "Get", "/$", false, "") + new ReRouteBuilder() + .WithDownstreamTemplate("/api/products/") + .WithUpstreamTemplate("/") + .WithUpstreamHttpMethod("Get") + .WithUpstreamTemplatePattern("/$") + .Build() })) .BDDfy(); } + private void GivenTheYamlConfigIsValid() + { + _validator + .Setup(x => x.IsValid(It.IsAny())) + .Returns(new OkResponse(new ConfigurationValidationResult(false))); + } + private void GivenTheYamlConfigIs(YamlConfiguration yamlConfiguration) { _yamlConfiguration = yamlConfiguration; @@ -122,7 +157,7 @@ namespace Ocelot.UnitTests.Configuration private void WhenIInstanciateTheOcelotConfig() { - _config = new OcelotConfiguration(_yamlConfig.Object); + _config = new OcelotConfiguration(_yamlConfig.Object, _validator.Object); } private void ThenTheReRoutesAre(List expectedReRoutes) diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs index 127ec7d8..5a2a73cd 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using Moq; +using Ocelot.Library.Infrastructure.Builder; using Ocelot.Library.Infrastructure.Configuration; using Ocelot.Library.Infrastructure.DownstreamRouteFinder; using Ocelot.Library.Infrastructure.Responses; @@ -34,17 +35,29 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder public void should_return_route() { this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath")) - .And(x => x.GivenTheTemplateVariableAndNameFinderReturns(new OkResponse>(new List()))) + .And( + x => + x.GivenTheTemplateVariableAndNameFinderReturns( + new OkResponse>(new List()))) .And(x => x.GivenTheConfigurationIs(new List - { - new ReRoute("someDownstreamPath","someUpstreamPath", "Get", "someUpstreamPath", false, "") - } - )) + { + new ReRouteBuilder() + .WithDownstreamTemplate("someDownstreamPath") + .WithUpstreamTemplate("someUpstreamPath") + .WithUpstreamHttpMethod("Get") + .WithUpstreamTemplatePattern("someUpstreamPath") + .Build() + } + )) .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true)))) .And(x => x.GivenTheUpstreamHttpMethodIs("Get")) .When(x => x.WhenICallTheFinder()) .Then( - x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List(), new ReRoute("someDownstreamPath","","","",false, "")))) + x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List(), + new ReRouteBuilder() + .WithDownstreamTemplate("someDownstreamPath") + .Build() + ))) .And(x => x.ThenTheUrlMatcherIsCalledCorrectly()) .BDDfy(); } @@ -53,18 +66,35 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder public void should_return_correct_route_for_http_verb() { this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath")) - .And(x => x.GivenTheTemplateVariableAndNameFinderReturns(new OkResponse>(new List()))) + .And( + x => + x.GivenTheTemplateVariableAndNameFinderReturns( + new OkResponse>(new List()))) .And(x => x.GivenTheConfigurationIs(new List - { - new ReRoute("someDownstreamPath", "someUpstreamPath", "Get", string.Empty, false, ""), - new ReRoute("someDownstreamPathForAPost", "someUpstreamPath", "Post", string.Empty, false, "") - } - )) + { + new ReRouteBuilder() + .WithDownstreamTemplate("someDownstreamPath") + .WithUpstreamTemplate("someUpstreamPath") + .WithUpstreamHttpMethod("Get") + .WithUpstreamTemplatePattern("") + .Build(), + new ReRouteBuilder() + .WithDownstreamTemplate("someDownstreamPathForAPost") + .WithUpstreamTemplate("someUpstreamPath") + .WithUpstreamHttpMethod("Post") + .WithUpstreamTemplatePattern("") + .Build() + } + )) .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true)))) .And(x => x.GivenTheUpstreamHttpMethodIs("Post")) .When(x => x.WhenICallTheFinder()) .Then( - x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List(), new ReRoute("someDownstreamPathForAPost", "","","",false, "")))) + x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List(), + new ReRouteBuilder() + .WithDownstreamTemplate("someDownstreamPathForAPost") + .Build() + ))) .BDDfy(); } @@ -74,7 +104,12 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder this.Given(x => x.GivenThereIsAnUpstreamUrlPath("somePath")) .And(x => x.GivenTheConfigurationIs(new List { - new ReRoute("somPath", "somePath", "Get", "somePath", false, "") + new ReRouteBuilder() + .WithDownstreamTemplate("somPath") + .WithUpstreamTemplate("somePath") + .WithUpstreamHttpMethod("Get") + .WithUpstreamTemplatePattern("somePath") + .Build(), } )) .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(false)))) diff --git a/test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs index 793bd66a..3adf0c61 100644 --- a/test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs @@ -7,6 +7,7 @@ using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Moq; using Ocelot.Library.Infrastructure.Authentication; +using Ocelot.Library.Infrastructure.Builder; using Ocelot.Library.Infrastructure.DownstreamRouteFinder; using Ocelot.Library.Infrastructure.Middleware; using Ocelot.Library.Infrastructure.Repository; @@ -57,7 +58,7 @@ namespace Ocelot.UnitTests.Middleware [Fact] public void happy_path() { - this.Given(x => x.GivenTheDownStreamRouteIs(new DownstreamRoute(new List(), new ReRoute("","","","",false, "")))) + 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/Middleware/DownstreamRouteFinderMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/DownstreamRouteFinderMiddlewareTests.cs index ec48f886..07ca69e4 100644 --- a/test/Ocelot.UnitTests/Middleware/DownstreamRouteFinderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Middleware/DownstreamRouteFinderMiddlewareTests.cs @@ -1,23 +1,22 @@ -using Ocelot.Library.Infrastructure.Middleware; +using System; +using System.Collections.Generic; +using System.IO; +using System.Net.Http; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using Moq; +using Ocelot.Library.Infrastructure.Builder; +using Ocelot.Library.Infrastructure.DownstreamRouteFinder; +using Ocelot.Library.Infrastructure.Middleware; +using Ocelot.Library.Infrastructure.Repository; +using Ocelot.Library.Infrastructure.Responses; +using Ocelot.Library.Infrastructure.UrlMatcher; +using TestStack.BDDfy; +using Xunit; namespace Ocelot.UnitTests.Middleware { - using System; - using System.Collections.Generic; - using System.IO; - using System.Net.Http; - using Library.Infrastructure.Configuration; - using Library.Infrastructure.DownstreamRouteFinder; - using Library.Infrastructure.Repository; - using Library.Infrastructure.Responses; - using Library.Infrastructure.UrlMatcher; - using Microsoft.AspNetCore.Hosting; - using Microsoft.AspNetCore.TestHost; - using Microsoft.Extensions.DependencyInjection; - using Moq; - using TestStack.BDDfy; - using Xunit; - public class DownstreamRouteFinderMiddlewareTests : IDisposable { private readonly Mock _downstreamRouteFinder; @@ -57,7 +56,7 @@ namespace Ocelot.UnitTests.Middleware [Fact] public void happy_path() { - this.Given(x => x.GivenTheDownStreamRouteFinderReturns(new DownstreamRoute(new List(), new ReRoute("any old string", "", "", "",false, "")))) + 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/Middleware/DownstreamUrlCreatorMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/DownstreamUrlCreatorMiddlewareTests.cs index d9545f2f..b1d165ba 100644 --- a/test/Ocelot.UnitTests/Middleware/DownstreamUrlCreatorMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Middleware/DownstreamUrlCreatorMiddlewareTests.cs @@ -1,4 +1,5 @@ -using Ocelot.Library.Infrastructure.Middleware; +using Ocelot.Library.Infrastructure.Builder; +using Ocelot.Library.Infrastructure.Middleware; namespace Ocelot.UnitTests.Middleware { @@ -59,7 +60,7 @@ namespace Ocelot.UnitTests.Middleware [Fact] public void happy_path() { - this.Given(x => x.GivenTheDownStreamRouteIs(new DownstreamRoute(new List(), new ReRoute("any old string", "", "", "", false, "")))) + 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()) diff --git a/test/Ocelot.UnitTests/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs b/test/Ocelot.UnitTests/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs index 18bf22d8..961341c9 100644 --- a/test/Ocelot.UnitTests/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs +++ b/test/Ocelot.UnitTests/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Ocelot.Library.Infrastructure.Builder; using Ocelot.Library.Infrastructure.DownstreamRouteFinder; using Ocelot.Library.Infrastructure.Responses; using Ocelot.Library.Infrastructure.UrlMatcher; @@ -25,7 +26,7 @@ namespace Ocelot.UnitTests.UrlTemplateReplacer [Fact] public void can_replace_no_template_variables() { - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), new ReRoute("", "", "", "", false, "")))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), new ReRouteBuilder().Build()))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("")) .BDDfy(); @@ -34,7 +35,7 @@ namespace Ocelot.UnitTests.UrlTemplateReplacer [Fact] public void can_replace_no_template_variables_with_slash() { - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), new ReRoute("/", "", "", "", false, "")))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), new ReRouteBuilder().WithDownstreamTemplate("/").Build()))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("/")) .BDDfy(); @@ -43,7 +44,7 @@ namespace Ocelot.UnitTests.UrlTemplateReplacer [Fact] public void can_replace_url_no_slash() { - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), new ReRoute("api", "", "", "", false, "")))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), new ReRouteBuilder().WithDownstreamTemplate("api").Build()))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api")) .BDDfy(); @@ -52,7 +53,7 @@ namespace Ocelot.UnitTests.UrlTemplateReplacer [Fact] public void can_replace_url_one_slash() { - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), new ReRoute("api/", "", "", "", false, "")))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), new ReRouteBuilder().WithDownstreamTemplate("api/").Build()))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api/")) .BDDfy(); @@ -61,7 +62,7 @@ namespace Ocelot.UnitTests.UrlTemplateReplacer [Fact] public void can_replace_url_multiple_slash() { - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), new ReRoute("api/product/products/", "", "", "", false, "")))) + 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(); @@ -75,7 +76,7 @@ namespace Ocelot.UnitTests.UrlTemplateReplacer new TemplateVariableNameAndValue("{productId}", "1") }; - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, new ReRoute("productservice/products/{productId}/", "", "", "", false, "")))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, new ReRouteBuilder().WithDownstreamTemplate("productservice/products/{productId}/").Build()))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/")) .BDDfy(); @@ -89,7 +90,7 @@ namespace Ocelot.UnitTests.UrlTemplateReplacer new TemplateVariableNameAndValue("{productId}", "1") }; - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, new ReRoute("productservice/products/{productId}/variants", "", "", "", false, "")))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, new ReRouteBuilder().WithDownstreamTemplate("productservice/products/{productId}/variants").Build()))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/variants")) .BDDfy(); @@ -104,7 +105,7 @@ namespace Ocelot.UnitTests.UrlTemplateReplacer new TemplateVariableNameAndValue("{variantId}", "12") }; - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, new ReRoute("productservice/products/{productId}/variants/{variantId}", "", "", "", false, "")))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, new ReRouteBuilder().WithDownstreamTemplate("productservice/products/{productId}/variants/{variantId}").Build()))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/variants/12")) .BDDfy(); @@ -120,7 +121,7 @@ namespace Ocelot.UnitTests.UrlTemplateReplacer new TemplateVariableNameAndValue("{categoryId}", "34") }; - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, new ReRoute("productservice/category/{categoryId}/products/{productId}/variants/{variantId}", "", "", "", false, "")))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, new ReRouteBuilder().WithDownstreamTemplate("productservice/category/{categoryId}/products/{productId}/variants/{variantId}").Build()))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/category/34/products/1/variants/12")) .BDDfy(); From 3d60602c7e141a7eb17049b5469540beaf16036c Mon Sep 17 00:00:00 2001 From: "tom.pallister" Date: Mon, 17 Oct 2016 18:00:36 +0100 Subject: [PATCH 087/183] Added a get authentication test, removed the infrastructure name space as it seemed pointless, started thinking about how to pass claims on with the request --- .../Authentication/AuthenticationHandler.cs | 6 +- .../AuthenticationHandlerCreator.cs | 14 +- .../AuthenticationHandlerFactory.cs | 14 +- .../IAuthenticationHandlerCreator.cs | 12 ++ .../IAuthenticationHandlerFactory.cs | 11 ++ .../SupportAuthenticationProviders.cs | 2 +- ...nableToCreateAuthenticationHandlerError.cs | 6 +- .../Builder/ReRouteBuilder.cs | 5 +- .../Configuration/AuthenticationOptions.cs | 6 +- .../Configuration/IOcelotConfiguration.cs | 6 +- .../Configuration/OcelotConfiguration.cs | 10 +- .../Configuration/ReRoute.cs | 2 +- .../Yaml/ConfigurationValidationResult.cs | 9 +- .../Yaml/ConfigurationValidator.cs | 16 +- .../DownstreamTemplateAlreadyUsedError.cs | 7 +- .../Yaml/IConfigurationValidator.cs | 6 +- .../UnsupportedAuthenticationProviderError.cs | 6 +- .../Yaml/YamlAuthenticationOptions.cs | 6 +- .../Configuration/Yaml/YamlConfiguration.cs | 6 +- .../Configuration/Yaml/YamlReRoute.cs | 2 +- .../ServiceCollectionExtensions.cs | 44 ++++++ .../DownstreamRouteFinder/DownstreamRoute.cs | 7 +- .../DownstreamRouteFinder.cs | 19 ++- .../IDownstreamRouteFinder.cs | 6 +- .../UnableToFindDownstreamRouteError.cs | 11 ++ .../{Infrastructure => }/Errors/Error.cs | 2 +- .../Errors/OcelotErrorCode.cs | 2 +- .../IAuthenticationHandlerCreator.cs | 12 -- .../IAuthenticationHandlerFactory.cs | 11 -- .../UnableToFindDownstreamRouteError.cs | 16 -- .../Requester/IHttpRequester.cs | 12 -- .../IErrorsToHttpStatusCodeMapper.cs | 11 -- .../IUrlPathToUrlTemplateMatcher.cs | 9 -- ...wnstreamUrlPathTemplateVariableReplacer.cs | 10 -- .../Middleware/AuthenticationMiddleware.cs | 22 +-- ...nticationMiddlewareMiddlewareExtensions.cs | 6 +- .../Middleware/ClaimsParserMiddleware.cs | 23 +++ .../DownstreamRouteFinderMiddleware.cs | 12 +- ...wnstreamRouteFinderMiddlewareExtensions.cs | 6 +- .../DownstreamUrlCreatorMiddleware.cs | 14 +- ...ownstreamUrlCreatorMiddlewareExtensions.cs | 6 +- .../HttpRequestBuilderMiddleware.cs | 12 +- .../HttpRequestBuilderMiddlewareExtensions.cs | 6 +- .../Middleware/HttpRequesterMiddleware.cs | 14 +- .../HttpRequesterMiddlewareExtensions.cs | 6 +- .../Middleware/HttpResponderMiddleware.cs | 14 +- .../HttpResponderMiddlewareExtensions.cs | 6 +- .../Middleware/OcelotMiddleware.cs | 11 +- .../Middleware/OcelotMiddlewareExtensions.cs | 24 +++ .../Middleware/UnauthenticatedError.cs | 6 +- .../Repository/CannotAddDataError.cs | 7 +- .../Repository/CannotFindDataError.cs | 7 +- .../IScopedRequestDataRepository.cs | 6 +- .../Repository/ScopedRequestDataRepository.cs | 14 +- .../RequestBuilder/HttpRequestBuilder.cs | 20 +-- .../RequestBuilder/IRequestBuilder.cs | 12 +- .../RequestBuilder/Request.cs | 8 +- .../Requester/HttpClientHttpRequester.cs | 18 +-- .../Requester/IHttpRequester.cs | 12 ++ .../Requester/UnableToCompleteRequestError.cs | 9 +- .../Responder/ErrorsToHttpStatusCodeMapper.cs | 12 +- .../Responder/HttpContextResponder.cs | 10 +- .../IErrorsToHttpStatusCodeMapper.cs | 11 ++ .../Responder/IHttpResponder.cs | 10 +- .../Responses/ErrorResponse.cs | 8 +- .../Responses/ErrorResponseGeneric.cs | 8 +- .../Responses/OkResponse.cs | 2 +- .../Responses/OkResponseGeneric.cs | 2 +- .../Responses/Response.cs | 8 +- .../Responses/ResponseGeneric.cs | 8 +- .../ITemplateVariableNameAndValueFinder.cs | 8 +- .../IUrlPathToUrlTemplateMatcher.cs | 9 ++ .../UrlMatcher/RegExUrlMatcher.cs | 8 +- .../TemplateVariableNameAndValue.cs | 2 +- .../TemplateVariableNameAndValueFinder.cs | 10 +- .../UrlMatcher/UrlMatch.cs | 2 +- .../DownstreamUrlTemplateVariableReplacer.cs | 10 +- ...wnstreamUrlPathTemplateVariableReplacer.cs | 10 ++ src/Ocelot/Startup.cs | 53 +------ .../AuthenticationTests.cs | 139 +++++++++++++----- test/Ocelot.AcceptanceTests/OcelotTests.cs | 3 +- .../AuthenticationHandlerFactoryTests.cs | 20 +-- .../ConfigurationValidationTests.cs | 5 +- .../Configuration/OcelotConfigurationTests.cs | 9 +- .../DownstreamRouteFinderTests.cs | 13 +- .../AuthenticationMiddlewareTests.cs | 15 +- .../DownstreamRouteFinderMiddlewareTests.cs | 13 +- .../DownstreamUrlCreatorMiddlewareTests.cs | 18 +-- .../HttpRequestBuilderMiddlewareTests.cs | 9 +- .../HttpRequesterMiddlewareTests.cs | 11 +- .../HttpResponderMiddlewareTests.cs | 9 +- .../ScopedRequestDataRepositoryTests.cs | 5 +- .../RequestBuilder/RequestBuilderTests.cs | 7 +- .../ErrorsToHttpStatusCodeMapperTests.cs | 9 +- .../UrlMatcher/RegExUrlMatcherTests.cs | 5 +- ...TemplateVariableNameAndValueFinderTests.cs | 5 +- ...eamUrlPathTemplateVariableReplacerTests.cs | 11 +- 97 files changed, 614 insertions(+), 508 deletions(-) rename src/Ocelot.Library/{Infrastructure => }/Authentication/AuthenticationHandler.cs (78%) rename src/Ocelot.Library/{Infrastructure => }/Authentication/AuthenticationHandlerCreator.cs (76%) rename src/Ocelot.Library/{Infrastructure => }/Authentication/AuthenticationHandlerFactory.cs (75%) create mode 100644 src/Ocelot.Library/Authentication/IAuthenticationHandlerCreator.cs create mode 100644 src/Ocelot.Library/Authentication/IAuthenticationHandlerFactory.cs rename src/Ocelot.Library/{Infrastructure => }/Authentication/SupportAuthenticationProviders.cs (59%) rename src/Ocelot.Library/{Infrastructure => }/Authentication/UnableToCreateAuthenticationHandlerError.cs (71%) rename src/Ocelot.Library/{Infrastructure => }/Builder/ReRouteBuilder.cs (96%) rename src/Ocelot.Library/{Infrastructure => }/Configuration/AuthenticationOptions.cs (90%) rename src/Ocelot.Library/{Infrastructure => }/Configuration/IOcelotConfiguration.cs (52%) rename src/Ocelot.Library/{Infrastructure => }/Configuration/OcelotConfiguration.cs (95%) rename src/Ocelot.Library/{Infrastructure => }/Configuration/ReRoute.cs (94%) rename src/Ocelot.Library/{Infrastructure => }/Configuration/Yaml/ConfigurationValidationResult.cs (72%) rename src/Ocelot.Library/{Infrastructure => }/Configuration/Yaml/ConfigurationValidator.cs (91%) rename src/Ocelot.Library/{Infrastructure => }/Configuration/Yaml/DownstreamTemplateAlreadyUsedError.cs (60%) rename src/Ocelot.Library/{Infrastructure => }/Configuration/Yaml/IConfigurationValidator.cs (58%) rename src/Ocelot.Library/{Infrastructure => }/Configuration/Yaml/UnsupportedAuthenticationProviderError.cs (70%) rename src/Ocelot.Library/{Infrastructure => }/Configuration/Yaml/YamlAuthenticationOptions.cs (78%) rename src/Ocelot.Library/{Infrastructure => }/Configuration/Yaml/YamlConfiguration.cs (68%) rename src/Ocelot.Library/{Infrastructure => }/Configuration/Yaml/YamlReRoute.cs (82%) create mode 100644 src/Ocelot.Library/DependencyInjection/ServiceCollectionExtensions.cs rename src/Ocelot.Library/{Infrastructure => }/DownstreamRouteFinder/DownstreamRoute.cs (76%) rename src/Ocelot.Library/{Infrastructure => }/DownstreamRouteFinder/DownstreamRouteFinder.cs (82%) rename src/Ocelot.Library/{Infrastructure => }/DownstreamRouteFinder/IDownstreamRouteFinder.cs (59%) create mode 100644 src/Ocelot.Library/DownstreamRouteFinder/UnableToFindDownstreamRouteError.cs rename src/Ocelot.Library/{Infrastructure => }/Errors/Error.cs (86%) rename src/Ocelot.Library/{Infrastructure => }/Errors/OcelotErrorCode.cs (88%) delete mode 100644 src/Ocelot.Library/Infrastructure/Authentication/IAuthenticationHandlerCreator.cs delete mode 100644 src/Ocelot.Library/Infrastructure/Authentication/IAuthenticationHandlerFactory.cs delete mode 100644 src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/UnableToFindDownstreamRouteError.cs delete mode 100644 src/Ocelot.Library/Infrastructure/Requester/IHttpRequester.cs delete mode 100644 src/Ocelot.Library/Infrastructure/Responder/IErrorsToHttpStatusCodeMapper.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs rename src/Ocelot.Library/{Infrastructure => }/Middleware/AuthenticationMiddleware.cs (83%) rename src/Ocelot.Library/{Infrastructure => }/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs (76%) create mode 100644 src/Ocelot.Library/Middleware/ClaimsParserMiddleware.cs rename src/Ocelot.Library/{Infrastructure => }/Middleware/DownstreamRouteFinderMiddleware.cs (85%) rename src/Ocelot.Library/{Infrastructure => }/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs (76%) rename src/Ocelot.Library/{Infrastructure => }/Middleware/DownstreamUrlCreatorMiddleware.cs (83%) rename src/Ocelot.Library/{Infrastructure => }/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs (76%) rename src/Ocelot.Library/{Infrastructure => }/Middleware/HttpRequestBuilderMiddleware.cs (87%) rename src/Ocelot.Library/{Infrastructure => }/Middleware/HttpRequestBuilderMiddlewareExtensions.cs (76%) rename src/Ocelot.Library/{Infrastructure => }/Middleware/HttpRequesterMiddleware.cs (82%) rename src/Ocelot.Library/{Infrastructure => }/Middleware/HttpRequesterMiddlewareExtensions.cs (75%) rename src/Ocelot.Library/{Infrastructure => }/Middleware/HttpResponderMiddleware.cs (87%) rename src/Ocelot.Library/{Infrastructure => }/Middleware/HttpResponderMiddlewareExtensions.cs (75%) rename src/Ocelot.Library/{Infrastructure => }/Middleware/OcelotMiddleware.cs (80%) create mode 100644 src/Ocelot.Library/Middleware/OcelotMiddlewareExtensions.cs rename src/Ocelot.Library/{Infrastructure => }/Middleware/UnauthenticatedError.cs (65%) rename src/Ocelot.Library/{Infrastructure => }/Repository/CannotAddDataError.cs (55%) rename src/Ocelot.Library/{Infrastructure => }/Repository/CannotFindDataError.cs (56%) rename src/Ocelot.Library/{Infrastructure => }/Repository/IScopedRequestDataRepository.cs (60%) rename src/Ocelot.Library/{Infrastructure => }/Repository/ScopedRequestDataRepository.cs (85%) rename src/Ocelot.Library/{Infrastructure => }/RequestBuilder/HttpRequestBuilder.cs (88%) rename src/Ocelot.Library/{Infrastructure => }/RequestBuilder/IRequestBuilder.cs (63%) rename src/Ocelot.Library/{Infrastructure => }/RequestBuilder/Request.cs (80%) rename src/Ocelot.Library/{Infrastructure => }/Requester/HttpClientHttpRequester.cs (75%) create mode 100644 src/Ocelot.Library/Requester/IHttpRequester.cs rename src/Ocelot.Library/{Infrastructure => }/Requester/UnableToCompleteRequestError.cs (64%) rename src/Ocelot.Library/{Infrastructure => }/Responder/ErrorsToHttpStatusCodeMapper.cs (65%) rename src/Ocelot.Library/{Infrastructure => }/Responder/HttpContextResponder.cs (88%) create mode 100644 src/Ocelot.Library/Responder/IErrorsToHttpStatusCodeMapper.cs rename src/Ocelot.Library/{Infrastructure => }/Responder/IHttpResponder.cs (62%) rename src/Ocelot.Library/{Infrastructure => }/Responses/ErrorResponse.cs (52%) rename src/Ocelot.Library/{Infrastructure => }/Responses/ErrorResponseGeneric.cs (53%) rename src/Ocelot.Library/{Infrastructure => }/Responses/OkResponse.cs (67%) rename src/Ocelot.Library/{Infrastructure => }/Responses/OkResponseGeneric.cs (71%) rename src/Ocelot.Library/{Infrastructure => }/Responses/Response.cs (77%) rename src/Ocelot.Library/{Infrastructure => }/Responses/ResponseGeneric.cs (68%) rename src/Ocelot.Library/{Infrastructure => }/UrlMatcher/ITemplateVariableNameAndValueFinder.cs (58%) create mode 100644 src/Ocelot.Library/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs rename src/Ocelot.Library/{Infrastructure => }/UrlMatcher/RegExUrlMatcher.cs (75%) rename src/Ocelot.Library/{Infrastructure => }/UrlMatcher/TemplateVariableNameAndValue.cs (89%) rename src/Ocelot.Library/{Infrastructure => }/UrlMatcher/TemplateVariableNameAndValueFinder.cs (93%) rename src/Ocelot.Library/{Infrastructure => }/UrlMatcher/UrlMatch.cs (76%) rename src/Ocelot.Library/{Infrastructure => }/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs (78%) create mode 100644 src/Ocelot.Library/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs diff --git a/src/Ocelot.Library/Infrastructure/Authentication/AuthenticationHandler.cs b/src/Ocelot.Library/Authentication/AuthenticationHandler.cs similarity index 78% rename from src/Ocelot.Library/Infrastructure/Authentication/AuthenticationHandler.cs rename to src/Ocelot.Library/Authentication/AuthenticationHandler.cs index 3830e33a..8a2a505e 100644 --- a/src/Ocelot.Library/Infrastructure/Authentication/AuthenticationHandler.cs +++ b/src/Ocelot.Library/Authentication/AuthenticationHandler.cs @@ -1,7 +1,7 @@ -using Microsoft.AspNetCore.Http; - -namespace Ocelot.Library.Infrastructure.Authentication +namespace Ocelot.Library.Authentication { + using Microsoft.AspNetCore.Http; + public class AuthenticationHandler { public AuthenticationHandler(string provider, RequestDelegate handler) diff --git a/src/Ocelot.Library/Infrastructure/Authentication/AuthenticationHandlerCreator.cs b/src/Ocelot.Library/Authentication/AuthenticationHandlerCreator.cs similarity index 76% rename from src/Ocelot.Library/Infrastructure/Authentication/AuthenticationHandlerCreator.cs rename to src/Ocelot.Library/Authentication/AuthenticationHandlerCreator.cs index ef0f9722..fd49bf7d 100644 --- a/src/Ocelot.Library/Infrastructure/Authentication/AuthenticationHandlerCreator.cs +++ b/src/Ocelot.Library/Authentication/AuthenticationHandlerCreator.cs @@ -1,11 +1,11 @@ -using IdentityServer4.AccessTokenValidation; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Ocelot.Library.Infrastructure.Responses; -using AuthenticationOptions = Ocelot.Library.Infrastructure.Configuration.AuthenticationOptions; - -namespace Ocelot.Library.Infrastructure.Authentication +namespace Ocelot.Library.Authentication { + using IdentityServer4.AccessTokenValidation; + using Microsoft.AspNetCore.Builder; + using Microsoft.AspNetCore.Http; + using Responses; + using AuthenticationOptions = Configuration.AuthenticationOptions; + /// /// Cannot unit test things in this class due to use of extension methods /// diff --git a/src/Ocelot.Library/Infrastructure/Authentication/AuthenticationHandlerFactory.cs b/src/Ocelot.Library/Authentication/AuthenticationHandlerFactory.cs similarity index 75% rename from src/Ocelot.Library/Infrastructure/Authentication/AuthenticationHandlerFactory.cs rename to src/Ocelot.Library/Authentication/AuthenticationHandlerFactory.cs index 1f606938..109d750e 100644 --- a/src/Ocelot.Library/Infrastructure/Authentication/AuthenticationHandlerFactory.cs +++ b/src/Ocelot.Library/Authentication/AuthenticationHandlerFactory.cs @@ -1,11 +1,11 @@ -using System.Collections.Generic; -using Microsoft.AspNetCore.Builder; -using Ocelot.Library.Infrastructure.Errors; -using Ocelot.Library.Infrastructure.Responses; -using AuthenticationOptions = Ocelot.Library.Infrastructure.Configuration.AuthenticationOptions; - -namespace Ocelot.Library.Infrastructure.Authentication +namespace Ocelot.Library.Authentication { + using System.Collections.Generic; + using Errors; + using Microsoft.AspNetCore.Builder; + using Responses; + using AuthenticationOptions = Configuration.AuthenticationOptions; + public class AuthenticationHandlerFactory : IAuthenticationHandlerFactory { private readonly IAuthenticationHandlerCreator _creator; diff --git a/src/Ocelot.Library/Authentication/IAuthenticationHandlerCreator.cs b/src/Ocelot.Library/Authentication/IAuthenticationHandlerCreator.cs new file mode 100644 index 00000000..5789ecf6 --- /dev/null +++ b/src/Ocelot.Library/Authentication/IAuthenticationHandlerCreator.cs @@ -0,0 +1,12 @@ +namespace Ocelot.Library.Authentication +{ + using Microsoft.AspNetCore.Builder; + using Microsoft.AspNetCore.Http; + using Responses; + using AuthenticationOptions = Configuration.AuthenticationOptions; + + public interface IAuthenticationHandlerCreator + { + Response CreateIdentityServerAuthenticationHandler(IApplicationBuilder app, AuthenticationOptions authOptions); + } +} diff --git a/src/Ocelot.Library/Authentication/IAuthenticationHandlerFactory.cs b/src/Ocelot.Library/Authentication/IAuthenticationHandlerFactory.cs new file mode 100644 index 00000000..ea583487 --- /dev/null +++ b/src/Ocelot.Library/Authentication/IAuthenticationHandlerFactory.cs @@ -0,0 +1,11 @@ +namespace Ocelot.Library.Authentication +{ + using Microsoft.AspNetCore.Builder; + using Responses; + using AuthenticationOptions = Configuration.AuthenticationOptions; + + public interface IAuthenticationHandlerFactory + { + Response Get(IApplicationBuilder app, AuthenticationOptions authOptions); + } +} diff --git a/src/Ocelot.Library/Infrastructure/Authentication/SupportAuthenticationProviders.cs b/src/Ocelot.Library/Authentication/SupportAuthenticationProviders.cs similarity index 59% rename from src/Ocelot.Library/Infrastructure/Authentication/SupportAuthenticationProviders.cs rename to src/Ocelot.Library/Authentication/SupportAuthenticationProviders.cs index 01ff98d0..e9eea91b 100644 --- a/src/Ocelot.Library/Infrastructure/Authentication/SupportAuthenticationProviders.cs +++ b/src/Ocelot.Library/Authentication/SupportAuthenticationProviders.cs @@ -1,4 +1,4 @@ -namespace Ocelot.Library.Infrastructure.Authentication +namespace Ocelot.Library.Authentication { public enum SupportAuthenticationProviders { diff --git a/src/Ocelot.Library/Infrastructure/Authentication/UnableToCreateAuthenticationHandlerError.cs b/src/Ocelot.Library/Authentication/UnableToCreateAuthenticationHandlerError.cs similarity index 71% rename from src/Ocelot.Library/Infrastructure/Authentication/UnableToCreateAuthenticationHandlerError.cs rename to src/Ocelot.Library/Authentication/UnableToCreateAuthenticationHandlerError.cs index 5637ef73..bcda8ef6 100644 --- a/src/Ocelot.Library/Infrastructure/Authentication/UnableToCreateAuthenticationHandlerError.cs +++ b/src/Ocelot.Library/Authentication/UnableToCreateAuthenticationHandlerError.cs @@ -1,7 +1,7 @@ -using Ocelot.Library.Infrastructure.Errors; - -namespace Ocelot.Library.Infrastructure.Authentication +namespace Ocelot.Library.Authentication { + using Errors; + public class UnableToCreateAuthenticationHandlerError : Error { public UnableToCreateAuthenticationHandlerError(string message) diff --git a/src/Ocelot.Library/Infrastructure/Builder/ReRouteBuilder.cs b/src/Ocelot.Library/Builder/ReRouteBuilder.cs similarity index 96% rename from src/Ocelot.Library/Infrastructure/Builder/ReRouteBuilder.cs rename to src/Ocelot.Library/Builder/ReRouteBuilder.cs index ee01b7d6..c4ff124a 100644 --- a/src/Ocelot.Library/Infrastructure/Builder/ReRouteBuilder.cs +++ b/src/Ocelot.Library/Builder/ReRouteBuilder.cs @@ -1,7 +1,6 @@ -using System.Collections.Generic; - -namespace Ocelot.Library.Infrastructure.Builder +namespace Ocelot.Library.Builder { + using System.Collections.Generic; using Configuration; public class ReRouteBuilder diff --git a/src/Ocelot.Library/Infrastructure/Configuration/AuthenticationOptions.cs b/src/Ocelot.Library/Configuration/AuthenticationOptions.cs similarity index 90% rename from src/Ocelot.Library/Infrastructure/Configuration/AuthenticationOptions.cs rename to src/Ocelot.Library/Configuration/AuthenticationOptions.cs index 9cda2672..99105c4a 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/AuthenticationOptions.cs +++ b/src/Ocelot.Library/Configuration/AuthenticationOptions.cs @@ -1,7 +1,7 @@ -using System.Collections.Generic; - -namespace Ocelot.Library.Infrastructure.Configuration +namespace Ocelot.Library.Configuration { + using System.Collections.Generic; + public class AuthenticationOptions { public AuthenticationOptions(string provider, string providerRootUrl, string scopeName, bool requireHttps, List additionalScopes, string scopeSecret) diff --git a/src/Ocelot.Library/Infrastructure/Configuration/IOcelotConfiguration.cs b/src/Ocelot.Library/Configuration/IOcelotConfiguration.cs similarity index 52% rename from src/Ocelot.Library/Infrastructure/Configuration/IOcelotConfiguration.cs rename to src/Ocelot.Library/Configuration/IOcelotConfiguration.cs index 837edbaf..0e7de3c7 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/IOcelotConfiguration.cs +++ b/src/Ocelot.Library/Configuration/IOcelotConfiguration.cs @@ -1,7 +1,7 @@ -using System.Collections.Generic; - -namespace Ocelot.Library.Infrastructure.Configuration +namespace Ocelot.Library.Configuration { + using System.Collections.Generic; + public interface IOcelotConfiguration { List ReRoutes { get; } diff --git a/src/Ocelot.Library/Infrastructure/Configuration/OcelotConfiguration.cs b/src/Ocelot.Library/Configuration/OcelotConfiguration.cs similarity index 95% rename from src/Ocelot.Library/Infrastructure/Configuration/OcelotConfiguration.cs rename to src/Ocelot.Library/Configuration/OcelotConfiguration.cs index afa768d2..b49f193a 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/OcelotConfiguration.cs +++ b/src/Ocelot.Library/Configuration/OcelotConfiguration.cs @@ -1,9 +1,9 @@ -using System.Collections.Generic; -using Microsoft.Extensions.Options; -using Ocelot.Library.Infrastructure.Configuration.Yaml; - -namespace Ocelot.Library.Infrastructure.Configuration +namespace Ocelot.Library.Configuration { + using System.Collections.Generic; + using Microsoft.Extensions.Options; + using Yaml; + public class OcelotConfiguration : IOcelotConfiguration { private readonly IOptions _options; diff --git a/src/Ocelot.Library/Infrastructure/Configuration/ReRoute.cs b/src/Ocelot.Library/Configuration/ReRoute.cs similarity index 94% rename from src/Ocelot.Library/Infrastructure/Configuration/ReRoute.cs rename to src/Ocelot.Library/Configuration/ReRoute.cs index 12dfd1b2..8e73a689 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/ReRoute.cs +++ b/src/Ocelot.Library/Configuration/ReRoute.cs @@ -1,4 +1,4 @@ -namespace Ocelot.Library.Infrastructure.Configuration +namespace Ocelot.Library.Configuration { public class ReRoute { diff --git a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/ConfigurationValidationResult.cs b/src/Ocelot.Library/Configuration/Yaml/ConfigurationValidationResult.cs similarity index 72% rename from src/Ocelot.Library/Infrastructure/Configuration/Yaml/ConfigurationValidationResult.cs rename to src/Ocelot.Library/Configuration/Yaml/ConfigurationValidationResult.cs index 577fe18c..31b6e1dc 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/ConfigurationValidationResult.cs +++ b/src/Ocelot.Library/Configuration/Yaml/ConfigurationValidationResult.cs @@ -1,9 +1,8 @@ -using System.Collections.Generic; -using Ocelot.Library.Infrastructure.Errors; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.Configuration.Yaml +namespace Ocelot.Library.Configuration.Yaml { + using System.Collections.Generic; + using Errors; + public class ConfigurationValidationResult { public ConfigurationValidationResult(bool isError) diff --git a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/ConfigurationValidator.cs b/src/Ocelot.Library/Configuration/Yaml/ConfigurationValidator.cs similarity index 91% rename from src/Ocelot.Library/Infrastructure/Configuration/Yaml/ConfigurationValidator.cs rename to src/Ocelot.Library/Configuration/Yaml/ConfigurationValidator.cs index 6c7aee98..38964f30 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/ConfigurationValidator.cs +++ b/src/Ocelot.Library/Configuration/Yaml/ConfigurationValidator.cs @@ -1,12 +1,12 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Ocelot.Library.Infrastructure.Authentication; -using Ocelot.Library.Infrastructure.Errors; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.Configuration.Yaml +namespace Ocelot.Library.Configuration.Yaml { + using System; + using System.Collections.Generic; + using System.Linq; + using Authentication; + using Errors; + using Responses; + public class ConfigurationValidator : IConfigurationValidator { public Response IsValid(YamlConfiguration configuration) diff --git a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/DownstreamTemplateAlreadyUsedError.cs b/src/Ocelot.Library/Configuration/Yaml/DownstreamTemplateAlreadyUsedError.cs similarity index 60% rename from src/Ocelot.Library/Infrastructure/Configuration/Yaml/DownstreamTemplateAlreadyUsedError.cs rename to src/Ocelot.Library/Configuration/Yaml/DownstreamTemplateAlreadyUsedError.cs index 533f1bb3..0ee8b6c8 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/DownstreamTemplateAlreadyUsedError.cs +++ b/src/Ocelot.Library/Configuration/Yaml/DownstreamTemplateAlreadyUsedError.cs @@ -1,8 +1,7 @@ -using Ocelot.Library.Infrastructure.Errors; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.Configuration.Yaml +namespace Ocelot.Library.Configuration.Yaml { + using Errors; + public class DownstreamTemplateAlreadyUsedError : Error { public DownstreamTemplateAlreadyUsedError(string message) : base(message, OcelotErrorCode.DownstreamTemplateAlreadyUsedError) diff --git a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/IConfigurationValidator.cs b/src/Ocelot.Library/Configuration/Yaml/IConfigurationValidator.cs similarity index 58% rename from src/Ocelot.Library/Infrastructure/Configuration/Yaml/IConfigurationValidator.cs rename to src/Ocelot.Library/Configuration/Yaml/IConfigurationValidator.cs index dd491928..38baf36b 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/IConfigurationValidator.cs +++ b/src/Ocelot.Library/Configuration/Yaml/IConfigurationValidator.cs @@ -1,7 +1,7 @@ -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.Configuration.Yaml +namespace Ocelot.Library.Configuration.Yaml { + using Responses; + public interface IConfigurationValidator { Response IsValid(YamlConfiguration configuration); diff --git a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/UnsupportedAuthenticationProviderError.cs b/src/Ocelot.Library/Configuration/Yaml/UnsupportedAuthenticationProviderError.cs similarity index 70% rename from src/Ocelot.Library/Infrastructure/Configuration/Yaml/UnsupportedAuthenticationProviderError.cs rename to src/Ocelot.Library/Configuration/Yaml/UnsupportedAuthenticationProviderError.cs index 1964ef80..9a589ca2 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/UnsupportedAuthenticationProviderError.cs +++ b/src/Ocelot.Library/Configuration/Yaml/UnsupportedAuthenticationProviderError.cs @@ -1,7 +1,7 @@ -using Ocelot.Library.Infrastructure.Errors; - -namespace Ocelot.Library.Infrastructure.Configuration.Yaml +namespace Ocelot.Library.Configuration.Yaml { + using Errors; + public class UnsupportedAuthenticationProviderError : Error { public UnsupportedAuthenticationProviderError(string message) diff --git a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/YamlAuthenticationOptions.cs b/src/Ocelot.Library/Configuration/Yaml/YamlAuthenticationOptions.cs similarity index 78% rename from src/Ocelot.Library/Infrastructure/Configuration/Yaml/YamlAuthenticationOptions.cs rename to src/Ocelot.Library/Configuration/Yaml/YamlAuthenticationOptions.cs index 463a75f5..2e9e9b27 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/YamlAuthenticationOptions.cs +++ b/src/Ocelot.Library/Configuration/Yaml/YamlAuthenticationOptions.cs @@ -1,7 +1,7 @@ -using System.Collections.Generic; - -namespace Ocelot.Library.Infrastructure.Configuration.Yaml +namespace Ocelot.Library.Configuration.Yaml { + using System.Collections.Generic; + public class YamlAuthenticationOptions { public string Provider { get; set; } diff --git a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/YamlConfiguration.cs b/src/Ocelot.Library/Configuration/Yaml/YamlConfiguration.cs similarity index 68% rename from src/Ocelot.Library/Infrastructure/Configuration/Yaml/YamlConfiguration.cs rename to src/Ocelot.Library/Configuration/Yaml/YamlConfiguration.cs index 69a7eb7a..dd6fb081 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/YamlConfiguration.cs +++ b/src/Ocelot.Library/Configuration/Yaml/YamlConfiguration.cs @@ -1,7 +1,7 @@ -using System.Collections.Generic; - -namespace Ocelot.Library.Infrastructure.Configuration.Yaml +namespace Ocelot.Library.Configuration.Yaml { + using System.Collections.Generic; + public class YamlConfiguration { public YamlConfiguration() diff --git a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/YamlReRoute.cs b/src/Ocelot.Library/Configuration/Yaml/YamlReRoute.cs similarity index 82% rename from src/Ocelot.Library/Infrastructure/Configuration/Yaml/YamlReRoute.cs rename to src/Ocelot.Library/Configuration/Yaml/YamlReRoute.cs index 26c1569b..0b7be040 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/Yaml/YamlReRoute.cs +++ b/src/Ocelot.Library/Configuration/Yaml/YamlReRoute.cs @@ -1,4 +1,4 @@ -namespace Ocelot.Library.Infrastructure.Configuration.Yaml +namespace Ocelot.Library.Configuration.Yaml { public class YamlReRoute { diff --git a/src/Ocelot.Library/DependencyInjection/ServiceCollectionExtensions.cs b/src/Ocelot.Library/DependencyInjection/ServiceCollectionExtensions.cs new file mode 100644 index 00000000..ad627355 --- /dev/null +++ b/src/Ocelot.Library/DependencyInjection/ServiceCollectionExtensions.cs @@ -0,0 +1,44 @@ +namespace Ocelot.Library.DependencyInjection +{ + using Authentication; + using Configuration; + using Configuration.Yaml; + using DownstreamRouteFinder; + using Microsoft.AspNetCore.Http; + using Microsoft.Extensions.Configuration; + using Microsoft.Extensions.DependencyInjection; + using Repository; + using RequestBuilder; + using Requester; + using Responder; + using UrlMatcher; + using UrlTemplateReplacer; + + public static class ServiceCollectionExtensions + { + public static IServiceCollection AddOcelot(this IServiceCollection services, IConfigurationRoot configurationRoot) + { + services.Configure(configurationRoot); + + // Add framework services. + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + + // see this for why we register this as singleton http://stackoverflow.com/questions/37371264/invalidoperationexception-unable-to-resolve-service-for-type-microsoft-aspnetc + services.AddSingleton(); + services.AddScoped(); + + return services; + } + } +} diff --git a/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRoute.cs b/src/Ocelot.Library/DownstreamRouteFinder/DownstreamRoute.cs similarity index 76% rename from src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRoute.cs rename to src/Ocelot.Library/DownstreamRouteFinder/DownstreamRoute.cs index 8d8cd074..ca80f270 100644 --- a/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRoute.cs +++ b/src/Ocelot.Library/DownstreamRouteFinder/DownstreamRoute.cs @@ -1,9 +1,8 @@ -using System.Collections.Generic; -using Ocelot.Library.Infrastructure.UrlMatcher; - -namespace Ocelot.Library.Infrastructure.DownstreamRouteFinder +namespace Ocelot.Library.DownstreamRouteFinder { + using System.Collections.Generic; using Configuration; + using UrlMatcher; public class DownstreamRoute { diff --git a/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRouteFinder.cs b/src/Ocelot.Library/DownstreamRouteFinder/DownstreamRouteFinder.cs similarity index 82% rename from src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRouteFinder.cs rename to src/Ocelot.Library/DownstreamRouteFinder/DownstreamRouteFinder.cs index 4d58b549..5962f808 100644 --- a/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRouteFinder.cs +++ b/src/Ocelot.Library/DownstreamRouteFinder/DownstreamRouteFinder.cs @@ -1,14 +1,13 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Microsoft.Extensions.Options; -using Ocelot.Library.Infrastructure.Configuration; -using Ocelot.Library.Infrastructure.Errors; -using Ocelot.Library.Infrastructure.Responses; -using Ocelot.Library.Infrastructure.UrlMatcher; - -namespace Ocelot.Library.Infrastructure.DownstreamRouteFinder +namespace Ocelot.Library.DownstreamRouteFinder { + using System; + using System.Collections.Generic; + using System.Linq; + using Configuration; + using Errors; + using Responses; + using UrlMatcher; + public class DownstreamRouteFinder : IDownstreamRouteFinder { private readonly IOcelotConfiguration _configuration; diff --git a/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/IDownstreamRouteFinder.cs b/src/Ocelot.Library/DownstreamRouteFinder/IDownstreamRouteFinder.cs similarity index 59% rename from src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/IDownstreamRouteFinder.cs rename to src/Ocelot.Library/DownstreamRouteFinder/IDownstreamRouteFinder.cs index 4b8f7105..41e2ffe6 100644 --- a/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/IDownstreamRouteFinder.cs +++ b/src/Ocelot.Library/DownstreamRouteFinder/IDownstreamRouteFinder.cs @@ -1,7 +1,7 @@ -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.DownstreamRouteFinder +namespace Ocelot.Library.DownstreamRouteFinder { + using Responses; + public interface IDownstreamRouteFinder { Response FindDownstreamRoute(string upstreamUrlPath, string upstreamHttpMethod); diff --git a/src/Ocelot.Library/DownstreamRouteFinder/UnableToFindDownstreamRouteError.cs b/src/Ocelot.Library/DownstreamRouteFinder/UnableToFindDownstreamRouteError.cs new file mode 100644 index 00000000..e8aacb7b --- /dev/null +++ b/src/Ocelot.Library/DownstreamRouteFinder/UnableToFindDownstreamRouteError.cs @@ -0,0 +1,11 @@ +namespace Ocelot.Library.DownstreamRouteFinder +{ + using Errors; + + public class UnableToFindDownstreamRouteError : Error + { + public UnableToFindDownstreamRouteError() : base("UnableToFindDownstreamRouteError", OcelotErrorCode.UnableToFindDownstreamRouteError) + { + } + } +} diff --git a/src/Ocelot.Library/Infrastructure/Errors/Error.cs b/src/Ocelot.Library/Errors/Error.cs similarity index 86% rename from src/Ocelot.Library/Infrastructure/Errors/Error.cs rename to src/Ocelot.Library/Errors/Error.cs index 50b27354..4c4d96d5 100644 --- a/src/Ocelot.Library/Infrastructure/Errors/Error.cs +++ b/src/Ocelot.Library/Errors/Error.cs @@ -1,4 +1,4 @@ -namespace Ocelot.Library.Infrastructure.Errors +namespace Ocelot.Library.Errors { public abstract class Error { diff --git a/src/Ocelot.Library/Infrastructure/Errors/OcelotErrorCode.cs b/src/Ocelot.Library/Errors/OcelotErrorCode.cs similarity index 88% rename from src/Ocelot.Library/Infrastructure/Errors/OcelotErrorCode.cs rename to src/Ocelot.Library/Errors/OcelotErrorCode.cs index 01ddfa39..dbe58dbe 100644 --- a/src/Ocelot.Library/Infrastructure/Errors/OcelotErrorCode.cs +++ b/src/Ocelot.Library/Errors/OcelotErrorCode.cs @@ -1,4 +1,4 @@ -namespace Ocelot.Library.Infrastructure.Errors +namespace Ocelot.Library.Errors { public enum OcelotErrorCode { diff --git a/src/Ocelot.Library/Infrastructure/Authentication/IAuthenticationHandlerCreator.cs b/src/Ocelot.Library/Infrastructure/Authentication/IAuthenticationHandlerCreator.cs deleted file mode 100644 index 553386d7..00000000 --- a/src/Ocelot.Library/Infrastructure/Authentication/IAuthenticationHandlerCreator.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Ocelot.Library.Infrastructure.Responses; -using AuthenticationOptions = Ocelot.Library.Infrastructure.Configuration.AuthenticationOptions; - -namespace Ocelot.Library.Infrastructure.Authentication -{ - public interface IAuthenticationHandlerCreator - { - Response CreateIdentityServerAuthenticationHandler(IApplicationBuilder app, AuthenticationOptions authOptions); - } -} diff --git a/src/Ocelot.Library/Infrastructure/Authentication/IAuthenticationHandlerFactory.cs b/src/Ocelot.Library/Infrastructure/Authentication/IAuthenticationHandlerFactory.cs deleted file mode 100644 index 87f62346..00000000 --- a/src/Ocelot.Library/Infrastructure/Authentication/IAuthenticationHandlerFactory.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Microsoft.AspNetCore.Builder; -using Ocelot.Library.Infrastructure.Responses; -using AuthenticationOptions = Ocelot.Library.Infrastructure.Configuration.AuthenticationOptions; - -namespace Ocelot.Library.Infrastructure.Authentication -{ - public interface IAuthenticationHandlerFactory - { - Response Get(IApplicationBuilder app, AuthenticationOptions authOptions); - } -} diff --git a/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/UnableToFindDownstreamRouteError.cs b/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/UnableToFindDownstreamRouteError.cs deleted file mode 100644 index e0f8d26a..00000000 --- a/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/UnableToFindDownstreamRouteError.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Ocelot.Library.Infrastructure.Errors; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.DownstreamRouteFinder -{ - public class UnableToFindDownstreamRouteError : Error - { - public UnableToFindDownstreamRouteError() : base("UnableToFindDownstreamRouteError", OcelotErrorCode.UnableToFindDownstreamRouteError) - { - } - } -} diff --git a/src/Ocelot.Library/Infrastructure/Requester/IHttpRequester.cs b/src/Ocelot.Library/Infrastructure/Requester/IHttpRequester.cs deleted file mode 100644 index eca3875e..00000000 --- a/src/Ocelot.Library/Infrastructure/Requester/IHttpRequester.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Net.Http; -using System.Threading.Tasks; -using Ocelot.Library.Infrastructure.RequestBuilder; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.Requester -{ - public interface IHttpRequester - { - Task> GetResponse(Request request); - } -} diff --git a/src/Ocelot.Library/Infrastructure/Responder/IErrorsToHttpStatusCodeMapper.cs b/src/Ocelot.Library/Infrastructure/Responder/IErrorsToHttpStatusCodeMapper.cs deleted file mode 100644 index 21932bdf..00000000 --- a/src/Ocelot.Library/Infrastructure/Responder/IErrorsToHttpStatusCodeMapper.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using Ocelot.Library.Infrastructure.Errors; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.Responder -{ - public interface IErrorsToHttpStatusCodeMapper - { - Response Map(List errors); - } -} diff --git a/src/Ocelot.Library/Infrastructure/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs b/src/Ocelot.Library/Infrastructure/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs deleted file mode 100644 index 6be56a81..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.UrlMatcher -{ - public interface IUrlPathToUrlTemplateMatcher - { - Response Match(string upstreamUrlPath, string upstreamUrlPathTemplate); - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs deleted file mode 100644 index 3d76671b..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Ocelot.Library.Infrastructure.DownstreamRouteFinder; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.UrlTemplateReplacer -{ - public interface IDownstreamUrlTemplateVariableReplacer - { - Response ReplaceTemplateVariables(DownstreamRoute downstreamRoute); - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Middleware/AuthenticationMiddleware.cs b/src/Ocelot.Library/Middleware/AuthenticationMiddleware.cs similarity index 83% rename from src/Ocelot.Library/Infrastructure/Middleware/AuthenticationMiddleware.cs rename to src/Ocelot.Library/Middleware/AuthenticationMiddleware.cs index 89bdd875..4042edca 100644 --- a/src/Ocelot.Library/Infrastructure/Middleware/AuthenticationMiddleware.cs +++ b/src/Ocelot.Library/Middleware/AuthenticationMiddleware.cs @@ -1,15 +1,15 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Ocelot.Library.Infrastructure.Authentication; -using Ocelot.Library.Infrastructure.Configuration; -using Ocelot.Library.Infrastructure.DownstreamRouteFinder; -using Ocelot.Library.Infrastructure.Errors; -using Ocelot.Library.Infrastructure.Repository; - -namespace Ocelot.Library.Infrastructure.Middleware +namespace Ocelot.Library.Middleware { + using System.Collections.Generic; + using System.Threading.Tasks; + using Authentication; + using Configuration; + using DownstreamRouteFinder; + using Errors; + using Microsoft.AspNetCore.Builder; + using Microsoft.AspNetCore.Http; + using Repository; + public class AuthenticationMiddleware : OcelotMiddleware { private readonly RequestDelegate _next; diff --git a/src/Ocelot.Library/Infrastructure/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs b/src/Ocelot.Library/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs similarity index 76% rename from src/Ocelot.Library/Infrastructure/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs rename to src/Ocelot.Library/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs index 43b90856..88b3a678 100644 --- a/src/Ocelot.Library/Infrastructure/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs +++ b/src/Ocelot.Library/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs @@ -1,7 +1,7 @@ -using Microsoft.AspNetCore.Builder; - -namespace Ocelot.Library.Infrastructure.Middleware +namespace Ocelot.Library.Middleware { + using Microsoft.AspNetCore.Builder; + public static class AuthenticationMiddlewareMiddlewareExtensions { public static IApplicationBuilder UseAuthenticationMiddleware(this IApplicationBuilder builder) diff --git a/src/Ocelot.Library/Middleware/ClaimsParserMiddleware.cs b/src/Ocelot.Library/Middleware/ClaimsParserMiddleware.cs new file mode 100644 index 00000000..553b6970 --- /dev/null +++ b/src/Ocelot.Library/Middleware/ClaimsParserMiddleware.cs @@ -0,0 +1,23 @@ +namespace Ocelot.Library.Middleware +{ + using System.Threading.Tasks; + using Microsoft.AspNetCore.Http; + using Repository; + + public class ClaimsParserMiddleware : OcelotMiddleware + { + private readonly RequestDelegate _next; + + public ClaimsParserMiddleware(RequestDelegate next, IScopedRequestDataRepository scopedRequestDataRepository) + : base(scopedRequestDataRepository) + { + _next = next; + } + + public async Task Invoke(HttpContext context) + { + + await _next.Invoke(context); + } + } +} diff --git a/src/Ocelot.Library/Infrastructure/Middleware/DownstreamRouteFinderMiddleware.cs b/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddleware.cs similarity index 85% rename from src/Ocelot.Library/Infrastructure/Middleware/DownstreamRouteFinderMiddleware.cs rename to src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddleware.cs index 1537ab45..f83e88ce 100644 --- a/src/Ocelot.Library/Infrastructure/Middleware/DownstreamRouteFinderMiddleware.cs +++ b/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddleware.cs @@ -1,10 +1,10 @@ -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using Ocelot.Library.Infrastructure.DownstreamRouteFinder; -using Ocelot.Library.Infrastructure.Repository; - -namespace Ocelot.Library.Infrastructure.Middleware +namespace Ocelot.Library.Middleware { + using System.Threading.Tasks; + using DownstreamRouteFinder; + using Microsoft.AspNetCore.Http; + using Repository; + public class DownstreamRouteFinderMiddleware : OcelotMiddleware { private readonly RequestDelegate _next; diff --git a/src/Ocelot.Library/Infrastructure/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs b/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs similarity index 76% rename from src/Ocelot.Library/Infrastructure/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs rename to src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs index 7f23d1de..b288d789 100644 --- a/src/Ocelot.Library/Infrastructure/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs +++ b/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs @@ -1,7 +1,7 @@ -using Microsoft.AspNetCore.Builder; - -namespace Ocelot.Library.Infrastructure.Middleware +namespace Ocelot.Library.Middleware { + using Microsoft.AspNetCore.Builder; + public static class DownstreamRouteFinderMiddlewareExtensions { public static IApplicationBuilder UseDownstreamRouteFinderMiddleware(this IApplicationBuilder builder) diff --git a/src/Ocelot.Library/Infrastructure/Middleware/DownstreamUrlCreatorMiddleware.cs b/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddleware.cs similarity index 83% rename from src/Ocelot.Library/Infrastructure/Middleware/DownstreamUrlCreatorMiddleware.cs rename to src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddleware.cs index 955e983a..64ca55cc 100644 --- a/src/Ocelot.Library/Infrastructure/Middleware/DownstreamUrlCreatorMiddleware.cs +++ b/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddleware.cs @@ -1,11 +1,11 @@ -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using Ocelot.Library.Infrastructure.DownstreamRouteFinder; -using Ocelot.Library.Infrastructure.Repository; -using Ocelot.Library.Infrastructure.UrlTemplateReplacer; - -namespace Ocelot.Library.Infrastructure.Middleware +namespace Ocelot.Library.Middleware { + using System.Threading.Tasks; + using DownstreamRouteFinder; + using Microsoft.AspNetCore.Http; + using Repository; + using UrlTemplateReplacer; + public class DownstreamUrlCreatorMiddleware : OcelotMiddleware { private readonly RequestDelegate _next; diff --git a/src/Ocelot.Library/Infrastructure/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs b/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs similarity index 76% rename from src/Ocelot.Library/Infrastructure/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs rename to src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs index b0997b7b..19839eb2 100644 --- a/src/Ocelot.Library/Infrastructure/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs +++ b/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs @@ -1,7 +1,7 @@ -using Microsoft.AspNetCore.Builder; - -namespace Ocelot.Library.Infrastructure.Middleware +namespace Ocelot.Library.Middleware { + using Microsoft.AspNetCore.Builder; + public static class DownstreamUrlCreatorMiddlewareExtensions { public static IApplicationBuilder UseDownstreamUrlCreatorMiddleware(this IApplicationBuilder builder) diff --git a/src/Ocelot.Library/Infrastructure/Middleware/HttpRequestBuilderMiddleware.cs b/src/Ocelot.Library/Middleware/HttpRequestBuilderMiddleware.cs similarity index 87% rename from src/Ocelot.Library/Infrastructure/Middleware/HttpRequestBuilderMiddleware.cs rename to src/Ocelot.Library/Middleware/HttpRequestBuilderMiddleware.cs index aa2c4017..f60f72d9 100644 --- a/src/Ocelot.Library/Infrastructure/Middleware/HttpRequestBuilderMiddleware.cs +++ b/src/Ocelot.Library/Middleware/HttpRequestBuilderMiddleware.cs @@ -1,10 +1,10 @@ -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using Ocelot.Library.Infrastructure.Repository; -using Ocelot.Library.Infrastructure.RequestBuilder; - -namespace Ocelot.Library.Infrastructure.Middleware +namespace Ocelot.Library.Middleware { + using System.Threading.Tasks; + using Microsoft.AspNetCore.Http; + using Repository; + using RequestBuilder; + public class HttpRequestBuilderMiddleware : OcelotMiddleware { private readonly RequestDelegate _next; diff --git a/src/Ocelot.Library/Infrastructure/Middleware/HttpRequestBuilderMiddlewareExtensions.cs b/src/Ocelot.Library/Middleware/HttpRequestBuilderMiddlewareExtensions.cs similarity index 76% rename from src/Ocelot.Library/Infrastructure/Middleware/HttpRequestBuilderMiddlewareExtensions.cs rename to src/Ocelot.Library/Middleware/HttpRequestBuilderMiddlewareExtensions.cs index fa36ce01..54877b09 100644 --- a/src/Ocelot.Library/Infrastructure/Middleware/HttpRequestBuilderMiddlewareExtensions.cs +++ b/src/Ocelot.Library/Middleware/HttpRequestBuilderMiddlewareExtensions.cs @@ -1,7 +1,7 @@ -using Microsoft.AspNetCore.Builder; - -namespace Ocelot.Library.Infrastructure.Middleware +namespace Ocelot.Library.Middleware { + using Microsoft.AspNetCore.Builder; + public static class HttpRequestBuilderMiddlewareExtensions { public static IApplicationBuilder UseHttpRequestBuilderMiddleware(this IApplicationBuilder builder) diff --git a/src/Ocelot.Library/Infrastructure/Middleware/HttpRequesterMiddleware.cs b/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs similarity index 82% rename from src/Ocelot.Library/Infrastructure/Middleware/HttpRequesterMiddleware.cs rename to src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs index 3cf988e4..f9aac74b 100644 --- a/src/Ocelot.Library/Infrastructure/Middleware/HttpRequesterMiddleware.cs +++ b/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs @@ -1,11 +1,11 @@ -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using Ocelot.Library.Infrastructure.Repository; -using Ocelot.Library.Infrastructure.RequestBuilder; -using Ocelot.Library.Infrastructure.Requester; - -namespace Ocelot.Library.Infrastructure.Middleware +namespace Ocelot.Library.Middleware { + using System.Threading.Tasks; + using Microsoft.AspNetCore.Http; + using Repository; + using RequestBuilder; + using Requester; + public class HttpRequesterMiddleware : OcelotMiddleware { private readonly RequestDelegate _next; diff --git a/src/Ocelot.Library/Infrastructure/Middleware/HttpRequesterMiddlewareExtensions.cs b/src/Ocelot.Library/Middleware/HttpRequesterMiddlewareExtensions.cs similarity index 75% rename from src/Ocelot.Library/Infrastructure/Middleware/HttpRequesterMiddlewareExtensions.cs rename to src/Ocelot.Library/Middleware/HttpRequesterMiddlewareExtensions.cs index b8b31f40..5ad921f2 100644 --- a/src/Ocelot.Library/Infrastructure/Middleware/HttpRequesterMiddlewareExtensions.cs +++ b/src/Ocelot.Library/Middleware/HttpRequesterMiddlewareExtensions.cs @@ -1,7 +1,7 @@ -using Microsoft.AspNetCore.Builder; - -namespace Ocelot.Library.Infrastructure.Middleware +namespace Ocelot.Library.Middleware { + using Microsoft.AspNetCore.Builder; + public static class HttpRequesterMiddlewareExtensions { public static IApplicationBuilder UseHttpRequesterMiddleware(this IApplicationBuilder builder) diff --git a/src/Ocelot.Library/Infrastructure/Middleware/HttpResponderMiddleware.cs b/src/Ocelot.Library/Middleware/HttpResponderMiddleware.cs similarity index 87% rename from src/Ocelot.Library/Infrastructure/Middleware/HttpResponderMiddleware.cs rename to src/Ocelot.Library/Middleware/HttpResponderMiddleware.cs index 0c8fba3c..7d40e5e6 100644 --- a/src/Ocelot.Library/Infrastructure/Middleware/HttpResponderMiddleware.cs +++ b/src/Ocelot.Library/Middleware/HttpResponderMiddleware.cs @@ -1,11 +1,11 @@ -using System.Net.Http; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using Ocelot.Library.Infrastructure.Repository; -using Ocelot.Library.Infrastructure.Responder; - -namespace Ocelot.Library.Infrastructure.Middleware +namespace Ocelot.Library.Middleware { + using System.Net.Http; + using System.Threading.Tasks; + using Microsoft.AspNetCore.Http; + using Repository; + using Responder; + public class HttpResponderMiddleware : OcelotMiddleware { private readonly RequestDelegate _next; diff --git a/src/Ocelot.Library/Infrastructure/Middleware/HttpResponderMiddlewareExtensions.cs b/src/Ocelot.Library/Middleware/HttpResponderMiddlewareExtensions.cs similarity index 75% rename from src/Ocelot.Library/Infrastructure/Middleware/HttpResponderMiddlewareExtensions.cs rename to src/Ocelot.Library/Middleware/HttpResponderMiddlewareExtensions.cs index 30d69ae7..04640d51 100644 --- a/src/Ocelot.Library/Infrastructure/Middleware/HttpResponderMiddlewareExtensions.cs +++ b/src/Ocelot.Library/Middleware/HttpResponderMiddlewareExtensions.cs @@ -1,7 +1,7 @@ -using Microsoft.AspNetCore.Builder; - -namespace Ocelot.Library.Infrastructure.Middleware +namespace Ocelot.Library.Middleware { + using Microsoft.AspNetCore.Builder; + public static class HttpResponderMiddlewareExtensions { public static IApplicationBuilder UseHttpResponderMiddleware(this IApplicationBuilder builder) diff --git a/src/Ocelot.Library/Infrastructure/Middleware/OcelotMiddleware.cs b/src/Ocelot.Library/Middleware/OcelotMiddleware.cs similarity index 80% rename from src/Ocelot.Library/Infrastructure/Middleware/OcelotMiddleware.cs rename to src/Ocelot.Library/Middleware/OcelotMiddleware.cs index 7af593e0..857d8369 100644 --- a/src/Ocelot.Library/Infrastructure/Middleware/OcelotMiddleware.cs +++ b/src/Ocelot.Library/Middleware/OcelotMiddleware.cs @@ -1,10 +1,9 @@ -using System.Collections.Generic; -using Ocelot.Library.Infrastructure.Errors; -using Ocelot.Library.Infrastructure.Repository; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.Middleware +namespace Ocelot.Library.Middleware { + using System.Collections.Generic; + using Errors; + using Repository; + public abstract class OcelotMiddleware { private readonly IScopedRequestDataRepository _scopedRequestDataRepository; diff --git a/src/Ocelot.Library/Middleware/OcelotMiddlewareExtensions.cs b/src/Ocelot.Library/Middleware/OcelotMiddlewareExtensions.cs new file mode 100644 index 00000000..1fc4bbd8 --- /dev/null +++ b/src/Ocelot.Library/Middleware/OcelotMiddlewareExtensions.cs @@ -0,0 +1,24 @@ +namespace Ocelot.Library.Middleware +{ + using Microsoft.AspNetCore.Builder; + + public static class OcelotMiddlewareExtensions + { + public static IApplicationBuilder UseOcelot(this IApplicationBuilder builder) + { + builder.UseHttpResponderMiddleware(); + + builder.UseDownstreamRouteFinderMiddleware(); + + builder.UseAuthenticationMiddleware(); + + builder.UseDownstreamUrlCreatorMiddleware(); + + builder.UseHttpRequestBuilderMiddleware(); + + builder.UseHttpRequesterMiddleware(); + + return builder; + } + } +} diff --git a/src/Ocelot.Library/Infrastructure/Middleware/UnauthenticatedError.cs b/src/Ocelot.Library/Middleware/UnauthenticatedError.cs similarity index 65% rename from src/Ocelot.Library/Infrastructure/Middleware/UnauthenticatedError.cs rename to src/Ocelot.Library/Middleware/UnauthenticatedError.cs index 3a7c3ec6..a8e29033 100644 --- a/src/Ocelot.Library/Infrastructure/Middleware/UnauthenticatedError.cs +++ b/src/Ocelot.Library/Middleware/UnauthenticatedError.cs @@ -1,7 +1,7 @@ -using Ocelot.Library.Infrastructure.Errors; - -namespace Ocelot.Library.Infrastructure.Middleware +namespace Ocelot.Library.Middleware { + using Errors; + public class UnauthenticatedError : Error { public UnauthenticatedError(string message) : base(message, OcelotErrorCode.UnauthenticatedError) diff --git a/src/Ocelot.Library/Infrastructure/Repository/CannotAddDataError.cs b/src/Ocelot.Library/Repository/CannotAddDataError.cs similarity index 55% rename from src/Ocelot.Library/Infrastructure/Repository/CannotAddDataError.cs rename to src/Ocelot.Library/Repository/CannotAddDataError.cs index 1bc0f26a..f3bd42de 100644 --- a/src/Ocelot.Library/Infrastructure/Repository/CannotAddDataError.cs +++ b/src/Ocelot.Library/Repository/CannotAddDataError.cs @@ -1,8 +1,7 @@ -using Ocelot.Library.Infrastructure.Errors; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.Repository +namespace Ocelot.Library.Repository { + using Errors; + public class CannotAddDataError : Error { public CannotAddDataError(string message) : base(message, OcelotErrorCode.CannotAddDataError) diff --git a/src/Ocelot.Library/Infrastructure/Repository/CannotFindDataError.cs b/src/Ocelot.Library/Repository/CannotFindDataError.cs similarity index 56% rename from src/Ocelot.Library/Infrastructure/Repository/CannotFindDataError.cs rename to src/Ocelot.Library/Repository/CannotFindDataError.cs index 08a814f4..b61069b5 100644 --- a/src/Ocelot.Library/Infrastructure/Repository/CannotFindDataError.cs +++ b/src/Ocelot.Library/Repository/CannotFindDataError.cs @@ -1,8 +1,7 @@ -using Ocelot.Library.Infrastructure.Errors; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.Repository +namespace Ocelot.Library.Repository { + using Errors; + public class CannotFindDataError : Error { public CannotFindDataError(string message) : base(message, OcelotErrorCode.CannotFindDataError) diff --git a/src/Ocelot.Library/Infrastructure/Repository/IScopedRequestDataRepository.cs b/src/Ocelot.Library/Repository/IScopedRequestDataRepository.cs similarity index 60% rename from src/Ocelot.Library/Infrastructure/Repository/IScopedRequestDataRepository.cs rename to src/Ocelot.Library/Repository/IScopedRequestDataRepository.cs index b88605d6..f8e37133 100644 --- a/src/Ocelot.Library/Infrastructure/Repository/IScopedRequestDataRepository.cs +++ b/src/Ocelot.Library/Repository/IScopedRequestDataRepository.cs @@ -1,7 +1,7 @@ -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.Repository +namespace Ocelot.Library.Repository { + using Responses; + public interface IScopedRequestDataRepository { Response Add(string key, T value); diff --git a/src/Ocelot.Library/Infrastructure/Repository/ScopedRequestDataRepository.cs b/src/Ocelot.Library/Repository/ScopedRequestDataRepository.cs similarity index 85% rename from src/Ocelot.Library/Infrastructure/Repository/ScopedRequestDataRepository.cs rename to src/Ocelot.Library/Repository/ScopedRequestDataRepository.cs index 9b41d655..b242617e 100644 --- a/src/Ocelot.Library/Infrastructure/Repository/ScopedRequestDataRepository.cs +++ b/src/Ocelot.Library/Repository/ScopedRequestDataRepository.cs @@ -1,11 +1,11 @@ -using System; -using System.Collections.Generic; -using Microsoft.AspNetCore.Http; -using Ocelot.Library.Infrastructure.Errors; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.Repository +namespace Ocelot.Library.Repository { + using System; + using System.Collections.Generic; + using Errors; + using Microsoft.AspNetCore.Http; + using Responses; + public class ScopedRequestDataRepository : IScopedRequestDataRepository { private readonly IHttpContextAccessor _httpContextAccessor; diff --git a/src/Ocelot.Library/Infrastructure/RequestBuilder/HttpRequestBuilder.cs b/src/Ocelot.Library/RequestBuilder/HttpRequestBuilder.cs similarity index 88% rename from src/Ocelot.Library/Infrastructure/RequestBuilder/HttpRequestBuilder.cs rename to src/Ocelot.Library/RequestBuilder/HttpRequestBuilder.cs index 2aa6c9e2..d12fec2f 100644 --- a/src/Ocelot.Library/Infrastructure/RequestBuilder/HttpRequestBuilder.cs +++ b/src/Ocelot.Library/RequestBuilder/HttpRequestBuilder.cs @@ -1,14 +1,14 @@ -using System; -using System.IO; -using System.Net; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.RequestBuilder +namespace Ocelot.Library.RequestBuilder { + using System; + using System.IO; + using System.Net; + using System.Net.Http; + using System.Net.Http.Headers; + using System.Threading.Tasks; + using Microsoft.AspNetCore.Http; + using Responses; + public class HttpRequestBuilder : IRequestBuilder { public async Task> Build(string httpMethod, string downstreamUrl, Stream content, IHeaderDictionary headers, diff --git a/src/Ocelot.Library/Infrastructure/RequestBuilder/IRequestBuilder.cs b/src/Ocelot.Library/RequestBuilder/IRequestBuilder.cs similarity index 63% rename from src/Ocelot.Library/Infrastructure/RequestBuilder/IRequestBuilder.cs rename to src/Ocelot.Library/RequestBuilder/IRequestBuilder.cs index 296e4442..353d438a 100644 --- a/src/Ocelot.Library/Infrastructure/RequestBuilder/IRequestBuilder.cs +++ b/src/Ocelot.Library/RequestBuilder/IRequestBuilder.cs @@ -1,10 +1,10 @@ -using System.IO; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.RequestBuilder +namespace Ocelot.Library.RequestBuilder { + using System.IO; + using System.Threading.Tasks; + using Microsoft.AspNetCore.Http; + using Responses; + public interface IRequestBuilder { Task> Build(string httpMethod, diff --git a/src/Ocelot.Library/Infrastructure/RequestBuilder/Request.cs b/src/Ocelot.Library/RequestBuilder/Request.cs similarity index 80% rename from src/Ocelot.Library/Infrastructure/RequestBuilder/Request.cs rename to src/Ocelot.Library/RequestBuilder/Request.cs index b35abf32..dae1243d 100644 --- a/src/Ocelot.Library/Infrastructure/RequestBuilder/Request.cs +++ b/src/Ocelot.Library/RequestBuilder/Request.cs @@ -1,8 +1,8 @@ -using System.Net; -using System.Net.Http; - -namespace Ocelot.Library.Infrastructure.RequestBuilder +namespace Ocelot.Library.RequestBuilder { + using System.Net; + using System.Net.Http; + public class Request { public Request(HttpRequestMessage httpRequestMessage, CookieContainer cookieContainer) diff --git a/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs b/src/Ocelot.Library/Requester/HttpClientHttpRequester.cs similarity index 75% rename from src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs rename to src/Ocelot.Library/Requester/HttpClientHttpRequester.cs index 912d7bff..534244b3 100644 --- a/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs +++ b/src/Ocelot.Library/Requester/HttpClientHttpRequester.cs @@ -1,13 +1,13 @@ -using System; -using System.Collections.Generic; -using System.Net.Http; -using System.Threading.Tasks; -using Ocelot.Library.Infrastructure.Errors; -using Ocelot.Library.Infrastructure.RequestBuilder; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.Requester +namespace Ocelot.Library.Requester { + using System; + using System.Collections.Generic; + using System.Net.Http; + using System.Threading.Tasks; + using Errors; + using RequestBuilder; + using Responses; + public class HttpClientHttpRequester : IHttpRequester { public async Task> GetResponse(Request request) diff --git a/src/Ocelot.Library/Requester/IHttpRequester.cs b/src/Ocelot.Library/Requester/IHttpRequester.cs new file mode 100644 index 00000000..8b195fe8 --- /dev/null +++ b/src/Ocelot.Library/Requester/IHttpRequester.cs @@ -0,0 +1,12 @@ +namespace Ocelot.Library.Requester +{ + using System.Net.Http; + using System.Threading.Tasks; + using RequestBuilder; + using Responses; + + public interface IHttpRequester + { + Task> GetResponse(Request request); + } +} diff --git a/src/Ocelot.Library/Infrastructure/Requester/UnableToCompleteRequestError.cs b/src/Ocelot.Library/Requester/UnableToCompleteRequestError.cs similarity index 64% rename from src/Ocelot.Library/Infrastructure/Requester/UnableToCompleteRequestError.cs rename to src/Ocelot.Library/Requester/UnableToCompleteRequestError.cs index 003e84e7..33d3d18e 100644 --- a/src/Ocelot.Library/Infrastructure/Requester/UnableToCompleteRequestError.cs +++ b/src/Ocelot.Library/Requester/UnableToCompleteRequestError.cs @@ -1,9 +1,8 @@ -using System; -using Ocelot.Library.Infrastructure.Errors; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.Requester +namespace Ocelot.Library.Requester { + using System; + using Errors; + public class UnableToCompleteRequestError : Error { public UnableToCompleteRequestError(Exception exception) diff --git a/src/Ocelot.Library/Infrastructure/Responder/ErrorsToHttpStatusCodeMapper.cs b/src/Ocelot.Library/Responder/ErrorsToHttpStatusCodeMapper.cs similarity index 65% rename from src/Ocelot.Library/Infrastructure/Responder/ErrorsToHttpStatusCodeMapper.cs rename to src/Ocelot.Library/Responder/ErrorsToHttpStatusCodeMapper.cs index 4798343e..902c5ac8 100644 --- a/src/Ocelot.Library/Infrastructure/Responder/ErrorsToHttpStatusCodeMapper.cs +++ b/src/Ocelot.Library/Responder/ErrorsToHttpStatusCodeMapper.cs @@ -1,10 +1,10 @@ -using System.Collections.Generic; -using System.Linq; -using Ocelot.Library.Infrastructure.Errors; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.Responder +namespace Ocelot.Library.Responder { + using System.Collections.Generic; + using System.Linq; + using Errors; + using Responses; + public class ErrorsToHttpStatusCodeMapper : IErrorsToHttpStatusCodeMapper { public Response Map(List errors) diff --git a/src/Ocelot.Library/Infrastructure/Responder/HttpContextResponder.cs b/src/Ocelot.Library/Responder/HttpContextResponder.cs similarity index 88% rename from src/Ocelot.Library/Infrastructure/Responder/HttpContextResponder.cs rename to src/Ocelot.Library/Responder/HttpContextResponder.cs index e5e31fe4..546dd114 100644 --- a/src/Ocelot.Library/Infrastructure/Responder/HttpContextResponder.cs +++ b/src/Ocelot.Library/Responder/HttpContextResponder.cs @@ -1,9 +1,9 @@ -using System.Net.Http; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; +namespace Ocelot.Library.Responder +{ + using System.Net.Http; + using System.Threading.Tasks; + using Microsoft.AspNetCore.Http; -namespace Ocelot.Library.Infrastructure.Responder -{ /// /// Cannot unit test things in this class due to methods not being implemented /// on .net concretes used for testing diff --git a/src/Ocelot.Library/Responder/IErrorsToHttpStatusCodeMapper.cs b/src/Ocelot.Library/Responder/IErrorsToHttpStatusCodeMapper.cs new file mode 100644 index 00000000..507b4b24 --- /dev/null +++ b/src/Ocelot.Library/Responder/IErrorsToHttpStatusCodeMapper.cs @@ -0,0 +1,11 @@ +namespace Ocelot.Library.Responder +{ + using System.Collections.Generic; + using Errors; + using Responses; + + public interface IErrorsToHttpStatusCodeMapper + { + Response Map(List errors); + } +} diff --git a/src/Ocelot.Library/Infrastructure/Responder/IHttpResponder.cs b/src/Ocelot.Library/Responder/IHttpResponder.cs similarity index 62% rename from src/Ocelot.Library/Infrastructure/Responder/IHttpResponder.cs rename to src/Ocelot.Library/Responder/IHttpResponder.cs index 9e18647b..972bb70a 100644 --- a/src/Ocelot.Library/Infrastructure/Responder/IHttpResponder.cs +++ b/src/Ocelot.Library/Responder/IHttpResponder.cs @@ -1,9 +1,9 @@ -using System.Net.Http; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; - -namespace Ocelot.Library.Infrastructure.Responder +namespace Ocelot.Library.Responder { + using System.Net.Http; + using System.Threading.Tasks; + using Microsoft.AspNetCore.Http; + public interface IHttpResponder { Task CreateResponse(HttpContext context, HttpResponseMessage response); diff --git a/src/Ocelot.Library/Infrastructure/Responses/ErrorResponse.cs b/src/Ocelot.Library/Responses/ErrorResponse.cs similarity index 52% rename from src/Ocelot.Library/Infrastructure/Responses/ErrorResponse.cs rename to src/Ocelot.Library/Responses/ErrorResponse.cs index 2ceb83a2..b097d961 100644 --- a/src/Ocelot.Library/Infrastructure/Responses/ErrorResponse.cs +++ b/src/Ocelot.Library/Responses/ErrorResponse.cs @@ -1,8 +1,8 @@ -using System.Collections.Generic; -using Ocelot.Library.Infrastructure.Errors; - -namespace Ocelot.Library.Infrastructure.Responses +namespace Ocelot.Library.Responses { + using System.Collections.Generic; + using Errors; + public class ErrorResponse : Response { public ErrorResponse(List errors) : base(errors) diff --git a/src/Ocelot.Library/Infrastructure/Responses/ErrorResponseGeneric.cs b/src/Ocelot.Library/Responses/ErrorResponseGeneric.cs similarity index 53% rename from src/Ocelot.Library/Infrastructure/Responses/ErrorResponseGeneric.cs rename to src/Ocelot.Library/Responses/ErrorResponseGeneric.cs index 86d884c1..c5f8ef0b 100644 --- a/src/Ocelot.Library/Infrastructure/Responses/ErrorResponseGeneric.cs +++ b/src/Ocelot.Library/Responses/ErrorResponseGeneric.cs @@ -1,8 +1,8 @@ -using System.Collections.Generic; -using Ocelot.Library.Infrastructure.Errors; - -namespace Ocelot.Library.Infrastructure.Responses +namespace Ocelot.Library.Responses { + using System.Collections.Generic; + using Errors; + public class ErrorResponse : Response { public ErrorResponse(List errors) : base(errors) diff --git a/src/Ocelot.Library/Infrastructure/Responses/OkResponse.cs b/src/Ocelot.Library/Responses/OkResponse.cs similarity index 67% rename from src/Ocelot.Library/Infrastructure/Responses/OkResponse.cs rename to src/Ocelot.Library/Responses/OkResponse.cs index 0b71f0d0..457afced 100644 --- a/src/Ocelot.Library/Infrastructure/Responses/OkResponse.cs +++ b/src/Ocelot.Library/Responses/OkResponse.cs @@ -1,4 +1,4 @@ -namespace Ocelot.Library.Infrastructure.Responses +namespace Ocelot.Library.Responses { public class OkResponse : Response { diff --git a/src/Ocelot.Library/Infrastructure/Responses/OkResponseGeneric.cs b/src/Ocelot.Library/Responses/OkResponseGeneric.cs similarity index 71% rename from src/Ocelot.Library/Infrastructure/Responses/OkResponseGeneric.cs rename to src/Ocelot.Library/Responses/OkResponseGeneric.cs index a18ac11f..d768f62f 100644 --- a/src/Ocelot.Library/Infrastructure/Responses/OkResponseGeneric.cs +++ b/src/Ocelot.Library/Responses/OkResponseGeneric.cs @@ -1,4 +1,4 @@ -namespace Ocelot.Library.Infrastructure.Responses +namespace Ocelot.Library.Responses { public class OkResponse : Response { diff --git a/src/Ocelot.Library/Infrastructure/Responses/Response.cs b/src/Ocelot.Library/Responses/Response.cs similarity index 77% rename from src/Ocelot.Library/Infrastructure/Responses/Response.cs rename to src/Ocelot.Library/Responses/Response.cs index 9818df78..c5628ac4 100644 --- a/src/Ocelot.Library/Infrastructure/Responses/Response.cs +++ b/src/Ocelot.Library/Responses/Response.cs @@ -1,8 +1,8 @@ -using System.Collections.Generic; -using Ocelot.Library.Infrastructure.Errors; - -namespace Ocelot.Library.Infrastructure.Responses +namespace Ocelot.Library.Responses { + using System.Collections.Generic; + using Errors; + public abstract class Response { protected Response() diff --git a/src/Ocelot.Library/Infrastructure/Responses/ResponseGeneric.cs b/src/Ocelot.Library/Responses/ResponseGeneric.cs similarity index 68% rename from src/Ocelot.Library/Infrastructure/Responses/ResponseGeneric.cs rename to src/Ocelot.Library/Responses/ResponseGeneric.cs index 790fe5c1..bcebf865 100644 --- a/src/Ocelot.Library/Infrastructure/Responses/ResponseGeneric.cs +++ b/src/Ocelot.Library/Responses/ResponseGeneric.cs @@ -1,8 +1,8 @@ -using System.Collections.Generic; -using Ocelot.Library.Infrastructure.Errors; - -namespace Ocelot.Library.Infrastructure.Responses +namespace Ocelot.Library.Responses { + using System.Collections.Generic; + using Errors; + public abstract class Response : Response { protected Response(T data) diff --git a/src/Ocelot.Library/Infrastructure/UrlMatcher/ITemplateVariableNameAndValueFinder.cs b/src/Ocelot.Library/UrlMatcher/ITemplateVariableNameAndValueFinder.cs similarity index 58% rename from src/Ocelot.Library/Infrastructure/UrlMatcher/ITemplateVariableNameAndValueFinder.cs rename to src/Ocelot.Library/UrlMatcher/ITemplateVariableNameAndValueFinder.cs index 3cadce39..ff8bb862 100644 --- a/src/Ocelot.Library/Infrastructure/UrlMatcher/ITemplateVariableNameAndValueFinder.cs +++ b/src/Ocelot.Library/UrlMatcher/ITemplateVariableNameAndValueFinder.cs @@ -1,8 +1,8 @@ -using System.Collections.Generic; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.UrlMatcher +namespace Ocelot.Library.UrlMatcher { + using System.Collections.Generic; + using Responses; + public interface ITemplateVariableNameAndValueFinder { Response> Find(string upstreamUrlPath, string upstreamUrlPathTemplate); diff --git a/src/Ocelot.Library/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs b/src/Ocelot.Library/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs new file mode 100644 index 00000000..996df64c --- /dev/null +++ b/src/Ocelot.Library/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs @@ -0,0 +1,9 @@ +namespace Ocelot.Library.UrlMatcher +{ + using Responses; + + public interface IUrlPathToUrlTemplateMatcher + { + Response Match(string upstreamUrlPath, string upstreamUrlPathTemplate); + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlMatcher/RegExUrlMatcher.cs b/src/Ocelot.Library/UrlMatcher/RegExUrlMatcher.cs similarity index 75% rename from src/Ocelot.Library/Infrastructure/UrlMatcher/RegExUrlMatcher.cs rename to src/Ocelot.Library/UrlMatcher/RegExUrlMatcher.cs index 55855eca..cfcd209d 100644 --- a/src/Ocelot.Library/Infrastructure/UrlMatcher/RegExUrlMatcher.cs +++ b/src/Ocelot.Library/UrlMatcher/RegExUrlMatcher.cs @@ -1,8 +1,8 @@ -using System.Text.RegularExpressions; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.UrlMatcher +namespace Ocelot.Library.UrlMatcher { + using System.Text.RegularExpressions; + using Responses; + public class RegExUrlMatcher : IUrlPathToUrlTemplateMatcher { public Response Match(string upstreamUrlPath, string upstreamUrlPathTemplate) diff --git a/src/Ocelot.Library/Infrastructure/UrlMatcher/TemplateVariableNameAndValue.cs b/src/Ocelot.Library/UrlMatcher/TemplateVariableNameAndValue.cs similarity index 89% rename from src/Ocelot.Library/Infrastructure/UrlMatcher/TemplateVariableNameAndValue.cs rename to src/Ocelot.Library/UrlMatcher/TemplateVariableNameAndValue.cs index 07935d08..ba81b4fd 100644 --- a/src/Ocelot.Library/Infrastructure/UrlMatcher/TemplateVariableNameAndValue.cs +++ b/src/Ocelot.Library/UrlMatcher/TemplateVariableNameAndValue.cs @@ -1,4 +1,4 @@ -namespace Ocelot.Library.Infrastructure.UrlMatcher +namespace Ocelot.Library.UrlMatcher { public class TemplateVariableNameAndValue { diff --git a/src/Ocelot.Library/Infrastructure/UrlMatcher/TemplateVariableNameAndValueFinder.cs b/src/Ocelot.Library/UrlMatcher/TemplateVariableNameAndValueFinder.cs similarity index 93% rename from src/Ocelot.Library/Infrastructure/UrlMatcher/TemplateVariableNameAndValueFinder.cs rename to src/Ocelot.Library/UrlMatcher/TemplateVariableNameAndValueFinder.cs index 30658afc..34f66095 100644 --- a/src/Ocelot.Library/Infrastructure/UrlMatcher/TemplateVariableNameAndValueFinder.cs +++ b/src/Ocelot.Library/UrlMatcher/TemplateVariableNameAndValueFinder.cs @@ -1,9 +1,9 @@ -using System.Collections.Generic; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.UrlMatcher +namespace Ocelot.Library.UrlMatcher { - public class TemplateVariableNameAndValueFinder : ITemplateVariableNameAndValueFinder + using System.Collections.Generic; + using Responses; + + public class TemplateVariableNameAndValueFinder : ITemplateVariableNameAndValueFinder { public Response> Find(string upstreamUrlPath, string upstreamUrlPathTemplate) { diff --git a/src/Ocelot.Library/Infrastructure/UrlMatcher/UrlMatch.cs b/src/Ocelot.Library/UrlMatcher/UrlMatch.cs similarity index 76% rename from src/Ocelot.Library/Infrastructure/UrlMatcher/UrlMatch.cs rename to src/Ocelot.Library/UrlMatcher/UrlMatch.cs index db569d4a..123b5091 100644 --- a/src/Ocelot.Library/Infrastructure/UrlMatcher/UrlMatch.cs +++ b/src/Ocelot.Library/UrlMatcher/UrlMatch.cs @@ -1,4 +1,4 @@ -namespace Ocelot.Library.Infrastructure.UrlMatcher +namespace Ocelot.Library.UrlMatcher { public class UrlMatch { diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs b/src/Ocelot.Library/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs similarity index 78% rename from src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs rename to src/Ocelot.Library/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs index 65f8a759..94f1ab24 100644 --- a/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs +++ b/src/Ocelot.Library/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs @@ -1,9 +1,9 @@ -using System.Text; -using Ocelot.Library.Infrastructure.DownstreamRouteFinder; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.UrlTemplateReplacer +namespace Ocelot.Library.UrlTemplateReplacer { + using System.Text; + using DownstreamRouteFinder; + using Responses; + public class DownstreamUrlTemplateVariableReplacer : IDownstreamUrlTemplateVariableReplacer { public Response ReplaceTemplateVariables(DownstreamRoute downstreamRoute) diff --git a/src/Ocelot.Library/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs b/src/Ocelot.Library/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs new file mode 100644 index 00000000..31c50726 --- /dev/null +++ b/src/Ocelot.Library/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs @@ -0,0 +1,10 @@ +namespace Ocelot.Library.UrlTemplateReplacer +{ + using DownstreamRouteFinder; + using Responses; + + public interface IDownstreamUrlTemplateVariableReplacer + { + Response ReplaceTemplateVariables(DownstreamRoute downstreamRoute); + } +} \ No newline at end of file diff --git a/src/Ocelot/Startup.cs b/src/Ocelot/Startup.cs index 1ea234e3..6b7d7973 100644 --- a/src/Ocelot/Startup.cs +++ b/src/Ocelot/Startup.cs @@ -1,26 +1,14 @@ -using System.Collections.Generic; -using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Configuration.Memory; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Ocelot.Library.Infrastructure.Authentication; -using Ocelot.Library.Infrastructure.Configuration; -using Ocelot.Library.Infrastructure.Configuration.Yaml; -using Ocelot.Library.Infrastructure.DownstreamRouteFinder; -using Ocelot.Library.Infrastructure.Middleware; -using Ocelot.Library.Infrastructure.Repository; -using Ocelot.Library.Infrastructure.RequestBuilder; -using Ocelot.Library.Infrastructure.Requester; -using Ocelot.Library.Infrastructure.Responder; -using Ocelot.Library.Infrastructure.UrlMatcher; -using Ocelot.Library.Infrastructure.UrlTemplateReplacer; namespace Ocelot { + using Library.DependencyInjection; + using Library.Middleware; + public class Startup { public Startup(IHostingEnvironment env) @@ -45,26 +33,7 @@ namespace Ocelot services.AddMvcCore().AddAuthorization().AddJsonFormatters(); services.AddAuthentication(); services.AddLogging(); - - services.Configure(Configuration); - - // Add framework services. - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - - // see this for why we register this as singleton http://stackoverflow.com/questions/37371264/invalidoperationexception-unable-to-resolve-service-for-type-microsoft-aspnetc - services.AddSingleton(); - services.AddScoped(); + services.AddOcelot(Configuration); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. @@ -74,17 +43,7 @@ namespace Ocelot loggerFactory.AddDebug(); - app.UseHttpResponderMiddleware(); - - app.UseDownstreamRouteFinderMiddleware(); - - app.UseAuthenticationMiddleware(); - - app.UseDownstreamUrlCreatorMiddleware(); - - app.UseHttpRequestBuilderMiddleware(); - - app.UseHttpRequesterMiddleware(); + app.UseOcelot(); } } } diff --git a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs index b38b70a7..8994e77c 100644 --- a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs +++ b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs @@ -13,7 +13,6 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; -using Ocelot.Library.Infrastructure.Configuration.Yaml; using Shouldly; using TestStack.BDDfy; using Xunit; @@ -21,6 +20,9 @@ using YamlDotNet.Serialization; namespace Ocelot.AcceptanceTests { + using System.Security.Claims; + using Library.Configuration.Yaml; + public class AuthenticationTests : IDisposable { private TestServer _ocelotServer; @@ -28,7 +30,7 @@ namespace Ocelot.AcceptanceTests private HttpResponseMessage _response; private readonly string _configurationPath; private StringContent _postContent; - private IWebHost _ocelotBbuilder; + private IWebHost _servicebuilder; // Sadly we need to change this when we update the netcoreapp version to make the test update the config correctly private double _netCoreAppVersion = 1.4; @@ -106,6 +108,42 @@ namespace Ocelot.AcceptanceTests .BDDfy(); } + [Fact] + public void should_return_response_200_using_identity_server() + { + + this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Jwt)) + .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura")) + .And(x => x.GivenIHaveAToken("http://localhost:51888")) + .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration + { + ReRoutes = new List + { + new YamlReRoute + { + DownstreamTemplate = "http://localhost:51876/", + UpstreamTemplate = "/", + UpstreamHttpMethod = "Get", + AuthenticationOptions = new YamlAuthenticationOptions + { + AdditionalScopes = new List(), + Provider = "IdentityServer", + ProviderRootUrl = "http://localhost:51888", + RequireHttps = false, + ScopeName = "api", + ScopeSecret = "secret" + } + } + } + })) + .And(x => x.GivenTheApiGatewayIsRunning()) + .And(x => x.GivenIHaveAddedATokenToMyRequest()) + .When(x => x.WhenIGetUrlOnTheApiGateway("/")) + .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + .And(x => x.ThenTheResponseBodyShouldBe("Hello from Laura")) + .BDDfy(); + } + [Fact] public void should_return_201_using_identity_server_access_token() { @@ -176,6 +214,21 @@ namespace Ocelot.AcceptanceTests .BDDfy(); } + private void WhenIGetUrlOnTheApiGateway(string url) + { + _response = _ocelotClient.GetAsync(url).Result; + } + + private void WhenIPostUrlOnTheApiGateway(string url) + { + _response = _ocelotClient.PostAsync(url, _postContent).Result; + } + + private void ThenTheResponseBodyShouldBe(string expectedBody) + { + _response.Content.ReadAsStringAsync().Result.ShouldBe(expectedBody); + } + private void GivenThePostHasContent(string postcontent) { _postContent = new StringContent(postcontent); @@ -209,7 +262,7 @@ namespace Ocelot.AcceptanceTests private void GivenThereIsAServiceRunningOn(string url, int statusCode, string responseBody) { - _ocelotBbuilder = new WebHostBuilder() + _servicebuilder = new WebHostBuilder() .UseUrls(url) .UseKestrel() .UseContentRoot(Directory.GetCurrentDirectory()) @@ -225,7 +278,7 @@ namespace Ocelot.AcceptanceTests }) .Build(); - _ocelotBbuilder.Start(); + _servicebuilder.Start(); } private void GivenThereIsAnIdentityServerOn(string url, string scopeName, AccessTokenType tokenType) @@ -240,41 +293,52 @@ namespace Ocelot.AcceptanceTests { services.AddLogging(); services.AddDeveloperIdentityServer() - .AddInMemoryScopes(new List { new Scope - { - Name = scopeName, - Description = "My API", - Enabled = true, - AllowUnrestrictedIntrospection = true, - ScopeSecrets = new List() + .AddInMemoryScopes(new List { - new Secret + new Scope { - Value = "secret".Sha256() + Name = scopeName, + Description = "My API", + Enabled = true, + AllowUnrestrictedIntrospection = true, + ScopeSecrets = new List() + { + new Secret + { + Value = "secret".Sha256() + } + } + }, + + StandardScopes.OpenId, + StandardScopes.OfflineAccess + }) + .AddInMemoryClients(new List + { + new Client + { + ClientId = "client", + AllowedGrantTypes = GrantTypes.ResourceOwnerPassword, + ClientSecrets = new List {new Secret("secret".Sha256())}, + AllowedScopes = new List { scopeName, "openid", "offline_access" }, + AccessTokenType = tokenType, + Enabled = true, + RequireClientSecret = false } - } - }}) - .AddInMemoryClients(new List { - new Client - { - ClientId = "client", - AllowedGrantTypes = GrantTypes.ResourceOwnerPassword, - ClientSecrets = new List { new Secret("secret".Sha256()) }, - AllowedScopes = new List { scopeName }, - AccessTokenType = tokenType, - Enabled = true, - RequireClientSecret = false - } }) - .AddInMemoryUsers(new List { new InMemoryUser - { - Username = "test", - Password = "test", - Enabled = true, - Subject = "asdads" - }}); + }) + .AddInMemoryUsers(new List + { + new InMemoryUser + { + Username = "test", + Password = "test", + Enabled = true, + Subject = "asdads" + } + }); }) .Configure(app => - { + { app.UseIdentityServer(); }) .Build(); @@ -322,11 +386,6 @@ namespace Ocelot.AcceptanceTests _ocelotClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _token.AccessToken); } - private void WhenIPostUrlOnTheApiGateway(string url) - { - _response = _ocelotClient.PostAsync(url, _postContent).Result; - } - private void ThenTheStatusCodeShouldBe(HttpStatusCode expectedHttpStatusCode) { _response.StatusCode.ShouldBe(expectedHttpStatusCode); @@ -334,7 +393,7 @@ namespace Ocelot.AcceptanceTests public void Dispose() { - _ocelotBbuilder?.Dispose(); + _servicebuilder?.Dispose(); _ocelotClient?.Dispose(); _ocelotServer?.Dispose(); _identityServerBuilder?.Dispose(); diff --git a/test/Ocelot.AcceptanceTests/OcelotTests.cs b/test/Ocelot.AcceptanceTests/OcelotTests.cs index 2f4fb53b..8caf3e17 100644 --- a/test/Ocelot.AcceptanceTests/OcelotTests.cs +++ b/test/Ocelot.AcceptanceTests/OcelotTests.cs @@ -7,7 +7,6 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.TestHost; -using Ocelot.Library.Infrastructure.Configuration.Yaml; using Shouldly; using TestStack.BDDfy; using Xunit; @@ -15,6 +14,8 @@ using YamlDotNet.Serialization; namespace Ocelot.AcceptanceTests { + using Library.Configuration.Yaml; + public class OcelotTests : IDisposable { private TestServer _server; diff --git a/test/Ocelot.UnitTests/Authentication/AuthenticationHandlerFactoryTests.cs b/test/Ocelot.UnitTests/Authentication/AuthenticationHandlerFactoryTests.cs index 1e2f6d42..fb6311c6 100644 --- a/test/Ocelot.UnitTests/Authentication/AuthenticationHandlerFactoryTests.cs +++ b/test/Ocelot.UnitTests/Authentication/AuthenticationHandlerFactoryTests.cs @@ -3,21 +3,23 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Moq; -using Ocelot.Library.Infrastructure.Authentication; -using Ocelot.Library.Infrastructure.Errors; -using Ocelot.Library.Infrastructure.Responses; using Shouldly; using TestStack.BDDfy; using Xunit; namespace Ocelot.UnitTests.Authentication { + using Library.Authentication; + using Library.Configuration; + using Library.Errors; + using Library.Responses; + public class AuthenticationHandlerFactoryTests { private readonly IAuthenticationHandlerFactory _authenticationHandlerFactory; private readonly Mock _app; private readonly Mock _creator; - private Library.Infrastructure.Configuration.AuthenticationOptions _authenticationOptions; + private AuthenticationOptions _authenticationOptions; private Response _result; public AuthenticationHandlerFactoryTests() @@ -30,7 +32,7 @@ namespace Ocelot.UnitTests.Authentication [Fact] public void should_return_identity_server_access_token_handler() { - this.Given(x => x.GivenTheAuthenticationOptionsAre(new Library.Infrastructure.Configuration.AuthenticationOptions("IdentityServer", "","",false, new List(), ""))) + this.Given(x => x.GivenTheAuthenticationOptionsAre(new AuthenticationOptions("IdentityServer", "","",false, new List(), ""))) .And(x => x.GivenTheCreatorReturns()) .When(x => x.WhenIGetFromTheFactory()) .Then(x => x.ThenTheHandlerIsReturned("IdentityServer")) @@ -40,14 +42,14 @@ namespace Ocelot.UnitTests.Authentication [Fact] public void should_return_error_if_cannot_create_handler() { - this.Given(x => x.GivenTheAuthenticationOptionsAre(new Library.Infrastructure.Configuration.AuthenticationOptions("IdentityServer", "", "", false, new List(), ""))) + this.Given(x => x.GivenTheAuthenticationOptionsAre(new AuthenticationOptions("IdentityServer", "", "", false, new List(), ""))) .And(x => x.GivenTheCreatorReturnsAnError()) .When(x => x.WhenIGetFromTheFactory()) .Then(x => x.ThenAnErrorResponseIsReturned()) .BDDfy(); } - private void GivenTheAuthenticationOptionsAre(Library.Infrastructure.Configuration.AuthenticationOptions authenticationOptions) + private void GivenTheAuthenticationOptionsAre(AuthenticationOptions authenticationOptions) { _authenticationOptions = authenticationOptions; } @@ -55,7 +57,7 @@ namespace Ocelot.UnitTests.Authentication private void GivenTheCreatorReturnsAnError() { _creator - .Setup(x => x.CreateIdentityServerAuthenticationHandler(It.IsAny(), It.IsAny())) + .Setup(x => x.CreateIdentityServerAuthenticationHandler(It.IsAny(), It.IsAny())) .Returns(new ErrorResponse(new List { new UnableToCreateAuthenticationHandlerError($"Unable to create authentication handler for xxx") @@ -65,7 +67,7 @@ namespace Ocelot.UnitTests.Authentication private void GivenTheCreatorReturns() { _creator - .Setup(x => x.CreateIdentityServerAuthenticationHandler(It.IsAny(), It.IsAny())) + .Setup(x => x.CreateIdentityServerAuthenticationHandler(It.IsAny(), It.IsAny())) .Returns(new OkResponse(x => Task.CompletedTask)); } diff --git a/test/Ocelot.UnitTests/Configuration/ConfigurationValidationTests.cs b/test/Ocelot.UnitTests/Configuration/ConfigurationValidationTests.cs index b797a9bf..a9650451 100644 --- a/test/Ocelot.UnitTests/Configuration/ConfigurationValidationTests.cs +++ b/test/Ocelot.UnitTests/Configuration/ConfigurationValidationTests.cs @@ -1,12 +1,13 @@ using System.Collections.Generic; -using Ocelot.Library.Infrastructure.Configuration.Yaml; -using Ocelot.Library.Infrastructure.Responses; using Shouldly; using TestStack.BDDfy; using Xunit; namespace Ocelot.UnitTests.Configuration { + using Library.Configuration.Yaml; + using Library.Responses; + public class ConfigurationValidationTests { private YamlConfiguration _yamlConfiguration; diff --git a/test/Ocelot.UnitTests/Configuration/OcelotConfigurationTests.cs b/test/Ocelot.UnitTests/Configuration/OcelotConfigurationTests.cs index bfbeee98..f1601a41 100644 --- a/test/Ocelot.UnitTests/Configuration/OcelotConfigurationTests.cs +++ b/test/Ocelot.UnitTests/Configuration/OcelotConfigurationTests.cs @@ -1,16 +1,17 @@ using System.Collections.Generic; using Microsoft.Extensions.Options; using Moq; -using Ocelot.Library.Infrastructure.Builder; -using Ocelot.Library.Infrastructure.Configuration; -using Ocelot.Library.Infrastructure.Configuration.Yaml; -using Ocelot.Library.Infrastructure.Responses; using Shouldly; using TestStack.BDDfy; using Xunit; namespace Ocelot.UnitTests.Configuration { + using Library.Builder; + using Library.Configuration; + using Library.Configuration.Yaml; + using Library.Responses; + public class OcelotConfigurationTests { private readonly Mock> _yamlConfig; diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs index 5a2a73cd..0f979b18 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs @@ -1,16 +1,17 @@ using System.Collections.Generic; using Moq; -using Ocelot.Library.Infrastructure.Builder; -using Ocelot.Library.Infrastructure.Configuration; -using Ocelot.Library.Infrastructure.DownstreamRouteFinder; -using Ocelot.Library.Infrastructure.Responses; -using Ocelot.Library.Infrastructure.UrlMatcher; using Shouldly; using TestStack.BDDfy; using Xunit; namespace Ocelot.UnitTests.DownstreamRouteFinder { + using Library.Builder; + using Library.Configuration; + using Library.DownstreamRouteFinder; + using Library.Responses; + using Library.UrlMatcher; + public class DownstreamRouteFinderTests { private readonly IDownstreamRouteFinder _downstreamRouteFinder; @@ -28,7 +29,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder _mockConfig = new Mock(); _mockMatcher = new Mock(); _finder = new Mock(); - _downstreamRouteFinder = new Library.Infrastructure.DownstreamRouteFinder.DownstreamRouteFinder(_mockConfig.Object, _mockMatcher.Object, _finder.Object); + _downstreamRouteFinder = new DownstreamRouteFinder(_mockConfig.Object, _mockMatcher.Object, _finder.Object); } [Fact] diff --git a/test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs index 3adf0c61..b9350cce 100644 --- a/test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs @@ -6,19 +6,18 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Moq; -using Ocelot.Library.Infrastructure.Authentication; -using Ocelot.Library.Infrastructure.Builder; -using Ocelot.Library.Infrastructure.DownstreamRouteFinder; -using Ocelot.Library.Infrastructure.Middleware; -using Ocelot.Library.Infrastructure.Repository; -using Ocelot.Library.Infrastructure.Responses; -using Ocelot.Library.Infrastructure.UrlMatcher; using TestStack.BDDfy; using Xunit; namespace Ocelot.UnitTests.Middleware { - using Library.Infrastructure.Configuration; + using Library.Authentication; + using Library.Builder; + using Library.DownstreamRouteFinder; + using Library.Middleware; + using Library.Repository; + using Library.Responses; + using Library.UrlMatcher; public class AuthenticationMiddlewareTests : IDisposable { diff --git a/test/Ocelot.UnitTests/Middleware/DownstreamRouteFinderMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/DownstreamRouteFinderMiddlewareTests.cs index 07ca69e4..894852d8 100644 --- a/test/Ocelot.UnitTests/Middleware/DownstreamRouteFinderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Middleware/DownstreamRouteFinderMiddlewareTests.cs @@ -6,17 +6,18 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Moq; -using Ocelot.Library.Infrastructure.Builder; -using Ocelot.Library.Infrastructure.DownstreamRouteFinder; -using Ocelot.Library.Infrastructure.Middleware; -using Ocelot.Library.Infrastructure.Repository; -using Ocelot.Library.Infrastructure.Responses; -using Ocelot.Library.Infrastructure.UrlMatcher; using TestStack.BDDfy; using Xunit; namespace Ocelot.UnitTests.Middleware { + using Library.Builder; + using Library.DownstreamRouteFinder; + using Library.Middleware; + using Library.Repository; + using Library.Responses; + using Library.UrlMatcher; + public class DownstreamRouteFinderMiddlewareTests : IDisposable { private readonly Mock _downstreamRouteFinder; diff --git a/test/Ocelot.UnitTests/Middleware/DownstreamUrlCreatorMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/DownstreamUrlCreatorMiddlewareTests.cs index b1d165ba..f97766d9 100644 --- a/test/Ocelot.UnitTests/Middleware/DownstreamUrlCreatorMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Middleware/DownstreamUrlCreatorMiddlewareTests.cs @@ -1,18 +1,16 @@ -using Ocelot.Library.Infrastructure.Builder; -using Ocelot.Library.Infrastructure.Middleware; - -namespace Ocelot.UnitTests.Middleware +namespace Ocelot.UnitTests.Middleware { using System; using System.Collections.Generic; using System.IO; using System.Net.Http; - using Library.Infrastructure.Configuration; - using Library.Infrastructure.DownstreamRouteFinder; - using Library.Infrastructure.Repository; - using Library.Infrastructure.Responses; - using Library.Infrastructure.UrlMatcher; - using Library.Infrastructure.UrlTemplateReplacer; + using Library.Builder; + using Library.DownstreamRouteFinder; + using Library.Middleware; + using Library.Repository; + using Library.Responses; + using Library.UrlMatcher; + using Library.UrlTemplateReplacer; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; diff --git a/test/Ocelot.UnitTests/Middleware/HttpRequestBuilderMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/HttpRequestBuilderMiddlewareTests.cs index 2a483330..9704fc6b 100644 --- a/test/Ocelot.UnitTests/Middleware/HttpRequestBuilderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Middleware/HttpRequestBuilderMiddlewareTests.cs @@ -7,15 +7,16 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Moq; -using Ocelot.Library.Infrastructure.Middleware; -using Ocelot.Library.Infrastructure.Repository; -using Ocelot.Library.Infrastructure.RequestBuilder; -using Ocelot.Library.Infrastructure.Responses; using TestStack.BDDfy; using Xunit; namespace Ocelot.UnitTests.Middleware { + using Library.Middleware; + using Library.Repository; + using Library.RequestBuilder; + using Library.Responses; + public class HttpRequestBuilderMiddlewareTests : IDisposable { private readonly Mock _requestBuilder; diff --git a/test/Ocelot.UnitTests/Middleware/HttpRequesterMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/HttpRequesterMiddlewareTests.cs index a2e24133..99cf1691 100644 --- a/test/Ocelot.UnitTests/Middleware/HttpRequesterMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Middleware/HttpRequesterMiddlewareTests.cs @@ -6,16 +6,17 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Moq; -using Ocelot.Library.Infrastructure.Middleware; -using Ocelot.Library.Infrastructure.Repository; -using Ocelot.Library.Infrastructure.RequestBuilder; -using Ocelot.Library.Infrastructure.Requester; -using Ocelot.Library.Infrastructure.Responses; using TestStack.BDDfy; using Xunit; namespace Ocelot.UnitTests.Middleware { + using Library.Middleware; + using Library.Repository; + using Library.RequestBuilder; + using Library.Requester; + using Library.Responses; + public class HttpRequesterMiddlewareTests : IDisposable { private readonly Mock _requester; diff --git a/test/Ocelot.UnitTests/Middleware/HttpResponderMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/HttpResponderMiddlewareTests.cs index e8f6ef10..f4648700 100644 --- a/test/Ocelot.UnitTests/Middleware/HttpResponderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Middleware/HttpResponderMiddlewareTests.cs @@ -6,15 +6,16 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Moq; -using Ocelot.Library.Infrastructure.Middleware; -using Ocelot.Library.Infrastructure.Repository; -using Ocelot.Library.Infrastructure.Responder; -using Ocelot.Library.Infrastructure.Responses; using TestStack.BDDfy; using Xunit; namespace Ocelot.UnitTests.Middleware { + using Library.Middleware; + using Library.Repository; + using Library.Responder; + using Library.Responses; + public class HttpResponderMiddlewareTests : IDisposable { private readonly Mock _responder; diff --git a/test/Ocelot.UnitTests/Repository/ScopedRequestDataRepositoryTests.cs b/test/Ocelot.UnitTests/Repository/ScopedRequestDataRepositoryTests.cs index 3236521d..9e688a30 100644 --- a/test/Ocelot.UnitTests/Repository/ScopedRequestDataRepositoryTests.cs +++ b/test/Ocelot.UnitTests/Repository/ScopedRequestDataRepositoryTests.cs @@ -1,12 +1,13 @@ using Microsoft.AspNetCore.Http; -using Ocelot.Library.Infrastructure.Repository; -using Ocelot.Library.Infrastructure.Responses; using Shouldly; using TestStack.BDDfy; using Xunit; namespace Ocelot.UnitTests.Repository { + using Library.Repository; + using Library.Responses; + public class ScopedRequestDataRepositoryTests { private IScopedRequestDataRepository _scopedRequestDataRepository; diff --git a/test/Ocelot.UnitTests/RequestBuilder/RequestBuilderTests.cs b/test/Ocelot.UnitTests/RequestBuilder/RequestBuilderTests.cs index ad11ae2a..80740e97 100644 --- a/test/Ocelot.UnitTests/RequestBuilder/RequestBuilderTests.cs +++ b/test/Ocelot.UnitTests/RequestBuilder/RequestBuilderTests.cs @@ -5,14 +5,15 @@ using System.Net; using System.Net.Http; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Internal; -using Ocelot.Library.Infrastructure.RequestBuilder; -using Ocelot.Library.Infrastructure.Responses; using Shouldly; using TestStack.BDDfy; using Xunit; namespace Ocelot.UnitTests.RequestBuilder { + using Library.RequestBuilder; + using Library.Responses; + public class RequestBuilderTests { private string _httpMethod; @@ -28,7 +29,7 @@ namespace Ocelot.UnitTests.RequestBuilder public RequestBuilderTests() { _content = new StringContent(string.Empty); - _requestBuilder = new Library.Infrastructure.RequestBuilder.HttpRequestBuilder(); + _requestBuilder = new HttpRequestBuilder(); } [Fact] diff --git a/test/Ocelot.UnitTests/Responder/ErrorsToHttpStatusCodeMapperTests.cs b/test/Ocelot.UnitTests/Responder/ErrorsToHttpStatusCodeMapperTests.cs index cc976b6d..fdd48842 100644 --- a/test/Ocelot.UnitTests/Responder/ErrorsToHttpStatusCodeMapperTests.cs +++ b/test/Ocelot.UnitTests/Responder/ErrorsToHttpStatusCodeMapperTests.cs @@ -2,16 +2,17 @@ using System.IO; using System.Net.Http; using Microsoft.AspNetCore.Http; -using Ocelot.Library.Infrastructure.Errors; -using Ocelot.Library.Infrastructure.Middleware; -using Ocelot.Library.Infrastructure.Responder; -using Ocelot.Library.Infrastructure.Responses; using Shouldly; using TestStack.BDDfy; using Xunit; namespace Ocelot.UnitTests.Responder { + using Library.Errors; + using Library.Middleware; + using Library.Responder; + using Library.Responses; + public class ErrorsToHttpStatusCodeMapperTests { private readonly IErrorsToHttpStatusCodeMapper _codeMapper; diff --git a/test/Ocelot.UnitTests/UrlMatcher/RegExUrlMatcherTests.cs b/test/Ocelot.UnitTests/UrlMatcher/RegExUrlMatcherTests.cs index 5774c573..392df6e2 100644 --- a/test/Ocelot.UnitTests/UrlMatcher/RegExUrlMatcherTests.cs +++ b/test/Ocelot.UnitTests/UrlMatcher/RegExUrlMatcherTests.cs @@ -1,11 +1,12 @@ -using Ocelot.Library.Infrastructure.Responses; -using Ocelot.Library.Infrastructure.UrlMatcher; using Shouldly; using TestStack.BDDfy; using Xunit; namespace Ocelot.UnitTests.UrlMatcher { + using Library.Responses; + using Library.UrlMatcher; + public class RegExUrlMatcherTests { private readonly IUrlPathToUrlTemplateMatcher _urlMatcher; diff --git a/test/Ocelot.UnitTests/UrlMatcher/TemplateVariableNameAndValueFinderTests.cs b/test/Ocelot.UnitTests/UrlMatcher/TemplateVariableNameAndValueFinderTests.cs index 6f7f4d7f..3bb3b428 100644 --- a/test/Ocelot.UnitTests/UrlMatcher/TemplateVariableNameAndValueFinderTests.cs +++ b/test/Ocelot.UnitTests/UrlMatcher/TemplateVariableNameAndValueFinderTests.cs @@ -1,13 +1,14 @@ using System.Collections.Generic; using System.Linq; -using Ocelot.Library.Infrastructure.Responses; -using Ocelot.Library.Infrastructure.UrlMatcher; using Shouldly; using TestStack.BDDfy; using Xunit; namespace Ocelot.UnitTests.UrlMatcher { + using Library.Responses; + using Library.UrlMatcher; + public class UrlPathToUrlTemplateMatcherTests { private readonly ITemplateVariableNameAndValueFinder _finder; diff --git a/test/Ocelot.UnitTests/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs b/test/Ocelot.UnitTests/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs index 961341c9..85f65d48 100644 --- a/test/Ocelot.UnitTests/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs +++ b/test/Ocelot.UnitTests/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs @@ -1,16 +1,15 @@ using System.Collections.Generic; -using Ocelot.Library.Infrastructure.Builder; -using Ocelot.Library.Infrastructure.DownstreamRouteFinder; -using Ocelot.Library.Infrastructure.Responses; -using Ocelot.Library.Infrastructure.UrlMatcher; -using Ocelot.Library.Infrastructure.UrlTemplateReplacer; using Shouldly; using TestStack.BDDfy; using Xunit; namespace Ocelot.UnitTests.UrlTemplateReplacer { - using Library.Infrastructure.Configuration; + using Library.Builder; + using Library.DownstreamRouteFinder; + using Library.Responses; + using Library.UrlMatcher; + using Library.UrlTemplateReplacer; public class UpstreamUrlPathTemplateVariableReplacerTests { From 2395736b6bc6f53ffe69bae023cc925aa2e23c08 Mon Sep 17 00:00:00 2001 From: "tom.pallister" Date: Mon, 17 Oct 2016 20:46:30 +0100 Subject: [PATCH 088/183] started working on stripping claims from token --- README.md | 2 +- .../Configuration/Yaml/YamlReRoute.cs | 8 ++++ .../AuthenticationTests.cs | 41 +++++++++++++++++++ test/Ocelot.AcceptanceTests/OcelotTests.cs | 2 +- .../Ocelot.AcceptanceTests/configuration.yaml | 14 +++++-- 5 files changed, 62 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 9bbaf309..5745ee79 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ ReRoutes: UpstreamTemplate: / UpstreamHttpMethod: Post AuthenticationOptions: - Provider: IdentityServer.AccessToken + Provider: IdentityServer ProviderRootUrl: http://localhost:51888 ScopeName: api AdditionalScopes: [] diff --git a/src/Ocelot.Library/Configuration/Yaml/YamlReRoute.cs b/src/Ocelot.Library/Configuration/Yaml/YamlReRoute.cs index 0b7be040..ed3410b5 100644 --- a/src/Ocelot.Library/Configuration/Yaml/YamlReRoute.cs +++ b/src/Ocelot.Library/Configuration/Yaml/YamlReRoute.cs @@ -1,10 +1,18 @@ namespace Ocelot.Library.Configuration.Yaml { + using System.Collections.Generic; + public class YamlReRoute { + public YamlReRoute() + { + AddHeadersToRequest = new Dictionary(); + } + public string DownstreamTemplate { get; set; } public string UpstreamTemplate { get; set; } public string UpstreamHttpMethod { get; set; } public YamlAuthenticationOptions AuthenticationOptions { get; set; } + public Dictionary AddHeadersToRequest { get; set; } } } \ No newline at end of file diff --git a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs index 8994e77c..c962b47b 100644 --- a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs +++ b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs @@ -144,6 +144,47 @@ namespace Ocelot.AcceptanceTests .BDDfy(); } + [Fact] + public void should_return_response_200_and_foward_claim_as_header() + { + + this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Jwt)) + .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura")) + .And(x => x.GivenIHaveAToken("http://localhost:51888")) + .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration + { + ReRoutes = new List + { + new YamlReRoute + { + DownstreamTemplate = "http://localhost:51876/", + UpstreamTemplate = "/", + UpstreamHttpMethod = "Get", + AuthenticationOptions = new YamlAuthenticationOptions + { + AdditionalScopes = new List(), + Provider = "IdentityServer", + ProviderRootUrl = "http://localhost:51888", + RequireHttps = false, + ScopeName = "api", + ScopeSecret = "secret" + }, + AddHeadersToRequest = + { + { "CustomerId","Claims[CustomerId] > long" }, + { "LocationId","Claims[LocationId] > int" } + } + } + } + })) + .And(x => x.GivenTheApiGatewayIsRunning()) + .And(x => x.GivenIHaveAddedATokenToMyRequest()) + .When(x => x.WhenIGetUrlOnTheApiGateway("/")) + .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + .And(x => x.ThenTheResponseBodyShouldBe("Hello from Laura")) + .BDDfy(); + } + [Fact] public void should_return_201_using_identity_server_access_token() { diff --git a/test/Ocelot.AcceptanceTests/OcelotTests.cs b/test/Ocelot.AcceptanceTests/OcelotTests.cs index 8caf3e17..b838736b 100644 --- a/test/Ocelot.AcceptanceTests/OcelotTests.cs +++ b/test/Ocelot.AcceptanceTests/OcelotTests.cs @@ -55,7 +55,7 @@ namespace Ocelot.AcceptanceTests { DownstreamTemplate = "http://localhost:51879/", UpstreamTemplate = "/", - UpstreamHttpMethod = "Get" + UpstreamHttpMethod = "Get", } } })) diff --git a/test/Ocelot.AcceptanceTests/configuration.yaml b/test/Ocelot.AcceptanceTests/configuration.yaml index c438428b..29e93d20 100644 --- a/test/Ocelot.AcceptanceTests/configuration.yaml +++ b/test/Ocelot.AcceptanceTests/configuration.yaml @@ -1,5 +1,13 @@ ReRoutes: -- DownstreamTemplate: http://localhost:51879/ +- DownstreamTemplate: http://localhost:51876/ UpstreamTemplate: / - UpstreamHttpMethod: Get - Authentication: IdentityServer.AccessToken + UpstreamHttpMethod: Post + AuthenticationOptions: + Provider: IdentityServer + ProviderRootUrl: http://localhost:51888 + ScopeName: api + AdditionalScopes: [] + ScopeSecret: secret + ProxyRequestHeaders: + - CustomerId: Claims[CustomerId] + From 279aae3151f2147876a32cfddfd2b95f5d1f02e4 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Mon, 17 Oct 2016 21:34:08 +0100 Subject: [PATCH 089/183] messing with dsl for stripping claims etc --- test/Ocelot.AcceptanceTests/AuthenticationTests.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs index c962b47b..1513b190 100644 --- a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs +++ b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs @@ -171,8 +171,10 @@ namespace Ocelot.AcceptanceTests }, AddHeadersToRequest = { - { "CustomerId","Claims[CustomerId] > long" }, - { "LocationId","Claims[LocationId] > int" } + { "CustomerId", "Claims[CustomerId] -> value" }, + { "LocationId", "Claims[LocationId] -> value"}, + { "UserId", "Claims[Subject] -> delimiter(|) -> value[0]" }, + { "UserId", "Claims[Subject] -> delimiter(|) -> value[1]" } } } } @@ -374,7 +376,12 @@ namespace Ocelot.AcceptanceTests Username = "test", Password = "test", Enabled = true, - Subject = "asdads" + Subject = "registered|1231231", + Claims = new List + { + new Claim("CustomerId", "123"), + new Claim("LocationId", "321") + } } }); }) From 84256e7bac0fa2c8ceba92bd8fe64c8015a37cea Mon Sep 17 00:00:00 2001 From: TomPallister Date: Tue, 18 Oct 2016 15:51:56 +0100 Subject: [PATCH 090/183] Added ability to strip claims and forward to downstream service as headers --- README.md | 21 +- src/Ocelot.Library/Builder/ReRouteBuilder.cs | 13 +- .../Configuration/OcelotConfiguration.cs | 44 ++- src/Ocelot.Library/Configuration/ReRoute.cs | 10 +- .../Configuration/Yaml/YamlReRoute.cs | 2 +- .../ServiceCollectionExtensions.cs | 3 + src/Ocelot.Library/Errors/OcelotErrorCode.cs | 6 +- .../Middleware/ClaimsParserMiddleware.cs | 23 -- .../HttpRequestHeadersBuilderMiddleware.cs | 41 +++ ...questHeadersBuilderMiddlewareExtensions.cs | 12 + .../Middleware/OcelotMiddlewareExtensions.cs | 2 + .../RequestBuilder/AddHeadersToRequest.cs | 42 +++ .../RequestBuilder/CannotFindClaimError.cs | 12 + .../RequestBuilder/ClaimsParser.cs | 55 ++++ .../ConfigurationHeaderExtractorProperties.cs | 18 ++ .../RequestBuilder/HeaderExtrator.cs | 73 +++++ .../RequestBuilder/IAddHeadersToRequest.cs | 12 + .../RequestBuilder/IClaimsParser.cs | 11 + .../IConfigurationHeaderExtrator.cs | 10 + .../InstructionNotForClaimsError.cs | 12 + .../RequestBuilder/NoInstructionsError.cs | 12 + .../ParsingConfigurationHeaderError.cs | 13 + .../Responder/HttpContextResponder.cs | 16 +- .../AuthenticationTests.cs | 43 --- .../ClaimsToHeadersForwardingTests.cs | 291 ++++++++++++++++++ .../ReturnsErrorTests.cs | 123 ++++++++ test/Ocelot.AcceptanceTests/project.json | 6 +- .../Configuration/OcelotConfigurationTests.cs | 134 +++++++- ...ttpRequestHeadersBuilderMiddlewareTests.cs | 110 +++++++ .../AddHeadersToRequestTests.cs | 152 +++++++++ .../RequestBuilder/ClaimParserTests.cs | 123 ++++++++ .../ConfigurationHeadersExtractorTests.cs | 116 +++++++ 32 files changed, 1467 insertions(+), 94 deletions(-) delete mode 100644 src/Ocelot.Library/Middleware/ClaimsParserMiddleware.cs create mode 100644 src/Ocelot.Library/Middleware/HttpRequestHeadersBuilderMiddleware.cs create mode 100644 src/Ocelot.Library/Middleware/HttpRequestHeadersBuilderMiddlewareExtensions.cs create mode 100644 src/Ocelot.Library/RequestBuilder/AddHeadersToRequest.cs create mode 100644 src/Ocelot.Library/RequestBuilder/CannotFindClaimError.cs create mode 100644 src/Ocelot.Library/RequestBuilder/ClaimsParser.cs create mode 100644 src/Ocelot.Library/RequestBuilder/ConfigurationHeaderExtractorProperties.cs create mode 100644 src/Ocelot.Library/RequestBuilder/HeaderExtrator.cs create mode 100644 src/Ocelot.Library/RequestBuilder/IAddHeadersToRequest.cs create mode 100644 src/Ocelot.Library/RequestBuilder/IClaimsParser.cs create mode 100644 src/Ocelot.Library/RequestBuilder/IConfigurationHeaderExtrator.cs create mode 100644 src/Ocelot.Library/RequestBuilder/InstructionNotForClaimsError.cs create mode 100644 src/Ocelot.Library/RequestBuilder/NoInstructionsError.cs create mode 100644 src/Ocelot.Library/RequestBuilder/ParsingConfigurationHeaderError.cs create mode 100644 test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs create mode 100644 test/Ocelot.AcceptanceTests/ReturnsErrorTests.cs create mode 100644 test/Ocelot.UnitTests/Middleware/HttpRequestHeadersBuilderMiddlewareTests.cs create mode 100644 test/Ocelot.UnitTests/RequestBuilder/AddHeadersToRequestTests.cs create mode 100644 test/Ocelot.UnitTests/RequestBuilder/ClaimParserTests.cs create mode 100644 test/Ocelot.UnitTests/RequestBuilder/ConfigurationHeadersExtractorTests.cs diff --git a/README.md b/README.md index 5745ee79..8330c331 100644 --- a/README.md +++ b/README.md @@ -38,12 +38,25 @@ Priorities TBC really but example configuration for a route below. ReRoutes: -- DownstreamTemplate: http://localhost:51876/ +# the url we are forwarding the request to +- DownstreamTemplate: http://localhost:52876/ +# the path we are listening on for this re route UpstreamTemplate: / - UpstreamHttpMethod: Post +# the method we are listening for on this re route + UpstreamHttpMethod: Get +# only support identity server at the moment AuthenticationOptions: Provider: IdentityServer - ProviderRootUrl: http://localhost:51888 + ProviderRootUrl: http://localhost:52888 ScopeName: api - AdditionalScopes: [] + AdditionalScopes: + - openid + - offline_access +#require if using reference tokens ScopeSecret: secret +# WARNING - will overwrite any headers already in the request with these values + AddHeadersToRequest: + CustomerId: Claims[CustomerId] > value + LocationId: Claims[LocationId] > value + UserType: Claims[sub] > value[0] > | + UserId: Claims[sub] > value[1] > | diff --git a/src/Ocelot.Library/Builder/ReRouteBuilder.cs b/src/Ocelot.Library/Builder/ReRouteBuilder.cs index c4ff124a..5668f15e 100644 --- a/src/Ocelot.Library/Builder/ReRouteBuilder.cs +++ b/src/Ocelot.Library/Builder/ReRouteBuilder.cs @@ -1,4 +1,6 @@ -namespace Ocelot.Library.Builder +using Ocelot.Library.RequestBuilder; + +namespace Ocelot.Library.Builder { using System.Collections.Generic; using Configuration; @@ -16,6 +18,7 @@ private List _additionalScopes; private bool _requireHttps; private string _scopeSecret; + private List _configHeaderExtractorProperties; public ReRouteBuilder() { @@ -86,9 +89,15 @@ return this; } + public ReRouteBuilder WithConfigurationHeaderExtractorProperties(List input) + { + _configHeaderExtractorProperties = input; + return this; + } + public ReRoute Build() { - return new ReRoute(_downstreamTemplate, _upstreamTemplate, _upstreamHttpMethod, _upstreamTemplatePattern, _isAuthenticated, new AuthenticationOptions(_authenticationProvider, _authenticationProviderUrl, _scopeName, _requireHttps, _additionalScopes, _scopeSecret)); + return new ReRoute(_downstreamTemplate, _upstreamTemplate, _upstreamHttpMethod, _upstreamTemplatePattern, _isAuthenticated, new AuthenticationOptions(_authenticationProvider, _authenticationProviderUrl, _scopeName, _requireHttps, _additionalScopes, _scopeSecret), _configHeaderExtractorProperties); } } } diff --git a/src/Ocelot.Library/Configuration/OcelotConfiguration.cs b/src/Ocelot.Library/Configuration/OcelotConfiguration.cs index b49f193a..d149baac 100644 --- a/src/Ocelot.Library/Configuration/OcelotConfiguration.cs +++ b/src/Ocelot.Library/Configuration/OcelotConfiguration.cs @@ -1,3 +1,8 @@ +using System; +using System.Linq; +using Microsoft.Extensions.Logging; +using Ocelot.Library.RequestBuilder; + namespace Ocelot.Library.Configuration { using System.Collections.Generic; @@ -11,11 +16,18 @@ namespace Ocelot.Library.Configuration private readonly List _reRoutes; private const string RegExMatchEverything = ".*"; private const string RegExMatchEndString = "$"; + private readonly IConfigurationHeaderExtrator _configurationHeaderExtrator; + private readonly ILogger _logger; - public OcelotConfiguration(IOptions options, IConfigurationValidator configurationValidator) + public OcelotConfiguration(IOptions options, + IConfigurationValidator configurationValidator, + IConfigurationHeaderExtrator configurationHeaderExtrator, + ILogger logger) { _options = options; _configurationValidator = configurationValidator; + _configurationHeaderExtrator = configurationHeaderExtrator; + _logger = logger; _reRoutes = new List(); SetUpConfiguration(); } @@ -43,7 +55,7 @@ namespace Ocelot.Library.Configuration var placeholders = new List(); - for (int i = 0; i < upstreamTemplate.Length; i++) + for (var i = 0; i < upstreamTemplate.Length; i++) { if (IsPlaceHolder(upstreamTemplate, i)) { @@ -70,17 +82,41 @@ namespace Ocelot.Library.Configuration reRoute.AuthenticationOptions.RequireHttps, reRoute.AuthenticationOptions.AdditionalScopes, reRoute.AuthenticationOptions.ScopeSecret); + var configHeaders = GetHeadersToAddToRequest(reRoute); + _reRoutes.Add(new ReRoute(reRoute.DownstreamTemplate, reRoute.UpstreamTemplate, - reRoute.UpstreamHttpMethod, upstreamTemplate, isAuthenticated, authOptionsForRoute + reRoute.UpstreamHttpMethod, upstreamTemplate, isAuthenticated, + authOptionsForRoute, configHeaders )); } else { _reRoutes.Add(new ReRoute(reRoute.DownstreamTemplate, reRoute.UpstreamTemplate, reRoute.UpstreamHttpMethod, - upstreamTemplate, isAuthenticated, null)); + upstreamTemplate, isAuthenticated, null, new List())); } } + private List GetHeadersToAddToRequest(YamlReRoute reRoute) + { + var configHeaders = new List(); + + foreach (var add in reRoute.AddHeadersToRequest) + { + var configurationHeader = _configurationHeaderExtrator.Extract(add.Key, add.Value); + + if (configurationHeader.IsError) + { + _logger.LogCritical(new EventId(1, "Application Failed to start"), + $"Unable to extract configuration for key: {add.Key} and value: {add.Value} your configuration file is incorrect"); + + throw new Exception(configurationHeader.Errors[0].Message); + } + configHeaders.Add(configurationHeader.Data); + } + + return configHeaders; + } + private bool IsPlaceHolder(string upstreamTemplate, int i) { return upstreamTemplate[i] == '{'; diff --git a/src/Ocelot.Library/Configuration/ReRoute.cs b/src/Ocelot.Library/Configuration/ReRoute.cs index 8e73a689..a94913ae 100644 --- a/src/Ocelot.Library/Configuration/ReRoute.cs +++ b/src/Ocelot.Library/Configuration/ReRoute.cs @@ -1,8 +1,11 @@ -namespace Ocelot.Library.Configuration +using System.Collections.Generic; +using Ocelot.Library.RequestBuilder; + +namespace Ocelot.Library.Configuration { public class ReRoute { - public ReRoute(string downstreamTemplate, string upstreamTemplate, string upstreamHttpMethod, string upstreamTemplatePattern, bool isAuthenticated, AuthenticationOptions authenticationOptions) + public ReRoute(string downstreamTemplate, string upstreamTemplate, string upstreamHttpMethod, string upstreamTemplatePattern, bool isAuthenticated, AuthenticationOptions authenticationOptions, List configurationHeaderExtractorProperties) { DownstreamTemplate = downstreamTemplate; UpstreamTemplate = upstreamTemplate; @@ -10,6 +13,8 @@ UpstreamTemplatePattern = upstreamTemplatePattern; IsAuthenticated = isAuthenticated; AuthenticationOptions = authenticationOptions; + ConfigurationHeaderExtractorProperties = configurationHeaderExtractorProperties + ?? new List(); } public string DownstreamTemplate { get; private set; } @@ -18,5 +23,6 @@ public string UpstreamHttpMethod { get; private set; } public bool IsAuthenticated { get; private set; } public AuthenticationOptions AuthenticationOptions { get; private set; } + public List ConfigurationHeaderExtractorProperties { get; private set; } } } \ No newline at end of file diff --git a/src/Ocelot.Library/Configuration/Yaml/YamlReRoute.cs b/src/Ocelot.Library/Configuration/Yaml/YamlReRoute.cs index ed3410b5..675044a3 100644 --- a/src/Ocelot.Library/Configuration/Yaml/YamlReRoute.cs +++ b/src/Ocelot.Library/Configuration/Yaml/YamlReRoute.cs @@ -13,6 +13,6 @@ public string UpstreamTemplate { get; set; } public string UpstreamHttpMethod { get; set; } public YamlAuthenticationOptions AuthenticationOptions { get; set; } - public Dictionary AddHeadersToRequest { get; set; } + public Dictionary AddHeadersToRequest { get; set; } } } \ No newline at end of file diff --git a/src/Ocelot.Library/DependencyInjection/ServiceCollectionExtensions.cs b/src/Ocelot.Library/DependencyInjection/ServiceCollectionExtensions.cs index ad627355..2bcdf6a6 100644 --- a/src/Ocelot.Library/DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/Ocelot.Library/DependencyInjection/ServiceCollectionExtensions.cs @@ -21,6 +21,9 @@ services.Configure(configurationRoot); // Add framework services. + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/src/Ocelot.Library/Errors/OcelotErrorCode.cs b/src/Ocelot.Library/Errors/OcelotErrorCode.cs index dbe58dbe..643f00ef 100644 --- a/src/Ocelot.Library/Errors/OcelotErrorCode.cs +++ b/src/Ocelot.Library/Errors/OcelotErrorCode.cs @@ -10,6 +10,10 @@ CannotFindDataError, UnableToCompleteRequestError, UnableToCreateAuthenticationHandlerError, - UnsupportedAuthenticationProviderError + UnsupportedAuthenticationProviderError, + CannotFindClaimError, + ParsingConfigurationHeaderError, + NoInstructionsError, + InstructionNotForClaimsError } } diff --git a/src/Ocelot.Library/Middleware/ClaimsParserMiddleware.cs b/src/Ocelot.Library/Middleware/ClaimsParserMiddleware.cs deleted file mode 100644 index 553b6970..00000000 --- a/src/Ocelot.Library/Middleware/ClaimsParserMiddleware.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace Ocelot.Library.Middleware -{ - using System.Threading.Tasks; - using Microsoft.AspNetCore.Http; - using Repository; - - public class ClaimsParserMiddleware : OcelotMiddleware - { - private readonly RequestDelegate _next; - - public ClaimsParserMiddleware(RequestDelegate next, IScopedRequestDataRepository scopedRequestDataRepository) - : base(scopedRequestDataRepository) - { - _next = next; - } - - public async Task Invoke(HttpContext context) - { - - await _next.Invoke(context); - } - } -} diff --git a/src/Ocelot.Library/Middleware/HttpRequestHeadersBuilderMiddleware.cs b/src/Ocelot.Library/Middleware/HttpRequestHeadersBuilderMiddleware.cs new file mode 100644 index 00000000..1d45b6c4 --- /dev/null +++ b/src/Ocelot.Library/Middleware/HttpRequestHeadersBuilderMiddleware.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; +using System.Linq; +using Microsoft.Extensions.Primitives; +using Ocelot.Library.DownstreamRouteFinder; +using Ocelot.Library.RequestBuilder; + +namespace Ocelot.Library.Middleware +{ + using System.Threading.Tasks; + using Microsoft.AspNetCore.Http; + using Repository; + + public class HttpRequestHeadersBuilderMiddleware : OcelotMiddleware + { + private readonly RequestDelegate _next; + private readonly IAddHeadersToRequest _addHeadersToRequest; + private readonly IScopedRequestDataRepository _scopedRequestDataRepository; + + public HttpRequestHeadersBuilderMiddleware(RequestDelegate next, + IScopedRequestDataRepository scopedRequestDataRepository, + IAddHeadersToRequest addHeadersToRequest) + : base(scopedRequestDataRepository) + { + _next = next; + _addHeadersToRequest = addHeadersToRequest; + _scopedRequestDataRepository = scopedRequestDataRepository; + } + + public async Task Invoke(HttpContext context) + { + var downstreamRoute = _scopedRequestDataRepository.Get("DownstreamRoute"); + + if (downstreamRoute.Data.ReRoute.ConfigurationHeaderExtractorProperties.Any()) + { + _addHeadersToRequest.SetHeadersOnContext(downstreamRoute.Data.ReRoute.ConfigurationHeaderExtractorProperties, context); + } + + await _next.Invoke(context); + } + } +} diff --git a/src/Ocelot.Library/Middleware/HttpRequestHeadersBuilderMiddlewareExtensions.cs b/src/Ocelot.Library/Middleware/HttpRequestHeadersBuilderMiddlewareExtensions.cs new file mode 100644 index 00000000..d657add1 --- /dev/null +++ b/src/Ocelot.Library/Middleware/HttpRequestHeadersBuilderMiddlewareExtensions.cs @@ -0,0 +1,12 @@ +namespace Ocelot.Library.Middleware +{ + using Microsoft.AspNetCore.Builder; + + public static class HttpRequestHeadersBuilderMiddlewareExtensions + { + public static IApplicationBuilder UseHttpRequestHeadersBuilderMiddleware(this IApplicationBuilder builder) + { + return builder.UseMiddleware(); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Middleware/OcelotMiddlewareExtensions.cs b/src/Ocelot.Library/Middleware/OcelotMiddlewareExtensions.cs index 1fc4bbd8..e1c0ffe6 100644 --- a/src/Ocelot.Library/Middleware/OcelotMiddlewareExtensions.cs +++ b/src/Ocelot.Library/Middleware/OcelotMiddlewareExtensions.cs @@ -12,6 +12,8 @@ builder.UseAuthenticationMiddleware(); + builder.UseHttpRequestHeadersBuilderMiddleware(); + builder.UseDownstreamUrlCreatorMiddleware(); builder.UseHttpRequestBuilderMiddleware(); diff --git a/src/Ocelot.Library/RequestBuilder/AddHeadersToRequest.cs b/src/Ocelot.Library/RequestBuilder/AddHeadersToRequest.cs new file mode 100644 index 00000000..387c69bc --- /dev/null +++ b/src/Ocelot.Library/RequestBuilder/AddHeadersToRequest.cs @@ -0,0 +1,42 @@ +using System.Collections.Generic; +using System.Linq; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Primitives; +using Ocelot.Library.Responses; + +namespace Ocelot.Library.RequestBuilder +{ + public class AddHeadersToRequest : IAddHeadersToRequest + { + private readonly IClaimsParser _claimsParser; + + public AddHeadersToRequest(IClaimsParser claimsParser) + { + _claimsParser = claimsParser; + } + + public Response SetHeadersOnContext(List configurationHeaderExtractorProperties, HttpContext context) + { + foreach (var config in configurationHeaderExtractorProperties) + { + var value = _claimsParser.GetValue(context.User.Claims, config.ClaimKey, config.Delimiter, config.Index); + + if (value.IsError) + { + return new ErrorResponse(value.Errors); + } + + var exists = context.Request.Headers.FirstOrDefault(x => x.Key == config.HeaderKey); + + if (!string.IsNullOrEmpty(exists.Key)) + { + context.Request.Headers.Remove(exists); + } + + context.Request.Headers.Add(config.HeaderKey, new StringValues(value.Data)); + } + + return new OkResponse(); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/RequestBuilder/CannotFindClaimError.cs b/src/Ocelot.Library/RequestBuilder/CannotFindClaimError.cs new file mode 100644 index 00000000..0c9e3dac --- /dev/null +++ b/src/Ocelot.Library/RequestBuilder/CannotFindClaimError.cs @@ -0,0 +1,12 @@ +using Ocelot.Library.Errors; + +namespace Ocelot.Library.RequestBuilder +{ + public class CannotFindClaimError : Error + { + public CannotFindClaimError(string message) + : base(message, OcelotErrorCode.CannotFindClaimError) + { + } + } +} diff --git a/src/Ocelot.Library/RequestBuilder/ClaimsParser.cs b/src/Ocelot.Library/RequestBuilder/ClaimsParser.cs new file mode 100644 index 00000000..504950e7 --- /dev/null +++ b/src/Ocelot.Library/RequestBuilder/ClaimsParser.cs @@ -0,0 +1,55 @@ +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using Ocelot.Library.Errors; +using Ocelot.Library.Responses; + +namespace Ocelot.Library.RequestBuilder +{ + public class ClaimsParser : IClaimsParser + { + public Response GetValue(IEnumerable claims, string key, string delimiter, int index) + { + var claimResponse = GetValue(claims, key); + + if (claimResponse.IsError) + { + return claimResponse; + } + + if (string.IsNullOrEmpty(delimiter)) + { + return claimResponse; + } + + var splits = claimResponse.Data.Split(delimiter.ToCharArray()); + + if (splits.Length < index || index < 0) + { + return new ErrorResponse(new List + { + new CannotFindClaimError($"Cannot find claim for key: {key}, delimiter: {delimiter}, index: {index}") + }); + } + + var value = splits[index]; + + return new OkResponse(value); + } + + private Response GetValue(IEnumerable claims, string key) + { + var claim = claims.FirstOrDefault(c => c.Type == key); + + if (claim != null) + { + return new OkResponse(claim.Value); + } + + return new ErrorResponse(new List + { + new CannotFindClaimError($"Cannot find claim for key: {key}") + }); + } + } +} diff --git a/src/Ocelot.Library/RequestBuilder/ConfigurationHeaderExtractorProperties.cs b/src/Ocelot.Library/RequestBuilder/ConfigurationHeaderExtractorProperties.cs new file mode 100644 index 00000000..0f95b580 --- /dev/null +++ b/src/Ocelot.Library/RequestBuilder/ConfigurationHeaderExtractorProperties.cs @@ -0,0 +1,18 @@ +namespace Ocelot.Library.RequestBuilder +{ + public class ConfigurationHeaderExtractorProperties + { + public ConfigurationHeaderExtractorProperties(string headerKey, string claimKey, string delimiter, int index) + { + ClaimKey = claimKey; + Delimiter = delimiter; + Index = index; + HeaderKey = headerKey; + } + + public string HeaderKey { get; private set; } + public string ClaimKey { get; private set; } + public string Delimiter { get; private set; } + public int Index { get; private set; } + } +} diff --git a/src/Ocelot.Library/RequestBuilder/HeaderExtrator.cs b/src/Ocelot.Library/RequestBuilder/HeaderExtrator.cs new file mode 100644 index 00000000..11165f4e --- /dev/null +++ b/src/Ocelot.Library/RequestBuilder/HeaderExtrator.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using Ocelot.Library.Errors; +using Ocelot.Library.Responses; + +namespace Ocelot.Library.RequestBuilder +{ + public class ConfigurationHeaderExtrator : IConfigurationHeaderExtrator + { + private readonly Regex _claimRegex = new Regex("Claims\\[.*\\]"); + private readonly Regex _indexRegex = new Regex("value\\[.*\\]"); + private const string SplitToken = ">"; + + public Response Extract(string headerKey, string value) + { + try + { + var instructions = value.Split(SplitToken.ToCharArray()); + + if (instructions.Length <= 1) + { + return new ErrorResponse( + new List + { + new NoInstructionsError(SplitToken) + }); + } + + var claimMatch = _claimRegex.IsMatch(instructions[0]); + + if (!claimMatch) + { + return new ErrorResponse( + new List + { + new InstructionNotForClaimsError() + }); + } + + var claimKey = GetIndexValue(instructions[0]); + var index = 0; + var delimiter = string.Empty; + + if (instructions.Length > 2 && _indexRegex.IsMatch(instructions[1])) + { + index = int.Parse(GetIndexValue(instructions[1])); + delimiter = instructions[2].Trim(); + } + + return new OkResponse( + new ConfigurationHeaderExtractorProperties(headerKey, claimKey, delimiter, index)); + } + catch (Exception exception) + { + return new ErrorResponse( + new List + { + new ParsingConfigurationHeaderError(exception) + }); + } + } + + private string GetIndexValue(string instruction) + { + var firstIndexer = instruction.IndexOf("[", StringComparison.Ordinal); + var lastIndexer = instruction.IndexOf("]", StringComparison.Ordinal); + var length = lastIndexer - firstIndexer; + var claimKey = instruction.Substring(firstIndexer + 1, length - 1); + return claimKey; + } + } +} diff --git a/src/Ocelot.Library/RequestBuilder/IAddHeadersToRequest.cs b/src/Ocelot.Library/RequestBuilder/IAddHeadersToRequest.cs new file mode 100644 index 00000000..d35cfb95 --- /dev/null +++ b/src/Ocelot.Library/RequestBuilder/IAddHeadersToRequest.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; +using Microsoft.AspNetCore.Http; +using Ocelot.Library.Responses; + +namespace Ocelot.Library.RequestBuilder +{ + public interface IAddHeadersToRequest + { + Response SetHeadersOnContext(List configurationHeaderExtractorProperties, + HttpContext context); + } +} diff --git a/src/Ocelot.Library/RequestBuilder/IClaimsParser.cs b/src/Ocelot.Library/RequestBuilder/IClaimsParser.cs new file mode 100644 index 00000000..c3cdd962 --- /dev/null +++ b/src/Ocelot.Library/RequestBuilder/IClaimsParser.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using System.Security.Claims; +using Ocelot.Library.Responses; + +namespace Ocelot.Library.RequestBuilder +{ + public interface IClaimsParser + { + Response GetValue(IEnumerable claims, string key, string delimiter, int index); + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/RequestBuilder/IConfigurationHeaderExtrator.cs b/src/Ocelot.Library/RequestBuilder/IConfigurationHeaderExtrator.cs new file mode 100644 index 00000000..29c3c153 --- /dev/null +++ b/src/Ocelot.Library/RequestBuilder/IConfigurationHeaderExtrator.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; +using Ocelot.Library.Responses; + +namespace Ocelot.Library.RequestBuilder +{ + public interface IConfigurationHeaderExtrator + { + Response Extract(string headerKey, string value); + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/RequestBuilder/InstructionNotForClaimsError.cs b/src/Ocelot.Library/RequestBuilder/InstructionNotForClaimsError.cs new file mode 100644 index 00000000..2802cfe5 --- /dev/null +++ b/src/Ocelot.Library/RequestBuilder/InstructionNotForClaimsError.cs @@ -0,0 +1,12 @@ +using Ocelot.Library.Errors; + +namespace Ocelot.Library.RequestBuilder +{ + public class InstructionNotForClaimsError : Error + { + public InstructionNotForClaimsError() + : base("instructions did not contain claims, at the moment we only support claims extraction", OcelotErrorCode.InstructionNotForClaimsError) + { + } + } +} diff --git a/src/Ocelot.Library/RequestBuilder/NoInstructionsError.cs b/src/Ocelot.Library/RequestBuilder/NoInstructionsError.cs new file mode 100644 index 00000000..9a2bc694 --- /dev/null +++ b/src/Ocelot.Library/RequestBuilder/NoInstructionsError.cs @@ -0,0 +1,12 @@ +using Ocelot.Library.Errors; + +namespace Ocelot.Library.RequestBuilder +{ + public class NoInstructionsError : Error + { + public NoInstructionsError(string splitToken) + : base($"There we no instructions splitting on {splitToken}", OcelotErrorCode.NoInstructionsError) + { + } + } +} diff --git a/src/Ocelot.Library/RequestBuilder/ParsingConfigurationHeaderError.cs b/src/Ocelot.Library/RequestBuilder/ParsingConfigurationHeaderError.cs new file mode 100644 index 00000000..1b8eaf54 --- /dev/null +++ b/src/Ocelot.Library/RequestBuilder/ParsingConfigurationHeaderError.cs @@ -0,0 +1,13 @@ +using System; +using Ocelot.Library.Errors; + +namespace Ocelot.Library.RequestBuilder +{ + public class ParsingConfigurationHeaderError : Error + { + public ParsingConfigurationHeaderError(Exception exception) + : base($"error parsing configuration eception is {exception.Message}", OcelotErrorCode.ParsingConfigurationHeaderError) + { + } + } +} diff --git a/src/Ocelot.Library/Responder/HttpContextResponder.cs b/src/Ocelot.Library/Responder/HttpContextResponder.cs index 546dd114..d092d36a 100644 --- a/src/Ocelot.Library/Responder/HttpContextResponder.cs +++ b/src/Ocelot.Library/Responder/HttpContextResponder.cs @@ -12,18 +12,14 @@ { public async Task CreateResponse(HttpContext context, HttpResponseMessage response) { - if (response.IsSuccessStatusCode) + context.Response.OnStarting(x => { - context.Response.OnStarting(x => - { - context.Response.StatusCode = (int)response.StatusCode; - return Task.CompletedTask; - }, context); + context.Response.StatusCode = (int)response.StatusCode; + return Task.CompletedTask; + }, context); - await context.Response.WriteAsync(await response.Content.ReadAsStringAsync()); - return context; - } - return context; + await context.Response.WriteAsync(await response.Content.ReadAsStringAsync()); + return context; } public async Task CreateErrorResponse(HttpContext context, int statusCode) diff --git a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs index 1513b190..ee8c6a5c 100644 --- a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs +++ b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs @@ -144,49 +144,6 @@ namespace Ocelot.AcceptanceTests .BDDfy(); } - [Fact] - public void should_return_response_200_and_foward_claim_as_header() - { - - this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Jwt)) - .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura")) - .And(x => x.GivenIHaveAToken("http://localhost:51888")) - .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration - { - ReRoutes = new List - { - new YamlReRoute - { - DownstreamTemplate = "http://localhost:51876/", - UpstreamTemplate = "/", - UpstreamHttpMethod = "Get", - AuthenticationOptions = new YamlAuthenticationOptions - { - AdditionalScopes = new List(), - Provider = "IdentityServer", - ProviderRootUrl = "http://localhost:51888", - RequireHttps = false, - ScopeName = "api", - ScopeSecret = "secret" - }, - AddHeadersToRequest = - { - { "CustomerId", "Claims[CustomerId] -> value" }, - { "LocationId", "Claims[LocationId] -> value"}, - { "UserId", "Claims[Subject] -> delimiter(|) -> value[0]" }, - { "UserId", "Claims[Subject] -> delimiter(|) -> value[1]" } - } - } - } - })) - .And(x => x.GivenTheApiGatewayIsRunning()) - .And(x => x.GivenIHaveAddedATokenToMyRequest()) - .When(x => x.WhenIGetUrlOnTheApiGateway("/")) - .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) - .And(x => x.ThenTheResponseBodyShouldBe("Hello from Laura")) - .BDDfy(); - } - [Fact] public void should_return_201_using_identity_server_access_token() { diff --git a/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs b/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs new file mode 100644 index 00000000..33bbe648 --- /dev/null +++ b/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs @@ -0,0 +1,291 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Security.Claims; +using IdentityServer4.Models; +using IdentityServer4.Services.InMemory; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using Newtonsoft.Json; +using Ocelot.Library.Configuration.Yaml; +using Shouldly; +using TestStack.BDDfy; +using Xunit; +using YamlDotNet.Serialization; + +[assembly: CollectionBehavior(DisableTestParallelization = true)] +namespace Ocelot.AcceptanceTests +{ + public class ClaimsToHeadersForwardingTests : IDisposable + { + private TestServer _ocelotServer; + private HttpClient _ocelotClient; + private HttpResponseMessage _response; + private readonly string _configurationPath; + private IWebHost _servicebuilder; + + // Sadly we need to change this when we update the netcoreapp version to make the test update the config correctly + private double _netCoreAppVersion = 1.4; + private BearerToken _token; + private IWebHost _identityServerBuilder; + + public ClaimsToHeadersForwardingTests() + { + _configurationPath = $"./bin/Debug/netcoreapp{_netCoreAppVersion}/configuration.yaml"; + } + + [Fact] + public void should_return_response_200_and_foward_claim_as_header() + { + var user = new InMemoryUser + { + Username = "test", + Password = "test", + Enabled = true, + Subject = "registered|1231231", + Claims = new List + { + new Claim("CustomerId", "123"), + new Claim("LocationId", "1") + } + }; + + this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:52888", "api", AccessTokenType.Jwt, user)) + .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:52876", 200)) + .And(x => x.GivenIHaveAToken("http://localhost:52888")) + .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration + { + ReRoutes = new List + { + new YamlReRoute + { + DownstreamTemplate = "http://localhost:52876/", + UpstreamTemplate = "/", + UpstreamHttpMethod = "Get", + AuthenticationOptions = new YamlAuthenticationOptions + { + AdditionalScopes = new List + { + "openid", "offline_access" + }, + Provider = "IdentityServer", + ProviderRootUrl = "http://localhost:52888", + RequireHttps = false, + ScopeName = "api", + ScopeSecret = "secret", + }, + AddHeadersToRequest = + { + {"CustomerId", "Claims[CustomerId] > value"}, + {"LocationId", "Claims[LocationId] > value"}, + {"UserType", "Claims[sub] > value[0] > |"}, + {"UserId", "Claims[sub] > value[1] > |"} + } + } + } + })) + .And(x => x.GivenTheApiGatewayIsRunning()) + .And(x => x.GivenIHaveAddedATokenToMyRequest()) + .When(x => x.WhenIGetUrlOnTheApiGateway("/")) + .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + .And(x => x.ThenTheResponseBodyShouldBe("CustomerId: 123 LocationId: 1 UserType: registered UserId: 1231231")) + .BDDfy(); + } + + private void WhenIGetUrlOnTheApiGateway(string url) + { + _response = _ocelotClient.GetAsync(url).Result; + } + + private void ThenTheResponseBodyShouldBe(string expectedBody) + { + _response.Content.ReadAsStringAsync().Result.ShouldBe(expectedBody); + } + + /// + /// This is annoying cos it should be in the constructor but we need to set up the yaml file before calling startup so its a step. + /// + private void GivenTheApiGatewayIsRunning() + { + _ocelotServer = new TestServer(new WebHostBuilder() + .UseStartup()); + + _ocelotClient = _ocelotServer.CreateClient(); + } + + private void GivenThereIsAConfiguration(YamlConfiguration yamlConfiguration) + { + var serializer = new Serializer(); + + if (File.Exists(_configurationPath)) + { + File.Delete(_configurationPath); + } + + using (TextWriter writer = File.CreateText(_configurationPath)) + { + serializer.Serialize(writer, yamlConfiguration); + } + } + + private void GivenThereIsAServiceRunningOn(string url, int statusCode) + { + _servicebuilder = new WebHostBuilder() + .UseUrls(url) + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseUrls(url) + .Configure(app => + { + app.Run(async context => + { + var customerId = context.Request.Headers.First(x => x.Key == "CustomerId").Value.First(); + var locationId = context.Request.Headers.First(x => x.Key == "LocationId").Value.First(); + var userType = context.Request.Headers.First(x => x.Key == "UserType").Value.First(); + var userId = context.Request.Headers.First(x => x.Key == "UserId").Value.First(); + + var responseBody = $"CustomerId: {customerId} LocationId: {locationId} UserType: {userType} UserId: {userId}"; + context.Response.StatusCode = statusCode; + await context.Response.WriteAsync(responseBody); + }); + }) + .Build(); + + _servicebuilder.Start(); + } + + private void GivenThereIsAnIdentityServerOn(string url, string scopeName, AccessTokenType tokenType, InMemoryUser user) + { + _identityServerBuilder = new WebHostBuilder() + .UseUrls(url) + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseUrls(url) + .ConfigureServices(services => + { + services.AddLogging(); + services.AddDeveloperIdentityServer() + .AddInMemoryScopes(new List + { + new Scope + { + Name = scopeName, + Description = "My API", + Enabled = true, + AllowUnrestrictedIntrospection = true, + ScopeSecrets = new List() + { + new Secret + { + Value = "secret".Sha256() + } + }, + IncludeAllClaimsForUser = true + }, + + StandardScopes.OpenId, + StandardScopes.OfflineAccess + }) + .AddInMemoryClients(new List + { + new Client + { + ClientId = "client", + AllowedGrantTypes = GrantTypes.ResourceOwnerPassword, + ClientSecrets = new List {new Secret("secret".Sha256())}, + AllowedScopes = new List { scopeName, "openid", "offline_access" }, + AccessTokenType = tokenType, + Enabled = true, + RequireClientSecret = false + } + }) + .AddInMemoryUsers(new List + { + user + }); + }) + .Configure(app => + { + app.UseIdentityServer(); + }) + .Build(); + + _identityServerBuilder.Start(); + + VerifyIdentiryServerStarted(url); + + } + + private void VerifyIdentiryServerStarted(string url) + { + using (var httpClient = new HttpClient()) + { + var response = httpClient.GetAsync($"{url}/.well-known/openid-configuration").Result; + response.EnsureSuccessStatusCode(); + } + } + + private void GivenIHaveAToken(string url) + { + var tokenUrl = $"{url}/connect/token"; + var formData = new List> + { + new KeyValuePair("client_id", "client"), + new KeyValuePair("client_secret", "secret"), + new KeyValuePair("scope", "api"), + new KeyValuePair("username", "test"), + new KeyValuePair("password", "test"), + new KeyValuePair("grant_type", "password") + }; + var content = new FormUrlEncodedContent(formData); + + using (var httpClient = new HttpClient()) + { + var response = httpClient.PostAsync(tokenUrl, content).Result; + response.EnsureSuccessStatusCode(); + var responseContent = response.Content.ReadAsStringAsync().Result; + _token = JsonConvert.DeserializeObject(responseContent); + } + } + + private void GivenIHaveAddedATokenToMyRequest() + { + _ocelotClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _token.AccessToken); + } + + private void ThenTheStatusCodeShouldBe(HttpStatusCode expectedHttpStatusCode) + { + _response.StatusCode.ShouldBe(expectedHttpStatusCode); + } + + public void Dispose() + { + _servicebuilder?.Dispose(); + _ocelotClient?.Dispose(); + _ocelotServer?.Dispose(); + _identityServerBuilder?.Dispose(); + } + + // ReSharper disable once ClassNeverInstantiated.Local + class BearerToken + { + [JsonProperty("access_token")] + public string AccessToken { get; set; } + + [JsonProperty("expires_in")] + public int ExpiresIn { get; set; } + + [JsonProperty("token_type")] + public string TokenType { get; set; } + } + } +} diff --git a/test/Ocelot.AcceptanceTests/ReturnsErrorTests.cs b/test/Ocelot.AcceptanceTests/ReturnsErrorTests.cs new file mode 100644 index 00000000..dafd69f1 --- /dev/null +++ b/test/Ocelot.AcceptanceTests/ReturnsErrorTests.cs @@ -0,0 +1,123 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Http; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.TestHost; +using Ocelot.Library.Configuration.Yaml; +using Shouldly; +using TestStack.BDDfy; +using Xunit; +using YamlDotNet.Serialization; + +namespace Ocelot.AcceptanceTests +{ + public class ReturnsErrorTests : IDisposable + { + private TestServer _ocelotServer; + private HttpClient _ocelotClient; + private HttpResponseMessage _response; + private readonly string _configurationPath; + private IWebHost _servicebuilder; + + // Sadly we need to change this when we update the netcoreapp version to make the test update the config correctly + private double _netCoreAppVersion = 1.4; + + public ReturnsErrorTests() + { + _configurationPath = $"./bin/Debug/netcoreapp{_netCoreAppVersion}/configuration.yaml"; + } + + [Fact] + public void should_return_response_200_and_foward_claim_as_header() + { + this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:53876")) + .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration + { + ReRoutes = new List + { + new YamlReRoute + { + DownstreamTemplate = "http://localhost:53876/", + UpstreamTemplate = "/", + UpstreamHttpMethod = "Get", + } + } + })) + .And(x => x.GivenTheApiGatewayIsRunning()) + .When(x => x.WhenIGetUrlOnTheApiGateway("/")) + .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.InternalServerError)) + .BDDfy(); + } + + private void WhenIGetUrlOnTheApiGateway(string url) + { + _response = _ocelotClient.GetAsync(url).Result; + } + + private void ThenTheResponseBodyShouldBe(string expectedBody) + { + _response.Content.ReadAsStringAsync().Result.ShouldBe(expectedBody); + } + + /// + /// This is annoying cos it should be in the constructor but we need to set up the yaml file before calling startup so its a step. + /// + private void GivenTheApiGatewayIsRunning() + { + _ocelotServer = new TestServer(new WebHostBuilder() + .UseStartup()); + + _ocelotClient = _ocelotServer.CreateClient(); + } + + private void GivenThereIsAConfiguration(YamlConfiguration yamlConfiguration) + { + var serializer = new Serializer(); + + if (File.Exists(_configurationPath)) + { + File.Delete(_configurationPath); + } + + using (TextWriter writer = File.CreateText(_configurationPath)) + { + serializer.Serialize(writer, yamlConfiguration); + } + } + + private void GivenThereIsAServiceRunningOn(string url) + { + _servicebuilder = new WebHostBuilder() + .UseUrls(url) + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseUrls(url) + .Configure(app => + { + app.Run(context => + { + throw new Exception("BLAMMMM"); + }); + }) + .Build(); + + _servicebuilder.Start(); + } + + private void ThenTheStatusCodeShouldBe(HttpStatusCode expectedHttpStatusCode) + { + _response.StatusCode.ShouldBe(expectedHttpStatusCode); + } + + public void Dispose() + { + _servicebuilder?.Dispose(); + _ocelotClient?.Dispose(); + _ocelotServer?.Dispose(); + } + } +} diff --git a/test/Ocelot.AcceptanceTests/project.json b/test/Ocelot.AcceptanceTests/project.json index 722e58e4..e36303e4 100644 --- a/test/Ocelot.AcceptanceTests/project.json +++ b/test/Ocelot.AcceptanceTests/project.json @@ -3,9 +3,9 @@ "buildOptions": { "copyToOutput": { - "include": [ - "configuration.yaml" - ] + "include": [ + "configuration.yaml" + ] } }, diff --git a/test/Ocelot.UnitTests/Configuration/OcelotConfigurationTests.cs b/test/Ocelot.UnitTests/Configuration/OcelotConfigurationTests.cs index f1601a41..7c37e4a9 100644 --- a/test/Ocelot.UnitTests/Configuration/OcelotConfigurationTests.cs +++ b/test/Ocelot.UnitTests/Configuration/OcelotConfigurationTests.cs @@ -1,6 +1,8 @@ using System.Collections.Generic; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Moq; +using Ocelot.Library.RequestBuilder; using Shouldly; using TestStack.BDDfy; using Xunit; @@ -18,9 +20,13 @@ namespace Ocelot.UnitTests.Configuration private readonly Mock _validator; private OcelotConfiguration _config; private YamlConfiguration _yamlConfiguration; + private readonly Mock _configExtractor; + private readonly Mock> _logger; public OcelotConfigurationTests() { + _logger = new Mock>(); + _configExtractor = new Mock(); _validator = new Mock(); _yamlConfig = new Mock>(); } @@ -54,6 +60,114 @@ namespace Ocelot.UnitTests.Configuration .BDDfy(); } + [Fact] + public void should_create_with_headers_to_extract() + { + var expected = new List + { + new ReRouteBuilder() + .WithDownstreamTemplate("/products/{productId}") + .WithUpstreamTemplate("/api/products/{productId}") + .WithUpstreamHttpMethod("Get") + .WithUpstreamTemplatePattern("/api/products/.*$") + .WithAuthenticationProvider("IdentityServer") + .WithAuthenticationProviderUrl("http://localhost:51888") + .WithRequireHttps(false) + .WithScopeSecret("secret") + .WithAuthenticationProviderScopeName("api") + .WithConfigurationHeaderExtractorProperties(new List + { + new ConfigurationHeaderExtractorProperties("CustomerId", "CustomerId", "", 0), + }) + .Build() + }; + + this.Given(x => x.GivenTheYamlConfigIs(new YamlConfiguration + { + ReRoutes = new List + { + new YamlReRoute + { + UpstreamTemplate = "/api/products/{productId}", + DownstreamTemplate = "/products/{productId}", + UpstreamHttpMethod = "Get", + AuthenticationOptions = new YamlAuthenticationOptions + { + AdditionalScopes = new List(), + Provider = "IdentityServer", + ProviderRootUrl = "http://localhost:51888", + RequireHttps = false, + ScopeName = "api", + ScopeSecret = "secret" + }, + AddHeadersToRequest = + { + {"CustomerId", "Claims[CustomerId] > value"}, + } + } + } + })) + .And(x => x.GivenTheYamlConfigIsValid()) + .And(x => x.GivenTheConfigHeaderExtractorReturns(new ConfigurationHeaderExtractorProperties("CustomerId", "CustomerId", "", 0))) + .When(x => x.WhenIInstanciateTheOcelotConfig()) + .Then(x => x.ThenTheReRoutesAre(expected)) + .And(x => x.ThenTheAuthenticationOptionsAre(expected)) + .BDDfy(); + } + + private void GivenTheConfigHeaderExtractorReturns(ConfigurationHeaderExtractorProperties expected) + { + _configExtractor + .Setup(x => x.Extract(It.IsAny(), It.IsAny())) + .Returns(new OkResponse(expected)); + } + + [Fact] + public void should_create_with_authentication_properties() + { + var expected = new List + { + new ReRouteBuilder() + .WithDownstreamTemplate("/products/{productId}") + .WithUpstreamTemplate("/api/products/{productId}") + .WithUpstreamHttpMethod("Get") + .WithUpstreamTemplatePattern("/api/products/.*$") + .WithAuthenticationProvider("IdentityServer") + .WithAuthenticationProviderUrl("http://localhost:51888") + .WithRequireHttps(false) + .WithScopeSecret("secret") + .WithAuthenticationProviderScopeName("api") + .Build() + }; + + this.Given(x => x.GivenTheYamlConfigIs(new YamlConfiguration + { + ReRoutes = new List + { + new YamlReRoute + { + UpstreamTemplate = "/api/products/{productId}", + DownstreamTemplate = "/products/{productId}", + UpstreamHttpMethod = "Get", + AuthenticationOptions = new YamlAuthenticationOptions + { + AdditionalScopes = new List(), + Provider = "IdentityServer", + ProviderRootUrl = "http://localhost:51888", + RequireHttps = false, + ScopeName = "api", + ScopeSecret = "secret" + } + } + } + })) + .And(x => x.GivenTheYamlConfigIsValid()) + .When(x => x.WhenIInstanciateTheOcelotConfig()) + .Then(x => x.ThenTheReRoutesAre(expected)) + .And(x => x.ThenTheAuthenticationOptionsAre(expected)) + .BDDfy(); + } + [Fact] public void should_create_template_pattern_that_matches_more_than_one_placeholder() { @@ -158,7 +272,8 @@ namespace Ocelot.UnitTests.Configuration private void WhenIInstanciateTheOcelotConfig() { - _config = new OcelotConfiguration(_yamlConfig.Object, _validator.Object); + _config = new OcelotConfiguration(_yamlConfig.Object, _validator.Object, + _configExtractor.Object, _logger.Object); } private void ThenTheReRoutesAre(List expectedReRoutes) @@ -174,5 +289,22 @@ namespace Ocelot.UnitTests.Configuration result.UpstreamTemplatePattern.ShouldBe(expected.UpstreamTemplatePattern); } } + + private void ThenTheAuthenticationOptionsAre(List expectedReRoutes) + { + for (int i = 0; i < _config.ReRoutes.Count; i++) + { + var result = _config.ReRoutes[i].AuthenticationOptions; + var expected = expectedReRoutes[i].AuthenticationOptions; + + result.AdditionalScopes.ShouldBe(expected.AdditionalScopes); + result.Provider.ShouldBe(expected.Provider); + result.ProviderRootUrl.ShouldBe(expected.ProviderRootUrl); + result.RequireHttps.ShouldBe(expected.RequireHttps); + result.ScopeName.ShouldBe(expected.ScopeName); + result.ScopeSecret.ShouldBe(expected.ScopeSecret); + + } + } } } diff --git a/test/Ocelot.UnitTests/Middleware/HttpRequestHeadersBuilderMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/HttpRequestHeadersBuilderMiddlewareTests.cs new file mode 100644 index 00000000..6dc7f77e --- /dev/null +++ b/test/Ocelot.UnitTests/Middleware/HttpRequestHeadersBuilderMiddlewareTests.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net.Http; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using Moq; +using Ocelot.Library.Builder; +using Ocelot.Library.DownstreamRouteFinder; +using Ocelot.Library.Middleware; +using Ocelot.Library.Repository; +using Ocelot.Library.RequestBuilder; +using Ocelot.Library.Responses; +using Ocelot.Library.UrlMatcher; +using TestStack.BDDfy; +using Xunit; + +namespace Ocelot.UnitTests.Middleware +{ + public class HttpRequestHeadersBuilderMiddlewareTests : IDisposable + { + private readonly Mock _scopedRepository; + private readonly Mock _addHeaders; + private readonly string _url; + private readonly TestServer _server; + private readonly HttpClient _client; + private Response _downstreamRoute; + private HttpResponseMessage _result; + + public HttpRequestHeadersBuilderMiddlewareTests() + { + _url = "http://localhost:51879"; + _scopedRepository = new Mock(); + _addHeaders = new Mock(); + var builder = new WebHostBuilder() + .ConfigureServices(x => + { + x.AddSingleton(_addHeaders.Object); + x.AddSingleton(_scopedRepository.Object); + }) + .UseUrls(_url) + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseUrls(_url) + .Configure(app => + { + app.UseHttpRequestHeadersBuilderMiddleware(); + }); + + _server = new TestServer(builder); + _client = _server.CreateClient(); + } + + [Fact] + public void happy_path() + { + var downstreamRoute = new DownstreamRoute(new List(), + new ReRouteBuilder() + .WithDownstreamTemplate("any old string") + .WithConfigurationHeaderExtractorProperties(new List + { + new ConfigurationHeaderExtractorProperties("UserId", "Subject", "", 0) + }) + .Build()); + + this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute)) + .And(x => x.GivenTheAddHeadersToRequestReturns("123")) + .When(x => x.WhenICallTheMiddleware()) + .Then(x => x.ThenTheAddHeadersToRequestIsCalledCorrectly()) + .BDDfy(); + } + + private void GivenTheAddHeadersToRequestReturns(string claimValue) + { + _addHeaders + .Setup(x => x.SetHeadersOnContext(It.IsAny>(), + It.IsAny())) + .Returns(new OkResponse()); + } + + private void ThenTheAddHeadersToRequestIsCalledCorrectly() + { + _addHeaders + .Verify(x => x.SetHeadersOnContext(It.IsAny>(), + It.IsAny()), Times.Once); + } + + private void WhenICallTheMiddleware() + { + _result = _client.GetAsync(_url).Result; + } + + private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute) + { + _downstreamRoute = new OkResponse(downstreamRoute); + _scopedRepository + .Setup(x => x.Get(It.IsAny())) + .Returns(_downstreamRoute); + } + + public void Dispose() + { + _client.Dispose(); + _server.Dispose(); + } + } +} diff --git a/test/Ocelot.UnitTests/RequestBuilder/AddHeadersToRequestTests.cs b/test/Ocelot.UnitTests/RequestBuilder/AddHeadersToRequestTests.cs new file mode 100644 index 00000000..28300c17 --- /dev/null +++ b/test/Ocelot.UnitTests/RequestBuilder/AddHeadersToRequestTests.cs @@ -0,0 +1,152 @@ +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Primitives; +using Moq; +using Ocelot.Library.Errors; +using Ocelot.Library.RequestBuilder; +using Ocelot.Library.Responses; +using Shouldly; +using TestStack.BDDfy; +using Xunit; + +namespace Ocelot.UnitTests.RequestBuilder +{ + public class AddHeadersToRequestTests + { + private readonly AddHeadersToRequest _addHeadersToRequest; + private readonly Mock _parser; + private List _configuration; + private HttpContext _context; + private Response _result; + private Response _claimValue; + + public AddHeadersToRequestTests() + { + _parser = new Mock(); + _addHeadersToRequest = new AddHeadersToRequest(_parser.Object); + } + + [Fact] + public void should_add_headers_to_context() + { + var context = new DefaultHttpContext + { + User = new ClaimsPrincipal(new ClaimsIdentity(new List + { + new Claim("test", "data") + })) + }; + + this.Given( + x => x.GivenConfigurationHeaderExtractorProperties(new List + { + new ConfigurationHeaderExtractorProperties("header-key", "", "", 0) + })) + .Given(x => x.GivenHttpContext(context)) + .And(x => x.GivenTheClaimParserReturns(new OkResponse("value"))) + .When(x => x.WhenIAddHeadersToTheRequest()) + .Then(x => x.ThenTheResultIsSuccess()) + .And(x => x.ThenTheHeaderIsAdded()) + .BDDfy(); + } + + [Fact] + public void if_header_exists_should_replace_it() + { + var context = new DefaultHttpContext + { + User = new ClaimsPrincipal(new ClaimsIdentity(new List + { + new Claim("test", "data") + })), + }; + + context.Request.Headers.Add("header-key", new StringValues("initial")); + + this.Given( + x => x.GivenConfigurationHeaderExtractorProperties(new List + { + new ConfigurationHeaderExtractorProperties("header-key", "", "", 0) + })) + .Given(x => x.GivenHttpContext(context)) + .And(x => x.GivenTheClaimParserReturns(new OkResponse("value"))) + .When(x => x.WhenIAddHeadersToTheRequest()) + .Then(x => x.ThenTheResultIsSuccess()) + .And(x => x.ThenTheHeaderIsAdded()) + .BDDfy(); + } + + [Fact] + public void should_return_error() + { + this.Given( + x => x.GivenConfigurationHeaderExtractorProperties(new List + { + new ConfigurationHeaderExtractorProperties("", "", "", 0) + })) + .Given(x => x.GivenHttpContext(new DefaultHttpContext())) + .And(x => x.GivenTheClaimParserReturns(new ErrorResponse(new List + { + new AnyError() + }))) + .When(x => x.WhenIAddHeadersToTheRequest()) + .Then(x => x.ThenTheResultIsError()) + .BDDfy(); + } + + private void ThenTheHeaderIsAdded() + { + var header = _context.Request.Headers.First(x => x.Key == "header-key"); + header.Value.First().ShouldBe(_claimValue.Data); + } + + private void GivenConfigurationHeaderExtractorProperties(List configuration) + { + _configuration = configuration; + } + + private void GivenHttpContext(HttpContext context) + { + _context = context; + } + + private void GivenTheClaimParserReturns(Response claimValue) + { + _claimValue = claimValue; + _parser + .Setup( + x => + x.GetValue(It.IsAny>(), + It.IsAny(), + It.IsAny(), + It.IsAny())) + .Returns(_claimValue); + } + + private void WhenIAddHeadersToTheRequest() + { + _result = _addHeadersToRequest.SetHeadersOnContext(_configuration, _context); + } + + private void ThenTheResultIsSuccess() + { + _result.IsError.ShouldBe(false); + } + + private void ThenTheResultIsError() + { + + _result.IsError.ShouldBe(true); + } + + class AnyError : Error + { + public AnyError() + : base("blahh", OcelotErrorCode.UnknownError) + { + } + } + } +} diff --git a/test/Ocelot.UnitTests/RequestBuilder/ClaimParserTests.cs b/test/Ocelot.UnitTests/RequestBuilder/ClaimParserTests.cs new file mode 100644 index 00000000..5daa7d6d --- /dev/null +++ b/test/Ocelot.UnitTests/RequestBuilder/ClaimParserTests.cs @@ -0,0 +1,123 @@ +using System.Collections.Generic; +using System.Security.Claims; +using Ocelot.Library.Errors; +using Ocelot.Library.RequestBuilder; +using Ocelot.Library.Responses; +using Shouldly; +using TestStack.BDDfy; +using Xunit; + +namespace Ocelot.UnitTests.RequestBuilder +{ + public class ClaimParserTests + { + private readonly IClaimsParser _claimsParser; + private readonly List _claims; + private string _key; + private Response _result; + private string _delimiter; + private int _index; + + public ClaimParserTests() + { + _claims = new List(); + _claimsParser = new Library.RequestBuilder.ClaimsParser(); + } + + [Fact] + public void can_parse_claims_dictionary_access_string_returning_value_to_function() + { + this.Given(x => x.GivenAClaimOf(new Claim("CustomerId", "1234"))) + .And(x => x.GivenTheKeyIs("CustomerId")) + .When(x => x.WhenICallTheParser()) + .Then(x => x.ThenTheResultIs(new OkResponse("1234"))) + .BDDfy(); + } + + [Fact] + public void should_return_error_response_when_cannot_find_requested_claim() + { + this.Given(x => x.GivenAClaimOf(new Claim("BallsId", "1234"))) + .And(x => x.GivenTheKeyIs("CustomerId")) + .When(x => x.WhenICallTheParser()) + .Then(x => x.ThenTheResultIs(new ErrorResponse(new List + { + new CannotFindClaimError($"Cannot find claim for key: {_key}") + }))) + .BDDfy(); + } + + [Fact] + public void can_parse_claims_dictionary_access_string_using_delimiter_and_retuning_at_correct_index() + { + this.Given(x => x.GivenAClaimOf(new Claim("Subject", "registered|4321"))) + .And(x => x.GivenTheDelimiterIs("|")) + .And(x => x.GivenTheIndexIs(1)) + .And(x => x.GivenTheKeyIs("Subject")) + .When(x => x.WhenICallTheParser()) + .Then(x => x.ThenTheResultIs(new OkResponse("4321"))) + .BDDfy(); + } + + [Fact] + public void should_return_error_response_if_index_too_large() + { + this.Given(x => x.GivenAClaimOf(new Claim("Subject", "registered|4321"))) + .And(x => x.GivenTheDelimiterIs("|")) + .And(x => x.GivenTheIndexIs(24)) + .And(x => x.GivenTheKeyIs("Subject")) + .When(x => x.WhenICallTheParser()) + .Then(x => x.ThenTheResultIs(new ErrorResponse(new List + { + new CannotFindClaimError($"Cannot find claim for key: {_key}, delimiter: {_delimiter}, index: {_index}") + }))) + .BDDfy(); + } + + [Fact] + public void should_return_error_response_if_index_too_small() + { + this.Given(x => x.GivenAClaimOf(new Claim("Subject", "registered|4321"))) + .And(x => x.GivenTheDelimiterIs("|")) + .And(x => x.GivenTheIndexIs(-1)) + .And(x => x.GivenTheKeyIs("Subject")) + .When(x => x.WhenICallTheParser()) + .Then(x => x.ThenTheResultIs(new ErrorResponse(new List + { + new CannotFindClaimError($"Cannot find claim for key: {_key}, delimiter: {_delimiter}, index: {_index}") + }))) + .BDDfy(); + } + + private void GivenTheIndexIs(int index) + { + _index = index; + } + + private void GivenTheDelimiterIs(string delimiter) + { + _delimiter = delimiter; + } + + private void GivenAClaimOf(Claim claim) + { + _claims.Add(claim); + } + + private void GivenTheKeyIs(string key) + { + _key = key; + } + + private void WhenICallTheParser() + { + _result = _claimsParser.GetValue(_claims, _key, _delimiter, _index); + } + + private void ThenTheResultIs(Response expected) + { + _result.Data.ShouldBe(expected.Data); + _result.IsError.ShouldBe(expected.IsError); + } + } +} diff --git a/test/Ocelot.UnitTests/RequestBuilder/ConfigurationHeadersExtractorTests.cs b/test/Ocelot.UnitTests/RequestBuilder/ConfigurationHeadersExtractorTests.cs new file mode 100644 index 00000000..238d9f1a --- /dev/null +++ b/test/Ocelot.UnitTests/RequestBuilder/ConfigurationHeadersExtractorTests.cs @@ -0,0 +1,116 @@ +using System.Collections.Generic; +using System.Linq; +using Ocelot.Library.Errors; +using Ocelot.Library.RequestBuilder; +using Ocelot.Library.Responses; +using Shouldly; +using TestStack.BDDfy; +using Xunit; + +namespace Ocelot.UnitTests.RequestBuilder +{ + public class ConfigurationHeadersExtractorTests + { + private Dictionary _dictionary; + private readonly IConfigurationHeaderExtrator _configurationHeaderExtrator; + private Response _result; + + public ConfigurationHeadersExtractorTests() + { + _configurationHeaderExtrator = new ConfigurationHeaderExtrator(); + } + + [Fact] + public void returns_no_instructions_error() + { + this.Given(x => x.GivenTheDictionaryIs(new Dictionary() + { + {"CustomerId", ""}, + })) + .When(x => x.WhenICallTheExtractor()) + .Then( + x => + x.ThenAnErrorIsReturned(new ErrorResponse( + new List + { + new NoInstructionsError(">") + }))) + .BDDfy(); + } + + [Fact] + public void returns_no_instructions_not_for_claims_error() + { + this.Given(x => x.GivenTheDictionaryIs(new Dictionary() + { + {"CustomerId", "Cheese[CustomerId] > value"}, + })) + .When(x => x.WhenICallTheExtractor()) + .Then( + x => + x.ThenAnErrorIsReturned(new ErrorResponse( + new List + { + new InstructionNotForClaimsError() + }))) + .BDDfy(); + } + + [Fact] + public void can_parse_entry_to_work_out_properties_with_key() + { + this.Given(x => x.GivenTheDictionaryIs(new Dictionary() + { + {"CustomerId", "Claims[CustomerId] > value"}, + })) + .When(x => x.WhenICallTheExtractor()) + .Then( + x => + x.ThenTheClaimParserPropertiesAreReturned( + new OkResponse( + new ConfigurationHeaderExtractorProperties("CustomerId", "CustomerId", "", 0)))) + .BDDfy(); + } + + [Fact] + public void can_parse_entry_to_work_out_properties_with_key_delimiter_and_index() + { + this.Given(x => x.GivenTheDictionaryIs(new Dictionary() + { + {"UserId", "Claims[Subject] > value[0] > |"}, + })) + .When(x => x.WhenICallTheExtractor()) + .Then( + x => + x.ThenTheClaimParserPropertiesAreReturned( + new OkResponse( + new ConfigurationHeaderExtractorProperties("UserId", "Subject", "|", 0)))) + .BDDfy(); + } + + private void ThenAnErrorIsReturned(Response expected) + { + _result.IsError.ShouldBe(expected.IsError); + _result.Errors[0].ShouldBeOfType(expected.Errors[0].GetType()); + } + + private void ThenTheClaimParserPropertiesAreReturned(Response expected) + { + _result.Data.ClaimKey.ShouldBe(expected.Data.ClaimKey); + _result.Data.Delimiter.ShouldBe(expected.Data.Delimiter); + _result.Data.Index.ShouldBe(expected.Data.Index); + _result.IsError.ShouldBe(expected.IsError); + } + + private void WhenICallTheExtractor() + { + var first = _dictionary.First(); + _result = _configurationHeaderExtrator.Extract(first.Key, first.Value); + } + + private void GivenTheDictionaryIs(Dictionary dictionary) + { + _dictionary = dictionary; + } + } +} From 707f1d6908eac53bafdb10958cfc5a1fd2cd1758 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Tue, 18 Oct 2016 16:22:51 +0100 Subject: [PATCH 091/183] renamed and removed some stuff that wasnt needed --- .../AuthenticationHandlerCreator.cs | 2 -- src/Ocelot.Library/Builder/ReRouteBuilder.cs | 10 +++----- .../ClaimToHeader.cs} | 6 ++--- .../ClaimToHeaderConfigurationParser.cs} | 17 +++++++------ .../IClaimToHeaderConfigurationParser.cs | 9 +++++++ .../Configuration/OcelotConfiguration.cs | 14 +++++------ src/Ocelot.Library/Configuration/ReRoute.cs | 9 +++---- .../ServiceCollectionExtensions.cs | 11 ++++++-- .../HttpRequestHeadersBuilderMiddleware.cs | 4 +-- .../RequestBuilder/AddHeadersToRequest.cs | 3 ++- .../RequestBuilder/IAddHeadersToRequest.cs | 3 ++- .../IConfigurationHeaderExtrator.cs | 10 -------- src/Ocelot/Controllers/HomeController.cs | 22 ---------------- src/Ocelot/Startup.cs | 5 ---- .../{OcelotTests.cs => RoutingTests.cs} | 4 +-- .../Configuration/OcelotConfigurationTests.cs | 14 +++++------ ...ttpRequestHeadersBuilderMiddlewareTests.cs | 9 ++++--- .../AddHeadersToRequestTests.cs | 17 +++++++------ .../ConfigurationHeadersExtractorTests.cs | 25 ++++++++++--------- 19 files changed, 87 insertions(+), 107 deletions(-) rename src/Ocelot.Library/{RequestBuilder/ConfigurationHeaderExtractorProperties.cs => Configuration/ClaimToHeader.cs} (63%) rename src/Ocelot.Library/{RequestBuilder/HeaderExtrator.cs => Configuration/ClaimToHeaderConfigurationParser.cs} (75%) create mode 100644 src/Ocelot.Library/Configuration/IClaimToHeaderConfigurationParser.cs delete mode 100644 src/Ocelot.Library/RequestBuilder/IConfigurationHeaderExtrator.cs delete mode 100644 src/Ocelot/Controllers/HomeController.cs rename test/Ocelot.AcceptanceTests/{OcelotTests.cs => RoutingTests.cs} (98%) diff --git a/src/Ocelot.Library/Authentication/AuthenticationHandlerCreator.cs b/src/Ocelot.Library/Authentication/AuthenticationHandlerCreator.cs index fd49bf7d..34fedf38 100644 --- a/src/Ocelot.Library/Authentication/AuthenticationHandlerCreator.cs +++ b/src/Ocelot.Library/Authentication/AuthenticationHandlerCreator.cs @@ -25,8 +25,6 @@ namespace Ocelot.Library.Authentication ScopeSecret = authOptions.ScopeSecret }); - builder.UseMvc(); - var authenticationNext = builder.Build(); return new OkResponse(authenticationNext); diff --git a/src/Ocelot.Library/Builder/ReRouteBuilder.cs b/src/Ocelot.Library/Builder/ReRouteBuilder.cs index 5668f15e..2cf9538d 100644 --- a/src/Ocelot.Library/Builder/ReRouteBuilder.cs +++ b/src/Ocelot.Library/Builder/ReRouteBuilder.cs @@ -1,10 +1,8 @@ -using Ocelot.Library.RequestBuilder; +using System.Collections.Generic; +using Ocelot.Library.Configuration; namespace Ocelot.Library.Builder { - using System.Collections.Generic; - using Configuration; - public class ReRouteBuilder { private string _downstreamTemplate; @@ -18,7 +16,7 @@ namespace Ocelot.Library.Builder private List _additionalScopes; private bool _requireHttps; private string _scopeSecret; - private List _configHeaderExtractorProperties; + private List _configHeaderExtractorProperties; public ReRouteBuilder() { @@ -89,7 +87,7 @@ namespace Ocelot.Library.Builder return this; } - public ReRouteBuilder WithConfigurationHeaderExtractorProperties(List input) + public ReRouteBuilder WithConfigurationHeaderExtractorProperties(List input) { _configHeaderExtractorProperties = input; return this; diff --git a/src/Ocelot.Library/RequestBuilder/ConfigurationHeaderExtractorProperties.cs b/src/Ocelot.Library/Configuration/ClaimToHeader.cs similarity index 63% rename from src/Ocelot.Library/RequestBuilder/ConfigurationHeaderExtractorProperties.cs rename to src/Ocelot.Library/Configuration/ClaimToHeader.cs index 0f95b580..d768046a 100644 --- a/src/Ocelot.Library/RequestBuilder/ConfigurationHeaderExtractorProperties.cs +++ b/src/Ocelot.Library/Configuration/ClaimToHeader.cs @@ -1,8 +1,8 @@ -namespace Ocelot.Library.RequestBuilder +namespace Ocelot.Library.Configuration { - public class ConfigurationHeaderExtractorProperties + public class ClaimToHeader { - public ConfigurationHeaderExtractorProperties(string headerKey, string claimKey, string delimiter, int index) + public ClaimToHeader(string headerKey, string claimKey, string delimiter, int index) { ClaimKey = claimKey; Delimiter = delimiter; diff --git a/src/Ocelot.Library/RequestBuilder/HeaderExtrator.cs b/src/Ocelot.Library/Configuration/ClaimToHeaderConfigurationParser.cs similarity index 75% rename from src/Ocelot.Library/RequestBuilder/HeaderExtrator.cs rename to src/Ocelot.Library/Configuration/ClaimToHeaderConfigurationParser.cs index 11165f4e..c81c5468 100644 --- a/src/Ocelot.Library/RequestBuilder/HeaderExtrator.cs +++ b/src/Ocelot.Library/Configuration/ClaimToHeaderConfigurationParser.cs @@ -2,17 +2,18 @@ using System.Collections.Generic; using System.Text.RegularExpressions; using Ocelot.Library.Errors; +using Ocelot.Library.RequestBuilder; using Ocelot.Library.Responses; -namespace Ocelot.Library.RequestBuilder +namespace Ocelot.Library.Configuration { - public class ConfigurationHeaderExtrator : IConfigurationHeaderExtrator + public class ClaimToHeaderConfigurationParser : IClaimToHeaderConfigurationParser { private readonly Regex _claimRegex = new Regex("Claims\\[.*\\]"); private readonly Regex _indexRegex = new Regex("value\\[.*\\]"); private const string SplitToken = ">"; - public Response Extract(string headerKey, string value) + public Response Extract(string headerKey, string value) { try { @@ -20,7 +21,7 @@ namespace Ocelot.Library.RequestBuilder if (instructions.Length <= 1) { - return new ErrorResponse( + return new ErrorResponse( new List { new NoInstructionsError(SplitToken) @@ -31,7 +32,7 @@ namespace Ocelot.Library.RequestBuilder if (!claimMatch) { - return new ErrorResponse( + return new ErrorResponse( new List { new InstructionNotForClaimsError() @@ -48,12 +49,12 @@ namespace Ocelot.Library.RequestBuilder delimiter = instructions[2].Trim(); } - return new OkResponse( - new ConfigurationHeaderExtractorProperties(headerKey, claimKey, delimiter, index)); + return new OkResponse( + new ClaimToHeader(headerKey, claimKey, delimiter, index)); } catch (Exception exception) { - return new ErrorResponse( + return new ErrorResponse( new List { new ParsingConfigurationHeaderError(exception) diff --git a/src/Ocelot.Library/Configuration/IClaimToHeaderConfigurationParser.cs b/src/Ocelot.Library/Configuration/IClaimToHeaderConfigurationParser.cs new file mode 100644 index 00000000..ad627ba5 --- /dev/null +++ b/src/Ocelot.Library/Configuration/IClaimToHeaderConfigurationParser.cs @@ -0,0 +1,9 @@ +using Ocelot.Library.Responses; + +namespace Ocelot.Library.Configuration +{ + public interface IClaimToHeaderConfigurationParser + { + Response Extract(string headerKey, string value); + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Configuration/OcelotConfiguration.cs b/src/Ocelot.Library/Configuration/OcelotConfiguration.cs index d149baac..ae1cf189 100644 --- a/src/Ocelot.Library/Configuration/OcelotConfiguration.cs +++ b/src/Ocelot.Library/Configuration/OcelotConfiguration.cs @@ -16,17 +16,17 @@ namespace Ocelot.Library.Configuration private readonly List _reRoutes; private const string RegExMatchEverything = ".*"; private const string RegExMatchEndString = "$"; - private readonly IConfigurationHeaderExtrator _configurationHeaderExtrator; + private readonly IClaimToHeaderConfigurationParser _claimToHeaderConfigurationParser; private readonly ILogger _logger; public OcelotConfiguration(IOptions options, IConfigurationValidator configurationValidator, - IConfigurationHeaderExtrator configurationHeaderExtrator, + IClaimToHeaderConfigurationParser claimToHeaderConfigurationParser, ILogger logger) { _options = options; _configurationValidator = configurationValidator; - _configurationHeaderExtrator = configurationHeaderExtrator; + _claimToHeaderConfigurationParser = claimToHeaderConfigurationParser; _logger = logger; _reRoutes = new List(); SetUpConfiguration(); @@ -92,17 +92,17 @@ namespace Ocelot.Library.Configuration else { _reRoutes.Add(new ReRoute(reRoute.DownstreamTemplate, reRoute.UpstreamTemplate, reRoute.UpstreamHttpMethod, - upstreamTemplate, isAuthenticated, null, new List())); + upstreamTemplate, isAuthenticated, null, new List())); } } - private List GetHeadersToAddToRequest(YamlReRoute reRoute) + private List GetHeadersToAddToRequest(YamlReRoute reRoute) { - var configHeaders = new List(); + var configHeaders = new List(); foreach (var add in reRoute.AddHeadersToRequest) { - var configurationHeader = _configurationHeaderExtrator.Extract(add.Key, add.Value); + var configurationHeader = _claimToHeaderConfigurationParser.Extract(add.Key, add.Value); if (configurationHeader.IsError) { diff --git a/src/Ocelot.Library/Configuration/ReRoute.cs b/src/Ocelot.Library/Configuration/ReRoute.cs index a94913ae..d6df121d 100644 --- a/src/Ocelot.Library/Configuration/ReRoute.cs +++ b/src/Ocelot.Library/Configuration/ReRoute.cs @@ -1,11 +1,10 @@ using System.Collections.Generic; -using Ocelot.Library.RequestBuilder; namespace Ocelot.Library.Configuration { public class ReRoute { - public ReRoute(string downstreamTemplate, string upstreamTemplate, string upstreamHttpMethod, string upstreamTemplatePattern, bool isAuthenticated, AuthenticationOptions authenticationOptions, List configurationHeaderExtractorProperties) + public ReRoute(string downstreamTemplate, string upstreamTemplate, string upstreamHttpMethod, string upstreamTemplatePattern, bool isAuthenticated, AuthenticationOptions authenticationOptions, List configurationHeaderExtractorProperties) { DownstreamTemplate = downstreamTemplate; UpstreamTemplate = upstreamTemplate; @@ -13,8 +12,8 @@ namespace Ocelot.Library.Configuration UpstreamTemplatePattern = upstreamTemplatePattern; IsAuthenticated = isAuthenticated; AuthenticationOptions = authenticationOptions; - ConfigurationHeaderExtractorProperties = configurationHeaderExtractorProperties - ?? new List(); + ClaimsToHeaders = configurationHeaderExtractorProperties + ?? new List(); } public string DownstreamTemplate { get; private set; } @@ -23,6 +22,6 @@ namespace Ocelot.Library.Configuration public string UpstreamHttpMethod { get; private set; } public bool IsAuthenticated { get; private set; } public AuthenticationOptions AuthenticationOptions { get; private set; } - public List ConfigurationHeaderExtractorProperties { get; private set; } + public List ClaimsToHeaders { get; private set; } } } \ No newline at end of file diff --git a/src/Ocelot.Library/DependencyInjection/ServiceCollectionExtensions.cs b/src/Ocelot.Library/DependencyInjection/ServiceCollectionExtensions.cs index 2bcdf6a6..19f80900 100644 --- a/src/Ocelot.Library/DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/Ocelot.Library/DependencyInjection/ServiceCollectionExtensions.cs @@ -18,12 +18,18 @@ { public static IServiceCollection AddOcelot(this IServiceCollection services, IConfigurationRoot configurationRoot) { + // framework services + services.AddOptions(); + services.AddMvcCore().AddJsonFormatters(); + services.AddLogging(); + + // initial configuration from yaml services.Configure(configurationRoot); - // Add framework services. + // ocelot services. services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); @@ -38,6 +44,7 @@ services.AddSingleton(); // see this for why we register this as singleton http://stackoverflow.com/questions/37371264/invalidoperationexception-unable-to-resolve-service-for-type-microsoft-aspnetc + // could maybe use a scoped data repository services.AddSingleton(); services.AddScoped(); diff --git a/src/Ocelot.Library/Middleware/HttpRequestHeadersBuilderMiddleware.cs b/src/Ocelot.Library/Middleware/HttpRequestHeadersBuilderMiddleware.cs index 1d45b6c4..562f898b 100644 --- a/src/Ocelot.Library/Middleware/HttpRequestHeadersBuilderMiddleware.cs +++ b/src/Ocelot.Library/Middleware/HttpRequestHeadersBuilderMiddleware.cs @@ -30,9 +30,9 @@ namespace Ocelot.Library.Middleware { var downstreamRoute = _scopedRequestDataRepository.Get("DownstreamRoute"); - if (downstreamRoute.Data.ReRoute.ConfigurationHeaderExtractorProperties.Any()) + if (downstreamRoute.Data.ReRoute.ClaimsToHeaders.Any()) { - _addHeadersToRequest.SetHeadersOnContext(downstreamRoute.Data.ReRoute.ConfigurationHeaderExtractorProperties, context); + _addHeadersToRequest.SetHeadersOnContext(downstreamRoute.Data.ReRoute.ClaimsToHeaders, context); } await _next.Invoke(context); diff --git a/src/Ocelot.Library/RequestBuilder/AddHeadersToRequest.cs b/src/Ocelot.Library/RequestBuilder/AddHeadersToRequest.cs index 387c69bc..88823097 100644 --- a/src/Ocelot.Library/RequestBuilder/AddHeadersToRequest.cs +++ b/src/Ocelot.Library/RequestBuilder/AddHeadersToRequest.cs @@ -2,6 +2,7 @@ using System.Linq; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; +using Ocelot.Library.Configuration; using Ocelot.Library.Responses; namespace Ocelot.Library.RequestBuilder @@ -15,7 +16,7 @@ namespace Ocelot.Library.RequestBuilder _claimsParser = claimsParser; } - public Response SetHeadersOnContext(List configurationHeaderExtractorProperties, HttpContext context) + public Response SetHeadersOnContext(List configurationHeaderExtractorProperties, HttpContext context) { foreach (var config in configurationHeaderExtractorProperties) { diff --git a/src/Ocelot.Library/RequestBuilder/IAddHeadersToRequest.cs b/src/Ocelot.Library/RequestBuilder/IAddHeadersToRequest.cs index d35cfb95..d1e96506 100644 --- a/src/Ocelot.Library/RequestBuilder/IAddHeadersToRequest.cs +++ b/src/Ocelot.Library/RequestBuilder/IAddHeadersToRequest.cs @@ -1,12 +1,13 @@ using System.Collections.Generic; using Microsoft.AspNetCore.Http; +using Ocelot.Library.Configuration; using Ocelot.Library.Responses; namespace Ocelot.Library.RequestBuilder { public interface IAddHeadersToRequest { - Response SetHeadersOnContext(List configurationHeaderExtractorProperties, + Response SetHeadersOnContext(List configurationHeaderExtractorProperties, HttpContext context); } } diff --git a/src/Ocelot.Library/RequestBuilder/IConfigurationHeaderExtrator.cs b/src/Ocelot.Library/RequestBuilder/IConfigurationHeaderExtrator.cs deleted file mode 100644 index 29c3c153..00000000 --- a/src/Ocelot.Library/RequestBuilder/IConfigurationHeaderExtrator.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Collections.Generic; -using Ocelot.Library.Responses; - -namespace Ocelot.Library.RequestBuilder -{ - public interface IConfigurationHeaderExtrator - { - Response Extract(string headerKey, string value); - } -} \ No newline at end of file diff --git a/src/Ocelot/Controllers/HomeController.cs b/src/Ocelot/Controllers/HomeController.cs deleted file mode 100644 index c6dbe9d2..00000000 --- a/src/Ocelot/Controllers/HomeController.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; - -namespace Ocelot.Controllers -{ - /// - /// This controller is a catch all for requests so that if we build it into a pipeline - /// the requests get authorised. - /// - public class HomeController : Controller - { - //[Authorize] - [Route("{*url}")] - public void Index() - { - if (true == true) - { - - } - } - } -} diff --git a/src/Ocelot/Startup.cs b/src/Ocelot/Startup.cs index 6b7d7973..66989428 100644 --- a/src/Ocelot/Startup.cs +++ b/src/Ocelot/Startup.cs @@ -28,11 +28,6 @@ namespace Ocelot // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { - services.AddOptions(); - services.AddMvc(); - services.AddMvcCore().AddAuthorization().AddJsonFormatters(); - services.AddAuthentication(); - services.AddLogging(); services.AddOcelot(Configuration); } diff --git a/test/Ocelot.AcceptanceTests/OcelotTests.cs b/test/Ocelot.AcceptanceTests/RoutingTests.cs similarity index 98% rename from test/Ocelot.AcceptanceTests/OcelotTests.cs rename to test/Ocelot.AcceptanceTests/RoutingTests.cs index b838736b..22accf7b 100644 --- a/test/Ocelot.AcceptanceTests/OcelotTests.cs +++ b/test/Ocelot.AcceptanceTests/RoutingTests.cs @@ -16,7 +16,7 @@ namespace Ocelot.AcceptanceTests { using Library.Configuration.Yaml; - public class OcelotTests : IDisposable + public class RoutingTests : IDisposable { private TestServer _server; private HttpClient _client; @@ -28,7 +28,7 @@ namespace Ocelot.AcceptanceTests // Sadly we need to change this when we update the netcoreapp version to make the test update the config correctly private double _netCoreAppVersion = 1.4; - public OcelotTests() + public RoutingTests() { _configurationPath = $"./bin/Debug/netcoreapp{_netCoreAppVersion}/configuration.yaml"; } diff --git a/test/Ocelot.UnitTests/Configuration/OcelotConfigurationTests.cs b/test/Ocelot.UnitTests/Configuration/OcelotConfigurationTests.cs index 7c37e4a9..8846d60d 100644 --- a/test/Ocelot.UnitTests/Configuration/OcelotConfigurationTests.cs +++ b/test/Ocelot.UnitTests/Configuration/OcelotConfigurationTests.cs @@ -20,13 +20,13 @@ namespace Ocelot.UnitTests.Configuration private readonly Mock _validator; private OcelotConfiguration _config; private YamlConfiguration _yamlConfiguration; - private readonly Mock _configExtractor; + private readonly Mock _configExtractor; private readonly Mock> _logger; public OcelotConfigurationTests() { _logger = new Mock>(); - _configExtractor = new Mock(); + _configExtractor = new Mock(); _validator = new Mock(); _yamlConfig = new Mock>(); } @@ -75,9 +75,9 @@ namespace Ocelot.UnitTests.Configuration .WithRequireHttps(false) .WithScopeSecret("secret") .WithAuthenticationProviderScopeName("api") - .WithConfigurationHeaderExtractorProperties(new List + .WithConfigurationHeaderExtractorProperties(new List { - new ConfigurationHeaderExtractorProperties("CustomerId", "CustomerId", "", 0), + new ClaimToHeader("CustomerId", "CustomerId", "", 0), }) .Build() }; @@ -108,18 +108,18 @@ namespace Ocelot.UnitTests.Configuration } })) .And(x => x.GivenTheYamlConfigIsValid()) - .And(x => x.GivenTheConfigHeaderExtractorReturns(new ConfigurationHeaderExtractorProperties("CustomerId", "CustomerId", "", 0))) + .And(x => x.GivenTheConfigHeaderExtractorReturns(new ClaimToHeader("CustomerId", "CustomerId", "", 0))) .When(x => x.WhenIInstanciateTheOcelotConfig()) .Then(x => x.ThenTheReRoutesAre(expected)) .And(x => x.ThenTheAuthenticationOptionsAre(expected)) .BDDfy(); } - private void GivenTheConfigHeaderExtractorReturns(ConfigurationHeaderExtractorProperties expected) + private void GivenTheConfigHeaderExtractorReturns(ClaimToHeader expected) { _configExtractor .Setup(x => x.Extract(It.IsAny(), It.IsAny())) - .Returns(new OkResponse(expected)); + .Returns(new OkResponse(expected)); } [Fact] diff --git a/test/Ocelot.UnitTests/Middleware/HttpRequestHeadersBuilderMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/HttpRequestHeadersBuilderMiddlewareTests.cs index 6dc7f77e..f04efbfc 100644 --- a/test/Ocelot.UnitTests/Middleware/HttpRequestHeadersBuilderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Middleware/HttpRequestHeadersBuilderMiddlewareTests.cs @@ -8,6 +8,7 @@ using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Moq; using Ocelot.Library.Builder; +using Ocelot.Library.Configuration; using Ocelot.Library.DownstreamRouteFinder; using Ocelot.Library.Middleware; using Ocelot.Library.Repository; @@ -60,9 +61,9 @@ namespace Ocelot.UnitTests.Middleware var downstreamRoute = new DownstreamRoute(new List(), new ReRouteBuilder() .WithDownstreamTemplate("any old string") - .WithConfigurationHeaderExtractorProperties(new List + .WithConfigurationHeaderExtractorProperties(new List { - new ConfigurationHeaderExtractorProperties("UserId", "Subject", "", 0) + new ClaimToHeader("UserId", "Subject", "", 0) }) .Build()); @@ -76,7 +77,7 @@ namespace Ocelot.UnitTests.Middleware private void GivenTheAddHeadersToRequestReturns(string claimValue) { _addHeaders - .Setup(x => x.SetHeadersOnContext(It.IsAny>(), + .Setup(x => x.SetHeadersOnContext(It.IsAny>(), It.IsAny())) .Returns(new OkResponse()); } @@ -84,7 +85,7 @@ namespace Ocelot.UnitTests.Middleware private void ThenTheAddHeadersToRequestIsCalledCorrectly() { _addHeaders - .Verify(x => x.SetHeadersOnContext(It.IsAny>(), + .Verify(x => x.SetHeadersOnContext(It.IsAny>(), It.IsAny()), Times.Once); } diff --git a/test/Ocelot.UnitTests/RequestBuilder/AddHeadersToRequestTests.cs b/test/Ocelot.UnitTests/RequestBuilder/AddHeadersToRequestTests.cs index 28300c17..91359d28 100644 --- a/test/Ocelot.UnitTests/RequestBuilder/AddHeadersToRequestTests.cs +++ b/test/Ocelot.UnitTests/RequestBuilder/AddHeadersToRequestTests.cs @@ -4,6 +4,7 @@ using System.Security.Claims; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; using Moq; +using Ocelot.Library.Configuration; using Ocelot.Library.Errors; using Ocelot.Library.RequestBuilder; using Ocelot.Library.Responses; @@ -17,7 +18,7 @@ namespace Ocelot.UnitTests.RequestBuilder { private readonly AddHeadersToRequest _addHeadersToRequest; private readonly Mock _parser; - private List _configuration; + private List _configuration; private HttpContext _context; private Response _result; private Response _claimValue; @@ -40,9 +41,9 @@ namespace Ocelot.UnitTests.RequestBuilder }; this.Given( - x => x.GivenConfigurationHeaderExtractorProperties(new List + x => x.GivenConfigurationHeaderExtractorProperties(new List { - new ConfigurationHeaderExtractorProperties("header-key", "", "", 0) + new ClaimToHeader("header-key", "", "", 0) })) .Given(x => x.GivenHttpContext(context)) .And(x => x.GivenTheClaimParserReturns(new OkResponse("value"))) @@ -66,9 +67,9 @@ namespace Ocelot.UnitTests.RequestBuilder context.Request.Headers.Add("header-key", new StringValues("initial")); this.Given( - x => x.GivenConfigurationHeaderExtractorProperties(new List + x => x.GivenConfigurationHeaderExtractorProperties(new List { - new ConfigurationHeaderExtractorProperties("header-key", "", "", 0) + new ClaimToHeader("header-key", "", "", 0) })) .Given(x => x.GivenHttpContext(context)) .And(x => x.GivenTheClaimParserReturns(new OkResponse("value"))) @@ -82,9 +83,9 @@ namespace Ocelot.UnitTests.RequestBuilder public void should_return_error() { this.Given( - x => x.GivenConfigurationHeaderExtractorProperties(new List + x => x.GivenConfigurationHeaderExtractorProperties(new List { - new ConfigurationHeaderExtractorProperties("", "", "", 0) + new ClaimToHeader("", "", "", 0) })) .Given(x => x.GivenHttpContext(new DefaultHttpContext())) .And(x => x.GivenTheClaimParserReturns(new ErrorResponse(new List @@ -102,7 +103,7 @@ namespace Ocelot.UnitTests.RequestBuilder header.Value.First().ShouldBe(_claimValue.Data); } - private void GivenConfigurationHeaderExtractorProperties(List configuration) + private void GivenConfigurationHeaderExtractorProperties(List configuration) { _configuration = configuration; } diff --git a/test/Ocelot.UnitTests/RequestBuilder/ConfigurationHeadersExtractorTests.cs b/test/Ocelot.UnitTests/RequestBuilder/ConfigurationHeadersExtractorTests.cs index 238d9f1a..48e93b8a 100644 --- a/test/Ocelot.UnitTests/RequestBuilder/ConfigurationHeadersExtractorTests.cs +++ b/test/Ocelot.UnitTests/RequestBuilder/ConfigurationHeadersExtractorTests.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq; +using Ocelot.Library.Configuration; using Ocelot.Library.Errors; using Ocelot.Library.RequestBuilder; using Ocelot.Library.Responses; @@ -12,12 +13,12 @@ namespace Ocelot.UnitTests.RequestBuilder public class ConfigurationHeadersExtractorTests { private Dictionary _dictionary; - private readonly IConfigurationHeaderExtrator _configurationHeaderExtrator; - private Response _result; + private readonly IClaimToHeaderConfigurationParser _claimToHeaderConfigurationParser; + private Response _result; public ConfigurationHeadersExtractorTests() { - _configurationHeaderExtrator = new ConfigurationHeaderExtrator(); + _claimToHeaderConfigurationParser = new ClaimToHeaderConfigurationParser(); } [Fact] @@ -30,7 +31,7 @@ namespace Ocelot.UnitTests.RequestBuilder .When(x => x.WhenICallTheExtractor()) .Then( x => - x.ThenAnErrorIsReturned(new ErrorResponse( + x.ThenAnErrorIsReturned(new ErrorResponse( new List { new NoInstructionsError(">") @@ -48,7 +49,7 @@ namespace Ocelot.UnitTests.RequestBuilder .When(x => x.WhenICallTheExtractor()) .Then( x => - x.ThenAnErrorIsReturned(new ErrorResponse( + x.ThenAnErrorIsReturned(new ErrorResponse( new List { new InstructionNotForClaimsError() @@ -67,8 +68,8 @@ namespace Ocelot.UnitTests.RequestBuilder .Then( x => x.ThenTheClaimParserPropertiesAreReturned( - new OkResponse( - new ConfigurationHeaderExtractorProperties("CustomerId", "CustomerId", "", 0)))) + new OkResponse( + new ClaimToHeader("CustomerId", "CustomerId", "", 0)))) .BDDfy(); } @@ -83,18 +84,18 @@ namespace Ocelot.UnitTests.RequestBuilder .Then( x => x.ThenTheClaimParserPropertiesAreReturned( - new OkResponse( - new ConfigurationHeaderExtractorProperties("UserId", "Subject", "|", 0)))) + new OkResponse( + new ClaimToHeader("UserId", "Subject", "|", 0)))) .BDDfy(); } - private void ThenAnErrorIsReturned(Response expected) + private void ThenAnErrorIsReturned(Response expected) { _result.IsError.ShouldBe(expected.IsError); _result.Errors[0].ShouldBeOfType(expected.Errors[0].GetType()); } - private void ThenTheClaimParserPropertiesAreReturned(Response expected) + private void ThenTheClaimParserPropertiesAreReturned(Response expected) { _result.Data.ClaimKey.ShouldBe(expected.Data.ClaimKey); _result.Data.Delimiter.ShouldBe(expected.Data.Delimiter); @@ -105,7 +106,7 @@ namespace Ocelot.UnitTests.RequestBuilder private void WhenICallTheExtractor() { var first = _dictionary.First(); - _result = _configurationHeaderExtrator.Extract(first.Key, first.Value); + _result = _claimToHeaderConfigurationParser.Extract(first.Key, first.Value); } private void GivenTheDictionaryIs(Dictionary dictionary) From 2e6640c6eff77621ff337822274845824624768f Mon Sep 17 00:00:00 2001 From: TomPallister Date: Tue, 18 Oct 2016 18:32:34 +0100 Subject: [PATCH 092/183] refactoring configuration code so its not so crazy, still need to work on the creator class --- .../Builder/ReRouteBuilder.cs | 3 +- .../Creator/IOcelotConfigurationCreator.cs | 9 ++ .../Configuration/OcelotConfiguration.cs | 121 +-------------- .../ClaimToHeaderConfigurationParser.cs | 2 +- .../IClaimToHeaderConfigurationParser.cs | 2 +- .../Provider/IOcelotConfigurationProvider.cs | 9 ++ .../IOcelotConfigurationRepository.cs | 10 ++ .../InMemoryOcelotConfigurationRepository.cs | 29 ++++ .../Yaml/YamlOcelotConfigurationCreator.cs | 138 ++++++++++++++++++ .../Yaml/YamlOcelotConfigurationProvider.cs | 49 +++++++ .../ServiceCollectionExtensions.cs | 33 +++-- .../DownstreamRouteFinder.cs | 28 ++-- src/Ocelot/Startup.cs | 3 +- .../InMemoryConfigurationRepositoryTests.cs | 114 +++++++++++++++ ...ts.cs => YamlConfigurationCreatorTests.cs} | 48 +++--- .../YamlConfigurationProviderTests.cs | 116 +++++++++++++++ .../DownstreamRouteFinderTests.cs | 11 +- .../AuthenticationMiddlewareTests.cs | 2 +- .../DownstreamRouteFinderMiddlewareTests.cs | 2 +- .../DownstreamUrlCreatorMiddlewareTests.cs | 5 +- ...ttpRequestHeadersBuilderMiddlewareTests.cs | 2 +- .../ConfigurationHeadersExtractorTests.cs | 1 + ...eamUrlPathTemplateVariableReplacerTests.cs | 2 +- 23 files changed, 561 insertions(+), 178 deletions(-) rename src/Ocelot.Library/{ => Configuration}/Builder/ReRouteBuilder.cs (97%) create mode 100644 src/Ocelot.Library/Configuration/Creator/IOcelotConfigurationCreator.cs rename src/Ocelot.Library/Configuration/{ => Parser}/ClaimToHeaderConfigurationParser.cs (98%) rename src/Ocelot.Library/Configuration/{ => Parser}/IClaimToHeaderConfigurationParser.cs (79%) create mode 100644 src/Ocelot.Library/Configuration/Provider/IOcelotConfigurationProvider.cs create mode 100644 src/Ocelot.Library/Configuration/Repository/IOcelotConfigurationRepository.cs create mode 100644 src/Ocelot.Library/Configuration/Repository/InMemoryOcelotConfigurationRepository.cs create mode 100644 src/Ocelot.Library/Configuration/Yaml/YamlOcelotConfigurationCreator.cs create mode 100644 src/Ocelot.Library/Configuration/Yaml/YamlOcelotConfigurationProvider.cs create mode 100644 test/Ocelot.UnitTests/Configuration/InMemoryConfigurationRepositoryTests.cs rename test/Ocelot.UnitTests/Configuration/{OcelotConfigurationTests.cs => YamlConfigurationCreatorTests.cs} (88%) create mode 100644 test/Ocelot.UnitTests/Configuration/YamlConfigurationProviderTests.cs diff --git a/src/Ocelot.Library/Builder/ReRouteBuilder.cs b/src/Ocelot.Library/Configuration/Builder/ReRouteBuilder.cs similarity index 97% rename from src/Ocelot.Library/Builder/ReRouteBuilder.cs rename to src/Ocelot.Library/Configuration/Builder/ReRouteBuilder.cs index 2cf9538d..c6f1e90a 100644 --- a/src/Ocelot.Library/Builder/ReRouteBuilder.cs +++ b/src/Ocelot.Library/Configuration/Builder/ReRouteBuilder.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; -using Ocelot.Library.Configuration; -namespace Ocelot.Library.Builder +namespace Ocelot.Library.Configuration.Builder { public class ReRouteBuilder { diff --git a/src/Ocelot.Library/Configuration/Creator/IOcelotConfigurationCreator.cs b/src/Ocelot.Library/Configuration/Creator/IOcelotConfigurationCreator.cs new file mode 100644 index 00000000..1465c23f --- /dev/null +++ b/src/Ocelot.Library/Configuration/Creator/IOcelotConfigurationCreator.cs @@ -0,0 +1,9 @@ +using Ocelot.Library.Responses; + +namespace Ocelot.Library.Configuration.Creator +{ + public interface IOcelotConfigurationCreator + { + Response Create(); + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Configuration/OcelotConfiguration.cs b/src/Ocelot.Library/Configuration/OcelotConfiguration.cs index ae1cf189..c6fc0786 100644 --- a/src/Ocelot.Library/Configuration/OcelotConfiguration.cs +++ b/src/Ocelot.Library/Configuration/OcelotConfiguration.cs @@ -1,127 +1,14 @@ -using System; -using System.Linq; -using Microsoft.Extensions.Logging; -using Ocelot.Library.RequestBuilder; +using System.Collections.Generic; namespace Ocelot.Library.Configuration { - using System.Collections.Generic; - using Microsoft.Extensions.Options; - using Yaml; - public class OcelotConfiguration : IOcelotConfiguration { - private readonly IOptions _options; - private readonly IConfigurationValidator _configurationValidator; - private readonly List _reRoutes; - private const string RegExMatchEverything = ".*"; - private const string RegExMatchEndString = "$"; - private readonly IClaimToHeaderConfigurationParser _claimToHeaderConfigurationParser; - private readonly ILogger _logger; - - public OcelotConfiguration(IOptions options, - IConfigurationValidator configurationValidator, - IClaimToHeaderConfigurationParser claimToHeaderConfigurationParser, - ILogger logger) + public OcelotConfiguration(List reRoutes) { - _options = options; - _configurationValidator = configurationValidator; - _claimToHeaderConfigurationParser = claimToHeaderConfigurationParser; - _logger = logger; - _reRoutes = new List(); - SetUpConfiguration(); + ReRoutes = reRoutes; } - /// - /// This method is meant to be tempoary to convert a yaml config to an ocelot config...probably wont keep this but we will see - /// will need a refactor at some point as its crap - /// - private void SetUpConfiguration() - { - var response = _configurationValidator.IsValid(_options.Value); - - if (!response.IsError && !response.Data.IsError) - { - foreach (var reRoute in _options.Value.ReRoutes) - { - SetUpReRoute(reRoute); - } - } - } - - private void SetUpReRoute(YamlReRoute reRoute) - { - var upstreamTemplate = reRoute.UpstreamTemplate; - - var placeholders = new List(); - - for (var i = 0; i < upstreamTemplate.Length; i++) - { - if (IsPlaceHolder(upstreamTemplate, i)) - { - var postitionOfPlaceHolderClosingBracket = upstreamTemplate.IndexOf('}', i); - var difference = postitionOfPlaceHolderClosingBracket - i + 1; - var variableName = upstreamTemplate.Substring(i, difference); - placeholders.Add(variableName); - } - } - - foreach (var placeholder in placeholders) - { - upstreamTemplate = upstreamTemplate.Replace(placeholder, RegExMatchEverything); - } - - upstreamTemplate = $"{upstreamTemplate}{RegExMatchEndString}"; - - var isAuthenticated = !string.IsNullOrEmpty(reRoute.AuthenticationOptions?.Provider); - - if (isAuthenticated) - { - var authOptionsForRoute = new AuthenticationOptions(reRoute.AuthenticationOptions.Provider, - reRoute.AuthenticationOptions.ProviderRootUrl, reRoute.AuthenticationOptions.ScopeName, - reRoute.AuthenticationOptions.RequireHttps, reRoute.AuthenticationOptions.AdditionalScopes, - reRoute.AuthenticationOptions.ScopeSecret); - - var configHeaders = GetHeadersToAddToRequest(reRoute); - - _reRoutes.Add(new ReRoute(reRoute.DownstreamTemplate, reRoute.UpstreamTemplate, - reRoute.UpstreamHttpMethod, upstreamTemplate, isAuthenticated, - authOptionsForRoute, configHeaders - )); - } - else - { - _reRoutes.Add(new ReRoute(reRoute.DownstreamTemplate, reRoute.UpstreamTemplate, reRoute.UpstreamHttpMethod, - upstreamTemplate, isAuthenticated, null, new List())); - } - } - - private List GetHeadersToAddToRequest(YamlReRoute reRoute) - { - var configHeaders = new List(); - - foreach (var add in reRoute.AddHeadersToRequest) - { - var configurationHeader = _claimToHeaderConfigurationParser.Extract(add.Key, add.Value); - - if (configurationHeader.IsError) - { - _logger.LogCritical(new EventId(1, "Application Failed to start"), - $"Unable to extract configuration for key: {add.Key} and value: {add.Value} your configuration file is incorrect"); - - throw new Exception(configurationHeader.Errors[0].Message); - } - configHeaders.Add(configurationHeader.Data); - } - - return configHeaders; - } - - private bool IsPlaceHolder(string upstreamTemplate, int i) - { - return upstreamTemplate[i] == '{'; - } - - public List ReRoutes => _reRoutes; + public List ReRoutes { get; } } } \ No newline at end of file diff --git a/src/Ocelot.Library/Configuration/ClaimToHeaderConfigurationParser.cs b/src/Ocelot.Library/Configuration/Parser/ClaimToHeaderConfigurationParser.cs similarity index 98% rename from src/Ocelot.Library/Configuration/ClaimToHeaderConfigurationParser.cs rename to src/Ocelot.Library/Configuration/Parser/ClaimToHeaderConfigurationParser.cs index c81c5468..e2aa94d5 100644 --- a/src/Ocelot.Library/Configuration/ClaimToHeaderConfigurationParser.cs +++ b/src/Ocelot.Library/Configuration/Parser/ClaimToHeaderConfigurationParser.cs @@ -5,7 +5,7 @@ using Ocelot.Library.Errors; using Ocelot.Library.RequestBuilder; using Ocelot.Library.Responses; -namespace Ocelot.Library.Configuration +namespace Ocelot.Library.Configuration.Parser { public class ClaimToHeaderConfigurationParser : IClaimToHeaderConfigurationParser { diff --git a/src/Ocelot.Library/Configuration/IClaimToHeaderConfigurationParser.cs b/src/Ocelot.Library/Configuration/Parser/IClaimToHeaderConfigurationParser.cs similarity index 79% rename from src/Ocelot.Library/Configuration/IClaimToHeaderConfigurationParser.cs rename to src/Ocelot.Library/Configuration/Parser/IClaimToHeaderConfigurationParser.cs index ad627ba5..633cfcc6 100644 --- a/src/Ocelot.Library/Configuration/IClaimToHeaderConfigurationParser.cs +++ b/src/Ocelot.Library/Configuration/Parser/IClaimToHeaderConfigurationParser.cs @@ -1,6 +1,6 @@ using Ocelot.Library.Responses; -namespace Ocelot.Library.Configuration +namespace Ocelot.Library.Configuration.Parser { public interface IClaimToHeaderConfigurationParser { diff --git a/src/Ocelot.Library/Configuration/Provider/IOcelotConfigurationProvider.cs b/src/Ocelot.Library/Configuration/Provider/IOcelotConfigurationProvider.cs new file mode 100644 index 00000000..6918ca6d --- /dev/null +++ b/src/Ocelot.Library/Configuration/Provider/IOcelotConfigurationProvider.cs @@ -0,0 +1,9 @@ +using Ocelot.Library.Responses; + +namespace Ocelot.Library.Configuration.Provider +{ + public interface IOcelotConfigurationProvider + { + Response Get(); + } +} diff --git a/src/Ocelot.Library/Configuration/Repository/IOcelotConfigurationRepository.cs b/src/Ocelot.Library/Configuration/Repository/IOcelotConfigurationRepository.cs new file mode 100644 index 00000000..bd99149c --- /dev/null +++ b/src/Ocelot.Library/Configuration/Repository/IOcelotConfigurationRepository.cs @@ -0,0 +1,10 @@ +using Ocelot.Library.Responses; + +namespace Ocelot.Library.Configuration.Repository +{ + public interface IOcelotConfigurationRepository + { + Response Get(); + Response AddOrReplace(IOcelotConfiguration ocelotConfiguration); + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Configuration/Repository/InMemoryOcelotConfigurationRepository.cs b/src/Ocelot.Library/Configuration/Repository/InMemoryOcelotConfigurationRepository.cs new file mode 100644 index 00000000..f590ce8b --- /dev/null +++ b/src/Ocelot.Library/Configuration/Repository/InMemoryOcelotConfigurationRepository.cs @@ -0,0 +1,29 @@ +using Ocelot.Library.Responses; + +namespace Ocelot.Library.Configuration.Repository +{ + /// + /// Register as singleton + /// + public class InMemoryOcelotConfigurationRepository : IOcelotConfigurationRepository + { + private static readonly object LockObject = new object(); + + private IOcelotConfiguration _ocelotConfiguration; + + public Response Get() + { + return new OkResponse(_ocelotConfiguration); + } + + public Response AddOrReplace(IOcelotConfiguration ocelotConfiguration) + { + lock (LockObject) + { + _ocelotConfiguration = ocelotConfiguration; + } + + return new OkResponse(); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Configuration/Yaml/YamlOcelotConfigurationCreator.cs b/src/Ocelot.Library/Configuration/Yaml/YamlOcelotConfigurationCreator.cs new file mode 100644 index 00000000..5d6179a0 --- /dev/null +++ b/src/Ocelot.Library/Configuration/Yaml/YamlOcelotConfigurationCreator.cs @@ -0,0 +1,138 @@ +using System; +using System.Collections.Generic; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Ocelot.Library.Configuration.Creator; +using Ocelot.Library.Configuration.Parser; +using Ocelot.Library.Configuration.Repository; +using Ocelot.Library.Errors; +using Ocelot.Library.Responses; + +namespace Ocelot.Library.Configuration.Yaml +{ + /// + /// Register as singleton + /// + public class YamlOcelotConfigurationCreator : IOcelotConfigurationCreator + { + private readonly IOptions _options; + private readonly IConfigurationValidator _configurationValidator; + private const string RegExMatchEverything = ".*"; + private const string RegExMatchEndString = "$"; + private readonly IClaimToHeaderConfigurationParser _claimToHeaderConfigurationParser; + private readonly ILogger _logger; + + public YamlOcelotConfigurationCreator( + IOptions options, + IConfigurationValidator configurationValidator, + IClaimToHeaderConfigurationParser claimToHeaderConfigurationParser, + ILogger logger) + { + _options = options; + _configurationValidator = configurationValidator; + _claimToHeaderConfigurationParser = claimToHeaderConfigurationParser; + _logger = logger; + } + + public Response Create() + { + var config = SetUpConfiguration(); + + return new OkResponse(config); + } + + /// + /// This method is meant to be tempoary to convert a yaml config to an ocelot config...probably wont keep this but we will see + /// will need a refactor at some point as its crap + /// + private IOcelotConfiguration SetUpConfiguration() + { + var response = _configurationValidator.IsValid(_options.Value); + + var reRoutes = new List(); + + if (!response.IsError && !response.Data.IsError) + { + + foreach (var yamlReRoute in _options.Value.ReRoutes) + { + var ocelotReRoute = SetUpReRoute(yamlReRoute); + reRoutes.Add(ocelotReRoute); + } + } + + return new OcelotConfiguration(reRoutes); + } + + private ReRoute SetUpReRoute(YamlReRoute reRoute) + { + var upstreamTemplate = reRoute.UpstreamTemplate; + + var placeholders = new List(); + + for (var i = 0; i < upstreamTemplate.Length; i++) + { + if (IsPlaceHolder(upstreamTemplate, i)) + { + var postitionOfPlaceHolderClosingBracket = upstreamTemplate.IndexOf('}', i); + var difference = postitionOfPlaceHolderClosingBracket - i + 1; + var variableName = upstreamTemplate.Substring(i, difference); + placeholders.Add(variableName); + } + } + + foreach (var placeholder in placeholders) + { + upstreamTemplate = upstreamTemplate.Replace(placeholder, RegExMatchEverything); + } + + upstreamTemplate = $"{upstreamTemplate}{RegExMatchEndString}"; + + var isAuthenticated = !string.IsNullOrEmpty(reRoute.AuthenticationOptions?.Provider); + + if (isAuthenticated) + { + var authOptionsForRoute = new AuthenticationOptions(reRoute.AuthenticationOptions.Provider, + reRoute.AuthenticationOptions.ProviderRootUrl, reRoute.AuthenticationOptions.ScopeName, + reRoute.AuthenticationOptions.RequireHttps, reRoute.AuthenticationOptions.AdditionalScopes, + reRoute.AuthenticationOptions.ScopeSecret); + + var configHeaders = GetHeadersToAddToRequest(reRoute); + + return new ReRoute(reRoute.DownstreamTemplate, reRoute.UpstreamTemplate, + reRoute.UpstreamHttpMethod, upstreamTemplate, isAuthenticated, + authOptionsForRoute, configHeaders + ); + } + + return new ReRoute(reRoute.DownstreamTemplate, reRoute.UpstreamTemplate, reRoute.UpstreamHttpMethod, + upstreamTemplate, isAuthenticated, null, new List()); + } + + private List GetHeadersToAddToRequest(YamlReRoute reRoute) + { + var configHeaders = new List(); + + foreach (var add in reRoute.AddHeadersToRequest) + { + var configurationHeader = _claimToHeaderConfigurationParser.Extract(add.Key, add.Value); + + if (configurationHeader.IsError) + { + _logger.LogCritical(new EventId(1, "Application Failed to start"), + $"Unable to extract configuration for key: {add.Key} and value: {add.Value} your configuration file is incorrect"); + + throw new Exception(configurationHeader.Errors[0].Message); + } + configHeaders.Add(configurationHeader.Data); + } + + return configHeaders; + } + + private bool IsPlaceHolder(string upstreamTemplate, int i) + { + return upstreamTemplate[i] == '{'; + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Configuration/Yaml/YamlOcelotConfigurationProvider.cs b/src/Ocelot.Library/Configuration/Yaml/YamlOcelotConfigurationProvider.cs new file mode 100644 index 00000000..534fe83c --- /dev/null +++ b/src/Ocelot.Library/Configuration/Yaml/YamlOcelotConfigurationProvider.cs @@ -0,0 +1,49 @@ +using Ocelot.Library.Configuration.Creator; +using Ocelot.Library.Configuration.Provider; +using Ocelot.Library.Configuration.Repository; +using Ocelot.Library.Responses; + +namespace Ocelot.Library.Configuration.Yaml +{ + /// + /// Register as singleton + /// + public class YamlOcelotConfigurationProvider : IOcelotConfigurationProvider + { + private readonly IOcelotConfigurationRepository _repo; + private readonly IOcelotConfigurationCreator _creator; + + public YamlOcelotConfigurationProvider(IOcelotConfigurationRepository repo, + IOcelotConfigurationCreator creator) + { + _repo = repo; + _creator = creator; + } + + public Response Get() + { + var config = _repo.Get(); + + if (config.IsError) + { + return new ErrorResponse(config.Errors); + } + + if (config.Data == null) + { + var configuration = _creator.Create(); + + if (configuration.IsError) + { + return new ErrorResponse(configuration.Errors); + } + + _repo.AddOrReplace(configuration.Data); + + return new OkResponse(configuration.Data); + } + + return new OkResponse(config.Data); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/DependencyInjection/ServiceCollectionExtensions.cs b/src/Ocelot.Library/DependencyInjection/ServiceCollectionExtensions.cs index 19f80900..882163c1 100644 --- a/src/Ocelot.Library/DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/Ocelot.Library/DependencyInjection/ServiceCollectionExtensions.cs @@ -1,4 +1,9 @@ -namespace Ocelot.Library.DependencyInjection +using Ocelot.Library.Configuration.Creator; +using Ocelot.Library.Configuration.Parser; +using Ocelot.Library.Configuration.Provider; +using Ocelot.Library.Configuration.Repository; + +namespace Ocelot.Library.DependencyInjection { using Authentication; using Configuration; @@ -16,22 +21,30 @@ public static class ServiceCollectionExtensions { - public static IServiceCollection AddOcelot(this IServiceCollection services, IConfigurationRoot configurationRoot) + public static IServiceCollection AddOcelotYamlConfiguration(this IServiceCollection services, IConfigurationRoot configurationRoot) { - // framework services - services.AddOptions(); - services.AddMvcCore().AddJsonFormatters(); - services.AddLogging(); - // initial configuration from yaml services.Configure(configurationRoot); // ocelot services. - services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + + return services; + } + + public static IServiceCollection AddOcelot(this IServiceCollection services) + { + // framework services + services.AddMvcCore().AddJsonFormatters(); + services.AddLogging(); + + // ocelot services. + services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/src/Ocelot.Library/DownstreamRouteFinder/DownstreamRouteFinder.cs b/src/Ocelot.Library/DownstreamRouteFinder/DownstreamRouteFinder.cs index 5962f808..542f7341 100644 --- a/src/Ocelot.Library/DownstreamRouteFinder/DownstreamRouteFinder.cs +++ b/src/Ocelot.Library/DownstreamRouteFinder/DownstreamRouteFinder.cs @@ -1,29 +1,31 @@ -namespace Ocelot.Library.DownstreamRouteFinder -{ - using System; - using System.Collections.Generic; - using System.Linq; - using Configuration; - using Errors; - using Responses; - using UrlMatcher; +using System; +using System.Collections.Generic; +using System.Linq; +using Ocelot.Library.Configuration.Provider; +using Ocelot.Library.Errors; +using Ocelot.Library.Responses; +using Ocelot.Library.UrlMatcher; +namespace Ocelot.Library.DownstreamRouteFinder +{ public class DownstreamRouteFinder : IDownstreamRouteFinder { - private readonly IOcelotConfiguration _configuration; + private readonly IOcelotConfigurationProvider _configProvider; private readonly IUrlPathToUrlTemplateMatcher _urlMatcher; private readonly ITemplateVariableNameAndValueFinder _templateVariableNameAndValueFinder; - public DownstreamRouteFinder(IOcelotConfiguration configuration, IUrlPathToUrlTemplateMatcher urlMatcher, ITemplateVariableNameAndValueFinder templateVariableNameAndValueFinder) + public DownstreamRouteFinder(IOcelotConfigurationProvider configProvider, IUrlPathToUrlTemplateMatcher urlMatcher, ITemplateVariableNameAndValueFinder templateVariableNameAndValueFinder) { - _configuration = configuration; + _configProvider = configProvider; _urlMatcher = urlMatcher; _templateVariableNameAndValueFinder = templateVariableNameAndValueFinder; } public Response FindDownstreamRoute(string upstreamUrlPath, string upstreamHttpMethod) { - foreach (var template in _configuration.ReRoutes.Where(r => string.Equals(r.UpstreamHttpMethod, upstreamHttpMethod, StringComparison.CurrentCultureIgnoreCase))) + var configuration = _configProvider.Get(); + + foreach (var template in configuration.Data.ReRoutes.Where(r => string.Equals(r.UpstreamHttpMethod, upstreamHttpMethod, StringComparison.CurrentCultureIgnoreCase))) { var urlMatch = _urlMatcher.Match(upstreamUrlPath, template.UpstreamTemplatePattern); diff --git a/src/Ocelot/Startup.cs b/src/Ocelot/Startup.cs index 66989428..ae9c59cd 100644 --- a/src/Ocelot/Startup.cs +++ b/src/Ocelot/Startup.cs @@ -28,7 +28,8 @@ namespace Ocelot // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { - services.AddOcelot(Configuration); + services.AddOcelotYamlConfiguration(Configuration); + services.AddOcelot(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. diff --git a/test/Ocelot.UnitTests/Configuration/InMemoryConfigurationRepositoryTests.cs b/test/Ocelot.UnitTests/Configuration/InMemoryConfigurationRepositoryTests.cs new file mode 100644 index 00000000..c46942da --- /dev/null +++ b/test/Ocelot.UnitTests/Configuration/InMemoryConfigurationRepositoryTests.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Ocelot.Library.Configuration; +using Ocelot.Library.Configuration.Builder; +using Ocelot.Library.Configuration.Repository; +using Ocelot.Library.Responses; +using Shouldly; +using TestStack.BDDfy; +using Xunit; + +namespace Ocelot.UnitTests.Configuration +{ + public class InMemoryConfigurationRepositoryTests + { + private readonly InMemoryOcelotConfigurationRepository _repo; + private IOcelotConfiguration _config; + private Response _result; + private Response _getResult; + + public InMemoryConfigurationRepositoryTests() + { + _repo = new InMemoryOcelotConfigurationRepository(); + } + + [Fact] + public void can_add_config() + { + this.Given(x => x.GivenTheConfigurationIs(new FakeConfig("initial"))) + .When(x => x.WhenIAddOrReplaceTheConfig()) + .Then(x => x.ThenNoErrorsAreReturned()) + .BDDfy(); + } + + [Fact] + public void can_get_config() + { + this.Given(x => x.GivenThereIsASavedConfiguration()) + .When(x => x.WhenIGetTheConfiguration()) + .Then(x => x.ThenTheConfigurationIsReturned()) + .BDDfy(); + } + + /// + /// long runnnig unit test to make sure repo thread safeok on + /// + [Fact] + public void repo_is_thread_safe() + { + var tasks = new Task[100000]; + for (int i = 0; i < tasks.Length; i++) + { + tasks[i] = Fire(); + } + + Task.WaitAll(tasks); + } + + private async Task Fire() + { + var taskGuid = Guid.NewGuid().ToString(); + _repo.AddOrReplace(new FakeConfig(taskGuid)); + var configuration = _repo.Get(); + configuration.Data.ReRoutes[0].DownstreamTemplate.ShouldBe(taskGuid); + } + + private void ThenTheConfigurationIsReturned() + { + _getResult.Data.ReRoutes[0].DownstreamTemplate.ShouldBe("initial"); + } + + private void WhenIGetTheConfiguration() + { + _getResult = _repo.Get(); + } + + private void GivenThereIsASavedConfiguration() + { + GivenTheConfigurationIs(new FakeConfig("initial")); + WhenIAddOrReplaceTheConfig(); + } + + private void GivenTheConfigurationIs(IOcelotConfiguration config) + { + _config = config; + } + + private void WhenIAddOrReplaceTheConfig() + { + _result = _repo.AddOrReplace(_config); + } + + private void ThenNoErrorsAreReturned() + { + _result.IsError.ShouldBeFalse(); + } + + class FakeConfig : IOcelotConfiguration + { + private readonly string _downstreamTemplate; + + public FakeConfig(string downstreamTemplate) + { + _downstreamTemplate = downstreamTemplate; + } + + public List ReRoutes => new List + { + new ReRouteBuilder().WithDownstreamTemplate(_downstreamTemplate).Build() + }; + } + } +} diff --git a/test/Ocelot.UnitTests/Configuration/OcelotConfigurationTests.cs b/test/Ocelot.UnitTests/Configuration/YamlConfigurationCreatorTests.cs similarity index 88% rename from test/Ocelot.UnitTests/Configuration/OcelotConfigurationTests.cs rename to test/Ocelot.UnitTests/Configuration/YamlConfigurationCreatorTests.cs index 8846d60d..4e6d5fa5 100644 --- a/test/Ocelot.UnitTests/Configuration/OcelotConfigurationTests.cs +++ b/test/Ocelot.UnitTests/Configuration/YamlConfigurationCreatorTests.cs @@ -2,6 +2,9 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Moq; +using Ocelot.Library.Configuration.Builder; +using Ocelot.Library.Configuration.Parser; +using Ocelot.Library.Configuration.Repository; using Ocelot.Library.RequestBuilder; using Shouldly; using TestStack.BDDfy; @@ -9,26 +12,28 @@ using Xunit; namespace Ocelot.UnitTests.Configuration { - using Library.Builder; using Library.Configuration; using Library.Configuration.Yaml; using Library.Responses; - public class OcelotConfigurationTests + public class YamlConfigurationCreatorTests { private readonly Mock> _yamlConfig; private readonly Mock _validator; - private OcelotConfiguration _config; + private Response _config; private YamlConfiguration _yamlConfiguration; - private readonly Mock _configExtractor; - private readonly Mock> _logger; + private readonly Mock _configParser; + private readonly Mock> _logger; + private readonly YamlOcelotConfigurationCreator _ocelotConfigurationCreator; - public OcelotConfigurationTests() + public YamlConfigurationCreatorTests() { - _logger = new Mock>(); - _configExtractor = new Mock(); + _logger = new Mock>(); + _configParser = new Mock(); _validator = new Mock(); _yamlConfig = new Mock>(); + _ocelotConfigurationCreator = new YamlOcelotConfigurationCreator( + _yamlConfig.Object, _validator.Object, _configParser.Object, _logger.Object); } [Fact] @@ -47,7 +52,7 @@ namespace Ocelot.UnitTests.Configuration } })) .And(x => x.GivenTheYamlConfigIsValid()) - .When(x => x.WhenIInstanciateTheOcelotConfig()) + .When(x => x.WhenICreateTheConfig()) .Then(x => x.ThenTheReRoutesAre(new List { new ReRouteBuilder() @@ -109,7 +114,7 @@ namespace Ocelot.UnitTests.Configuration })) .And(x => x.GivenTheYamlConfigIsValid()) .And(x => x.GivenTheConfigHeaderExtractorReturns(new ClaimToHeader("CustomerId", "CustomerId", "", 0))) - .When(x => x.WhenIInstanciateTheOcelotConfig()) + .When(x => x.WhenICreateTheConfig()) .Then(x => x.ThenTheReRoutesAre(expected)) .And(x => x.ThenTheAuthenticationOptionsAre(expected)) .BDDfy(); @@ -117,7 +122,7 @@ namespace Ocelot.UnitTests.Configuration private void GivenTheConfigHeaderExtractorReturns(ClaimToHeader expected) { - _configExtractor + _configParser .Setup(x => x.Extract(It.IsAny(), It.IsAny())) .Returns(new OkResponse(expected)); } @@ -162,7 +167,7 @@ namespace Ocelot.UnitTests.Configuration } })) .And(x => x.GivenTheYamlConfigIsValid()) - .When(x => x.WhenIInstanciateTheOcelotConfig()) + .When(x => x.WhenICreateTheConfig()) .Then(x => x.ThenTheReRoutesAre(expected)) .And(x => x.ThenTheAuthenticationOptionsAre(expected)) .BDDfy(); @@ -184,7 +189,7 @@ namespace Ocelot.UnitTests.Configuration } })) .And(x => x.GivenTheYamlConfigIsValid()) - .When(x => x.WhenIInstanciateTheOcelotConfig()) + .When(x => x.WhenICreateTheConfig()) .Then(x => x.ThenTheReRoutesAre(new List { new ReRouteBuilder() @@ -213,7 +218,7 @@ namespace Ocelot.UnitTests.Configuration } })) .And(x => x.GivenTheYamlConfigIsValid()) - .When(x => x.WhenIInstanciateTheOcelotConfig()) + .When(x => x.WhenICreateTheConfig()) .Then(x => x.ThenTheReRoutesAre(new List { new ReRouteBuilder() @@ -242,7 +247,7 @@ namespace Ocelot.UnitTests.Configuration } })) .And(x => x.GivenTheYamlConfigIsValid()) - .When(x => x.WhenIInstanciateTheOcelotConfig()) + .When(x => x.WhenICreateTheConfig()) .Then(x => x.ThenTheReRoutesAre(new List { new ReRouteBuilder() @@ -270,17 +275,16 @@ namespace Ocelot.UnitTests.Configuration .Returns(_yamlConfiguration); } - private void WhenIInstanciateTheOcelotConfig() + private void WhenICreateTheConfig() { - _config = new OcelotConfiguration(_yamlConfig.Object, _validator.Object, - _configExtractor.Object, _logger.Object); + _config = _ocelotConfigurationCreator.Create(); } private void ThenTheReRoutesAre(List expectedReRoutes) { - for (int i = 0; i < _config.ReRoutes.Count; i++) + for (int i = 0; i < _config.Data.ReRoutes.Count; i++) { - var result = _config.ReRoutes[i]; + var result = _config.Data.ReRoutes[i]; var expected = expectedReRoutes[i]; result.DownstreamTemplate.ShouldBe(expected.DownstreamTemplate); @@ -292,9 +296,9 @@ namespace Ocelot.UnitTests.Configuration private void ThenTheAuthenticationOptionsAre(List expectedReRoutes) { - for (int i = 0; i < _config.ReRoutes.Count; i++) + for (int i = 0; i < _config.Data.ReRoutes.Count; i++) { - var result = _config.ReRoutes[i].AuthenticationOptions; + var result = _config.Data.ReRoutes[i].AuthenticationOptions; var expected = expectedReRoutes[i].AuthenticationOptions; result.AdditionalScopes.ShouldBe(expected.AdditionalScopes); diff --git a/test/Ocelot.UnitTests/Configuration/YamlConfigurationProviderTests.cs b/test/Ocelot.UnitTests/Configuration/YamlConfigurationProviderTests.cs new file mode 100644 index 00000000..ae81c4f7 --- /dev/null +++ b/test/Ocelot.UnitTests/Configuration/YamlConfigurationProviderTests.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Moq; +using Ocelot.Library.Configuration; +using Ocelot.Library.Configuration.Creator; +using Ocelot.Library.Configuration.Provider; +using Ocelot.Library.Configuration.Repository; +using Ocelot.Library.Configuration.Yaml; +using Ocelot.Library.Errors; +using Ocelot.Library.Responses; +using Shouldly; +using TestStack.BDDfy; +using Xunit; + +namespace Ocelot.UnitTests.Configuration +{ + public class YamlConfigurationProviderTests + { + private readonly IOcelotConfigurationProvider _ocelotConfigurationProvider; + private readonly Mock _configurationRepository; + private readonly Mock _creator; + private Response _result; + + public YamlConfigurationProviderTests() + { + _creator = new Mock(); + _configurationRepository = new Mock(); + _ocelotConfigurationProvider = new YamlOcelotConfigurationProvider(_configurationRepository.Object, _creator.Object); + } + + [Fact] + public void should_get_config() + { + this.Given(x => x.GivenTheRepoReturns(new OkResponse(new OcelotConfiguration(new List())))) + .When(x => x.WhenIGetTheConfig()) + .Then(x => x.TheFollowingIsReturned(new OkResponse(new OcelotConfiguration(new List())))) + .BDDfy(); + } + + [Fact] + public void should_create_config_if_it_doesnt_exist() + { + this.Given(x => x.GivenTheRepoReturns(new OkResponse(null))) + .And(x => x.GivenTheCreatorReturns(new OkResponse(new OcelotConfiguration(new List())))) + .When(x => x.WhenIGetTheConfig()) + .Then(x => x.TheFollowingIsReturned(new OkResponse(new OcelotConfiguration(new List())))) + .BDDfy(); + } + + [Fact] + public void should_return_error() + { + this.Given(x => x.GivenTheRepoReturns(new ErrorResponse(new List + { + new AnyError() + }))) + .When(x => x.WhenIGetTheConfig()) + .Then(x => x.TheFollowingIsReturned( + new ErrorResponse(new List + { + new AnyError() + }))) + .BDDfy(); + } + + [Fact] + public void should_return_error_if_creator_errors() + { + this.Given(x => x.GivenTheRepoReturns(new OkResponse(null))) + .And(x => x.GivenTheCreatorReturns(new ErrorResponse(new List + { + new AnyError() + }))) + .When(x => x.WhenIGetTheConfig()) + .Then(x => x.TheFollowingIsReturned(new ErrorResponse(new List + { + new AnyError() + }))) + .BDDfy(); + } + + private void GivenTheCreatorReturns(Response config) + { + _creator + .Setup(x => x.Create()) + .Returns(config); + } + + private void GivenTheRepoReturns(Response config) + { + _configurationRepository + .Setup(x => x.Get()) + .Returns(config); + } + + private void WhenIGetTheConfig() + { + _result = _ocelotConfigurationProvider.Get(); + } + + private void TheFollowingIsReturned(Response expected) + { + _result.IsError.ShouldBe(expected.IsError); + } + + class AnyError : Error + { + public AnyError() + : base("blamo", OcelotErrorCode.UnknownError) + { + } + } + } +} diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs index 0f979b18..24ef25e7 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs @@ -1,12 +1,13 @@ using System.Collections.Generic; using Moq; +using Ocelot.Library.Configuration.Builder; +using Ocelot.Library.Configuration.Provider; using Shouldly; using TestStack.BDDfy; using Xunit; namespace Ocelot.UnitTests.DownstreamRouteFinder { - using Library.Builder; using Library.Configuration; using Library.DownstreamRouteFinder; using Library.Responses; @@ -15,7 +16,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder public class DownstreamRouteFinderTests { private readonly IDownstreamRouteFinder _downstreamRouteFinder; - private readonly Mock _mockConfig; + private readonly Mock _mockConfig; private readonly Mock _mockMatcher; private readonly Mock _finder; private string _upstreamUrlPath; @@ -26,7 +27,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder public DownstreamRouteFinderTests() { - _mockConfig = new Mock(); + _mockConfig = new Mock(); _mockMatcher = new Mock(); _finder = new Mock(); _downstreamRouteFinder = new DownstreamRouteFinder(_mockConfig.Object, _mockMatcher.Object, _finder.Object); @@ -157,8 +158,8 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder { _reRoutesConfig = reRoutesConfig; _mockConfig - .Setup(x => x.ReRoutes) - .Returns(_reRoutesConfig); + .Setup(x => x.Get()) + .Returns(new OkResponse(new OcelotConfiguration(_reRoutesConfig))); } private void GivenThereIsAnUpstreamUrlPath(string upstreamUrlPath) diff --git a/test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs index b9350cce..eebccfa3 100644 --- a/test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs @@ -6,13 +6,13 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Moq; +using Ocelot.Library.Configuration.Builder; using TestStack.BDDfy; using Xunit; namespace Ocelot.UnitTests.Middleware { using Library.Authentication; - using Library.Builder; using Library.DownstreamRouteFinder; using Library.Middleware; using Library.Repository; diff --git a/test/Ocelot.UnitTests/Middleware/DownstreamRouteFinderMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/DownstreamRouteFinderMiddlewareTests.cs index 894852d8..898e1648 100644 --- a/test/Ocelot.UnitTests/Middleware/DownstreamRouteFinderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Middleware/DownstreamRouteFinderMiddlewareTests.cs @@ -6,12 +6,12 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Moq; +using Ocelot.Library.Configuration.Builder; using TestStack.BDDfy; using Xunit; namespace Ocelot.UnitTests.Middleware { - using Library.Builder; using Library.DownstreamRouteFinder; using Library.Middleware; using Library.Repository; diff --git a/test/Ocelot.UnitTests/Middleware/DownstreamUrlCreatorMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/DownstreamUrlCreatorMiddlewareTests.cs index f97766d9..56c0493c 100644 --- a/test/Ocelot.UnitTests/Middleware/DownstreamUrlCreatorMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Middleware/DownstreamUrlCreatorMiddlewareTests.cs @@ -1,10 +1,11 @@ -namespace Ocelot.UnitTests.Middleware +using Ocelot.Library.Configuration.Builder; + +namespace Ocelot.UnitTests.Middleware { using System; using System.Collections.Generic; using System.IO; using System.Net.Http; - using Library.Builder; using Library.DownstreamRouteFinder; using Library.Middleware; using Library.Repository; diff --git a/test/Ocelot.UnitTests/Middleware/HttpRequestHeadersBuilderMiddlewareTests.cs b/test/Ocelot.UnitTests/Middleware/HttpRequestHeadersBuilderMiddlewareTests.cs index f04efbfc..ec0104cd 100644 --- a/test/Ocelot.UnitTests/Middleware/HttpRequestHeadersBuilderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Middleware/HttpRequestHeadersBuilderMiddlewareTests.cs @@ -7,8 +7,8 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Moq; -using Ocelot.Library.Builder; using Ocelot.Library.Configuration; +using Ocelot.Library.Configuration.Builder; using Ocelot.Library.DownstreamRouteFinder; using Ocelot.Library.Middleware; using Ocelot.Library.Repository; diff --git a/test/Ocelot.UnitTests/RequestBuilder/ConfigurationHeadersExtractorTests.cs b/test/Ocelot.UnitTests/RequestBuilder/ConfigurationHeadersExtractorTests.cs index 48e93b8a..d61daaa7 100644 --- a/test/Ocelot.UnitTests/RequestBuilder/ConfigurationHeadersExtractorTests.cs +++ b/test/Ocelot.UnitTests/RequestBuilder/ConfigurationHeadersExtractorTests.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Linq; using Ocelot.Library.Configuration; +using Ocelot.Library.Configuration.Parser; using Ocelot.Library.Errors; using Ocelot.Library.RequestBuilder; using Ocelot.Library.Responses; diff --git a/test/Ocelot.UnitTests/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs b/test/Ocelot.UnitTests/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs index 85f65d48..3db2b611 100644 --- a/test/Ocelot.UnitTests/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs +++ b/test/Ocelot.UnitTests/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs @@ -1,11 +1,11 @@ using System.Collections.Generic; +using Ocelot.Library.Configuration.Builder; using Shouldly; using TestStack.BDDfy; using Xunit; namespace Ocelot.UnitTests.UrlTemplateReplacer { - using Library.Builder; using Library.DownstreamRouteFinder; using Library.Responses; using Library.UrlMatcher; From f79b76b414cfe1c5658b970e51739e423e592235 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Tue, 18 Oct 2016 18:52:43 +0100 Subject: [PATCH 093/183] reorganised project so its a bit more vertical for features --- .../{ => Handler}/AuthenticationHandler.cs | 6 +-- .../Creator}/AuthenticationHandlerCreator.cs | 11 +++--- .../Creator}/IAuthenticationHandlerCreator.cs | 9 +++-- .../Factory}/AuthenticationHandlerFactory.cs | 12 +++--- .../Factory}/IAuthenticationHandlerFactory.cs | 7 ++-- ...nableToCreateAuthenticationHandlerError.cs | 6 +-- .../SupportedAuthenticationProviders.cs | 7 ++++ .../Middleware/AuthenticationMiddleware.cs | 23 ++++++------ ...nticationMiddlewareMiddlewareExtensions.cs | 6 +-- .../SupportAuthenticationProviders.cs | 7 ---- .../YamlOcelotConfigurationCreator.cs | 7 ++-- .../Parser}/InstructionNotForClaimsError.cs | 2 +- .../Parser}/NoInstructionsError.cs | 2 +- .../ParsingConfigurationHeaderError.cs | 2 +- .../YamlOcelotConfigurationProvider.cs | 3 +- .../ConfigurationValidationResult.cs | 8 ++-- .../ConfigurationValidator.cs | 20 +++++----- .../DownstreamTemplateAlreadyUsedError.cs | 6 +-- .../IConfigurationValidator.cs | 7 ++-- .../UnsupportedAuthenticationProviderError.cs | 6 +-- .../ServiceCollectionExtensions.cs | 17 ++++++--- .../DownstreamRouteFinder/DownstreamRoute.cs | 5 ++- .../{ => Finder}/DownstreamRouteFinder.cs | 4 +- .../{ => Finder}/IDownstreamRouteFinder.cs | 6 +-- .../UnableToFindDownstreamRouteError.cs | 6 +-- .../DownstreamRouteFinderMiddleware.cs | 13 ++++--- ...wnstreamRouteFinderMiddlewareExtensions.cs | 6 +-- .../ITemplateVariableNameAndValueFinder.cs | 8 ++-- .../IUrlPathToUrlTemplateMatcher.cs | 6 +-- .../UrlMatcher/RegExUrlMatcher.cs | 8 ++-- .../TemplateVariableNameAndValue.cs | 2 +- .../TemplateVariableNameAndValueFinder.cs | 8 ++-- .../UrlMatcher/UrlMatch.cs | 2 +- .../DownstreamUrlCreatorMiddleware.cs | 15 ++++---- ...ownstreamUrlCreatorMiddlewareExtensions.cs | 6 +-- .../DownstreamUrlTemplateVariableReplacer.cs | 10 ++--- ...wnstreamUrlPathTemplateVariableReplacer.cs | 8 ++-- .../AddHeadersToRequest.cs | 3 +- .../IAddHeadersToRequest.cs | 2 +- .../HttpRequestHeadersBuilderMiddleware.cs | 15 +++----- ...questHeadersBuilderMiddlewareExtensions.cs | 6 +-- .../Parser}/CannotFindClaimError.cs | 2 +- .../Parser}/ClaimsParser.cs | 2 +- .../Parser}/IClaimsParser.cs | 2 +- .../Middleware/OcelotMiddleware.cs | 5 ++- .../Middleware/OcelotMiddlewareExtensions.cs | 10 ++++- .../{ => Builder}/HttpRequestBuilder.cs | 20 +++++----- .../{ => Builder}/IRequestBuilder.cs | 12 +++--- .../HttpRequestBuilderMiddleware.cs | 13 ++++--- .../HttpRequestBuilderMiddlewareExtensions.cs | 6 +-- .../Middleware/HttpRequesterMiddleware.cs | 14 +++---- .../HttpRequesterMiddlewareExtensions.cs | 6 +-- .../Middleware/HttpResponderMiddleware.cs | 14 +++---- .../HttpResponderMiddlewareExtensions.cs | 6 +-- .../CannotAddDataError.cs | 6 +-- .../CannotFindDataError.cs | 6 +-- .../IScopedRequestDataRepository.cs | 6 +-- .../ScopedRequestDataRepository.cs | 14 +++---- .../AuthenticationHandlerFactoryTests.cs | 3 ++ .../AuthenticationMiddlewareTests.cs | 15 ++++---- .../ConfigurationHeadersExtractorTests.cs | 3 +- .../ConfigurationValidationTests.cs | 1 + .../YamlConfigurationCreatorTests.cs | 2 + .../DownstreamRouteFinderMiddlewareTests.cs | 14 +++---- .../DownstreamRouteFinderTests.cs | 5 ++- .../UrlMatcher/RegExUrlMatcherTests.cs | 7 ++-- ...TemplateVariableNameAndValueFinderTests.cs | 7 ++-- .../DownstreamUrlCreatorMiddlewareTests.cs | 37 +++++++++---------- ...eamUrlPathTemplateVariableReplacerTests.cs | 11 +++--- .../AddHeadersToRequestTests.cs | 5 ++- .../ClaimParserTests.cs | 6 +-- ...ttpRequestHeadersBuilderMiddlewareTests.cs | 10 ++--- .../ScopedRequestDataRepositoryTests.cs | 2 +- .../HttpRequestBuilderMiddlewareTests.cs | 12 +++--- .../RequestBuilder/RequestBuilderTests.cs | 1 + .../HttpRequesterMiddlewareTests.cs | 13 +++---- .../HttpResponderMiddlewareTests.cs | 11 +++--- 77 files changed, 324 insertions(+), 298 deletions(-) rename src/Ocelot.Library/Authentication/{ => Handler}/AuthenticationHandler.cs (79%) rename src/Ocelot.Library/Authentication/{ => Handler/Creator}/AuthenticationHandlerCreator.cs (84%) rename src/Ocelot.Library/Authentication/{ => Handler/Creator}/IAuthenticationHandlerCreator.cs (63%) rename src/Ocelot.Library/Authentication/{ => Handler/Factory}/AuthenticationHandlerFactory.cs (80%) rename src/Ocelot.Library/Authentication/{ => Handler/Factory}/IAuthenticationHandlerFactory.cs (65%) rename src/Ocelot.Library/Authentication/{ => Handler/Factory}/UnableToCreateAuthenticationHandlerError.cs (74%) create mode 100644 src/Ocelot.Library/Authentication/Handler/SupportedAuthenticationProviders.cs rename src/Ocelot.Library/{ => Authentication}/Middleware/AuthenticationMiddleware.cs (84%) rename src/Ocelot.Library/{ => Authentication}/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs (76%) delete mode 100644 src/Ocelot.Library/Authentication/SupportAuthenticationProviders.cs rename src/Ocelot.Library/Configuration/{Yaml => Creator}/YamlOcelotConfigurationCreator.cs (97%) rename src/Ocelot.Library/{RequestBuilder => Configuration/Parser}/InstructionNotForClaimsError.cs (87%) rename src/Ocelot.Library/{RequestBuilder => Configuration/Parser}/NoInstructionsError.cs (85%) rename src/Ocelot.Library/{RequestBuilder => Configuration/Parser}/ParsingConfigurationHeaderError.cs (88%) rename src/Ocelot.Library/Configuration/{Yaml => Provider}/YamlOcelotConfigurationProvider.cs (93%) rename src/Ocelot.Library/Configuration/{Yaml => Validator}/ConfigurationValidationResult.cs (80%) rename src/Ocelot.Library/Configuration/{Yaml => Validator}/ConfigurationValidator.cs (88%) rename src/Ocelot.Library/Configuration/{Yaml => Validator}/DownstreamTemplateAlreadyUsedError.cs (74%) rename src/Ocelot.Library/Configuration/{Yaml => Validator}/IConfigurationValidator.cs (54%) rename src/Ocelot.Library/Configuration/{Yaml => Validator}/UnsupportedAuthenticationProviderError.cs (75%) rename src/Ocelot.Library/DownstreamRouteFinder/{ => Finder}/DownstreamRouteFinder.cs (94%) rename src/Ocelot.Library/DownstreamRouteFinder/{ => Finder}/IDownstreamRouteFinder.cs (65%) rename src/Ocelot.Library/DownstreamRouteFinder/{ => Finder}/UnableToFindDownstreamRouteError.cs (73%) rename src/Ocelot.Library/{ => DownstreamRouteFinder}/Middleware/DownstreamRouteFinderMiddleware.cs (84%) rename src/Ocelot.Library/{ => DownstreamRouteFinder}/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs (75%) rename src/Ocelot.Library/{ => DownstreamRouteFinder}/UrlMatcher/ITemplateVariableNameAndValueFinder.cs (59%) rename src/Ocelot.Library/{ => DownstreamRouteFinder}/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs (63%) rename src/Ocelot.Library/{ => DownstreamRouteFinder}/UrlMatcher/RegExUrlMatcher.cs (76%) rename src/Ocelot.Library/{ => DownstreamRouteFinder}/UrlMatcher/TemplateVariableNameAndValue.cs (87%) rename src/Ocelot.Library/{ => DownstreamRouteFinder}/UrlMatcher/TemplateVariableNameAndValueFinder.cs (96%) rename src/Ocelot.Library/{ => DownstreamRouteFinder}/UrlMatcher/UrlMatch.cs (74%) rename src/Ocelot.Library/{ => DownstreamUrlCreator}/Middleware/DownstreamUrlCreatorMiddleware.cs (82%) rename src/Ocelot.Library/{ => DownstreamUrlCreator}/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs (75%) rename src/Ocelot.Library/{ => DownstreamUrlCreator}/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs (80%) rename src/Ocelot.Library/{ => DownstreamUrlCreator}/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs (53%) rename src/Ocelot.Library/{RequestBuilder => HeaderBuilder}/AddHeadersToRequest.cs (94%) rename src/Ocelot.Library/{RequestBuilder => HeaderBuilder}/IAddHeadersToRequest.cs (89%) rename src/Ocelot.Library/{ => HeaderBuilder}/Middleware/HttpRequestHeadersBuilderMiddleware.cs (82%) rename src/Ocelot.Library/{ => HeaderBuilder}/Middleware/HttpRequestHeadersBuilderMiddlewareExtensions.cs (77%) rename src/Ocelot.Library/{RequestBuilder => HeaderBuilder/Parser}/CannotFindClaimError.cs (83%) rename src/Ocelot.Library/{RequestBuilder => HeaderBuilder/Parser}/ClaimsParser.cs (97%) rename src/Ocelot.Library/{RequestBuilder => HeaderBuilder/Parser}/IClaimsParser.cs (84%) rename src/Ocelot.Library/RequestBuilder/{ => Builder}/HttpRequestBuilder.cs (88%) rename src/Ocelot.Library/RequestBuilder/{ => Builder}/IRequestBuilder.cs (66%) rename src/Ocelot.Library/{ => RequestBuilder}/Middleware/HttpRequestBuilderMiddleware.cs (86%) rename src/Ocelot.Library/{ => RequestBuilder}/Middleware/HttpRequestBuilderMiddlewareExtensions.cs (76%) rename src/Ocelot.Library/{ => Requester}/Middleware/HttpRequesterMiddleware.cs (85%) rename src/Ocelot.Library/{ => Requester}/Middleware/HttpRequesterMiddlewareExtensions.cs (76%) rename src/Ocelot.Library/{ => Responder}/Middleware/HttpResponderMiddleware.cs (89%) rename src/Ocelot.Library/{ => Responder}/Middleware/HttpResponderMiddlewareExtensions.cs (76%) rename src/Ocelot.Library/{Repository => ScopedData}/CannotAddDataError.cs (72%) rename src/Ocelot.Library/{Repository => ScopedData}/CannotFindDataError.cs (73%) rename src/Ocelot.Library/{Repository => ScopedData}/IScopedRequestDataRepository.cs (69%) rename src/Ocelot.Library/{Repository => ScopedData}/ScopedRequestDataRepository.cs (87%) rename test/Ocelot.UnitTests/{Middleware => Authentication}/AuthenticationMiddlewareTests.cs (89%) rename test/Ocelot.UnitTests/{RequestBuilder => Configuration}/ConfigurationHeadersExtractorTests.cs (98%) rename test/Ocelot.UnitTests/{Middleware => DownstreamRouteFinder}/DownstreamRouteFinderMiddlewareTests.cs (90%) rename test/Ocelot.UnitTests/{ => DownstreamRouteFinder}/UrlMatcher/RegExUrlMatcherTests.cs (97%) rename test/Ocelot.UnitTests/{ => DownstreamRouteFinder}/UrlMatcher/TemplateVariableNameAndValueFinderTests.cs (97%) rename test/Ocelot.UnitTests/{Middleware => DownstreamUrlCreator}/DownstreamUrlCreatorMiddlewareTests.cs (83%) rename test/Ocelot.UnitTests/{ => DownstreamUrlCreator}/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs (95%) rename test/Ocelot.UnitTests/{RequestBuilder => HeaderBuilder}/AddHeadersToRequestTests.cs (97%) rename test/Ocelot.UnitTests/{RequestBuilder => HeaderBuilder}/ClaimParserTests.cs (96%) rename test/Ocelot.UnitTests/{Middleware => HeaderBuilder}/HttpRequestHeadersBuilderMiddlewareTests.cs (94%) rename test/Ocelot.UnitTests/{Middleware => RequestBuilder}/HttpRequestBuilderMiddlewareTests.cs (93%) rename test/Ocelot.UnitTests/{Middleware => Requester}/HttpRequesterMiddlewareTests.cs (93%) rename test/Ocelot.UnitTests/{Middleware => Responder}/HttpResponderMiddlewareTests.cs (94%) diff --git a/src/Ocelot.Library/Authentication/AuthenticationHandler.cs b/src/Ocelot.Library/Authentication/Handler/AuthenticationHandler.cs similarity index 79% rename from src/Ocelot.Library/Authentication/AuthenticationHandler.cs rename to src/Ocelot.Library/Authentication/Handler/AuthenticationHandler.cs index 8a2a505e..ccdf0a66 100644 --- a/src/Ocelot.Library/Authentication/AuthenticationHandler.cs +++ b/src/Ocelot.Library/Authentication/Handler/AuthenticationHandler.cs @@ -1,7 +1,7 @@ -namespace Ocelot.Library.Authentication -{ - using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http; +namespace Ocelot.Library.Authentication.Handler +{ public class AuthenticationHandler { public AuthenticationHandler(string provider, RequestDelegate handler) diff --git a/src/Ocelot.Library/Authentication/AuthenticationHandlerCreator.cs b/src/Ocelot.Library/Authentication/Handler/Creator/AuthenticationHandlerCreator.cs similarity index 84% rename from src/Ocelot.Library/Authentication/AuthenticationHandlerCreator.cs rename to src/Ocelot.Library/Authentication/Handler/Creator/AuthenticationHandlerCreator.cs index 34fedf38..1ff79b20 100644 --- a/src/Ocelot.Library/Authentication/AuthenticationHandlerCreator.cs +++ b/src/Ocelot.Library/Authentication/Handler/Creator/AuthenticationHandlerCreator.cs @@ -1,9 +1,10 @@ -namespace Ocelot.Library.Authentication +using IdentityServer4.AccessTokenValidation; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Ocelot.Library.Responses; + +namespace Ocelot.Library.Authentication.Handler.Creator { - using IdentityServer4.AccessTokenValidation; - using Microsoft.AspNetCore.Builder; - using Microsoft.AspNetCore.Http; - using Responses; using AuthenticationOptions = Configuration.AuthenticationOptions; /// diff --git a/src/Ocelot.Library/Authentication/IAuthenticationHandlerCreator.cs b/src/Ocelot.Library/Authentication/Handler/Creator/IAuthenticationHandlerCreator.cs similarity index 63% rename from src/Ocelot.Library/Authentication/IAuthenticationHandlerCreator.cs rename to src/Ocelot.Library/Authentication/Handler/Creator/IAuthenticationHandlerCreator.cs index 5789ecf6..7d3e64c1 100644 --- a/src/Ocelot.Library/Authentication/IAuthenticationHandlerCreator.cs +++ b/src/Ocelot.Library/Authentication/Handler/Creator/IAuthenticationHandlerCreator.cs @@ -1,8 +1,9 @@ -namespace Ocelot.Library.Authentication +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Ocelot.Library.Responses; + +namespace Ocelot.Library.Authentication.Handler.Creator { - using Microsoft.AspNetCore.Builder; - using Microsoft.AspNetCore.Http; - using Responses; using AuthenticationOptions = Configuration.AuthenticationOptions; public interface IAuthenticationHandlerCreator diff --git a/src/Ocelot.Library/Authentication/AuthenticationHandlerFactory.cs b/src/Ocelot.Library/Authentication/Handler/Factory/AuthenticationHandlerFactory.cs similarity index 80% rename from src/Ocelot.Library/Authentication/AuthenticationHandlerFactory.cs rename to src/Ocelot.Library/Authentication/Handler/Factory/AuthenticationHandlerFactory.cs index 109d750e..8ef9993c 100644 --- a/src/Ocelot.Library/Authentication/AuthenticationHandlerFactory.cs +++ b/src/Ocelot.Library/Authentication/Handler/Factory/AuthenticationHandlerFactory.cs @@ -1,9 +1,11 @@ -namespace Ocelot.Library.Authentication +using System.Collections.Generic; +using Microsoft.AspNetCore.Builder; +using Ocelot.Library.Authentication.Handler.Creator; +using Ocelot.Library.Errors; +using Ocelot.Library.Responses; + +namespace Ocelot.Library.Authentication.Handler.Factory { - using System.Collections.Generic; - using Errors; - using Microsoft.AspNetCore.Builder; - using Responses; using AuthenticationOptions = Configuration.AuthenticationOptions; public class AuthenticationHandlerFactory : IAuthenticationHandlerFactory diff --git a/src/Ocelot.Library/Authentication/IAuthenticationHandlerFactory.cs b/src/Ocelot.Library/Authentication/Handler/Factory/IAuthenticationHandlerFactory.cs similarity index 65% rename from src/Ocelot.Library/Authentication/IAuthenticationHandlerFactory.cs rename to src/Ocelot.Library/Authentication/Handler/Factory/IAuthenticationHandlerFactory.cs index ea583487..97b7d005 100644 --- a/src/Ocelot.Library/Authentication/IAuthenticationHandlerFactory.cs +++ b/src/Ocelot.Library/Authentication/Handler/Factory/IAuthenticationHandlerFactory.cs @@ -1,7 +1,8 @@ -namespace Ocelot.Library.Authentication +using Microsoft.AspNetCore.Builder; +using Ocelot.Library.Responses; + +namespace Ocelot.Library.Authentication.Handler.Factory { - using Microsoft.AspNetCore.Builder; - using Responses; using AuthenticationOptions = Configuration.AuthenticationOptions; public interface IAuthenticationHandlerFactory diff --git a/src/Ocelot.Library/Authentication/UnableToCreateAuthenticationHandlerError.cs b/src/Ocelot.Library/Authentication/Handler/Factory/UnableToCreateAuthenticationHandlerError.cs similarity index 74% rename from src/Ocelot.Library/Authentication/UnableToCreateAuthenticationHandlerError.cs rename to src/Ocelot.Library/Authentication/Handler/Factory/UnableToCreateAuthenticationHandlerError.cs index bcda8ef6..ba066955 100644 --- a/src/Ocelot.Library/Authentication/UnableToCreateAuthenticationHandlerError.cs +++ b/src/Ocelot.Library/Authentication/Handler/Factory/UnableToCreateAuthenticationHandlerError.cs @@ -1,7 +1,7 @@ -namespace Ocelot.Library.Authentication -{ - using Errors; +using Ocelot.Library.Errors; +namespace Ocelot.Library.Authentication.Handler.Factory +{ public class UnableToCreateAuthenticationHandlerError : Error { public UnableToCreateAuthenticationHandlerError(string message) diff --git a/src/Ocelot.Library/Authentication/Handler/SupportedAuthenticationProviders.cs b/src/Ocelot.Library/Authentication/Handler/SupportedAuthenticationProviders.cs new file mode 100644 index 00000000..c2d624fe --- /dev/null +++ b/src/Ocelot.Library/Authentication/Handler/SupportedAuthenticationProviders.cs @@ -0,0 +1,7 @@ +namespace Ocelot.Library.Authentication.Handler +{ + public enum SupportedAuthenticationProviders + { + IdentityServer + } +} diff --git a/src/Ocelot.Library/Middleware/AuthenticationMiddleware.cs b/src/Ocelot.Library/Authentication/Middleware/AuthenticationMiddleware.cs similarity index 84% rename from src/Ocelot.Library/Middleware/AuthenticationMiddleware.cs rename to src/Ocelot.Library/Authentication/Middleware/AuthenticationMiddleware.cs index 4042edca..7a74bd6a 100644 --- a/src/Ocelot.Library/Middleware/AuthenticationMiddleware.cs +++ b/src/Ocelot.Library/Authentication/Middleware/AuthenticationMiddleware.cs @@ -1,15 +1,16 @@ -namespace Ocelot.Library.Middleware -{ - using System.Collections.Generic; - using System.Threading.Tasks; - using Authentication; - using Configuration; - using DownstreamRouteFinder; - using Errors; - using Microsoft.AspNetCore.Builder; - using Microsoft.AspNetCore.Http; - using Repository; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Ocelot.Library.Authentication.Handler.Factory; +using Ocelot.Library.Configuration; +using Ocelot.Library.DownstreamRouteFinder; +using Ocelot.Library.Errors; +using Ocelot.Library.Middleware; +using Ocelot.Library.ScopedData; +namespace Ocelot.Library.Authentication.Middleware +{ public class AuthenticationMiddleware : OcelotMiddleware { private readonly RequestDelegate _next; diff --git a/src/Ocelot.Library/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs b/src/Ocelot.Library/Authentication/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs similarity index 76% rename from src/Ocelot.Library/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs rename to src/Ocelot.Library/Authentication/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs index 88b3a678..9083a1b2 100644 --- a/src/Ocelot.Library/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs +++ b/src/Ocelot.Library/Authentication/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs @@ -1,7 +1,7 @@ -namespace Ocelot.Library.Middleware -{ - using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Builder; +namespace Ocelot.Library.Authentication.Middleware +{ public static class AuthenticationMiddlewareMiddlewareExtensions { public static IApplicationBuilder UseAuthenticationMiddleware(this IApplicationBuilder builder) diff --git a/src/Ocelot.Library/Authentication/SupportAuthenticationProviders.cs b/src/Ocelot.Library/Authentication/SupportAuthenticationProviders.cs deleted file mode 100644 index e9eea91b..00000000 --- a/src/Ocelot.Library/Authentication/SupportAuthenticationProviders.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Ocelot.Library.Authentication -{ - public enum SupportAuthenticationProviders - { - IdentityServer - } -} diff --git a/src/Ocelot.Library/Configuration/Yaml/YamlOcelotConfigurationCreator.cs b/src/Ocelot.Library/Configuration/Creator/YamlOcelotConfigurationCreator.cs similarity index 97% rename from src/Ocelot.Library/Configuration/Yaml/YamlOcelotConfigurationCreator.cs rename to src/Ocelot.Library/Configuration/Creator/YamlOcelotConfigurationCreator.cs index 5d6179a0..433acc66 100644 --- a/src/Ocelot.Library/Configuration/Yaml/YamlOcelotConfigurationCreator.cs +++ b/src/Ocelot.Library/Configuration/Creator/YamlOcelotConfigurationCreator.cs @@ -2,13 +2,12 @@ using System; using System.Collections.Generic; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Ocelot.Library.Configuration.Creator; using Ocelot.Library.Configuration.Parser; -using Ocelot.Library.Configuration.Repository; -using Ocelot.Library.Errors; +using Ocelot.Library.Configuration.Validator; +using Ocelot.Library.Configuration.Yaml; using Ocelot.Library.Responses; -namespace Ocelot.Library.Configuration.Yaml +namespace Ocelot.Library.Configuration.Creator { /// /// Register as singleton diff --git a/src/Ocelot.Library/RequestBuilder/InstructionNotForClaimsError.cs b/src/Ocelot.Library/Configuration/Parser/InstructionNotForClaimsError.cs similarity index 87% rename from src/Ocelot.Library/RequestBuilder/InstructionNotForClaimsError.cs rename to src/Ocelot.Library/Configuration/Parser/InstructionNotForClaimsError.cs index 2802cfe5..651d9caa 100644 --- a/src/Ocelot.Library/RequestBuilder/InstructionNotForClaimsError.cs +++ b/src/Ocelot.Library/Configuration/Parser/InstructionNotForClaimsError.cs @@ -1,6 +1,6 @@ using Ocelot.Library.Errors; -namespace Ocelot.Library.RequestBuilder +namespace Ocelot.Library.Configuration.Parser { public class InstructionNotForClaimsError : Error { diff --git a/src/Ocelot.Library/RequestBuilder/NoInstructionsError.cs b/src/Ocelot.Library/Configuration/Parser/NoInstructionsError.cs similarity index 85% rename from src/Ocelot.Library/RequestBuilder/NoInstructionsError.cs rename to src/Ocelot.Library/Configuration/Parser/NoInstructionsError.cs index 9a2bc694..732603a3 100644 --- a/src/Ocelot.Library/RequestBuilder/NoInstructionsError.cs +++ b/src/Ocelot.Library/Configuration/Parser/NoInstructionsError.cs @@ -1,6 +1,6 @@ using Ocelot.Library.Errors; -namespace Ocelot.Library.RequestBuilder +namespace Ocelot.Library.Configuration.Parser { public class NoInstructionsError : Error { diff --git a/src/Ocelot.Library/RequestBuilder/ParsingConfigurationHeaderError.cs b/src/Ocelot.Library/Configuration/Parser/ParsingConfigurationHeaderError.cs similarity index 88% rename from src/Ocelot.Library/RequestBuilder/ParsingConfigurationHeaderError.cs rename to src/Ocelot.Library/Configuration/Parser/ParsingConfigurationHeaderError.cs index 1b8eaf54..0b7409bc 100644 --- a/src/Ocelot.Library/RequestBuilder/ParsingConfigurationHeaderError.cs +++ b/src/Ocelot.Library/Configuration/Parser/ParsingConfigurationHeaderError.cs @@ -1,7 +1,7 @@ using System; using Ocelot.Library.Errors; -namespace Ocelot.Library.RequestBuilder +namespace Ocelot.Library.Configuration.Parser { public class ParsingConfigurationHeaderError : Error { diff --git a/src/Ocelot.Library/Configuration/Yaml/YamlOcelotConfigurationProvider.cs b/src/Ocelot.Library/Configuration/Provider/YamlOcelotConfigurationProvider.cs similarity index 93% rename from src/Ocelot.Library/Configuration/Yaml/YamlOcelotConfigurationProvider.cs rename to src/Ocelot.Library/Configuration/Provider/YamlOcelotConfigurationProvider.cs index 534fe83c..bf3faab7 100644 --- a/src/Ocelot.Library/Configuration/Yaml/YamlOcelotConfigurationProvider.cs +++ b/src/Ocelot.Library/Configuration/Provider/YamlOcelotConfigurationProvider.cs @@ -1,9 +1,8 @@ using Ocelot.Library.Configuration.Creator; -using Ocelot.Library.Configuration.Provider; using Ocelot.Library.Configuration.Repository; using Ocelot.Library.Responses; -namespace Ocelot.Library.Configuration.Yaml +namespace Ocelot.Library.Configuration.Provider { /// /// Register as singleton diff --git a/src/Ocelot.Library/Configuration/Yaml/ConfigurationValidationResult.cs b/src/Ocelot.Library/Configuration/Validator/ConfigurationValidationResult.cs similarity index 80% rename from src/Ocelot.Library/Configuration/Yaml/ConfigurationValidationResult.cs rename to src/Ocelot.Library/Configuration/Validator/ConfigurationValidationResult.cs index 31b6e1dc..3e40a412 100644 --- a/src/Ocelot.Library/Configuration/Yaml/ConfigurationValidationResult.cs +++ b/src/Ocelot.Library/Configuration/Validator/ConfigurationValidationResult.cs @@ -1,8 +1,8 @@ -namespace Ocelot.Library.Configuration.Yaml -{ - using System.Collections.Generic; - using Errors; +using System.Collections.Generic; +using Ocelot.Library.Errors; +namespace Ocelot.Library.Configuration.Validator +{ public class ConfigurationValidationResult { public ConfigurationValidationResult(bool isError) diff --git a/src/Ocelot.Library/Configuration/Yaml/ConfigurationValidator.cs b/src/Ocelot.Library/Configuration/Validator/ConfigurationValidator.cs similarity index 88% rename from src/Ocelot.Library/Configuration/Yaml/ConfigurationValidator.cs rename to src/Ocelot.Library/Configuration/Validator/ConfigurationValidator.cs index 38964f30..60beb06f 100644 --- a/src/Ocelot.Library/Configuration/Yaml/ConfigurationValidator.cs +++ b/src/Ocelot.Library/Configuration/Validator/ConfigurationValidator.cs @@ -1,12 +1,14 @@ -namespace Ocelot.Library.Configuration.Yaml -{ - using System; - using System.Collections.Generic; - using System.Linq; - using Authentication; - using Errors; - using Responses; +using System; +using System.Collections.Generic; +using System.Linq; +using Ocelot.Library.Authentication; +using Ocelot.Library.Authentication.Handler; +using Ocelot.Library.Configuration.Yaml; +using Ocelot.Library.Errors; +using Ocelot.Library.Responses; +namespace Ocelot.Library.Configuration.Validator +{ public class ConfigurationValidator : IConfigurationValidator { public Response IsValid(YamlConfiguration configuration) @@ -57,7 +59,7 @@ private bool IsSupportedAuthenticationProvider(string provider) { - SupportAuthenticationProviders supportedProvider; + SupportedAuthenticationProviders supportedProvider; return Enum.TryParse(provider, true, out supportedProvider); } diff --git a/src/Ocelot.Library/Configuration/Yaml/DownstreamTemplateAlreadyUsedError.cs b/src/Ocelot.Library/Configuration/Validator/DownstreamTemplateAlreadyUsedError.cs similarity index 74% rename from src/Ocelot.Library/Configuration/Yaml/DownstreamTemplateAlreadyUsedError.cs rename to src/Ocelot.Library/Configuration/Validator/DownstreamTemplateAlreadyUsedError.cs index 0ee8b6c8..ff9a44fa 100644 --- a/src/Ocelot.Library/Configuration/Yaml/DownstreamTemplateAlreadyUsedError.cs +++ b/src/Ocelot.Library/Configuration/Validator/DownstreamTemplateAlreadyUsedError.cs @@ -1,7 +1,7 @@ -namespace Ocelot.Library.Configuration.Yaml -{ - using Errors; +using Ocelot.Library.Errors; +namespace Ocelot.Library.Configuration.Validator +{ public class DownstreamTemplateAlreadyUsedError : Error { public DownstreamTemplateAlreadyUsedError(string message) : base(message, OcelotErrorCode.DownstreamTemplateAlreadyUsedError) diff --git a/src/Ocelot.Library/Configuration/Yaml/IConfigurationValidator.cs b/src/Ocelot.Library/Configuration/Validator/IConfigurationValidator.cs similarity index 54% rename from src/Ocelot.Library/Configuration/Yaml/IConfigurationValidator.cs rename to src/Ocelot.Library/Configuration/Validator/IConfigurationValidator.cs index 38baf36b..ddb2831d 100644 --- a/src/Ocelot.Library/Configuration/Yaml/IConfigurationValidator.cs +++ b/src/Ocelot.Library/Configuration/Validator/IConfigurationValidator.cs @@ -1,7 +1,8 @@ -namespace Ocelot.Library.Configuration.Yaml -{ - using Responses; +using Ocelot.Library.Configuration.Yaml; +using Ocelot.Library.Responses; +namespace Ocelot.Library.Configuration.Validator +{ public interface IConfigurationValidator { Response IsValid(YamlConfiguration configuration); diff --git a/src/Ocelot.Library/Configuration/Yaml/UnsupportedAuthenticationProviderError.cs b/src/Ocelot.Library/Configuration/Validator/UnsupportedAuthenticationProviderError.cs similarity index 75% rename from src/Ocelot.Library/Configuration/Yaml/UnsupportedAuthenticationProviderError.cs rename to src/Ocelot.Library/Configuration/Validator/UnsupportedAuthenticationProviderError.cs index 9a589ca2..e963cb17 100644 --- a/src/Ocelot.Library/Configuration/Yaml/UnsupportedAuthenticationProviderError.cs +++ b/src/Ocelot.Library/Configuration/Validator/UnsupportedAuthenticationProviderError.cs @@ -1,7 +1,7 @@ -namespace Ocelot.Library.Configuration.Yaml -{ - using Errors; +using Ocelot.Library.Errors; +namespace Ocelot.Library.Configuration.Validator +{ public class UnsupportedAuthenticationProviderError : Error { public UnsupportedAuthenticationProviderError(string message) diff --git a/src/Ocelot.Library/DependencyInjection/ServiceCollectionExtensions.cs b/src/Ocelot.Library/DependencyInjection/ServiceCollectionExtensions.cs index 882163c1..1452923b 100644 --- a/src/Ocelot.Library/DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/Ocelot.Library/DependencyInjection/ServiceCollectionExtensions.cs @@ -1,7 +1,17 @@ -using Ocelot.Library.Configuration.Creator; +using Ocelot.Library.Authentication.Handler.Creator; +using Ocelot.Library.Authentication.Handler.Factory; +using Ocelot.Library.Configuration.Creator; using Ocelot.Library.Configuration.Parser; using Ocelot.Library.Configuration.Provider; using Ocelot.Library.Configuration.Repository; +using Ocelot.Library.Configuration.Validator; +using Ocelot.Library.DownstreamRouteFinder.Finder; +using Ocelot.Library.DownstreamRouteFinder.UrlMatcher; +using Ocelot.Library.DownstreamUrlCreator.UrlTemplateReplacer; +using Ocelot.Library.HeaderBuilder; +using Ocelot.Library.HeaderBuilder.Parser; +using Ocelot.Library.RequestBuilder.Builder; +using Ocelot.Library.ScopedData; namespace Ocelot.Library.DependencyInjection { @@ -12,12 +22,9 @@ namespace Ocelot.Library.DependencyInjection using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; - using Repository; using RequestBuilder; using Requester; using Responder; - using UrlMatcher; - using UrlTemplateReplacer; public static class ServiceCollectionExtensions { @@ -48,7 +55,7 @@ namespace Ocelot.Library.DependencyInjection services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/src/Ocelot.Library/DownstreamRouteFinder/DownstreamRoute.cs b/src/Ocelot.Library/DownstreamRouteFinder/DownstreamRoute.cs index ca80f270..7f7fcc61 100644 --- a/src/Ocelot.Library/DownstreamRouteFinder/DownstreamRoute.cs +++ b/src/Ocelot.Library/DownstreamRouteFinder/DownstreamRoute.cs @@ -1,8 +1,9 @@ -namespace Ocelot.Library.DownstreamRouteFinder +using Ocelot.Library.DownstreamRouteFinder.UrlMatcher; + +namespace Ocelot.Library.DownstreamRouteFinder { using System.Collections.Generic; using Configuration; - using UrlMatcher; public class DownstreamRoute { diff --git a/src/Ocelot.Library/DownstreamRouteFinder/DownstreamRouteFinder.cs b/src/Ocelot.Library/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs similarity index 94% rename from src/Ocelot.Library/DownstreamRouteFinder/DownstreamRouteFinder.cs rename to src/Ocelot.Library/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs index 542f7341..340ca4d7 100644 --- a/src/Ocelot.Library/DownstreamRouteFinder/DownstreamRouteFinder.cs +++ b/src/Ocelot.Library/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs @@ -2,11 +2,11 @@ using System.Collections.Generic; using System.Linq; using Ocelot.Library.Configuration.Provider; +using Ocelot.Library.DownstreamRouteFinder.UrlMatcher; using Ocelot.Library.Errors; using Ocelot.Library.Responses; -using Ocelot.Library.UrlMatcher; -namespace Ocelot.Library.DownstreamRouteFinder +namespace Ocelot.Library.DownstreamRouteFinder.Finder { public class DownstreamRouteFinder : IDownstreamRouteFinder { diff --git a/src/Ocelot.Library/DownstreamRouteFinder/IDownstreamRouteFinder.cs b/src/Ocelot.Library/DownstreamRouteFinder/Finder/IDownstreamRouteFinder.cs similarity index 65% rename from src/Ocelot.Library/DownstreamRouteFinder/IDownstreamRouteFinder.cs rename to src/Ocelot.Library/DownstreamRouteFinder/Finder/IDownstreamRouteFinder.cs index 41e2ffe6..3e0cafb4 100644 --- a/src/Ocelot.Library/DownstreamRouteFinder/IDownstreamRouteFinder.cs +++ b/src/Ocelot.Library/DownstreamRouteFinder/Finder/IDownstreamRouteFinder.cs @@ -1,7 +1,7 @@ -namespace Ocelot.Library.DownstreamRouteFinder -{ - using Responses; +using Ocelot.Library.Responses; +namespace Ocelot.Library.DownstreamRouteFinder.Finder +{ public interface IDownstreamRouteFinder { Response FindDownstreamRoute(string upstreamUrlPath, string upstreamHttpMethod); diff --git a/src/Ocelot.Library/DownstreamRouteFinder/UnableToFindDownstreamRouteError.cs b/src/Ocelot.Library/DownstreamRouteFinder/Finder/UnableToFindDownstreamRouteError.cs similarity index 73% rename from src/Ocelot.Library/DownstreamRouteFinder/UnableToFindDownstreamRouteError.cs rename to src/Ocelot.Library/DownstreamRouteFinder/Finder/UnableToFindDownstreamRouteError.cs index e8aacb7b..92595ea2 100644 --- a/src/Ocelot.Library/DownstreamRouteFinder/UnableToFindDownstreamRouteError.cs +++ b/src/Ocelot.Library/DownstreamRouteFinder/Finder/UnableToFindDownstreamRouteError.cs @@ -1,7 +1,7 @@ -namespace Ocelot.Library.DownstreamRouteFinder -{ - using Errors; +using Ocelot.Library.Errors; +namespace Ocelot.Library.DownstreamRouteFinder.Finder +{ public class UnableToFindDownstreamRouteError : Error { public UnableToFindDownstreamRouteError() : base("UnableToFindDownstreamRouteError", OcelotErrorCode.UnableToFindDownstreamRouteError) diff --git a/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddleware.cs b/src/Ocelot.Library/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddleware.cs similarity index 84% rename from src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddleware.cs rename to src/Ocelot.Library/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddleware.cs index f83e88ce..9dddc81a 100644 --- a/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddleware.cs +++ b/src/Ocelot.Library/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddleware.cs @@ -1,10 +1,11 @@ -namespace Ocelot.Library.Middleware -{ - using System.Threading.Tasks; - using DownstreamRouteFinder; - using Microsoft.AspNetCore.Http; - using Repository; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Ocelot.Library.DownstreamRouteFinder.Finder; +using Ocelot.Library.Middleware; +using Ocelot.Library.ScopedData; +namespace Ocelot.Library.DownstreamRouteFinder.Middleware +{ public class DownstreamRouteFinderMiddleware : OcelotMiddleware { private readonly RequestDelegate _next; diff --git a/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs b/src/Ocelot.Library/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs similarity index 75% rename from src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs rename to src/Ocelot.Library/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs index b288d789..e07cbcc5 100644 --- a/src/Ocelot.Library/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs +++ b/src/Ocelot.Library/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs @@ -1,7 +1,7 @@ -namespace Ocelot.Library.Middleware -{ - using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Builder; +namespace Ocelot.Library.DownstreamRouteFinder.Middleware +{ public static class DownstreamRouteFinderMiddlewareExtensions { public static IApplicationBuilder UseDownstreamRouteFinderMiddleware(this IApplicationBuilder builder) diff --git a/src/Ocelot.Library/UrlMatcher/ITemplateVariableNameAndValueFinder.cs b/src/Ocelot.Library/DownstreamRouteFinder/UrlMatcher/ITemplateVariableNameAndValueFinder.cs similarity index 59% rename from src/Ocelot.Library/UrlMatcher/ITemplateVariableNameAndValueFinder.cs rename to src/Ocelot.Library/DownstreamRouteFinder/UrlMatcher/ITemplateVariableNameAndValueFinder.cs index ff8bb862..31136199 100644 --- a/src/Ocelot.Library/UrlMatcher/ITemplateVariableNameAndValueFinder.cs +++ b/src/Ocelot.Library/DownstreamRouteFinder/UrlMatcher/ITemplateVariableNameAndValueFinder.cs @@ -1,8 +1,8 @@ -namespace Ocelot.Library.UrlMatcher -{ - using System.Collections.Generic; - using Responses; +using System.Collections.Generic; +using Ocelot.Library.Responses; +namespace Ocelot.Library.DownstreamRouteFinder.UrlMatcher +{ public interface ITemplateVariableNameAndValueFinder { Response> Find(string upstreamUrlPath, string upstreamUrlPathTemplate); diff --git a/src/Ocelot.Library/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs b/src/Ocelot.Library/DownstreamRouteFinder/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs similarity index 63% rename from src/Ocelot.Library/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs rename to src/Ocelot.Library/DownstreamRouteFinder/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs index 996df64c..86af26bb 100644 --- a/src/Ocelot.Library/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs +++ b/src/Ocelot.Library/DownstreamRouteFinder/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs @@ -1,7 +1,7 @@ -namespace Ocelot.Library.UrlMatcher -{ - using Responses; +using Ocelot.Library.Responses; +namespace Ocelot.Library.DownstreamRouteFinder.UrlMatcher +{ public interface IUrlPathToUrlTemplateMatcher { Response Match(string upstreamUrlPath, string upstreamUrlPathTemplate); diff --git a/src/Ocelot.Library/UrlMatcher/RegExUrlMatcher.cs b/src/Ocelot.Library/DownstreamRouteFinder/UrlMatcher/RegExUrlMatcher.cs similarity index 76% rename from src/Ocelot.Library/UrlMatcher/RegExUrlMatcher.cs rename to src/Ocelot.Library/DownstreamRouteFinder/UrlMatcher/RegExUrlMatcher.cs index cfcd209d..0005c81a 100644 --- a/src/Ocelot.Library/UrlMatcher/RegExUrlMatcher.cs +++ b/src/Ocelot.Library/DownstreamRouteFinder/UrlMatcher/RegExUrlMatcher.cs @@ -1,8 +1,8 @@ -namespace Ocelot.Library.UrlMatcher -{ - using System.Text.RegularExpressions; - using Responses; +using System.Text.RegularExpressions; +using Ocelot.Library.Responses; +namespace Ocelot.Library.DownstreamRouteFinder.UrlMatcher +{ public class RegExUrlMatcher : IUrlPathToUrlTemplateMatcher { public Response Match(string upstreamUrlPath, string upstreamUrlPathTemplate) diff --git a/src/Ocelot.Library/UrlMatcher/TemplateVariableNameAndValue.cs b/src/Ocelot.Library/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValue.cs similarity index 87% rename from src/Ocelot.Library/UrlMatcher/TemplateVariableNameAndValue.cs rename to src/Ocelot.Library/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValue.cs index ba81b4fd..c2283720 100644 --- a/src/Ocelot.Library/UrlMatcher/TemplateVariableNameAndValue.cs +++ b/src/Ocelot.Library/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValue.cs @@ -1,4 +1,4 @@ -namespace Ocelot.Library.UrlMatcher +namespace Ocelot.Library.DownstreamRouteFinder.UrlMatcher { public class TemplateVariableNameAndValue { diff --git a/src/Ocelot.Library/UrlMatcher/TemplateVariableNameAndValueFinder.cs b/src/Ocelot.Library/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValueFinder.cs similarity index 96% rename from src/Ocelot.Library/UrlMatcher/TemplateVariableNameAndValueFinder.cs rename to src/Ocelot.Library/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValueFinder.cs index 34f66095..cffada4c 100644 --- a/src/Ocelot.Library/UrlMatcher/TemplateVariableNameAndValueFinder.cs +++ b/src/Ocelot.Library/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValueFinder.cs @@ -1,8 +1,8 @@ -namespace Ocelot.Library.UrlMatcher -{ - using System.Collections.Generic; - using Responses; +using System.Collections.Generic; +using Ocelot.Library.Responses; +namespace Ocelot.Library.DownstreamRouteFinder.UrlMatcher +{ public class TemplateVariableNameAndValueFinder : ITemplateVariableNameAndValueFinder { public Response> Find(string upstreamUrlPath, string upstreamUrlPathTemplate) diff --git a/src/Ocelot.Library/UrlMatcher/UrlMatch.cs b/src/Ocelot.Library/DownstreamRouteFinder/UrlMatcher/UrlMatch.cs similarity index 74% rename from src/Ocelot.Library/UrlMatcher/UrlMatch.cs rename to src/Ocelot.Library/DownstreamRouteFinder/UrlMatcher/UrlMatch.cs index 123b5091..55ebb807 100644 --- a/src/Ocelot.Library/UrlMatcher/UrlMatch.cs +++ b/src/Ocelot.Library/DownstreamRouteFinder/UrlMatcher/UrlMatch.cs @@ -1,4 +1,4 @@ -namespace Ocelot.Library.UrlMatcher +namespace Ocelot.Library.DownstreamRouteFinder.UrlMatcher { public class UrlMatch { diff --git a/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddleware.cs b/src/Ocelot.Library/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs similarity index 82% rename from src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddleware.cs rename to src/Ocelot.Library/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs index 64ca55cc..604c9132 100644 --- a/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddleware.cs +++ b/src/Ocelot.Library/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs @@ -1,11 +1,12 @@ -namespace Ocelot.Library.Middleware -{ - using System.Threading.Tasks; - using DownstreamRouteFinder; - using Microsoft.AspNetCore.Http; - using Repository; - using UrlTemplateReplacer; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Ocelot.Library.DownstreamRouteFinder; +using Ocelot.Library.DownstreamUrlCreator.UrlTemplateReplacer; +using Ocelot.Library.Middleware; +using Ocelot.Library.ScopedData; +namespace Ocelot.Library.DownstreamUrlCreator.Middleware +{ public class DownstreamUrlCreatorMiddleware : OcelotMiddleware { private readonly RequestDelegate _next; diff --git a/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs b/src/Ocelot.Library/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs similarity index 75% rename from src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs rename to src/Ocelot.Library/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs index 19839eb2..63d847d2 100644 --- a/src/Ocelot.Library/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs +++ b/src/Ocelot.Library/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs @@ -1,7 +1,7 @@ -namespace Ocelot.Library.Middleware -{ - using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Builder; +namespace Ocelot.Library.DownstreamUrlCreator.Middleware +{ public static class DownstreamUrlCreatorMiddlewareExtensions { public static IApplicationBuilder UseDownstreamUrlCreatorMiddleware(this IApplicationBuilder builder) diff --git a/src/Ocelot.Library/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs b/src/Ocelot.Library/DownstreamUrlCreator/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs similarity index 80% rename from src/Ocelot.Library/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs rename to src/Ocelot.Library/DownstreamUrlCreator/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs index 94f1ab24..b8ff44d9 100644 --- a/src/Ocelot.Library/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs +++ b/src/Ocelot.Library/DownstreamUrlCreator/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs @@ -1,9 +1,9 @@ -namespace Ocelot.Library.UrlTemplateReplacer -{ - using System.Text; - using DownstreamRouteFinder; - using Responses; +using System.Text; +using Ocelot.Library.DownstreamRouteFinder; +using Ocelot.Library.Responses; +namespace Ocelot.Library.DownstreamUrlCreator.UrlTemplateReplacer +{ public class DownstreamUrlTemplateVariableReplacer : IDownstreamUrlTemplateVariableReplacer { public Response ReplaceTemplateVariables(DownstreamRoute downstreamRoute) diff --git a/src/Ocelot.Library/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs b/src/Ocelot.Library/DownstreamUrlCreator/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs similarity index 53% rename from src/Ocelot.Library/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs rename to src/Ocelot.Library/DownstreamUrlCreator/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs index 31c50726..ba92174a 100644 --- a/src/Ocelot.Library/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs +++ b/src/Ocelot.Library/DownstreamUrlCreator/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs @@ -1,8 +1,8 @@ -namespace Ocelot.Library.UrlTemplateReplacer -{ - using DownstreamRouteFinder; - using Responses; +using Ocelot.Library.DownstreamRouteFinder; +using Ocelot.Library.Responses; +namespace Ocelot.Library.DownstreamUrlCreator.UrlTemplateReplacer +{ public interface IDownstreamUrlTemplateVariableReplacer { Response ReplaceTemplateVariables(DownstreamRoute downstreamRoute); diff --git a/src/Ocelot.Library/RequestBuilder/AddHeadersToRequest.cs b/src/Ocelot.Library/HeaderBuilder/AddHeadersToRequest.cs similarity index 94% rename from src/Ocelot.Library/RequestBuilder/AddHeadersToRequest.cs rename to src/Ocelot.Library/HeaderBuilder/AddHeadersToRequest.cs index 88823097..6c2634fa 100644 --- a/src/Ocelot.Library/RequestBuilder/AddHeadersToRequest.cs +++ b/src/Ocelot.Library/HeaderBuilder/AddHeadersToRequest.cs @@ -3,9 +3,10 @@ using System.Linq; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; using Ocelot.Library.Configuration; +using Ocelot.Library.HeaderBuilder.Parser; using Ocelot.Library.Responses; -namespace Ocelot.Library.RequestBuilder +namespace Ocelot.Library.HeaderBuilder { public class AddHeadersToRequest : IAddHeadersToRequest { diff --git a/src/Ocelot.Library/RequestBuilder/IAddHeadersToRequest.cs b/src/Ocelot.Library/HeaderBuilder/IAddHeadersToRequest.cs similarity index 89% rename from src/Ocelot.Library/RequestBuilder/IAddHeadersToRequest.cs rename to src/Ocelot.Library/HeaderBuilder/IAddHeadersToRequest.cs index d1e96506..c958f199 100644 --- a/src/Ocelot.Library/RequestBuilder/IAddHeadersToRequest.cs +++ b/src/Ocelot.Library/HeaderBuilder/IAddHeadersToRequest.cs @@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Http; using Ocelot.Library.Configuration; using Ocelot.Library.Responses; -namespace Ocelot.Library.RequestBuilder +namespace Ocelot.Library.HeaderBuilder { public interface IAddHeadersToRequest { diff --git a/src/Ocelot.Library/Middleware/HttpRequestHeadersBuilderMiddleware.cs b/src/Ocelot.Library/HeaderBuilder/Middleware/HttpRequestHeadersBuilderMiddleware.cs similarity index 82% rename from src/Ocelot.Library/Middleware/HttpRequestHeadersBuilderMiddleware.cs rename to src/Ocelot.Library/HeaderBuilder/Middleware/HttpRequestHeadersBuilderMiddleware.cs index 562f898b..001a424b 100644 --- a/src/Ocelot.Library/Middleware/HttpRequestHeadersBuilderMiddleware.cs +++ b/src/Ocelot.Library/HeaderBuilder/Middleware/HttpRequestHeadersBuilderMiddleware.cs @@ -1,15 +1,12 @@ -using System.Collections.Generic; -using System.Linq; -using Microsoft.Extensions.Primitives; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; using Ocelot.Library.DownstreamRouteFinder; -using Ocelot.Library.RequestBuilder; +using Ocelot.Library.Middleware; +using Ocelot.Library.ScopedData; -namespace Ocelot.Library.Middleware +namespace Ocelot.Library.HeaderBuilder.Middleware { - using System.Threading.Tasks; - using Microsoft.AspNetCore.Http; - using Repository; - public class HttpRequestHeadersBuilderMiddleware : OcelotMiddleware { private readonly RequestDelegate _next; diff --git a/src/Ocelot.Library/Middleware/HttpRequestHeadersBuilderMiddlewareExtensions.cs b/src/Ocelot.Library/HeaderBuilder/Middleware/HttpRequestHeadersBuilderMiddlewareExtensions.cs similarity index 77% rename from src/Ocelot.Library/Middleware/HttpRequestHeadersBuilderMiddlewareExtensions.cs rename to src/Ocelot.Library/HeaderBuilder/Middleware/HttpRequestHeadersBuilderMiddlewareExtensions.cs index d657add1..acb1cd28 100644 --- a/src/Ocelot.Library/Middleware/HttpRequestHeadersBuilderMiddlewareExtensions.cs +++ b/src/Ocelot.Library/HeaderBuilder/Middleware/HttpRequestHeadersBuilderMiddlewareExtensions.cs @@ -1,7 +1,7 @@ -namespace Ocelot.Library.Middleware -{ - using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Builder; +namespace Ocelot.Library.HeaderBuilder.Middleware +{ public static class HttpRequestHeadersBuilderMiddlewareExtensions { public static IApplicationBuilder UseHttpRequestHeadersBuilderMiddleware(this IApplicationBuilder builder) diff --git a/src/Ocelot.Library/RequestBuilder/CannotFindClaimError.cs b/src/Ocelot.Library/HeaderBuilder/Parser/CannotFindClaimError.cs similarity index 83% rename from src/Ocelot.Library/RequestBuilder/CannotFindClaimError.cs rename to src/Ocelot.Library/HeaderBuilder/Parser/CannotFindClaimError.cs index 0c9e3dac..f3270269 100644 --- a/src/Ocelot.Library/RequestBuilder/CannotFindClaimError.cs +++ b/src/Ocelot.Library/HeaderBuilder/Parser/CannotFindClaimError.cs @@ -1,6 +1,6 @@ using Ocelot.Library.Errors; -namespace Ocelot.Library.RequestBuilder +namespace Ocelot.Library.HeaderBuilder.Parser { public class CannotFindClaimError : Error { diff --git a/src/Ocelot.Library/RequestBuilder/ClaimsParser.cs b/src/Ocelot.Library/HeaderBuilder/Parser/ClaimsParser.cs similarity index 97% rename from src/Ocelot.Library/RequestBuilder/ClaimsParser.cs rename to src/Ocelot.Library/HeaderBuilder/Parser/ClaimsParser.cs index 504950e7..5ef6eab6 100644 --- a/src/Ocelot.Library/RequestBuilder/ClaimsParser.cs +++ b/src/Ocelot.Library/HeaderBuilder/Parser/ClaimsParser.cs @@ -4,7 +4,7 @@ using System.Security.Claims; using Ocelot.Library.Errors; using Ocelot.Library.Responses; -namespace Ocelot.Library.RequestBuilder +namespace Ocelot.Library.HeaderBuilder.Parser { public class ClaimsParser : IClaimsParser { diff --git a/src/Ocelot.Library/RequestBuilder/IClaimsParser.cs b/src/Ocelot.Library/HeaderBuilder/Parser/IClaimsParser.cs similarity index 84% rename from src/Ocelot.Library/RequestBuilder/IClaimsParser.cs rename to src/Ocelot.Library/HeaderBuilder/Parser/IClaimsParser.cs index c3cdd962..7f662d59 100644 --- a/src/Ocelot.Library/RequestBuilder/IClaimsParser.cs +++ b/src/Ocelot.Library/HeaderBuilder/Parser/IClaimsParser.cs @@ -2,7 +2,7 @@ using System.Security.Claims; using Ocelot.Library.Responses; -namespace Ocelot.Library.RequestBuilder +namespace Ocelot.Library.HeaderBuilder.Parser { public interface IClaimsParser { diff --git a/src/Ocelot.Library/Middleware/OcelotMiddleware.cs b/src/Ocelot.Library/Middleware/OcelotMiddleware.cs index 857d8369..eeccc65e 100644 --- a/src/Ocelot.Library/Middleware/OcelotMiddleware.cs +++ b/src/Ocelot.Library/Middleware/OcelotMiddleware.cs @@ -1,8 +1,9 @@ -namespace Ocelot.Library.Middleware +using Ocelot.Library.ScopedData; + +namespace Ocelot.Library.Middleware { using System.Collections.Generic; using Errors; - using Repository; public abstract class OcelotMiddleware { diff --git a/src/Ocelot.Library/Middleware/OcelotMiddlewareExtensions.cs b/src/Ocelot.Library/Middleware/OcelotMiddlewareExtensions.cs index e1c0ffe6..3fb320bd 100644 --- a/src/Ocelot.Library/Middleware/OcelotMiddlewareExtensions.cs +++ b/src/Ocelot.Library/Middleware/OcelotMiddlewareExtensions.cs @@ -1,4 +1,12 @@ -namespace Ocelot.Library.Middleware +using Ocelot.Library.Authentication.Middleware; +using Ocelot.Library.DownstreamRouteFinder.Middleware; +using Ocelot.Library.DownstreamUrlCreator.Middleware; +using Ocelot.Library.HeaderBuilder.Middleware; +using Ocelot.Library.RequestBuilder.Middleware; +using Ocelot.Library.Requester.Middleware; +using Ocelot.Library.Responder.Middleware; + +namespace Ocelot.Library.Middleware { using Microsoft.AspNetCore.Builder; diff --git a/src/Ocelot.Library/RequestBuilder/HttpRequestBuilder.cs b/src/Ocelot.Library/RequestBuilder/Builder/HttpRequestBuilder.cs similarity index 88% rename from src/Ocelot.Library/RequestBuilder/HttpRequestBuilder.cs rename to src/Ocelot.Library/RequestBuilder/Builder/HttpRequestBuilder.cs index d12fec2f..b1846e6e 100644 --- a/src/Ocelot.Library/RequestBuilder/HttpRequestBuilder.cs +++ b/src/Ocelot.Library/RequestBuilder/Builder/HttpRequestBuilder.cs @@ -1,14 +1,14 @@ -namespace Ocelot.Library.RequestBuilder -{ - using System; - using System.IO; - using System.Net; - using System.Net.Http; - using System.Net.Http.Headers; - using System.Threading.Tasks; - using Microsoft.AspNetCore.Http; - using Responses; +using System; +using System.IO; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Ocelot.Library.Responses; +namespace Ocelot.Library.RequestBuilder.Builder +{ public class HttpRequestBuilder : IRequestBuilder { public async Task> Build(string httpMethod, string downstreamUrl, Stream content, IHeaderDictionary headers, diff --git a/src/Ocelot.Library/RequestBuilder/IRequestBuilder.cs b/src/Ocelot.Library/RequestBuilder/Builder/IRequestBuilder.cs similarity index 66% rename from src/Ocelot.Library/RequestBuilder/IRequestBuilder.cs rename to src/Ocelot.Library/RequestBuilder/Builder/IRequestBuilder.cs index 353d438a..a2c51eb5 100644 --- a/src/Ocelot.Library/RequestBuilder/IRequestBuilder.cs +++ b/src/Ocelot.Library/RequestBuilder/Builder/IRequestBuilder.cs @@ -1,10 +1,10 @@ -namespace Ocelot.Library.RequestBuilder -{ - using System.IO; - using System.Threading.Tasks; - using Microsoft.AspNetCore.Http; - using Responses; +using System.IO; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Ocelot.Library.Responses; +namespace Ocelot.Library.RequestBuilder.Builder +{ public interface IRequestBuilder { Task> Build(string httpMethod, diff --git a/src/Ocelot.Library/Middleware/HttpRequestBuilderMiddleware.cs b/src/Ocelot.Library/RequestBuilder/Middleware/HttpRequestBuilderMiddleware.cs similarity index 86% rename from src/Ocelot.Library/Middleware/HttpRequestBuilderMiddleware.cs rename to src/Ocelot.Library/RequestBuilder/Middleware/HttpRequestBuilderMiddleware.cs index f60f72d9..3d3be229 100644 --- a/src/Ocelot.Library/Middleware/HttpRequestBuilderMiddleware.cs +++ b/src/Ocelot.Library/RequestBuilder/Middleware/HttpRequestBuilderMiddleware.cs @@ -1,10 +1,11 @@ -namespace Ocelot.Library.Middleware -{ - using System.Threading.Tasks; - using Microsoft.AspNetCore.Http; - using Repository; - using RequestBuilder; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Ocelot.Library.Middleware; +using Ocelot.Library.RequestBuilder.Builder; +using Ocelot.Library.ScopedData; +namespace Ocelot.Library.RequestBuilder.Middleware +{ public class HttpRequestBuilderMiddleware : OcelotMiddleware { private readonly RequestDelegate _next; diff --git a/src/Ocelot.Library/Middleware/HttpRequestBuilderMiddlewareExtensions.cs b/src/Ocelot.Library/RequestBuilder/Middleware/HttpRequestBuilderMiddlewareExtensions.cs similarity index 76% rename from src/Ocelot.Library/Middleware/HttpRequestBuilderMiddlewareExtensions.cs rename to src/Ocelot.Library/RequestBuilder/Middleware/HttpRequestBuilderMiddlewareExtensions.cs index 54877b09..b82d437e 100644 --- a/src/Ocelot.Library/Middleware/HttpRequestBuilderMiddlewareExtensions.cs +++ b/src/Ocelot.Library/RequestBuilder/Middleware/HttpRequestBuilderMiddlewareExtensions.cs @@ -1,7 +1,7 @@ -namespace Ocelot.Library.Middleware -{ - using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Builder; +namespace Ocelot.Library.RequestBuilder.Middleware +{ public static class HttpRequestBuilderMiddlewareExtensions { public static IApplicationBuilder UseHttpRequestBuilderMiddleware(this IApplicationBuilder builder) diff --git a/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs b/src/Ocelot.Library/Requester/Middleware/HttpRequesterMiddleware.cs similarity index 85% rename from src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs rename to src/Ocelot.Library/Requester/Middleware/HttpRequesterMiddleware.cs index f9aac74b..b24995f4 100644 --- a/src/Ocelot.Library/Middleware/HttpRequesterMiddleware.cs +++ b/src/Ocelot.Library/Requester/Middleware/HttpRequesterMiddleware.cs @@ -1,11 +1,11 @@ -namespace Ocelot.Library.Middleware -{ - using System.Threading.Tasks; - using Microsoft.AspNetCore.Http; - using Repository; - using RequestBuilder; - using Requester; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Ocelot.Library.Middleware; +using Ocelot.Library.RequestBuilder; +using Ocelot.Library.ScopedData; +namespace Ocelot.Library.Requester.Middleware +{ public class HttpRequesterMiddleware : OcelotMiddleware { private readonly RequestDelegate _next; diff --git a/src/Ocelot.Library/Middleware/HttpRequesterMiddlewareExtensions.cs b/src/Ocelot.Library/Requester/Middleware/HttpRequesterMiddlewareExtensions.cs similarity index 76% rename from src/Ocelot.Library/Middleware/HttpRequesterMiddlewareExtensions.cs rename to src/Ocelot.Library/Requester/Middleware/HttpRequesterMiddlewareExtensions.cs index 5ad921f2..73af0cd2 100644 --- a/src/Ocelot.Library/Middleware/HttpRequesterMiddlewareExtensions.cs +++ b/src/Ocelot.Library/Requester/Middleware/HttpRequesterMiddlewareExtensions.cs @@ -1,7 +1,7 @@ -namespace Ocelot.Library.Middleware -{ - using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Builder; +namespace Ocelot.Library.Requester.Middleware +{ public static class HttpRequesterMiddlewareExtensions { public static IApplicationBuilder UseHttpRequesterMiddleware(this IApplicationBuilder builder) diff --git a/src/Ocelot.Library/Middleware/HttpResponderMiddleware.cs b/src/Ocelot.Library/Responder/Middleware/HttpResponderMiddleware.cs similarity index 89% rename from src/Ocelot.Library/Middleware/HttpResponderMiddleware.cs rename to src/Ocelot.Library/Responder/Middleware/HttpResponderMiddleware.cs index 7d40e5e6..b822d6b7 100644 --- a/src/Ocelot.Library/Middleware/HttpResponderMiddleware.cs +++ b/src/Ocelot.Library/Responder/Middleware/HttpResponderMiddleware.cs @@ -1,11 +1,11 @@ -namespace Ocelot.Library.Middleware -{ - using System.Net.Http; - using System.Threading.Tasks; - using Microsoft.AspNetCore.Http; - using Repository; - using Responder; +using System.Net.Http; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Ocelot.Library.Middleware; +using Ocelot.Library.ScopedData; +namespace Ocelot.Library.Responder.Middleware +{ public class HttpResponderMiddleware : OcelotMiddleware { private readonly RequestDelegate _next; diff --git a/src/Ocelot.Library/Middleware/HttpResponderMiddlewareExtensions.cs b/src/Ocelot.Library/Responder/Middleware/HttpResponderMiddlewareExtensions.cs similarity index 76% rename from src/Ocelot.Library/Middleware/HttpResponderMiddlewareExtensions.cs rename to src/Ocelot.Library/Responder/Middleware/HttpResponderMiddlewareExtensions.cs index 04640d51..7ef7db83 100644 --- a/src/Ocelot.Library/Middleware/HttpResponderMiddlewareExtensions.cs +++ b/src/Ocelot.Library/Responder/Middleware/HttpResponderMiddlewareExtensions.cs @@ -1,7 +1,7 @@ -namespace Ocelot.Library.Middleware -{ - using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Builder; +namespace Ocelot.Library.Responder.Middleware +{ public static class HttpResponderMiddlewareExtensions { public static IApplicationBuilder UseHttpResponderMiddleware(this IApplicationBuilder builder) diff --git a/src/Ocelot.Library/Repository/CannotAddDataError.cs b/src/Ocelot.Library/ScopedData/CannotAddDataError.cs similarity index 72% rename from src/Ocelot.Library/Repository/CannotAddDataError.cs rename to src/Ocelot.Library/ScopedData/CannotAddDataError.cs index f3bd42de..bcdd5c28 100644 --- a/src/Ocelot.Library/Repository/CannotAddDataError.cs +++ b/src/Ocelot.Library/ScopedData/CannotAddDataError.cs @@ -1,7 +1,7 @@ -namespace Ocelot.Library.Repository -{ - using Errors; +using Ocelot.Library.Errors; +namespace Ocelot.Library.ScopedData +{ public class CannotAddDataError : Error { public CannotAddDataError(string message) : base(message, OcelotErrorCode.CannotAddDataError) diff --git a/src/Ocelot.Library/Repository/CannotFindDataError.cs b/src/Ocelot.Library/ScopedData/CannotFindDataError.cs similarity index 73% rename from src/Ocelot.Library/Repository/CannotFindDataError.cs rename to src/Ocelot.Library/ScopedData/CannotFindDataError.cs index b61069b5..9daedcd4 100644 --- a/src/Ocelot.Library/Repository/CannotFindDataError.cs +++ b/src/Ocelot.Library/ScopedData/CannotFindDataError.cs @@ -1,7 +1,7 @@ -namespace Ocelot.Library.Repository -{ - using Errors; +using Ocelot.Library.Errors; +namespace Ocelot.Library.ScopedData +{ public class CannotFindDataError : Error { public CannotFindDataError(string message) : base(message, OcelotErrorCode.CannotFindDataError) diff --git a/src/Ocelot.Library/Repository/IScopedRequestDataRepository.cs b/src/Ocelot.Library/ScopedData/IScopedRequestDataRepository.cs similarity index 69% rename from src/Ocelot.Library/Repository/IScopedRequestDataRepository.cs rename to src/Ocelot.Library/ScopedData/IScopedRequestDataRepository.cs index f8e37133..852a6121 100644 --- a/src/Ocelot.Library/Repository/IScopedRequestDataRepository.cs +++ b/src/Ocelot.Library/ScopedData/IScopedRequestDataRepository.cs @@ -1,7 +1,7 @@ -namespace Ocelot.Library.Repository -{ - using Responses; +using Ocelot.Library.Responses; +namespace Ocelot.Library.ScopedData +{ public interface IScopedRequestDataRepository { Response Add(string key, T value); diff --git a/src/Ocelot.Library/Repository/ScopedRequestDataRepository.cs b/src/Ocelot.Library/ScopedData/ScopedRequestDataRepository.cs similarity index 87% rename from src/Ocelot.Library/Repository/ScopedRequestDataRepository.cs rename to src/Ocelot.Library/ScopedData/ScopedRequestDataRepository.cs index b242617e..928e1ebb 100644 --- a/src/Ocelot.Library/Repository/ScopedRequestDataRepository.cs +++ b/src/Ocelot.Library/ScopedData/ScopedRequestDataRepository.cs @@ -1,11 +1,11 @@ -namespace Ocelot.Library.Repository -{ - using System; - using System.Collections.Generic; - using Errors; - using Microsoft.AspNetCore.Http; - using Responses; +using System; +using System.Collections.Generic; +using Microsoft.AspNetCore.Http; +using Ocelot.Library.Errors; +using Ocelot.Library.Responses; +namespace Ocelot.Library.ScopedData +{ public class ScopedRequestDataRepository : IScopedRequestDataRepository { private readonly IHttpContextAccessor _httpContextAccessor; diff --git a/test/Ocelot.UnitTests/Authentication/AuthenticationHandlerFactoryTests.cs b/test/Ocelot.UnitTests/Authentication/AuthenticationHandlerFactoryTests.cs index fb6311c6..483857c8 100644 --- a/test/Ocelot.UnitTests/Authentication/AuthenticationHandlerFactoryTests.cs +++ b/test/Ocelot.UnitTests/Authentication/AuthenticationHandlerFactoryTests.cs @@ -3,6 +3,9 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Moq; +using Ocelot.Library.Authentication.Handler; +using Ocelot.Library.Authentication.Handler.Creator; +using Ocelot.Library.Authentication.Handler.Factory; using Shouldly; using TestStack.BDDfy; using Xunit; diff --git a/test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs b/test/Ocelot.UnitTests/Authentication/AuthenticationMiddlewareTests.cs similarity index 89% rename from test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs rename to test/Ocelot.UnitTests/Authentication/AuthenticationMiddlewareTests.cs index eebccfa3..89b84a1e 100644 --- a/test/Ocelot.UnitTests/Middleware/AuthenticationMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Authentication/AuthenticationMiddlewareTests.cs @@ -6,19 +6,18 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Moq; +using Ocelot.Library.Authentication.Handler.Factory; +using Ocelot.Library.Authentication.Middleware; using Ocelot.Library.Configuration.Builder; +using Ocelot.Library.DownstreamRouteFinder; +using Ocelot.Library.DownstreamRouteFinder.UrlMatcher; +using Ocelot.Library.Responses; +using Ocelot.Library.ScopedData; using TestStack.BDDfy; using Xunit; -namespace Ocelot.UnitTests.Middleware +namespace Ocelot.UnitTests.Authentication { - using Library.Authentication; - using Library.DownstreamRouteFinder; - using Library.Middleware; - using Library.Repository; - using Library.Responses; - using Library.UrlMatcher; - public class AuthenticationMiddlewareTests : IDisposable { private readonly Mock _scopedRepository; diff --git a/test/Ocelot.UnitTests/RequestBuilder/ConfigurationHeadersExtractorTests.cs b/test/Ocelot.UnitTests/Configuration/ConfigurationHeadersExtractorTests.cs similarity index 98% rename from test/Ocelot.UnitTests/RequestBuilder/ConfigurationHeadersExtractorTests.cs rename to test/Ocelot.UnitTests/Configuration/ConfigurationHeadersExtractorTests.cs index d61daaa7..29f674be 100644 --- a/test/Ocelot.UnitTests/RequestBuilder/ConfigurationHeadersExtractorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/ConfigurationHeadersExtractorTests.cs @@ -3,13 +3,12 @@ using System.Linq; using Ocelot.Library.Configuration; using Ocelot.Library.Configuration.Parser; using Ocelot.Library.Errors; -using Ocelot.Library.RequestBuilder; using Ocelot.Library.Responses; using Shouldly; using TestStack.BDDfy; using Xunit; -namespace Ocelot.UnitTests.RequestBuilder +namespace Ocelot.UnitTests.Configuration { public class ConfigurationHeadersExtractorTests { diff --git a/test/Ocelot.UnitTests/Configuration/ConfigurationValidationTests.cs b/test/Ocelot.UnitTests/Configuration/ConfigurationValidationTests.cs index a9650451..a9395a93 100644 --- a/test/Ocelot.UnitTests/Configuration/ConfigurationValidationTests.cs +++ b/test/Ocelot.UnitTests/Configuration/ConfigurationValidationTests.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Ocelot.Library.Configuration.Validator; using Shouldly; using TestStack.BDDfy; using Xunit; diff --git a/test/Ocelot.UnitTests/Configuration/YamlConfigurationCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/YamlConfigurationCreatorTests.cs index 4e6d5fa5..102b0eae 100644 --- a/test/Ocelot.UnitTests/Configuration/YamlConfigurationCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/YamlConfigurationCreatorTests.cs @@ -3,8 +3,10 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Moq; using Ocelot.Library.Configuration.Builder; +using Ocelot.Library.Configuration.Creator; using Ocelot.Library.Configuration.Parser; using Ocelot.Library.Configuration.Repository; +using Ocelot.Library.Configuration.Validator; using Ocelot.Library.RequestBuilder; using Shouldly; using TestStack.BDDfy; diff --git a/test/Ocelot.UnitTests/Middleware/DownstreamRouteFinderMiddlewareTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs similarity index 90% rename from test/Ocelot.UnitTests/Middleware/DownstreamRouteFinderMiddlewareTests.cs rename to test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs index 898e1648..f3ab97cb 100644 --- a/test/Ocelot.UnitTests/Middleware/DownstreamRouteFinderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs @@ -7,17 +7,17 @@ using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Moq; using Ocelot.Library.Configuration.Builder; +using Ocelot.Library.DownstreamRouteFinder; +using Ocelot.Library.DownstreamRouteFinder.Finder; +using Ocelot.Library.DownstreamRouteFinder.Middleware; +using Ocelot.Library.DownstreamRouteFinder.UrlMatcher; +using Ocelot.Library.Responses; +using Ocelot.Library.ScopedData; using TestStack.BDDfy; using Xunit; -namespace Ocelot.UnitTests.Middleware +namespace Ocelot.UnitTests.DownstreamRouteFinder { - using Library.DownstreamRouteFinder; - using Library.Middleware; - using Library.Repository; - using Library.Responses; - using Library.UrlMatcher; - public class DownstreamRouteFinderMiddlewareTests : IDisposable { private readonly Mock _downstreamRouteFinder; diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs index 24ef25e7..8ea8e581 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs @@ -2,6 +2,8 @@ using Moq; using Ocelot.Library.Configuration.Builder; using Ocelot.Library.Configuration.Provider; +using Ocelot.Library.DownstreamRouteFinder.Finder; +using Ocelot.Library.DownstreamRouteFinder.UrlMatcher; using Shouldly; using TestStack.BDDfy; using Xunit; @@ -11,7 +13,6 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder using Library.Configuration; using Library.DownstreamRouteFinder; using Library.Responses; - using Library.UrlMatcher; public class DownstreamRouteFinderTests { @@ -30,7 +31,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder _mockConfig = new Mock(); _mockMatcher = new Mock(); _finder = new Mock(); - _downstreamRouteFinder = new DownstreamRouteFinder(_mockConfig.Object, _mockMatcher.Object, _finder.Object); + _downstreamRouteFinder = new Library.DownstreamRouteFinder.Finder.DownstreamRouteFinder(_mockConfig.Object, _mockMatcher.Object, _finder.Object); } [Fact] diff --git a/test/Ocelot.UnitTests/UrlMatcher/RegExUrlMatcherTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/UrlMatcher/RegExUrlMatcherTests.cs similarity index 97% rename from test/Ocelot.UnitTests/UrlMatcher/RegExUrlMatcherTests.cs rename to test/Ocelot.UnitTests/DownstreamRouteFinder/UrlMatcher/RegExUrlMatcherTests.cs index 392df6e2..0b0c8b50 100644 --- a/test/Ocelot.UnitTests/UrlMatcher/RegExUrlMatcherTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/UrlMatcher/RegExUrlMatcherTests.cs @@ -1,12 +1,11 @@ +using Ocelot.Library.DownstreamRouteFinder.UrlMatcher; +using Ocelot.Library.Responses; using Shouldly; using TestStack.BDDfy; using Xunit; -namespace Ocelot.UnitTests.UrlMatcher +namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher { - using Library.Responses; - using Library.UrlMatcher; - public class RegExUrlMatcherTests { private readonly IUrlPathToUrlTemplateMatcher _urlMatcher; diff --git a/test/Ocelot.UnitTests/UrlMatcher/TemplateVariableNameAndValueFinderTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValueFinderTests.cs similarity index 97% rename from test/Ocelot.UnitTests/UrlMatcher/TemplateVariableNameAndValueFinderTests.cs rename to test/Ocelot.UnitTests/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValueFinderTests.cs index 3bb3b428..800f2024 100644 --- a/test/Ocelot.UnitTests/UrlMatcher/TemplateVariableNameAndValueFinderTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValueFinderTests.cs @@ -1,14 +1,13 @@ using System.Collections.Generic; using System.Linq; +using Ocelot.Library.DownstreamRouteFinder.UrlMatcher; +using Ocelot.Library.Responses; using Shouldly; using TestStack.BDDfy; using Xunit; -namespace Ocelot.UnitTests.UrlMatcher +namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher { - using Library.Responses; - using Library.UrlMatcher; - public class UrlPathToUrlTemplateMatcherTests { private readonly ITemplateVariableNameAndValueFinder _finder; diff --git a/test/Ocelot.UnitTests/Middleware/DownstreamUrlCreatorMiddlewareTests.cs b/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs similarity index 83% rename from test/Ocelot.UnitTests/Middleware/DownstreamUrlCreatorMiddlewareTests.cs rename to test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs index 56c0493c..5ba07e06 100644 --- a/test/Ocelot.UnitTests/Middleware/DownstreamUrlCreatorMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs @@ -1,24 +1,23 @@ -using Ocelot.Library.Configuration.Builder; +using System; +using System.Collections.Generic; +using System.IO; +using System.Net.Http; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using Moq; +using Ocelot.Library.Configuration.Builder; +using Ocelot.Library.DownstreamRouteFinder; +using Ocelot.Library.DownstreamRouteFinder.UrlMatcher; +using Ocelot.Library.DownstreamUrlCreator.Middleware; +using Ocelot.Library.DownstreamUrlCreator.UrlTemplateReplacer; +using Ocelot.Library.Responses; +using Ocelot.Library.ScopedData; +using TestStack.BDDfy; +using Xunit; -namespace Ocelot.UnitTests.Middleware +namespace Ocelot.UnitTests.DownstreamUrlCreator { - using System; - using System.Collections.Generic; - using System.IO; - using System.Net.Http; - using Library.DownstreamRouteFinder; - using Library.Middleware; - using Library.Repository; - using Library.Responses; - using Library.UrlMatcher; - using Library.UrlTemplateReplacer; - using Microsoft.AspNetCore.Hosting; - using Microsoft.AspNetCore.TestHost; - using Microsoft.Extensions.DependencyInjection; - using Moq; - using TestStack.BDDfy; - using Xunit; - public class DownstreamUrlCreatorMiddlewareTests : IDisposable { private readonly Mock _downstreamUrlTemplateVariableReplacer; diff --git a/test/Ocelot.UnitTests/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs b/test/Ocelot.UnitTests/DownstreamUrlCreator/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs similarity index 95% rename from test/Ocelot.UnitTests/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs rename to test/Ocelot.UnitTests/DownstreamUrlCreator/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs index 3db2b611..c842a223 100644 --- a/test/Ocelot.UnitTests/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs +++ b/test/Ocelot.UnitTests/DownstreamUrlCreator/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs @@ -1,16 +1,15 @@ using System.Collections.Generic; using Ocelot.Library.Configuration.Builder; +using Ocelot.Library.DownstreamRouteFinder; +using Ocelot.Library.DownstreamRouteFinder.UrlMatcher; +using Ocelot.Library.DownstreamUrlCreator.UrlTemplateReplacer; +using Ocelot.Library.Responses; using Shouldly; using TestStack.BDDfy; using Xunit; -namespace Ocelot.UnitTests.UrlTemplateReplacer +namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer { - using Library.DownstreamRouteFinder; - using Library.Responses; - using Library.UrlMatcher; - using Library.UrlTemplateReplacer; - public class UpstreamUrlPathTemplateVariableReplacerTests { private DownstreamRoute _downstreamRoute; diff --git a/test/Ocelot.UnitTests/RequestBuilder/AddHeadersToRequestTests.cs b/test/Ocelot.UnitTests/HeaderBuilder/AddHeadersToRequestTests.cs similarity index 97% rename from test/Ocelot.UnitTests/RequestBuilder/AddHeadersToRequestTests.cs rename to test/Ocelot.UnitTests/HeaderBuilder/AddHeadersToRequestTests.cs index 91359d28..2e277823 100644 --- a/test/Ocelot.UnitTests/RequestBuilder/AddHeadersToRequestTests.cs +++ b/test/Ocelot.UnitTests/HeaderBuilder/AddHeadersToRequestTests.cs @@ -6,13 +6,14 @@ using Microsoft.Extensions.Primitives; using Moq; using Ocelot.Library.Configuration; using Ocelot.Library.Errors; -using Ocelot.Library.RequestBuilder; +using Ocelot.Library.HeaderBuilder; +using Ocelot.Library.HeaderBuilder.Parser; using Ocelot.Library.Responses; using Shouldly; using TestStack.BDDfy; using Xunit; -namespace Ocelot.UnitTests.RequestBuilder +namespace Ocelot.UnitTests.HeaderBuilder { public class AddHeadersToRequestTests { diff --git a/test/Ocelot.UnitTests/RequestBuilder/ClaimParserTests.cs b/test/Ocelot.UnitTests/HeaderBuilder/ClaimParserTests.cs similarity index 96% rename from test/Ocelot.UnitTests/RequestBuilder/ClaimParserTests.cs rename to test/Ocelot.UnitTests/HeaderBuilder/ClaimParserTests.cs index 5daa7d6d..7be9226b 100644 --- a/test/Ocelot.UnitTests/RequestBuilder/ClaimParserTests.cs +++ b/test/Ocelot.UnitTests/HeaderBuilder/ClaimParserTests.cs @@ -1,13 +1,13 @@ using System.Collections.Generic; using System.Security.Claims; using Ocelot.Library.Errors; -using Ocelot.Library.RequestBuilder; +using Ocelot.Library.HeaderBuilder.Parser; using Ocelot.Library.Responses; using Shouldly; using TestStack.BDDfy; using Xunit; -namespace Ocelot.UnitTests.RequestBuilder +namespace Ocelot.UnitTests.HeaderBuilder { public class ClaimParserTests { @@ -21,7 +21,7 @@ namespace Ocelot.UnitTests.RequestBuilder public ClaimParserTests() { _claims = new List(); - _claimsParser = new Library.RequestBuilder.ClaimsParser(); + _claimsParser = new ClaimsParser(); } [Fact] diff --git a/test/Ocelot.UnitTests/Middleware/HttpRequestHeadersBuilderMiddlewareTests.cs b/test/Ocelot.UnitTests/HeaderBuilder/HttpRequestHeadersBuilderMiddlewareTests.cs similarity index 94% rename from test/Ocelot.UnitTests/Middleware/HttpRequestHeadersBuilderMiddlewareTests.cs rename to test/Ocelot.UnitTests/HeaderBuilder/HttpRequestHeadersBuilderMiddlewareTests.cs index ec0104cd..d7ab00b6 100644 --- a/test/Ocelot.UnitTests/Middleware/HttpRequestHeadersBuilderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/HeaderBuilder/HttpRequestHeadersBuilderMiddlewareTests.cs @@ -10,15 +10,15 @@ using Moq; using Ocelot.Library.Configuration; using Ocelot.Library.Configuration.Builder; using Ocelot.Library.DownstreamRouteFinder; -using Ocelot.Library.Middleware; -using Ocelot.Library.Repository; -using Ocelot.Library.RequestBuilder; +using Ocelot.Library.DownstreamRouteFinder.UrlMatcher; +using Ocelot.Library.HeaderBuilder; +using Ocelot.Library.HeaderBuilder.Middleware; using Ocelot.Library.Responses; -using Ocelot.Library.UrlMatcher; +using Ocelot.Library.ScopedData; using TestStack.BDDfy; using Xunit; -namespace Ocelot.UnitTests.Middleware +namespace Ocelot.UnitTests.HeaderBuilder { public class HttpRequestHeadersBuilderMiddlewareTests : IDisposable { diff --git a/test/Ocelot.UnitTests/Repository/ScopedRequestDataRepositoryTests.cs b/test/Ocelot.UnitTests/Repository/ScopedRequestDataRepositoryTests.cs index 9e688a30..53e573ad 100644 --- a/test/Ocelot.UnitTests/Repository/ScopedRequestDataRepositoryTests.cs +++ b/test/Ocelot.UnitTests/Repository/ScopedRequestDataRepositoryTests.cs @@ -1,11 +1,11 @@ using Microsoft.AspNetCore.Http; +using Ocelot.Library.ScopedData; using Shouldly; using TestStack.BDDfy; using Xunit; namespace Ocelot.UnitTests.Repository { - using Library.Repository; using Library.Responses; public class ScopedRequestDataRepositoryTests diff --git a/test/Ocelot.UnitTests/Middleware/HttpRequestBuilderMiddlewareTests.cs b/test/Ocelot.UnitTests/RequestBuilder/HttpRequestBuilderMiddlewareTests.cs similarity index 93% rename from test/Ocelot.UnitTests/Middleware/HttpRequestBuilderMiddlewareTests.cs rename to test/Ocelot.UnitTests/RequestBuilder/HttpRequestBuilderMiddlewareTests.cs index 9704fc6b..03a3d9a1 100644 --- a/test/Ocelot.UnitTests/Middleware/HttpRequestBuilderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/RequestBuilder/HttpRequestBuilderMiddlewareTests.cs @@ -7,16 +7,16 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Moq; +using Ocelot.Library.RequestBuilder; +using Ocelot.Library.RequestBuilder.Builder; +using Ocelot.Library.RequestBuilder.Middleware; +using Ocelot.Library.Responses; +using Ocelot.Library.ScopedData; using TestStack.BDDfy; using Xunit; -namespace Ocelot.UnitTests.Middleware +namespace Ocelot.UnitTests.RequestBuilder { - using Library.Middleware; - using Library.Repository; - using Library.RequestBuilder; - using Library.Responses; - public class HttpRequestBuilderMiddlewareTests : IDisposable { private readonly Mock _requestBuilder; diff --git a/test/Ocelot.UnitTests/RequestBuilder/RequestBuilderTests.cs b/test/Ocelot.UnitTests/RequestBuilder/RequestBuilderTests.cs index 80740e97..224f9624 100644 --- a/test/Ocelot.UnitTests/RequestBuilder/RequestBuilderTests.cs +++ b/test/Ocelot.UnitTests/RequestBuilder/RequestBuilderTests.cs @@ -5,6 +5,7 @@ using System.Net; using System.Net.Http; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Internal; +using Ocelot.Library.RequestBuilder.Builder; using Shouldly; using TestStack.BDDfy; using Xunit; diff --git a/test/Ocelot.UnitTests/Middleware/HttpRequesterMiddlewareTests.cs b/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs similarity index 93% rename from test/Ocelot.UnitTests/Middleware/HttpRequesterMiddlewareTests.cs rename to test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs index 99cf1691..2c7bdb8b 100644 --- a/test/Ocelot.UnitTests/Middleware/HttpRequesterMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs @@ -6,17 +6,16 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Moq; +using Ocelot.Library.RequestBuilder; +using Ocelot.Library.Requester; +using Ocelot.Library.Requester.Middleware; +using Ocelot.Library.Responses; +using Ocelot.Library.ScopedData; using TestStack.BDDfy; using Xunit; -namespace Ocelot.UnitTests.Middleware +namespace Ocelot.UnitTests.Requester { - using Library.Middleware; - using Library.Repository; - using Library.RequestBuilder; - using Library.Requester; - using Library.Responses; - public class HttpRequesterMiddlewareTests : IDisposable { private readonly Mock _requester; diff --git a/test/Ocelot.UnitTests/Middleware/HttpResponderMiddlewareTests.cs b/test/Ocelot.UnitTests/Responder/HttpResponderMiddlewareTests.cs similarity index 94% rename from test/Ocelot.UnitTests/Middleware/HttpResponderMiddlewareTests.cs rename to test/Ocelot.UnitTests/Responder/HttpResponderMiddlewareTests.cs index f4648700..b8c3c5eb 100644 --- a/test/Ocelot.UnitTests/Middleware/HttpResponderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Responder/HttpResponderMiddlewareTests.cs @@ -6,16 +6,15 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Moq; +using Ocelot.Library.Responder; +using Ocelot.Library.Responder.Middleware; +using Ocelot.Library.Responses; +using Ocelot.Library.ScopedData; using TestStack.BDDfy; using Xunit; -namespace Ocelot.UnitTests.Middleware +namespace Ocelot.UnitTests.Responder { - using Library.Middleware; - using Library.Repository; - using Library.Responder; - using Library.Responses; - public class HttpResponderMiddlewareTests : IDisposable { private readonly Mock _responder; From acfeeed86ab9b6d0a201911d610647500cb59e37 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Tue, 18 Oct 2016 19:04:46 +0100 Subject: [PATCH 094/183] removed ocelot website project from src and added a manual test project for this, renamed library project to just be ocelot --- Ocelot.sln | 16 +++--- .../Handler/AuthenticationHandler.cs | 0 .../Creator/AuthenticationHandlerCreator.cs | 0 .../Creator/IAuthenticationHandlerCreator.cs | 0 .../Factory/AuthenticationHandlerFactory.cs | 0 .../Factory/IAuthenticationHandlerFactory.cs | 0 ...nableToCreateAuthenticationHandlerError.cs | 0 .../SupportedAuthenticationProviders.cs | 0 .../Middleware/AuthenticationMiddleware.cs | 0 ...nticationMiddlewareMiddlewareExtensions.cs | 0 .../Configuration/AuthenticationOptions.cs | 0 .../Configuration/Builder/ReRouteBuilder.cs | 0 .../Configuration/ClaimToHeader.cs | 0 .../Creator/IOcelotConfigurationCreator.cs | 0 .../Creator/YamlOcelotConfigurationCreator.cs | 0 .../Configuration/IOcelotConfiguration.cs | 0 .../Configuration/OcelotConfiguration.cs | 0 .../ClaimToHeaderConfigurationParser.cs | 0 .../IClaimToHeaderConfigurationParser.cs | 0 .../Parser/InstructionNotForClaimsError.cs | 0 .../Parser/NoInstructionsError.cs | 0 .../Parser/ParsingConfigurationHeaderError.cs | 0 .../Provider/IOcelotConfigurationProvider.cs | 0 .../YamlOcelotConfigurationProvider.cs | 0 .../Configuration/ReRoute.cs | 0 .../IOcelotConfigurationRepository.cs | 0 .../InMemoryOcelotConfigurationRepository.cs | 0 .../ConfigurationValidationResult.cs | 0 .../Validator/ConfigurationValidator.cs | 0 .../DownstreamTemplateAlreadyUsedError.cs | 0 .../Validator/IConfigurationValidator.cs | 0 .../UnsupportedAuthenticationProviderError.cs | 0 .../Yaml/YamlAuthenticationOptions.cs | 0 .../Configuration/Yaml/YamlConfiguration.cs | 0 .../Configuration/Yaml/YamlReRoute.cs | 0 .../ServiceCollectionExtensions.cs | 0 .../DownstreamRouteFinder/DownstreamRoute.cs | 0 .../Finder/DownstreamRouteFinder.cs | 0 .../Finder/IDownstreamRouteFinder.cs | 0 .../UnableToFindDownstreamRouteError.cs | 0 .../DownstreamRouteFinderMiddleware.cs | 0 ...wnstreamRouteFinderMiddlewareExtensions.cs | 0 .../ITemplateVariableNameAndValueFinder.cs | 0 .../IUrlPathToUrlTemplateMatcher.cs | 0 .../UrlMatcher/RegExUrlMatcher.cs | 0 .../TemplateVariableNameAndValue.cs | 0 .../TemplateVariableNameAndValueFinder.cs | 0 .../UrlMatcher/UrlMatch.cs | 0 .../DownstreamUrlCreatorMiddleware.cs | 0 ...ownstreamUrlCreatorMiddlewareExtensions.cs | 0 .../DownstreamUrlTemplateVariableReplacer.cs | 0 ...wnstreamUrlPathTemplateVariableReplacer.cs | 0 .../Errors/Error.cs | 0 .../Errors/OcelotErrorCode.cs | 0 .../HeaderBuilder/AddHeadersToRequest.cs | 0 .../HeaderBuilder/IAddHeadersToRequest.cs | 0 .../HttpRequestHeadersBuilderMiddleware.cs | 0 ...questHeadersBuilderMiddlewareExtensions.cs | 0 .../Parser/CannotFindClaimError.cs | 0 .../HeaderBuilder/Parser/ClaimsParser.cs | 0 .../HeaderBuilder/Parser/IClaimsParser.cs | 0 .../Middleware/OcelotMiddleware.cs | 0 .../Middleware/OcelotMiddlewareExtensions.cs | 0 .../Middleware/UnauthenticatedError.cs | 0 src/Ocelot/Ocelot.xproj | 11 +--- .../Properties/AssemblyInfo.cs | 0 .../Builder/HttpRequestBuilder.cs | 0 .../RequestBuilder/Builder/IRequestBuilder.cs | 0 .../HttpRequestBuilderMiddleware.cs | 0 .../HttpRequestBuilderMiddlewareExtensions.cs | 0 .../RequestBuilder/Request.cs | 0 .../Requester/HttpClientHttpRequester.cs | 0 .../Requester/IHttpRequester.cs | 0 .../Middleware/HttpRequesterMiddleware.cs | 0 .../HttpRequesterMiddlewareExtensions.cs | 0 .../Requester/UnableToCompleteRequestError.cs | 0 .../Responder/ErrorsToHttpStatusCodeMapper.cs | 0 .../Responder/HttpContextResponder.cs | 0 .../IErrorsToHttpStatusCodeMapper.cs | 0 .../Responder/IHttpResponder.cs | 0 .../Middleware/HttpResponderMiddleware.cs | 0 .../HttpResponderMiddlewareExtensions.cs | 0 .../Responses/ErrorResponse.cs | 0 .../Responses/ErrorResponseGeneric.cs | 0 .../Responses/OkResponse.cs | 0 .../Responses/OkResponseGeneric.cs | 0 .../Responses/Response.cs | 0 .../Responses/ResponseGeneric.cs | 0 .../ScopedData/CannotAddDataError.cs | 0 .../ScopedData/CannotFindDataError.cs | 0 .../IScopedRequestDataRepository.cs | 0 .../ScopedData/ScopedRequestDataRepository.cs | 0 src/Ocelot/project.json | 55 +++++-------------- .../AuthenticationTests.cs | 1 + .../ClaimsToHeadersForwardingTests.cs | 1 + .../ReturnsErrorTests.cs | 1 + test/Ocelot.AcceptanceTests/RoutingTests.cs | 1 + test/Ocelot.AcceptanceTests/project.json | 4 +- .../Ocelot.ManualTest/Ocelot.ManualTest.xproj | 12 ++-- .../Ocelot.ManualTest}/Program.cs | 2 +- .../Properties/launchSettings.json | 7 +-- .../Ocelot.ManualTest}/Startup.cs | 7 +-- .../Ocelot.ManualTest}/appsettings.json | 0 .../Ocelot.ManualTest}/configuration.yaml | 0 .../Ocelot.ManualTest}/project.json | 55 ++++++++++++++----- .../Ocelot.ManualTest}/web.config | 0 test/Ocelot.UnitTests/project.json | 2 +- 107 files changed, 88 insertions(+), 87 deletions(-) rename src/{Ocelot.Library => Ocelot}/Authentication/Handler/AuthenticationHandler.cs (100%) rename src/{Ocelot.Library => Ocelot}/Authentication/Handler/Creator/AuthenticationHandlerCreator.cs (100%) rename src/{Ocelot.Library => Ocelot}/Authentication/Handler/Creator/IAuthenticationHandlerCreator.cs (100%) rename src/{Ocelot.Library => Ocelot}/Authentication/Handler/Factory/AuthenticationHandlerFactory.cs (100%) rename src/{Ocelot.Library => Ocelot}/Authentication/Handler/Factory/IAuthenticationHandlerFactory.cs (100%) rename src/{Ocelot.Library => Ocelot}/Authentication/Handler/Factory/UnableToCreateAuthenticationHandlerError.cs (100%) rename src/{Ocelot.Library => Ocelot}/Authentication/Handler/SupportedAuthenticationProviders.cs (100%) rename src/{Ocelot.Library => Ocelot}/Authentication/Middleware/AuthenticationMiddleware.cs (100%) rename src/{Ocelot.Library => Ocelot}/Authentication/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs (100%) rename src/{Ocelot.Library => Ocelot}/Configuration/AuthenticationOptions.cs (100%) rename src/{Ocelot.Library => Ocelot}/Configuration/Builder/ReRouteBuilder.cs (100%) rename src/{Ocelot.Library => Ocelot}/Configuration/ClaimToHeader.cs (100%) rename src/{Ocelot.Library => Ocelot}/Configuration/Creator/IOcelotConfigurationCreator.cs (100%) rename src/{Ocelot.Library => Ocelot}/Configuration/Creator/YamlOcelotConfigurationCreator.cs (100%) rename src/{Ocelot.Library => Ocelot}/Configuration/IOcelotConfiguration.cs (100%) rename src/{Ocelot.Library => Ocelot}/Configuration/OcelotConfiguration.cs (100%) rename src/{Ocelot.Library => Ocelot}/Configuration/Parser/ClaimToHeaderConfigurationParser.cs (100%) rename src/{Ocelot.Library => Ocelot}/Configuration/Parser/IClaimToHeaderConfigurationParser.cs (100%) rename src/{Ocelot.Library => Ocelot}/Configuration/Parser/InstructionNotForClaimsError.cs (100%) rename src/{Ocelot.Library => Ocelot}/Configuration/Parser/NoInstructionsError.cs (100%) rename src/{Ocelot.Library => Ocelot}/Configuration/Parser/ParsingConfigurationHeaderError.cs (100%) rename src/{Ocelot.Library => Ocelot}/Configuration/Provider/IOcelotConfigurationProvider.cs (100%) rename src/{Ocelot.Library => Ocelot}/Configuration/Provider/YamlOcelotConfigurationProvider.cs (100%) rename src/{Ocelot.Library => Ocelot}/Configuration/ReRoute.cs (100%) rename src/{Ocelot.Library => Ocelot}/Configuration/Repository/IOcelotConfigurationRepository.cs (100%) rename src/{Ocelot.Library => Ocelot}/Configuration/Repository/InMemoryOcelotConfigurationRepository.cs (100%) rename src/{Ocelot.Library => Ocelot}/Configuration/Validator/ConfigurationValidationResult.cs (100%) rename src/{Ocelot.Library => Ocelot}/Configuration/Validator/ConfigurationValidator.cs (100%) rename src/{Ocelot.Library => Ocelot}/Configuration/Validator/DownstreamTemplateAlreadyUsedError.cs (100%) rename src/{Ocelot.Library => Ocelot}/Configuration/Validator/IConfigurationValidator.cs (100%) rename src/{Ocelot.Library => Ocelot}/Configuration/Validator/UnsupportedAuthenticationProviderError.cs (100%) rename src/{Ocelot.Library => Ocelot}/Configuration/Yaml/YamlAuthenticationOptions.cs (100%) rename src/{Ocelot.Library => Ocelot}/Configuration/Yaml/YamlConfiguration.cs (100%) rename src/{Ocelot.Library => Ocelot}/Configuration/Yaml/YamlReRoute.cs (100%) rename src/{Ocelot.Library => Ocelot}/DependencyInjection/ServiceCollectionExtensions.cs (100%) rename src/{Ocelot.Library => Ocelot}/DownstreamRouteFinder/DownstreamRoute.cs (100%) rename src/{Ocelot.Library => Ocelot}/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs (100%) rename src/{Ocelot.Library => Ocelot}/DownstreamRouteFinder/Finder/IDownstreamRouteFinder.cs (100%) rename src/{Ocelot.Library => Ocelot}/DownstreamRouteFinder/Finder/UnableToFindDownstreamRouteError.cs (100%) rename src/{Ocelot.Library => Ocelot}/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddleware.cs (100%) rename src/{Ocelot.Library => Ocelot}/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs (100%) rename src/{Ocelot.Library => Ocelot}/DownstreamRouteFinder/UrlMatcher/ITemplateVariableNameAndValueFinder.cs (100%) rename src/{Ocelot.Library => Ocelot}/DownstreamRouteFinder/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs (100%) rename src/{Ocelot.Library => Ocelot}/DownstreamRouteFinder/UrlMatcher/RegExUrlMatcher.cs (100%) rename src/{Ocelot.Library => Ocelot}/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValue.cs (100%) rename src/{Ocelot.Library => Ocelot}/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValueFinder.cs (100%) rename src/{Ocelot.Library => Ocelot}/DownstreamRouteFinder/UrlMatcher/UrlMatch.cs (100%) rename src/{Ocelot.Library => Ocelot}/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs (100%) rename src/{Ocelot.Library => Ocelot}/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs (100%) rename src/{Ocelot.Library => Ocelot}/DownstreamUrlCreator/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs (100%) rename src/{Ocelot.Library => Ocelot}/DownstreamUrlCreator/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs (100%) rename src/{Ocelot.Library => Ocelot}/Errors/Error.cs (100%) rename src/{Ocelot.Library => Ocelot}/Errors/OcelotErrorCode.cs (100%) rename src/{Ocelot.Library => Ocelot}/HeaderBuilder/AddHeadersToRequest.cs (100%) rename src/{Ocelot.Library => Ocelot}/HeaderBuilder/IAddHeadersToRequest.cs (100%) rename src/{Ocelot.Library => Ocelot}/HeaderBuilder/Middleware/HttpRequestHeadersBuilderMiddleware.cs (100%) rename src/{Ocelot.Library => Ocelot}/HeaderBuilder/Middleware/HttpRequestHeadersBuilderMiddlewareExtensions.cs (100%) rename src/{Ocelot.Library => Ocelot}/HeaderBuilder/Parser/CannotFindClaimError.cs (100%) rename src/{Ocelot.Library => Ocelot}/HeaderBuilder/Parser/ClaimsParser.cs (100%) rename src/{Ocelot.Library => Ocelot}/HeaderBuilder/Parser/IClaimsParser.cs (100%) rename src/{Ocelot.Library => Ocelot}/Middleware/OcelotMiddleware.cs (100%) rename src/{Ocelot.Library => Ocelot}/Middleware/OcelotMiddlewareExtensions.cs (100%) rename src/{Ocelot.Library => Ocelot}/Middleware/UnauthenticatedError.cs (100%) rename src/{Ocelot.Library => Ocelot}/Properties/AssemblyInfo.cs (100%) rename src/{Ocelot.Library => Ocelot}/RequestBuilder/Builder/HttpRequestBuilder.cs (100%) rename src/{Ocelot.Library => Ocelot}/RequestBuilder/Builder/IRequestBuilder.cs (100%) rename src/{Ocelot.Library => Ocelot}/RequestBuilder/Middleware/HttpRequestBuilderMiddleware.cs (100%) rename src/{Ocelot.Library => Ocelot}/RequestBuilder/Middleware/HttpRequestBuilderMiddlewareExtensions.cs (100%) rename src/{Ocelot.Library => Ocelot}/RequestBuilder/Request.cs (100%) rename src/{Ocelot.Library => Ocelot}/Requester/HttpClientHttpRequester.cs (100%) rename src/{Ocelot.Library => Ocelot}/Requester/IHttpRequester.cs (100%) rename src/{Ocelot.Library => Ocelot}/Requester/Middleware/HttpRequesterMiddleware.cs (100%) rename src/{Ocelot.Library => Ocelot}/Requester/Middleware/HttpRequesterMiddlewareExtensions.cs (100%) rename src/{Ocelot.Library => Ocelot}/Requester/UnableToCompleteRequestError.cs (100%) rename src/{Ocelot.Library => Ocelot}/Responder/ErrorsToHttpStatusCodeMapper.cs (100%) rename src/{Ocelot.Library => Ocelot}/Responder/HttpContextResponder.cs (100%) rename src/{Ocelot.Library => Ocelot}/Responder/IErrorsToHttpStatusCodeMapper.cs (100%) rename src/{Ocelot.Library => Ocelot}/Responder/IHttpResponder.cs (100%) rename src/{Ocelot.Library => Ocelot}/Responder/Middleware/HttpResponderMiddleware.cs (100%) rename src/{Ocelot.Library => Ocelot}/Responder/Middleware/HttpResponderMiddlewareExtensions.cs (100%) rename src/{Ocelot.Library => Ocelot}/Responses/ErrorResponse.cs (100%) rename src/{Ocelot.Library => Ocelot}/Responses/ErrorResponseGeneric.cs (100%) rename src/{Ocelot.Library => Ocelot}/Responses/OkResponse.cs (100%) rename src/{Ocelot.Library => Ocelot}/Responses/OkResponseGeneric.cs (100%) rename src/{Ocelot.Library => Ocelot}/Responses/Response.cs (100%) rename src/{Ocelot.Library => Ocelot}/Responses/ResponseGeneric.cs (100%) rename src/{Ocelot.Library => Ocelot}/ScopedData/CannotAddDataError.cs (100%) rename src/{Ocelot.Library => Ocelot}/ScopedData/CannotFindDataError.cs (100%) rename src/{Ocelot.Library => Ocelot}/ScopedData/IScopedRequestDataRepository.cs (100%) rename src/{Ocelot.Library => Ocelot}/ScopedData/ScopedRequestDataRepository.cs (100%) rename src/Ocelot.Library/Ocelot.Library.xproj => test/Ocelot.ManualTest/Ocelot.ManualTest.xproj (67%) rename {src/Ocelot => test/Ocelot.ManualTest}/Program.cs (93%) rename {src/Ocelot => test/Ocelot.ManualTest}/Properties/launchSettings.json (76%) rename {src/Ocelot => test/Ocelot.ManualTest}/Startup.cs (93%) rename {src/Ocelot => test/Ocelot.ManualTest}/appsettings.json (100%) rename {src/Ocelot => test/Ocelot.ManualTest}/configuration.yaml (100%) rename {src/Ocelot.Library => test/Ocelot.ManualTest}/project.json (50%) rename {src/Ocelot => test/Ocelot.ManualTest}/web.config (100%) diff --git a/Ocelot.sln b/Ocelot.sln index f06eb7cf..75f70f63 100644 --- a/Ocelot.sln +++ b/Ocelot.sln @@ -18,9 +18,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution run-tests.bat = run-tests.bat EndProjectSection EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Ocelot", "src\Ocelot\Ocelot.xproj", "{AEC8FB40-B370-48A6-9B38-78E560041F01}" -EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Ocelot.Library", "src\Ocelot.Library\Ocelot.Library.xproj", "{D6DF4206-0DBA-41D8-884D-C3E08290FDBB}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Ocelot", "src\Ocelot\Ocelot.xproj", "{D6DF4206-0DBA-41D8-884D-C3E08290FDBB}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{5B401523-36DA-4491-B73A-7590A26E420B}" EndProject @@ -28,16 +26,14 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Ocelot.UnitTests", "test\Oc EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Ocelot.AcceptanceTests", "test\Ocelot.AcceptanceTests\Ocelot.AcceptanceTests.xproj", "{F8C224FE-36BE-45F5-9B0E-666D8F4A9B52}" EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Ocelot.ManualTest", "test\Ocelot.ManualTest\Ocelot.ManualTest.xproj", "{02BBF4C5-517E-4157-8D21-4B8B9E118B7A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {AEC8FB40-B370-48A6-9B38-78E560041F01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AEC8FB40-B370-48A6-9B38-78E560041F01}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AEC8FB40-B370-48A6-9B38-78E560041F01}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AEC8FB40-B370-48A6-9B38-78E560041F01}.Release|Any CPU.Build.0 = Release|Any CPU {D6DF4206-0DBA-41D8-884D-C3E08290FDBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D6DF4206-0DBA-41D8-884D-C3E08290FDBB}.Debug|Any CPU.Build.0 = Debug|Any CPU {D6DF4206-0DBA-41D8-884D-C3E08290FDBB}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -50,14 +46,18 @@ Global {F8C224FE-36BE-45F5-9B0E-666D8F4A9B52}.Debug|Any CPU.Build.0 = Debug|Any CPU {F8C224FE-36BE-45F5-9B0E-666D8F4A9B52}.Release|Any CPU.ActiveCfg = Release|Any CPU {F8C224FE-36BE-45F5-9B0E-666D8F4A9B52}.Release|Any CPU.Build.0 = Release|Any CPU + {02BBF4C5-517E-4157-8D21-4B8B9E118B7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {02BBF4C5-517E-4157-8D21-4B8B9E118B7A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {02BBF4C5-517E-4157-8D21-4B8B9E118B7A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {02BBF4C5-517E-4157-8D21-4B8B9E118B7A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {AEC8FB40-B370-48A6-9B38-78E560041F01} = {5CFB79B7-C9DC-45A4-9A75-625D92471702} {D6DF4206-0DBA-41D8-884D-C3E08290FDBB} = {5CFB79B7-C9DC-45A4-9A75-625D92471702} {54E84F1A-E525-4443-96EC-039CBD50C263} = {5B401523-36DA-4491-B73A-7590A26E420B} {F8C224FE-36BE-45F5-9B0E-666D8F4A9B52} = {5B401523-36DA-4491-B73A-7590A26E420B} + {02BBF4C5-517E-4157-8D21-4B8B9E118B7A} = {5B401523-36DA-4491-B73A-7590A26E420B} EndGlobalSection EndGlobal diff --git a/src/Ocelot.Library/Authentication/Handler/AuthenticationHandler.cs b/src/Ocelot/Authentication/Handler/AuthenticationHandler.cs similarity index 100% rename from src/Ocelot.Library/Authentication/Handler/AuthenticationHandler.cs rename to src/Ocelot/Authentication/Handler/AuthenticationHandler.cs diff --git a/src/Ocelot.Library/Authentication/Handler/Creator/AuthenticationHandlerCreator.cs b/src/Ocelot/Authentication/Handler/Creator/AuthenticationHandlerCreator.cs similarity index 100% rename from src/Ocelot.Library/Authentication/Handler/Creator/AuthenticationHandlerCreator.cs rename to src/Ocelot/Authentication/Handler/Creator/AuthenticationHandlerCreator.cs diff --git a/src/Ocelot.Library/Authentication/Handler/Creator/IAuthenticationHandlerCreator.cs b/src/Ocelot/Authentication/Handler/Creator/IAuthenticationHandlerCreator.cs similarity index 100% rename from src/Ocelot.Library/Authentication/Handler/Creator/IAuthenticationHandlerCreator.cs rename to src/Ocelot/Authentication/Handler/Creator/IAuthenticationHandlerCreator.cs diff --git a/src/Ocelot.Library/Authentication/Handler/Factory/AuthenticationHandlerFactory.cs b/src/Ocelot/Authentication/Handler/Factory/AuthenticationHandlerFactory.cs similarity index 100% rename from src/Ocelot.Library/Authentication/Handler/Factory/AuthenticationHandlerFactory.cs rename to src/Ocelot/Authentication/Handler/Factory/AuthenticationHandlerFactory.cs diff --git a/src/Ocelot.Library/Authentication/Handler/Factory/IAuthenticationHandlerFactory.cs b/src/Ocelot/Authentication/Handler/Factory/IAuthenticationHandlerFactory.cs similarity index 100% rename from src/Ocelot.Library/Authentication/Handler/Factory/IAuthenticationHandlerFactory.cs rename to src/Ocelot/Authentication/Handler/Factory/IAuthenticationHandlerFactory.cs diff --git a/src/Ocelot.Library/Authentication/Handler/Factory/UnableToCreateAuthenticationHandlerError.cs b/src/Ocelot/Authentication/Handler/Factory/UnableToCreateAuthenticationHandlerError.cs similarity index 100% rename from src/Ocelot.Library/Authentication/Handler/Factory/UnableToCreateAuthenticationHandlerError.cs rename to src/Ocelot/Authentication/Handler/Factory/UnableToCreateAuthenticationHandlerError.cs diff --git a/src/Ocelot.Library/Authentication/Handler/SupportedAuthenticationProviders.cs b/src/Ocelot/Authentication/Handler/SupportedAuthenticationProviders.cs similarity index 100% rename from src/Ocelot.Library/Authentication/Handler/SupportedAuthenticationProviders.cs rename to src/Ocelot/Authentication/Handler/SupportedAuthenticationProviders.cs diff --git a/src/Ocelot.Library/Authentication/Middleware/AuthenticationMiddleware.cs b/src/Ocelot/Authentication/Middleware/AuthenticationMiddleware.cs similarity index 100% rename from src/Ocelot.Library/Authentication/Middleware/AuthenticationMiddleware.cs rename to src/Ocelot/Authentication/Middleware/AuthenticationMiddleware.cs diff --git a/src/Ocelot.Library/Authentication/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs b/src/Ocelot/Authentication/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs similarity index 100% rename from src/Ocelot.Library/Authentication/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs rename to src/Ocelot/Authentication/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs diff --git a/src/Ocelot.Library/Configuration/AuthenticationOptions.cs b/src/Ocelot/Configuration/AuthenticationOptions.cs similarity index 100% rename from src/Ocelot.Library/Configuration/AuthenticationOptions.cs rename to src/Ocelot/Configuration/AuthenticationOptions.cs diff --git a/src/Ocelot.Library/Configuration/Builder/ReRouteBuilder.cs b/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs similarity index 100% rename from src/Ocelot.Library/Configuration/Builder/ReRouteBuilder.cs rename to src/Ocelot/Configuration/Builder/ReRouteBuilder.cs diff --git a/src/Ocelot.Library/Configuration/ClaimToHeader.cs b/src/Ocelot/Configuration/ClaimToHeader.cs similarity index 100% rename from src/Ocelot.Library/Configuration/ClaimToHeader.cs rename to src/Ocelot/Configuration/ClaimToHeader.cs diff --git a/src/Ocelot.Library/Configuration/Creator/IOcelotConfigurationCreator.cs b/src/Ocelot/Configuration/Creator/IOcelotConfigurationCreator.cs similarity index 100% rename from src/Ocelot.Library/Configuration/Creator/IOcelotConfigurationCreator.cs rename to src/Ocelot/Configuration/Creator/IOcelotConfigurationCreator.cs diff --git a/src/Ocelot.Library/Configuration/Creator/YamlOcelotConfigurationCreator.cs b/src/Ocelot/Configuration/Creator/YamlOcelotConfigurationCreator.cs similarity index 100% rename from src/Ocelot.Library/Configuration/Creator/YamlOcelotConfigurationCreator.cs rename to src/Ocelot/Configuration/Creator/YamlOcelotConfigurationCreator.cs diff --git a/src/Ocelot.Library/Configuration/IOcelotConfiguration.cs b/src/Ocelot/Configuration/IOcelotConfiguration.cs similarity index 100% rename from src/Ocelot.Library/Configuration/IOcelotConfiguration.cs rename to src/Ocelot/Configuration/IOcelotConfiguration.cs diff --git a/src/Ocelot.Library/Configuration/OcelotConfiguration.cs b/src/Ocelot/Configuration/OcelotConfiguration.cs similarity index 100% rename from src/Ocelot.Library/Configuration/OcelotConfiguration.cs rename to src/Ocelot/Configuration/OcelotConfiguration.cs diff --git a/src/Ocelot.Library/Configuration/Parser/ClaimToHeaderConfigurationParser.cs b/src/Ocelot/Configuration/Parser/ClaimToHeaderConfigurationParser.cs similarity index 100% rename from src/Ocelot.Library/Configuration/Parser/ClaimToHeaderConfigurationParser.cs rename to src/Ocelot/Configuration/Parser/ClaimToHeaderConfigurationParser.cs diff --git a/src/Ocelot.Library/Configuration/Parser/IClaimToHeaderConfigurationParser.cs b/src/Ocelot/Configuration/Parser/IClaimToHeaderConfigurationParser.cs similarity index 100% rename from src/Ocelot.Library/Configuration/Parser/IClaimToHeaderConfigurationParser.cs rename to src/Ocelot/Configuration/Parser/IClaimToHeaderConfigurationParser.cs diff --git a/src/Ocelot.Library/Configuration/Parser/InstructionNotForClaimsError.cs b/src/Ocelot/Configuration/Parser/InstructionNotForClaimsError.cs similarity index 100% rename from src/Ocelot.Library/Configuration/Parser/InstructionNotForClaimsError.cs rename to src/Ocelot/Configuration/Parser/InstructionNotForClaimsError.cs diff --git a/src/Ocelot.Library/Configuration/Parser/NoInstructionsError.cs b/src/Ocelot/Configuration/Parser/NoInstructionsError.cs similarity index 100% rename from src/Ocelot.Library/Configuration/Parser/NoInstructionsError.cs rename to src/Ocelot/Configuration/Parser/NoInstructionsError.cs diff --git a/src/Ocelot.Library/Configuration/Parser/ParsingConfigurationHeaderError.cs b/src/Ocelot/Configuration/Parser/ParsingConfigurationHeaderError.cs similarity index 100% rename from src/Ocelot.Library/Configuration/Parser/ParsingConfigurationHeaderError.cs rename to src/Ocelot/Configuration/Parser/ParsingConfigurationHeaderError.cs diff --git a/src/Ocelot.Library/Configuration/Provider/IOcelotConfigurationProvider.cs b/src/Ocelot/Configuration/Provider/IOcelotConfigurationProvider.cs similarity index 100% rename from src/Ocelot.Library/Configuration/Provider/IOcelotConfigurationProvider.cs rename to src/Ocelot/Configuration/Provider/IOcelotConfigurationProvider.cs diff --git a/src/Ocelot.Library/Configuration/Provider/YamlOcelotConfigurationProvider.cs b/src/Ocelot/Configuration/Provider/YamlOcelotConfigurationProvider.cs similarity index 100% rename from src/Ocelot.Library/Configuration/Provider/YamlOcelotConfigurationProvider.cs rename to src/Ocelot/Configuration/Provider/YamlOcelotConfigurationProvider.cs diff --git a/src/Ocelot.Library/Configuration/ReRoute.cs b/src/Ocelot/Configuration/ReRoute.cs similarity index 100% rename from src/Ocelot.Library/Configuration/ReRoute.cs rename to src/Ocelot/Configuration/ReRoute.cs diff --git a/src/Ocelot.Library/Configuration/Repository/IOcelotConfigurationRepository.cs b/src/Ocelot/Configuration/Repository/IOcelotConfigurationRepository.cs similarity index 100% rename from src/Ocelot.Library/Configuration/Repository/IOcelotConfigurationRepository.cs rename to src/Ocelot/Configuration/Repository/IOcelotConfigurationRepository.cs diff --git a/src/Ocelot.Library/Configuration/Repository/InMemoryOcelotConfigurationRepository.cs b/src/Ocelot/Configuration/Repository/InMemoryOcelotConfigurationRepository.cs similarity index 100% rename from src/Ocelot.Library/Configuration/Repository/InMemoryOcelotConfigurationRepository.cs rename to src/Ocelot/Configuration/Repository/InMemoryOcelotConfigurationRepository.cs diff --git a/src/Ocelot.Library/Configuration/Validator/ConfigurationValidationResult.cs b/src/Ocelot/Configuration/Validator/ConfigurationValidationResult.cs similarity index 100% rename from src/Ocelot.Library/Configuration/Validator/ConfigurationValidationResult.cs rename to src/Ocelot/Configuration/Validator/ConfigurationValidationResult.cs diff --git a/src/Ocelot.Library/Configuration/Validator/ConfigurationValidator.cs b/src/Ocelot/Configuration/Validator/ConfigurationValidator.cs similarity index 100% rename from src/Ocelot.Library/Configuration/Validator/ConfigurationValidator.cs rename to src/Ocelot/Configuration/Validator/ConfigurationValidator.cs diff --git a/src/Ocelot.Library/Configuration/Validator/DownstreamTemplateAlreadyUsedError.cs b/src/Ocelot/Configuration/Validator/DownstreamTemplateAlreadyUsedError.cs similarity index 100% rename from src/Ocelot.Library/Configuration/Validator/DownstreamTemplateAlreadyUsedError.cs rename to src/Ocelot/Configuration/Validator/DownstreamTemplateAlreadyUsedError.cs diff --git a/src/Ocelot.Library/Configuration/Validator/IConfigurationValidator.cs b/src/Ocelot/Configuration/Validator/IConfigurationValidator.cs similarity index 100% rename from src/Ocelot.Library/Configuration/Validator/IConfigurationValidator.cs rename to src/Ocelot/Configuration/Validator/IConfigurationValidator.cs diff --git a/src/Ocelot.Library/Configuration/Validator/UnsupportedAuthenticationProviderError.cs b/src/Ocelot/Configuration/Validator/UnsupportedAuthenticationProviderError.cs similarity index 100% rename from src/Ocelot.Library/Configuration/Validator/UnsupportedAuthenticationProviderError.cs rename to src/Ocelot/Configuration/Validator/UnsupportedAuthenticationProviderError.cs diff --git a/src/Ocelot.Library/Configuration/Yaml/YamlAuthenticationOptions.cs b/src/Ocelot/Configuration/Yaml/YamlAuthenticationOptions.cs similarity index 100% rename from src/Ocelot.Library/Configuration/Yaml/YamlAuthenticationOptions.cs rename to src/Ocelot/Configuration/Yaml/YamlAuthenticationOptions.cs diff --git a/src/Ocelot.Library/Configuration/Yaml/YamlConfiguration.cs b/src/Ocelot/Configuration/Yaml/YamlConfiguration.cs similarity index 100% rename from src/Ocelot.Library/Configuration/Yaml/YamlConfiguration.cs rename to src/Ocelot/Configuration/Yaml/YamlConfiguration.cs diff --git a/src/Ocelot.Library/Configuration/Yaml/YamlReRoute.cs b/src/Ocelot/Configuration/Yaml/YamlReRoute.cs similarity index 100% rename from src/Ocelot.Library/Configuration/Yaml/YamlReRoute.cs rename to src/Ocelot/Configuration/Yaml/YamlReRoute.cs diff --git a/src/Ocelot.Library/DependencyInjection/ServiceCollectionExtensions.cs b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs similarity index 100% rename from src/Ocelot.Library/DependencyInjection/ServiceCollectionExtensions.cs rename to src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs diff --git a/src/Ocelot.Library/DownstreamRouteFinder/DownstreamRoute.cs b/src/Ocelot/DownstreamRouteFinder/DownstreamRoute.cs similarity index 100% rename from src/Ocelot.Library/DownstreamRouteFinder/DownstreamRoute.cs rename to src/Ocelot/DownstreamRouteFinder/DownstreamRoute.cs diff --git a/src/Ocelot.Library/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs b/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs similarity index 100% rename from src/Ocelot.Library/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs rename to src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs diff --git a/src/Ocelot.Library/DownstreamRouteFinder/Finder/IDownstreamRouteFinder.cs b/src/Ocelot/DownstreamRouteFinder/Finder/IDownstreamRouteFinder.cs similarity index 100% rename from src/Ocelot.Library/DownstreamRouteFinder/Finder/IDownstreamRouteFinder.cs rename to src/Ocelot/DownstreamRouteFinder/Finder/IDownstreamRouteFinder.cs diff --git a/src/Ocelot.Library/DownstreamRouteFinder/Finder/UnableToFindDownstreamRouteError.cs b/src/Ocelot/DownstreamRouteFinder/Finder/UnableToFindDownstreamRouteError.cs similarity index 100% rename from src/Ocelot.Library/DownstreamRouteFinder/Finder/UnableToFindDownstreamRouteError.cs rename to src/Ocelot/DownstreamRouteFinder/Finder/UnableToFindDownstreamRouteError.cs diff --git a/src/Ocelot.Library/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddleware.cs b/src/Ocelot/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddleware.cs similarity index 100% rename from src/Ocelot.Library/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddleware.cs rename to src/Ocelot/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddleware.cs diff --git a/src/Ocelot.Library/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs b/src/Ocelot/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs similarity index 100% rename from src/Ocelot.Library/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs rename to src/Ocelot/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs diff --git a/src/Ocelot.Library/DownstreamRouteFinder/UrlMatcher/ITemplateVariableNameAndValueFinder.cs b/src/Ocelot/DownstreamRouteFinder/UrlMatcher/ITemplateVariableNameAndValueFinder.cs similarity index 100% rename from src/Ocelot.Library/DownstreamRouteFinder/UrlMatcher/ITemplateVariableNameAndValueFinder.cs rename to src/Ocelot/DownstreamRouteFinder/UrlMatcher/ITemplateVariableNameAndValueFinder.cs diff --git a/src/Ocelot.Library/DownstreamRouteFinder/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs b/src/Ocelot/DownstreamRouteFinder/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs similarity index 100% rename from src/Ocelot.Library/DownstreamRouteFinder/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs rename to src/Ocelot/DownstreamRouteFinder/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs diff --git a/src/Ocelot.Library/DownstreamRouteFinder/UrlMatcher/RegExUrlMatcher.cs b/src/Ocelot/DownstreamRouteFinder/UrlMatcher/RegExUrlMatcher.cs similarity index 100% rename from src/Ocelot.Library/DownstreamRouteFinder/UrlMatcher/RegExUrlMatcher.cs rename to src/Ocelot/DownstreamRouteFinder/UrlMatcher/RegExUrlMatcher.cs diff --git a/src/Ocelot.Library/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValue.cs b/src/Ocelot/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValue.cs similarity index 100% rename from src/Ocelot.Library/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValue.cs rename to src/Ocelot/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValue.cs diff --git a/src/Ocelot.Library/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValueFinder.cs b/src/Ocelot/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValueFinder.cs similarity index 100% rename from src/Ocelot.Library/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValueFinder.cs rename to src/Ocelot/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValueFinder.cs diff --git a/src/Ocelot.Library/DownstreamRouteFinder/UrlMatcher/UrlMatch.cs b/src/Ocelot/DownstreamRouteFinder/UrlMatcher/UrlMatch.cs similarity index 100% rename from src/Ocelot.Library/DownstreamRouteFinder/UrlMatcher/UrlMatch.cs rename to src/Ocelot/DownstreamRouteFinder/UrlMatcher/UrlMatch.cs diff --git a/src/Ocelot.Library/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs b/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs similarity index 100% rename from src/Ocelot.Library/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs rename to src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs diff --git a/src/Ocelot.Library/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs b/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs similarity index 100% rename from src/Ocelot.Library/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs rename to src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs diff --git a/src/Ocelot.Library/DownstreamUrlCreator/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs b/src/Ocelot/DownstreamUrlCreator/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs similarity index 100% rename from src/Ocelot.Library/DownstreamUrlCreator/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs rename to src/Ocelot/DownstreamUrlCreator/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs diff --git a/src/Ocelot.Library/DownstreamUrlCreator/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs b/src/Ocelot/DownstreamUrlCreator/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs similarity index 100% rename from src/Ocelot.Library/DownstreamUrlCreator/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs rename to src/Ocelot/DownstreamUrlCreator/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs diff --git a/src/Ocelot.Library/Errors/Error.cs b/src/Ocelot/Errors/Error.cs similarity index 100% rename from src/Ocelot.Library/Errors/Error.cs rename to src/Ocelot/Errors/Error.cs diff --git a/src/Ocelot.Library/Errors/OcelotErrorCode.cs b/src/Ocelot/Errors/OcelotErrorCode.cs similarity index 100% rename from src/Ocelot.Library/Errors/OcelotErrorCode.cs rename to src/Ocelot/Errors/OcelotErrorCode.cs diff --git a/src/Ocelot.Library/HeaderBuilder/AddHeadersToRequest.cs b/src/Ocelot/HeaderBuilder/AddHeadersToRequest.cs similarity index 100% rename from src/Ocelot.Library/HeaderBuilder/AddHeadersToRequest.cs rename to src/Ocelot/HeaderBuilder/AddHeadersToRequest.cs diff --git a/src/Ocelot.Library/HeaderBuilder/IAddHeadersToRequest.cs b/src/Ocelot/HeaderBuilder/IAddHeadersToRequest.cs similarity index 100% rename from src/Ocelot.Library/HeaderBuilder/IAddHeadersToRequest.cs rename to src/Ocelot/HeaderBuilder/IAddHeadersToRequest.cs diff --git a/src/Ocelot.Library/HeaderBuilder/Middleware/HttpRequestHeadersBuilderMiddleware.cs b/src/Ocelot/HeaderBuilder/Middleware/HttpRequestHeadersBuilderMiddleware.cs similarity index 100% rename from src/Ocelot.Library/HeaderBuilder/Middleware/HttpRequestHeadersBuilderMiddleware.cs rename to src/Ocelot/HeaderBuilder/Middleware/HttpRequestHeadersBuilderMiddleware.cs diff --git a/src/Ocelot.Library/HeaderBuilder/Middleware/HttpRequestHeadersBuilderMiddlewareExtensions.cs b/src/Ocelot/HeaderBuilder/Middleware/HttpRequestHeadersBuilderMiddlewareExtensions.cs similarity index 100% rename from src/Ocelot.Library/HeaderBuilder/Middleware/HttpRequestHeadersBuilderMiddlewareExtensions.cs rename to src/Ocelot/HeaderBuilder/Middleware/HttpRequestHeadersBuilderMiddlewareExtensions.cs diff --git a/src/Ocelot.Library/HeaderBuilder/Parser/CannotFindClaimError.cs b/src/Ocelot/HeaderBuilder/Parser/CannotFindClaimError.cs similarity index 100% rename from src/Ocelot.Library/HeaderBuilder/Parser/CannotFindClaimError.cs rename to src/Ocelot/HeaderBuilder/Parser/CannotFindClaimError.cs diff --git a/src/Ocelot.Library/HeaderBuilder/Parser/ClaimsParser.cs b/src/Ocelot/HeaderBuilder/Parser/ClaimsParser.cs similarity index 100% rename from src/Ocelot.Library/HeaderBuilder/Parser/ClaimsParser.cs rename to src/Ocelot/HeaderBuilder/Parser/ClaimsParser.cs diff --git a/src/Ocelot.Library/HeaderBuilder/Parser/IClaimsParser.cs b/src/Ocelot/HeaderBuilder/Parser/IClaimsParser.cs similarity index 100% rename from src/Ocelot.Library/HeaderBuilder/Parser/IClaimsParser.cs rename to src/Ocelot/HeaderBuilder/Parser/IClaimsParser.cs diff --git a/src/Ocelot.Library/Middleware/OcelotMiddleware.cs b/src/Ocelot/Middleware/OcelotMiddleware.cs similarity index 100% rename from src/Ocelot.Library/Middleware/OcelotMiddleware.cs rename to src/Ocelot/Middleware/OcelotMiddleware.cs diff --git a/src/Ocelot.Library/Middleware/OcelotMiddlewareExtensions.cs b/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs similarity index 100% rename from src/Ocelot.Library/Middleware/OcelotMiddlewareExtensions.cs rename to src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs diff --git a/src/Ocelot.Library/Middleware/UnauthenticatedError.cs b/src/Ocelot/Middleware/UnauthenticatedError.cs similarity index 100% rename from src/Ocelot.Library/Middleware/UnauthenticatedError.cs rename to src/Ocelot/Middleware/UnauthenticatedError.cs diff --git a/src/Ocelot/Ocelot.xproj b/src/Ocelot/Ocelot.xproj index ec987923..5f2a7cc5 100644 --- a/src/Ocelot/Ocelot.xproj +++ b/src/Ocelot/Ocelot.xproj @@ -6,19 +6,14 @@ - aec8fb40-b370-48a6-9b38-78e560041f01 + d6df4206-0dba-41d8-884d-c3e08290fdbb Ocelot .\obj .\bin\ - v4.5.2 + v4.5 2.0 - - - - - - + \ No newline at end of file diff --git a/src/Ocelot.Library/Properties/AssemblyInfo.cs b/src/Ocelot/Properties/AssemblyInfo.cs similarity index 100% rename from src/Ocelot.Library/Properties/AssemblyInfo.cs rename to src/Ocelot/Properties/AssemblyInfo.cs diff --git a/src/Ocelot.Library/RequestBuilder/Builder/HttpRequestBuilder.cs b/src/Ocelot/RequestBuilder/Builder/HttpRequestBuilder.cs similarity index 100% rename from src/Ocelot.Library/RequestBuilder/Builder/HttpRequestBuilder.cs rename to src/Ocelot/RequestBuilder/Builder/HttpRequestBuilder.cs diff --git a/src/Ocelot.Library/RequestBuilder/Builder/IRequestBuilder.cs b/src/Ocelot/RequestBuilder/Builder/IRequestBuilder.cs similarity index 100% rename from src/Ocelot.Library/RequestBuilder/Builder/IRequestBuilder.cs rename to src/Ocelot/RequestBuilder/Builder/IRequestBuilder.cs diff --git a/src/Ocelot.Library/RequestBuilder/Middleware/HttpRequestBuilderMiddleware.cs b/src/Ocelot/RequestBuilder/Middleware/HttpRequestBuilderMiddleware.cs similarity index 100% rename from src/Ocelot.Library/RequestBuilder/Middleware/HttpRequestBuilderMiddleware.cs rename to src/Ocelot/RequestBuilder/Middleware/HttpRequestBuilderMiddleware.cs diff --git a/src/Ocelot.Library/RequestBuilder/Middleware/HttpRequestBuilderMiddlewareExtensions.cs b/src/Ocelot/RequestBuilder/Middleware/HttpRequestBuilderMiddlewareExtensions.cs similarity index 100% rename from src/Ocelot.Library/RequestBuilder/Middleware/HttpRequestBuilderMiddlewareExtensions.cs rename to src/Ocelot/RequestBuilder/Middleware/HttpRequestBuilderMiddlewareExtensions.cs diff --git a/src/Ocelot.Library/RequestBuilder/Request.cs b/src/Ocelot/RequestBuilder/Request.cs similarity index 100% rename from src/Ocelot.Library/RequestBuilder/Request.cs rename to src/Ocelot/RequestBuilder/Request.cs diff --git a/src/Ocelot.Library/Requester/HttpClientHttpRequester.cs b/src/Ocelot/Requester/HttpClientHttpRequester.cs similarity index 100% rename from src/Ocelot.Library/Requester/HttpClientHttpRequester.cs rename to src/Ocelot/Requester/HttpClientHttpRequester.cs diff --git a/src/Ocelot.Library/Requester/IHttpRequester.cs b/src/Ocelot/Requester/IHttpRequester.cs similarity index 100% rename from src/Ocelot.Library/Requester/IHttpRequester.cs rename to src/Ocelot/Requester/IHttpRequester.cs diff --git a/src/Ocelot.Library/Requester/Middleware/HttpRequesterMiddleware.cs b/src/Ocelot/Requester/Middleware/HttpRequesterMiddleware.cs similarity index 100% rename from src/Ocelot.Library/Requester/Middleware/HttpRequesterMiddleware.cs rename to src/Ocelot/Requester/Middleware/HttpRequesterMiddleware.cs diff --git a/src/Ocelot.Library/Requester/Middleware/HttpRequesterMiddlewareExtensions.cs b/src/Ocelot/Requester/Middleware/HttpRequesterMiddlewareExtensions.cs similarity index 100% rename from src/Ocelot.Library/Requester/Middleware/HttpRequesterMiddlewareExtensions.cs rename to src/Ocelot/Requester/Middleware/HttpRequesterMiddlewareExtensions.cs diff --git a/src/Ocelot.Library/Requester/UnableToCompleteRequestError.cs b/src/Ocelot/Requester/UnableToCompleteRequestError.cs similarity index 100% rename from src/Ocelot.Library/Requester/UnableToCompleteRequestError.cs rename to src/Ocelot/Requester/UnableToCompleteRequestError.cs diff --git a/src/Ocelot.Library/Responder/ErrorsToHttpStatusCodeMapper.cs b/src/Ocelot/Responder/ErrorsToHttpStatusCodeMapper.cs similarity index 100% rename from src/Ocelot.Library/Responder/ErrorsToHttpStatusCodeMapper.cs rename to src/Ocelot/Responder/ErrorsToHttpStatusCodeMapper.cs diff --git a/src/Ocelot.Library/Responder/HttpContextResponder.cs b/src/Ocelot/Responder/HttpContextResponder.cs similarity index 100% rename from src/Ocelot.Library/Responder/HttpContextResponder.cs rename to src/Ocelot/Responder/HttpContextResponder.cs diff --git a/src/Ocelot.Library/Responder/IErrorsToHttpStatusCodeMapper.cs b/src/Ocelot/Responder/IErrorsToHttpStatusCodeMapper.cs similarity index 100% rename from src/Ocelot.Library/Responder/IErrorsToHttpStatusCodeMapper.cs rename to src/Ocelot/Responder/IErrorsToHttpStatusCodeMapper.cs diff --git a/src/Ocelot.Library/Responder/IHttpResponder.cs b/src/Ocelot/Responder/IHttpResponder.cs similarity index 100% rename from src/Ocelot.Library/Responder/IHttpResponder.cs rename to src/Ocelot/Responder/IHttpResponder.cs diff --git a/src/Ocelot.Library/Responder/Middleware/HttpResponderMiddleware.cs b/src/Ocelot/Responder/Middleware/HttpResponderMiddleware.cs similarity index 100% rename from src/Ocelot.Library/Responder/Middleware/HttpResponderMiddleware.cs rename to src/Ocelot/Responder/Middleware/HttpResponderMiddleware.cs diff --git a/src/Ocelot.Library/Responder/Middleware/HttpResponderMiddlewareExtensions.cs b/src/Ocelot/Responder/Middleware/HttpResponderMiddlewareExtensions.cs similarity index 100% rename from src/Ocelot.Library/Responder/Middleware/HttpResponderMiddlewareExtensions.cs rename to src/Ocelot/Responder/Middleware/HttpResponderMiddlewareExtensions.cs diff --git a/src/Ocelot.Library/Responses/ErrorResponse.cs b/src/Ocelot/Responses/ErrorResponse.cs similarity index 100% rename from src/Ocelot.Library/Responses/ErrorResponse.cs rename to src/Ocelot/Responses/ErrorResponse.cs diff --git a/src/Ocelot.Library/Responses/ErrorResponseGeneric.cs b/src/Ocelot/Responses/ErrorResponseGeneric.cs similarity index 100% rename from src/Ocelot.Library/Responses/ErrorResponseGeneric.cs rename to src/Ocelot/Responses/ErrorResponseGeneric.cs diff --git a/src/Ocelot.Library/Responses/OkResponse.cs b/src/Ocelot/Responses/OkResponse.cs similarity index 100% rename from src/Ocelot.Library/Responses/OkResponse.cs rename to src/Ocelot/Responses/OkResponse.cs diff --git a/src/Ocelot.Library/Responses/OkResponseGeneric.cs b/src/Ocelot/Responses/OkResponseGeneric.cs similarity index 100% rename from src/Ocelot.Library/Responses/OkResponseGeneric.cs rename to src/Ocelot/Responses/OkResponseGeneric.cs diff --git a/src/Ocelot.Library/Responses/Response.cs b/src/Ocelot/Responses/Response.cs similarity index 100% rename from src/Ocelot.Library/Responses/Response.cs rename to src/Ocelot/Responses/Response.cs diff --git a/src/Ocelot.Library/Responses/ResponseGeneric.cs b/src/Ocelot/Responses/ResponseGeneric.cs similarity index 100% rename from src/Ocelot.Library/Responses/ResponseGeneric.cs rename to src/Ocelot/Responses/ResponseGeneric.cs diff --git a/src/Ocelot.Library/ScopedData/CannotAddDataError.cs b/src/Ocelot/ScopedData/CannotAddDataError.cs similarity index 100% rename from src/Ocelot.Library/ScopedData/CannotAddDataError.cs rename to src/Ocelot/ScopedData/CannotAddDataError.cs diff --git a/src/Ocelot.Library/ScopedData/CannotFindDataError.cs b/src/Ocelot/ScopedData/CannotFindDataError.cs similarity index 100% rename from src/Ocelot.Library/ScopedData/CannotFindDataError.cs rename to src/Ocelot/ScopedData/CannotFindDataError.cs diff --git a/src/Ocelot.Library/ScopedData/IScopedRequestDataRepository.cs b/src/Ocelot/ScopedData/IScopedRequestDataRepository.cs similarity index 100% rename from src/Ocelot.Library/ScopedData/IScopedRequestDataRepository.cs rename to src/Ocelot/ScopedData/IScopedRequestDataRepository.cs diff --git a/src/Ocelot.Library/ScopedData/ScopedRequestDataRepository.cs b/src/Ocelot/ScopedData/ScopedRequestDataRepository.cs similarity index 100% rename from src/Ocelot.Library/ScopedData/ScopedRequestDataRepository.cs rename to src/Ocelot/ScopedData/ScopedRequestDataRepository.cs diff --git a/src/Ocelot/project.json b/src/Ocelot/project.json index 98c5d1e5..f57d8566 100644 --- a/src/Ocelot/project.json +++ b/src/Ocelot/project.json @@ -1,4 +1,4 @@ -{ +{ "version": "1.0.0-*", "dependencies": { @@ -7,7 +7,6 @@ "type": "platform" }, "Microsoft.AspNetCore.Mvc": "1.0.0", - "Microsoft.AspNetCore.Http": "1.0.0", "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", @@ -17,12 +16,19 @@ "Microsoft.Extensions.Logging.Console": "1.0.0", "Microsoft.Extensions.Logging.Debug": "1.0.0", "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", - "Ocelot.Library": "1.0.0-*", - "NetEscapades.Configuration.Yaml": "1.1.0" - }, - - "tools": { - "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final" + "Microsoft.AspNetCore.Http": "1.0.0", + "System.Text.RegularExpressions": "4.1.0", + "YamlDotNet": "3.9.0", + "Microsoft.AspNetCore.Authentication.OAuth": "1.0.0", + "Microsoft.AspNetCore.Authentication.JwtBearer": "1.0.0", + "Microsoft.AspNetCore.Authentication.OpenIdConnect": "1.0.0", + "Microsoft.AspNetCore.Authentication.Cookies": "1.0.0", + "Microsoft.AspNetCore.Authentication.Google": "1.0.0", + "Microsoft.AspNetCore.Authentication.Facebook": "1.0.0", + "Microsoft.AspNetCore.Authentication.Twitter": "1.0.0", + "Microsoft.AspNetCore.Authentication.MicrosoftAccount": "1.0.0", + "Microsoft.AspNetCore.Authentication": "1.0.0", + "IdentityServer4.AccessTokenValidation": "1.0.1-rc2" }, "frameworks": { @@ -32,36 +38,5 @@ "portable-net45+win8" ] } - }, - - "buildOptions": { - "emitEntryPoint": true, - "preserveCompilationContext": true, - "copyToOutput": { - "include": [ - "configuration.yaml" - ] - } - }, - - "runtimeOptions": { - "configProperties": { - "System.GC.Server": true - } - }, - - "publishOptions": { - "include": [ - "wwwroot", - "Views", - "Areas/**/Views", - "appsettings.json", - "web.config", - "configuration.yaml" - ] - }, - - "scripts": { - "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ] - } } +} diff --git a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs index ee8c6a5c..ab202d70 100644 --- a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs +++ b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs @@ -13,6 +13,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; +using Ocelot.ManualTest; using Shouldly; using TestStack.BDDfy; using Xunit; diff --git a/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs b/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs index 33bbe648..44c79872 100644 --- a/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs +++ b/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs @@ -15,6 +15,7 @@ using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; using Ocelot.Library.Configuration.Yaml; +using Ocelot.ManualTest; using Shouldly; using TestStack.BDDfy; using Xunit; diff --git a/test/Ocelot.AcceptanceTests/ReturnsErrorTests.cs b/test/Ocelot.AcceptanceTests/ReturnsErrorTests.cs index dafd69f1..43dbbdb2 100644 --- a/test/Ocelot.AcceptanceTests/ReturnsErrorTests.cs +++ b/test/Ocelot.AcceptanceTests/ReturnsErrorTests.cs @@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Ocelot.Library.Configuration.Yaml; +using Ocelot.ManualTest; using Shouldly; using TestStack.BDDfy; using Xunit; diff --git a/test/Ocelot.AcceptanceTests/RoutingTests.cs b/test/Ocelot.AcceptanceTests/RoutingTests.cs index 22accf7b..42b9fea5 100644 --- a/test/Ocelot.AcceptanceTests/RoutingTests.cs +++ b/test/Ocelot.AcceptanceTests/RoutingTests.cs @@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.TestHost; +using Ocelot.ManualTest; using Shouldly; using TestStack.BDDfy; using Xunit; diff --git a/test/Ocelot.AcceptanceTests/project.json b/test/Ocelot.AcceptanceTests/project.json index e36303e4..56f49099 100644 --- a/test/Ocelot.AcceptanceTests/project.json +++ b/test/Ocelot.AcceptanceTests/project.json @@ -27,11 +27,11 @@ "Microsoft.Extensions.Logging.Debug": "1.0.0", "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", "Microsoft.AspNetCore.Http": "1.0.0", - "Ocelot.Library": "1.0.0-*", + "Ocelot": "1.0.0-*", "xunit": "2.1.0", "dotnet-test-xunit": "2.2.0-preview2-build1029", "Shouldly": "2.8.0", - "Ocelot": "1.0.0-*", + "Ocelot.ManualTest": "1.0.0-*", "Microsoft.AspNetCore.TestHost": "1.0.0", "TestStack.BDDfy": "4.3.1", "YamlDotNet": "3.9.0", diff --git a/src/Ocelot.Library/Ocelot.Library.xproj b/test/Ocelot.ManualTest/Ocelot.ManualTest.xproj similarity index 67% rename from src/Ocelot.Library/Ocelot.Library.xproj rename to test/Ocelot.ManualTest/Ocelot.ManualTest.xproj index d5f127c2..16a89a50 100644 --- a/src/Ocelot.Library/Ocelot.Library.xproj +++ b/test/Ocelot.ManualTest/Ocelot.ManualTest.xproj @@ -7,15 +7,19 @@ - d6df4206-0dba-41d8-884d-c3e08290fdbb - Ocelot.Library + 02bbf4c5-517e-4157-8d21-4b8b9e118b7a + Ocelot.ManualTest .\obj .\bin\ - v4.5 + v4.6.1 2.0 - + + + + + diff --git a/src/Ocelot/Program.cs b/test/Ocelot.ManualTest/Program.cs similarity index 93% rename from src/Ocelot/Program.cs rename to test/Ocelot.ManualTest/Program.cs index 1fdd2ad8..7b6b8535 100644 --- a/src/Ocelot/Program.cs +++ b/test/Ocelot.ManualTest/Program.cs @@ -1,7 +1,7 @@ using System.IO; using Microsoft.AspNetCore.Hosting; -namespace Ocelot +namespace Ocelot.ManualTest { public class Program { diff --git a/src/Ocelot/Properties/launchSettings.json b/test/Ocelot.ManualTest/Properties/launchSettings.json similarity index 76% rename from src/Ocelot/Properties/launchSettings.json rename to test/Ocelot.ManualTest/Properties/launchSettings.json index 7fc77fcd..e2e8ad9a 100644 --- a/src/Ocelot/Properties/launchSettings.json +++ b/test/Ocelot.ManualTest/Properties/launchSettings.json @@ -3,7 +3,7 @@ "windowsAuthentication": false, "anonymousAuthentication": true, "iisExpress": { - "applicationUrl": "http://localhost:1798/", + "applicationUrl": "http://localhost:24620/", "sslPort": 0 } }, @@ -11,15 +11,14 @@ "IIS Express": { "commandName": "IISExpress", "launchBrowser": true, - "launchUrl": "api/values", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } }, - "Ocelot": { + "Ocelot.ManualTest": { "commandName": "Project", "launchBrowser": true, - "launchUrl": "http://localhost:5000/api/values", + "launchUrl": "http://localhost:5000", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } diff --git a/src/Ocelot/Startup.cs b/test/Ocelot.ManualTest/Startup.cs similarity index 93% rename from src/Ocelot/Startup.cs rename to test/Ocelot.ManualTest/Startup.cs index ae9c59cd..c8d12f85 100644 --- a/src/Ocelot/Startup.cs +++ b/test/Ocelot.ManualTest/Startup.cs @@ -3,12 +3,11 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Ocelot.Library.DependencyInjection; +using Ocelot.Library.Middleware; -namespace Ocelot +namespace Ocelot.ManualTest { - using Library.DependencyInjection; - using Library.Middleware; - public class Startup { public Startup(IHostingEnvironment env) diff --git a/src/Ocelot/appsettings.json b/test/Ocelot.ManualTest/appsettings.json similarity index 100% rename from src/Ocelot/appsettings.json rename to test/Ocelot.ManualTest/appsettings.json diff --git a/src/Ocelot/configuration.yaml b/test/Ocelot.ManualTest/configuration.yaml similarity index 100% rename from src/Ocelot/configuration.yaml rename to test/Ocelot.ManualTest/configuration.yaml diff --git a/src/Ocelot.Library/project.json b/test/Ocelot.ManualTest/project.json similarity index 50% rename from src/Ocelot.Library/project.json rename to test/Ocelot.ManualTest/project.json index f57d8566..39425e9d 100644 --- a/src/Ocelot.Library/project.json +++ b/test/Ocelot.ManualTest/project.json @@ -1,4 +1,4 @@ -{ +{ "version": "1.0.0-*", "dependencies": { @@ -7,6 +7,7 @@ "type": "platform" }, "Microsoft.AspNetCore.Mvc": "1.0.0", + "Microsoft.AspNetCore.Http": "1.0.0", "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", @@ -16,19 +17,12 @@ "Microsoft.Extensions.Logging.Console": "1.0.0", "Microsoft.Extensions.Logging.Debug": "1.0.0", "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", - "Microsoft.AspNetCore.Http": "1.0.0", - "System.Text.RegularExpressions": "4.1.0", - "YamlDotNet": "3.9.0", - "Microsoft.AspNetCore.Authentication.OAuth": "1.0.0", - "Microsoft.AspNetCore.Authentication.JwtBearer": "1.0.0", - "Microsoft.AspNetCore.Authentication.OpenIdConnect": "1.0.0", - "Microsoft.AspNetCore.Authentication.Cookies": "1.0.0", - "Microsoft.AspNetCore.Authentication.Google": "1.0.0", - "Microsoft.AspNetCore.Authentication.Facebook": "1.0.0", - "Microsoft.AspNetCore.Authentication.Twitter": "1.0.0", - "Microsoft.AspNetCore.Authentication.MicrosoftAccount": "1.0.0", - "Microsoft.AspNetCore.Authentication": "1.0.0", - "IdentityServer4.AccessTokenValidation": "1.0.1-rc2" + "Ocelot": "1.0.0-*", + "NetEscapades.Configuration.Yaml": "1.1.0" + }, + + "tools": { + "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final" }, "frameworks": { @@ -38,5 +32,36 @@ "portable-net45+win8" ] } + }, + + "buildOptions": { + "emitEntryPoint": true, + "preserveCompilationContext": true, + "copyToOutput": { + "include": [ + "configuration.yaml" + ] + } + }, + + "runtimeOptions": { + "configProperties": { + "System.GC.Server": true + } + }, + + "publishOptions": { + "include": [ + "wwwroot", + "Views", + "Areas/**/Views", + "appsettings.json", + "web.config", + "configuration.yaml" + ] + }, + + "scripts": { + "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ] + } } -} diff --git a/src/Ocelot/web.config b/test/Ocelot.ManualTest/web.config similarity index 100% rename from src/Ocelot/web.config rename to test/Ocelot.ManualTest/web.config diff --git a/test/Ocelot.UnitTests/project.json b/test/Ocelot.UnitTests/project.json index 4c8f0f4f..f747872f 100644 --- a/test/Ocelot.UnitTests/project.json +++ b/test/Ocelot.UnitTests/project.json @@ -19,7 +19,7 @@ "Microsoft.Extensions.Logging.Debug": "1.0.0", "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", "Microsoft.AspNetCore.Http": "1.0.0", - "Ocelot.Library": "1.0.0-*", + "Ocelot": "1.0.0-*", "xunit": "2.1.0", "dotnet-test-xunit": "2.2.0-preview2-build1029", "Shouldly": "2.8.0", From 8b0ceeda5b8668bd9ae2796182f1e8a0e0ed1b7d Mon Sep 17 00:00:00 2001 From: TomPallister Date: Tue, 18 Oct 2016 19:10:09 +0100 Subject: [PATCH 095/183] removed library namespace --- .../Handler/AuthenticationHandler.cs | 2 +- .../Creator/AuthenticationHandlerCreator.cs | 4 +- .../Creator/IAuthenticationHandlerCreator.cs | 4 +- .../Factory/AuthenticationHandlerFactory.cs | 8 ++-- .../Factory/IAuthenticationHandlerFactory.cs | 4 +- ...nableToCreateAuthenticationHandlerError.cs | 4 +- .../SupportedAuthenticationProviders.cs | 2 +- .../Middleware/AuthenticationMiddleware.cs | 14 +++--- ...nticationMiddlewareMiddlewareExtensions.cs | 2 +- .../Configuration/AuthenticationOptions.cs | 6 +-- .../Configuration/Builder/ReRouteBuilder.cs | 2 +- src/Ocelot/Configuration/ClaimToHeader.cs | 2 +- .../Creator/IOcelotConfigurationCreator.cs | 4 +- .../Creator/YamlOcelotConfigurationCreator.cs | 10 ++-- .../Configuration/IOcelotConfiguration.cs | 6 +-- .../Configuration/OcelotConfiguration.cs | 2 +- .../ClaimToHeaderConfigurationParser.cs | 7 ++- .../IClaimToHeaderConfigurationParser.cs | 4 +- .../Parser/InstructionNotForClaimsError.cs | 4 +- .../Parser/NoInstructionsError.cs | 4 +- .../Parser/ParsingConfigurationHeaderError.cs | 4 +- .../Provider/IOcelotConfigurationProvider.cs | 4 +- .../YamlOcelotConfigurationProvider.cs | 8 ++-- src/Ocelot/Configuration/ReRoute.cs | 2 +- .../IOcelotConfigurationRepository.cs | 4 +- .../InMemoryOcelotConfigurationRepository.cs | 4 +- .../ConfigurationValidationResult.cs | 4 +- .../Validator/ConfigurationValidator.cs | 11 ++--- .../DownstreamTemplateAlreadyUsedError.cs | 4 +- .../Validator/IConfigurationValidator.cs | 6 +-- .../UnsupportedAuthenticationProviderError.cs | 4 +- .../Yaml/YamlAuthenticationOptions.cs | 6 +-- .../Configuration/Yaml/YamlConfiguration.cs | 6 +-- src/Ocelot/Configuration/Yaml/YamlReRoute.cs | 6 +-- .../ServiceCollectionExtensions.cs | 47 +++++++++---------- .../DownstreamRouteFinder/DownstreamRoute.cs | 9 ++-- .../Finder/DownstreamRouteFinder.cs | 10 ++-- .../Finder/IDownstreamRouteFinder.cs | 4 +- .../UnableToFindDownstreamRouteError.cs | 4 +- .../DownstreamRouteFinderMiddleware.cs | 8 ++-- ...wnstreamRouteFinderMiddlewareExtensions.cs | 2 +- .../ITemplateVariableNameAndValueFinder.cs | 4 +- .../IUrlPathToUrlTemplateMatcher.cs | 4 +- .../UrlMatcher/RegExUrlMatcher.cs | 4 +- .../TemplateVariableNameAndValue.cs | 2 +- .../TemplateVariableNameAndValueFinder.cs | 4 +- .../UrlMatcher/UrlMatch.cs | 2 +- .../DownstreamUrlCreatorMiddleware.cs | 10 ++-- ...ownstreamUrlCreatorMiddlewareExtensions.cs | 2 +- .../DownstreamUrlTemplateVariableReplacer.cs | 6 +-- ...wnstreamUrlPathTemplateVariableReplacer.cs | 6 +-- src/Ocelot/Errors/Error.cs | 2 +- src/Ocelot/Errors/OcelotErrorCode.cs | 2 +- .../HeaderBuilder/AddHeadersToRequest.cs | 8 ++-- .../HeaderBuilder/IAddHeadersToRequest.cs | 6 +-- .../HttpRequestHeadersBuilderMiddleware.cs | 8 ++-- ...questHeadersBuilderMiddlewareExtensions.cs | 2 +- .../Parser/CannotFindClaimError.cs | 4 +- .../HeaderBuilder/Parser/ClaimsParser.cs | 6 +-- .../HeaderBuilder/Parser/IClaimsParser.cs | 4 +- src/Ocelot/Middleware/OcelotMiddleware.cs | 9 ++-- .../Middleware/OcelotMiddlewareExtensions.cs | 19 ++++---- src/Ocelot/Middleware/UnauthenticatedError.cs | 6 +-- src/Ocelot/Properties/AssemblyInfo.cs | 2 +- .../Builder/HttpRequestBuilder.cs | 4 +- .../RequestBuilder/Builder/IRequestBuilder.cs | 4 +- .../HttpRequestBuilderMiddleware.cs | 8 ++-- .../HttpRequestBuilderMiddlewareExtensions.cs | 2 +- src/Ocelot/RequestBuilder/Request.cs | 8 ++-- .../Requester/HttpClientHttpRequester.cs | 18 +++---- src/Ocelot/Requester/IHttpRequester.cs | 12 ++--- .../Middleware/HttpRequesterMiddleware.cs | 8 ++-- .../HttpRequesterMiddlewareExtensions.cs | 2 +- .../Requester/UnableToCompleteRequestError.cs | 8 ++-- .../Responder/ErrorsToHttpStatusCodeMapper.cs | 12 ++--- src/Ocelot/Responder/HttpContextResponder.cs | 10 ++-- .../IErrorsToHttpStatusCodeMapper.cs | 10 ++-- src/Ocelot/Responder/IHttpResponder.cs | 10 ++-- .../Middleware/HttpResponderMiddleware.cs | 6 +-- .../HttpResponderMiddlewareExtensions.cs | 2 +- src/Ocelot/Responses/ErrorResponse.cs | 8 ++-- src/Ocelot/Responses/ErrorResponseGeneric.cs | 8 ++-- src/Ocelot/Responses/OkResponse.cs | 2 +- src/Ocelot/Responses/OkResponseGeneric.cs | 2 +- src/Ocelot/Responses/Response.cs | 8 ++-- src/Ocelot/Responses/ResponseGeneric.cs | 8 ++-- src/Ocelot/ScopedData/CannotAddDataError.cs | 4 +- src/Ocelot/ScopedData/CannotFindDataError.cs | 4 +- .../IScopedRequestDataRepository.cs | 4 +- .../ScopedData/ScopedRequestDataRepository.cs | 6 +-- .../AuthenticationTests.cs | 2 +- .../ClaimsToHeadersForwardingTests.cs | 2 +- .../ReturnsErrorTests.cs | 2 +- test/Ocelot.AcceptanceTests/RoutingTests.cs | 3 +- test/Ocelot.ManualTest/Startup.cs | 4 +- .../AuthenticationHandlerFactoryTests.cs | 14 +++--- .../AuthenticationMiddlewareTests.cs | 14 +++--- .../ConfigurationHeadersExtractorTests.cs | 8 ++-- .../ConfigurationValidationTests.cs | 7 ++- .../InMemoryConfigurationRepositoryTests.cs | 8 ++-- .../YamlConfigurationCreatorTests.cs | 17 +++---- .../YamlConfigurationProviderTests.cs | 13 +++-- .../DownstreamRouteFinderMiddlewareTests.cs | 14 +++--- .../DownstreamRouteFinderTests.cs | 17 ++++--- .../UrlMatcher/RegExUrlMatcherTests.cs | 4 +- ...TemplateVariableNameAndValueFinderTests.cs | 4 +- .../DownstreamUrlCreatorMiddlewareTests.cs | 14 +++--- ...eamUrlPathTemplateVariableReplacerTests.cs | 10 ++-- .../HeaderBuilder/AddHeadersToRequestTests.cs | 10 ++-- .../HeaderBuilder/ClaimParserTests.cs | 6 +-- ...ttpRequestHeadersBuilderMiddlewareTests.cs | 16 +++---- .../ScopedRequestDataRepositoryTests.cs | 5 +- .../HttpRequestBuilderMiddlewareTests.cs | 10 ++-- .../RequestBuilder/RequestBuilderTests.cs | 7 ++- .../Requester/HttpRequesterMiddlewareTests.cs | 10 ++-- .../ErrorsToHttpStatusCodeMapperTests.cs | 9 ++-- .../Responder/HttpResponderMiddlewareTests.cs | 8 ++-- 117 files changed, 384 insertions(+), 406 deletions(-) diff --git a/src/Ocelot/Authentication/Handler/AuthenticationHandler.cs b/src/Ocelot/Authentication/Handler/AuthenticationHandler.cs index ccdf0a66..029147d6 100644 --- a/src/Ocelot/Authentication/Handler/AuthenticationHandler.cs +++ b/src/Ocelot/Authentication/Handler/AuthenticationHandler.cs @@ -1,6 +1,6 @@ using Microsoft.AspNetCore.Http; -namespace Ocelot.Library.Authentication.Handler +namespace Ocelot.Authentication.Handler { public class AuthenticationHandler { diff --git a/src/Ocelot/Authentication/Handler/Creator/AuthenticationHandlerCreator.cs b/src/Ocelot/Authentication/Handler/Creator/AuthenticationHandlerCreator.cs index 1ff79b20..82765d21 100644 --- a/src/Ocelot/Authentication/Handler/Creator/AuthenticationHandlerCreator.cs +++ b/src/Ocelot/Authentication/Handler/Creator/AuthenticationHandlerCreator.cs @@ -1,9 +1,9 @@ using IdentityServer4.AccessTokenValidation; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; -using Ocelot.Library.Responses; +using Ocelot.Responses; -namespace Ocelot.Library.Authentication.Handler.Creator +namespace Ocelot.Authentication.Handler.Creator { using AuthenticationOptions = Configuration.AuthenticationOptions; diff --git a/src/Ocelot/Authentication/Handler/Creator/IAuthenticationHandlerCreator.cs b/src/Ocelot/Authentication/Handler/Creator/IAuthenticationHandlerCreator.cs index 7d3e64c1..6baa0385 100644 --- a/src/Ocelot/Authentication/Handler/Creator/IAuthenticationHandlerCreator.cs +++ b/src/Ocelot/Authentication/Handler/Creator/IAuthenticationHandlerCreator.cs @@ -1,8 +1,8 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; -using Ocelot.Library.Responses; +using Ocelot.Responses; -namespace Ocelot.Library.Authentication.Handler.Creator +namespace Ocelot.Authentication.Handler.Creator { using AuthenticationOptions = Configuration.AuthenticationOptions; diff --git a/src/Ocelot/Authentication/Handler/Factory/AuthenticationHandlerFactory.cs b/src/Ocelot/Authentication/Handler/Factory/AuthenticationHandlerFactory.cs index 8ef9993c..46594435 100644 --- a/src/Ocelot/Authentication/Handler/Factory/AuthenticationHandlerFactory.cs +++ b/src/Ocelot/Authentication/Handler/Factory/AuthenticationHandlerFactory.cs @@ -1,10 +1,10 @@ using System.Collections.Generic; using Microsoft.AspNetCore.Builder; -using Ocelot.Library.Authentication.Handler.Creator; -using Ocelot.Library.Errors; -using Ocelot.Library.Responses; +using Ocelot.Authentication.Handler.Creator; +using Ocelot.Errors; +using Ocelot.Responses; -namespace Ocelot.Library.Authentication.Handler.Factory +namespace Ocelot.Authentication.Handler.Factory { using AuthenticationOptions = Configuration.AuthenticationOptions; diff --git a/src/Ocelot/Authentication/Handler/Factory/IAuthenticationHandlerFactory.cs b/src/Ocelot/Authentication/Handler/Factory/IAuthenticationHandlerFactory.cs index 97b7d005..abc09ed8 100644 --- a/src/Ocelot/Authentication/Handler/Factory/IAuthenticationHandlerFactory.cs +++ b/src/Ocelot/Authentication/Handler/Factory/IAuthenticationHandlerFactory.cs @@ -1,7 +1,7 @@ using Microsoft.AspNetCore.Builder; -using Ocelot.Library.Responses; +using Ocelot.Responses; -namespace Ocelot.Library.Authentication.Handler.Factory +namespace Ocelot.Authentication.Handler.Factory { using AuthenticationOptions = Configuration.AuthenticationOptions; diff --git a/src/Ocelot/Authentication/Handler/Factory/UnableToCreateAuthenticationHandlerError.cs b/src/Ocelot/Authentication/Handler/Factory/UnableToCreateAuthenticationHandlerError.cs index ba066955..7e18b203 100644 --- a/src/Ocelot/Authentication/Handler/Factory/UnableToCreateAuthenticationHandlerError.cs +++ b/src/Ocelot/Authentication/Handler/Factory/UnableToCreateAuthenticationHandlerError.cs @@ -1,6 +1,6 @@ -using Ocelot.Library.Errors; +using Ocelot.Errors; -namespace Ocelot.Library.Authentication.Handler.Factory +namespace Ocelot.Authentication.Handler.Factory { public class UnableToCreateAuthenticationHandlerError : Error { diff --git a/src/Ocelot/Authentication/Handler/SupportedAuthenticationProviders.cs b/src/Ocelot/Authentication/Handler/SupportedAuthenticationProviders.cs index c2d624fe..2a815ee0 100644 --- a/src/Ocelot/Authentication/Handler/SupportedAuthenticationProviders.cs +++ b/src/Ocelot/Authentication/Handler/SupportedAuthenticationProviders.cs @@ -1,4 +1,4 @@ -namespace Ocelot.Library.Authentication.Handler +namespace Ocelot.Authentication.Handler { public enum SupportedAuthenticationProviders { diff --git a/src/Ocelot/Authentication/Middleware/AuthenticationMiddleware.cs b/src/Ocelot/Authentication/Middleware/AuthenticationMiddleware.cs index 7a74bd6a..9712a6cd 100644 --- a/src/Ocelot/Authentication/Middleware/AuthenticationMiddleware.cs +++ b/src/Ocelot/Authentication/Middleware/AuthenticationMiddleware.cs @@ -2,14 +2,14 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; -using Ocelot.Library.Authentication.Handler.Factory; -using Ocelot.Library.Configuration; -using Ocelot.Library.DownstreamRouteFinder; -using Ocelot.Library.Errors; -using Ocelot.Library.Middleware; -using Ocelot.Library.ScopedData; +using Ocelot.Authentication.Handler.Factory; +using Ocelot.Configuration; +using Ocelot.DownstreamRouteFinder; +using Ocelot.Errors; +using Ocelot.Middleware; +using Ocelot.ScopedData; -namespace Ocelot.Library.Authentication.Middleware +namespace Ocelot.Authentication.Middleware { public class AuthenticationMiddleware : OcelotMiddleware { diff --git a/src/Ocelot/Authentication/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs b/src/Ocelot/Authentication/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs index 9083a1b2..8e1a97e8 100644 --- a/src/Ocelot/Authentication/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs +++ b/src/Ocelot/Authentication/Middleware/AuthenticationMiddlewareMiddlewareExtensions.cs @@ -1,6 +1,6 @@ using Microsoft.AspNetCore.Builder; -namespace Ocelot.Library.Authentication.Middleware +namespace Ocelot.Authentication.Middleware { public static class AuthenticationMiddlewareMiddlewareExtensions { diff --git a/src/Ocelot/Configuration/AuthenticationOptions.cs b/src/Ocelot/Configuration/AuthenticationOptions.cs index 99105c4a..3b36453c 100644 --- a/src/Ocelot/Configuration/AuthenticationOptions.cs +++ b/src/Ocelot/Configuration/AuthenticationOptions.cs @@ -1,7 +1,7 @@ -namespace Ocelot.Library.Configuration -{ - using System.Collections.Generic; +using System.Collections.Generic; +namespace Ocelot.Configuration +{ public class AuthenticationOptions { public AuthenticationOptions(string provider, string providerRootUrl, string scopeName, bool requireHttps, List additionalScopes, string scopeSecret) diff --git a/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs b/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs index c6f1e90a..e369d78d 100644 --- a/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs +++ b/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace Ocelot.Library.Configuration.Builder +namespace Ocelot.Configuration.Builder { public class ReRouteBuilder { diff --git a/src/Ocelot/Configuration/ClaimToHeader.cs b/src/Ocelot/Configuration/ClaimToHeader.cs index d768046a..dce96268 100644 --- a/src/Ocelot/Configuration/ClaimToHeader.cs +++ b/src/Ocelot/Configuration/ClaimToHeader.cs @@ -1,4 +1,4 @@ -namespace Ocelot.Library.Configuration +namespace Ocelot.Configuration { public class ClaimToHeader { diff --git a/src/Ocelot/Configuration/Creator/IOcelotConfigurationCreator.cs b/src/Ocelot/Configuration/Creator/IOcelotConfigurationCreator.cs index 1465c23f..6cc7c2e8 100644 --- a/src/Ocelot/Configuration/Creator/IOcelotConfigurationCreator.cs +++ b/src/Ocelot/Configuration/Creator/IOcelotConfigurationCreator.cs @@ -1,6 +1,6 @@ -using Ocelot.Library.Responses; +using Ocelot.Responses; -namespace Ocelot.Library.Configuration.Creator +namespace Ocelot.Configuration.Creator { public interface IOcelotConfigurationCreator { diff --git a/src/Ocelot/Configuration/Creator/YamlOcelotConfigurationCreator.cs b/src/Ocelot/Configuration/Creator/YamlOcelotConfigurationCreator.cs index 433acc66..b4ff9d15 100644 --- a/src/Ocelot/Configuration/Creator/YamlOcelotConfigurationCreator.cs +++ b/src/Ocelot/Configuration/Creator/YamlOcelotConfigurationCreator.cs @@ -2,12 +2,12 @@ using System; using System.Collections.Generic; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Ocelot.Library.Configuration.Parser; -using Ocelot.Library.Configuration.Validator; -using Ocelot.Library.Configuration.Yaml; -using Ocelot.Library.Responses; +using Ocelot.Configuration.Parser; +using Ocelot.Configuration.Validator; +using Ocelot.Configuration.Yaml; +using Ocelot.Responses; -namespace Ocelot.Library.Configuration.Creator +namespace Ocelot.Configuration.Creator { /// /// Register as singleton diff --git a/src/Ocelot/Configuration/IOcelotConfiguration.cs b/src/Ocelot/Configuration/IOcelotConfiguration.cs index 0e7de3c7..8359a2e1 100644 --- a/src/Ocelot/Configuration/IOcelotConfiguration.cs +++ b/src/Ocelot/Configuration/IOcelotConfiguration.cs @@ -1,7 +1,7 @@ -namespace Ocelot.Library.Configuration -{ - using System.Collections.Generic; +using System.Collections.Generic; +namespace Ocelot.Configuration +{ public interface IOcelotConfiguration { List ReRoutes { get; } diff --git a/src/Ocelot/Configuration/OcelotConfiguration.cs b/src/Ocelot/Configuration/OcelotConfiguration.cs index c6fc0786..3b0858eb 100644 --- a/src/Ocelot/Configuration/OcelotConfiguration.cs +++ b/src/Ocelot/Configuration/OcelotConfiguration.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace Ocelot.Library.Configuration +namespace Ocelot.Configuration { public class OcelotConfiguration : IOcelotConfiguration { diff --git a/src/Ocelot/Configuration/Parser/ClaimToHeaderConfigurationParser.cs b/src/Ocelot/Configuration/Parser/ClaimToHeaderConfigurationParser.cs index e2aa94d5..2d81ec1b 100644 --- a/src/Ocelot/Configuration/Parser/ClaimToHeaderConfigurationParser.cs +++ b/src/Ocelot/Configuration/Parser/ClaimToHeaderConfigurationParser.cs @@ -1,11 +1,10 @@ using System; using System.Collections.Generic; using System.Text.RegularExpressions; -using Ocelot.Library.Errors; -using Ocelot.Library.RequestBuilder; -using Ocelot.Library.Responses; +using Ocelot.Errors; +using Ocelot.Responses; -namespace Ocelot.Library.Configuration.Parser +namespace Ocelot.Configuration.Parser { public class ClaimToHeaderConfigurationParser : IClaimToHeaderConfigurationParser { diff --git a/src/Ocelot/Configuration/Parser/IClaimToHeaderConfigurationParser.cs b/src/Ocelot/Configuration/Parser/IClaimToHeaderConfigurationParser.cs index 633cfcc6..d45cd337 100644 --- a/src/Ocelot/Configuration/Parser/IClaimToHeaderConfigurationParser.cs +++ b/src/Ocelot/Configuration/Parser/IClaimToHeaderConfigurationParser.cs @@ -1,6 +1,6 @@ -using Ocelot.Library.Responses; +using Ocelot.Responses; -namespace Ocelot.Library.Configuration.Parser +namespace Ocelot.Configuration.Parser { public interface IClaimToHeaderConfigurationParser { diff --git a/src/Ocelot/Configuration/Parser/InstructionNotForClaimsError.cs b/src/Ocelot/Configuration/Parser/InstructionNotForClaimsError.cs index 651d9caa..62cf8741 100644 --- a/src/Ocelot/Configuration/Parser/InstructionNotForClaimsError.cs +++ b/src/Ocelot/Configuration/Parser/InstructionNotForClaimsError.cs @@ -1,6 +1,6 @@ -using Ocelot.Library.Errors; +using Ocelot.Errors; -namespace Ocelot.Library.Configuration.Parser +namespace Ocelot.Configuration.Parser { public class InstructionNotForClaimsError : Error { diff --git a/src/Ocelot/Configuration/Parser/NoInstructionsError.cs b/src/Ocelot/Configuration/Parser/NoInstructionsError.cs index 732603a3..09aa0ccb 100644 --- a/src/Ocelot/Configuration/Parser/NoInstructionsError.cs +++ b/src/Ocelot/Configuration/Parser/NoInstructionsError.cs @@ -1,6 +1,6 @@ -using Ocelot.Library.Errors; +using Ocelot.Errors; -namespace Ocelot.Library.Configuration.Parser +namespace Ocelot.Configuration.Parser { public class NoInstructionsError : Error { diff --git a/src/Ocelot/Configuration/Parser/ParsingConfigurationHeaderError.cs b/src/Ocelot/Configuration/Parser/ParsingConfigurationHeaderError.cs index 0b7409bc..9b03c95d 100644 --- a/src/Ocelot/Configuration/Parser/ParsingConfigurationHeaderError.cs +++ b/src/Ocelot/Configuration/Parser/ParsingConfigurationHeaderError.cs @@ -1,7 +1,7 @@ using System; -using Ocelot.Library.Errors; +using Ocelot.Errors; -namespace Ocelot.Library.Configuration.Parser +namespace Ocelot.Configuration.Parser { public class ParsingConfigurationHeaderError : Error { diff --git a/src/Ocelot/Configuration/Provider/IOcelotConfigurationProvider.cs b/src/Ocelot/Configuration/Provider/IOcelotConfigurationProvider.cs index 6918ca6d..30ded2e9 100644 --- a/src/Ocelot/Configuration/Provider/IOcelotConfigurationProvider.cs +++ b/src/Ocelot/Configuration/Provider/IOcelotConfigurationProvider.cs @@ -1,6 +1,6 @@ -using Ocelot.Library.Responses; +using Ocelot.Responses; -namespace Ocelot.Library.Configuration.Provider +namespace Ocelot.Configuration.Provider { public interface IOcelotConfigurationProvider { diff --git a/src/Ocelot/Configuration/Provider/YamlOcelotConfigurationProvider.cs b/src/Ocelot/Configuration/Provider/YamlOcelotConfigurationProvider.cs index bf3faab7..2a92f786 100644 --- a/src/Ocelot/Configuration/Provider/YamlOcelotConfigurationProvider.cs +++ b/src/Ocelot/Configuration/Provider/YamlOcelotConfigurationProvider.cs @@ -1,8 +1,8 @@ -using Ocelot.Library.Configuration.Creator; -using Ocelot.Library.Configuration.Repository; -using Ocelot.Library.Responses; +using Ocelot.Configuration.Creator; +using Ocelot.Configuration.Repository; +using Ocelot.Responses; -namespace Ocelot.Library.Configuration.Provider +namespace Ocelot.Configuration.Provider { /// /// Register as singleton diff --git a/src/Ocelot/Configuration/ReRoute.cs b/src/Ocelot/Configuration/ReRoute.cs index d6df121d..8a67de84 100644 --- a/src/Ocelot/Configuration/ReRoute.cs +++ b/src/Ocelot/Configuration/ReRoute.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace Ocelot.Library.Configuration +namespace Ocelot.Configuration { public class ReRoute { diff --git a/src/Ocelot/Configuration/Repository/IOcelotConfigurationRepository.cs b/src/Ocelot/Configuration/Repository/IOcelotConfigurationRepository.cs index bd99149c..312b5553 100644 --- a/src/Ocelot/Configuration/Repository/IOcelotConfigurationRepository.cs +++ b/src/Ocelot/Configuration/Repository/IOcelotConfigurationRepository.cs @@ -1,6 +1,6 @@ -using Ocelot.Library.Responses; +using Ocelot.Responses; -namespace Ocelot.Library.Configuration.Repository +namespace Ocelot.Configuration.Repository { public interface IOcelotConfigurationRepository { diff --git a/src/Ocelot/Configuration/Repository/InMemoryOcelotConfigurationRepository.cs b/src/Ocelot/Configuration/Repository/InMemoryOcelotConfigurationRepository.cs index f590ce8b..04f34f8d 100644 --- a/src/Ocelot/Configuration/Repository/InMemoryOcelotConfigurationRepository.cs +++ b/src/Ocelot/Configuration/Repository/InMemoryOcelotConfigurationRepository.cs @@ -1,6 +1,6 @@ -using Ocelot.Library.Responses; +using Ocelot.Responses; -namespace Ocelot.Library.Configuration.Repository +namespace Ocelot.Configuration.Repository { /// /// Register as singleton diff --git a/src/Ocelot/Configuration/Validator/ConfigurationValidationResult.cs b/src/Ocelot/Configuration/Validator/ConfigurationValidationResult.cs index 3e40a412..32dec98b 100644 --- a/src/Ocelot/Configuration/Validator/ConfigurationValidationResult.cs +++ b/src/Ocelot/Configuration/Validator/ConfigurationValidationResult.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; -using Ocelot.Library.Errors; +using Ocelot.Errors; -namespace Ocelot.Library.Configuration.Validator +namespace Ocelot.Configuration.Validator { public class ConfigurationValidationResult { diff --git a/src/Ocelot/Configuration/Validator/ConfigurationValidator.cs b/src/Ocelot/Configuration/Validator/ConfigurationValidator.cs index 60beb06f..30b30fc3 100644 --- a/src/Ocelot/Configuration/Validator/ConfigurationValidator.cs +++ b/src/Ocelot/Configuration/Validator/ConfigurationValidator.cs @@ -1,13 +1,12 @@ using System; using System.Collections.Generic; using System.Linq; -using Ocelot.Library.Authentication; -using Ocelot.Library.Authentication.Handler; -using Ocelot.Library.Configuration.Yaml; -using Ocelot.Library.Errors; -using Ocelot.Library.Responses; +using Ocelot.Authentication.Handler; +using Ocelot.Configuration.Yaml; +using Ocelot.Errors; +using Ocelot.Responses; -namespace Ocelot.Library.Configuration.Validator +namespace Ocelot.Configuration.Validator { public class ConfigurationValidator : IConfigurationValidator { diff --git a/src/Ocelot/Configuration/Validator/DownstreamTemplateAlreadyUsedError.cs b/src/Ocelot/Configuration/Validator/DownstreamTemplateAlreadyUsedError.cs index ff9a44fa..b836b1eb 100644 --- a/src/Ocelot/Configuration/Validator/DownstreamTemplateAlreadyUsedError.cs +++ b/src/Ocelot/Configuration/Validator/DownstreamTemplateAlreadyUsedError.cs @@ -1,6 +1,6 @@ -using Ocelot.Library.Errors; +using Ocelot.Errors; -namespace Ocelot.Library.Configuration.Validator +namespace Ocelot.Configuration.Validator { public class DownstreamTemplateAlreadyUsedError : Error { diff --git a/src/Ocelot/Configuration/Validator/IConfigurationValidator.cs b/src/Ocelot/Configuration/Validator/IConfigurationValidator.cs index ddb2831d..10955836 100644 --- a/src/Ocelot/Configuration/Validator/IConfigurationValidator.cs +++ b/src/Ocelot/Configuration/Validator/IConfigurationValidator.cs @@ -1,7 +1,7 @@ -using Ocelot.Library.Configuration.Yaml; -using Ocelot.Library.Responses; +using Ocelot.Configuration.Yaml; +using Ocelot.Responses; -namespace Ocelot.Library.Configuration.Validator +namespace Ocelot.Configuration.Validator { public interface IConfigurationValidator { diff --git a/src/Ocelot/Configuration/Validator/UnsupportedAuthenticationProviderError.cs b/src/Ocelot/Configuration/Validator/UnsupportedAuthenticationProviderError.cs index e963cb17..e4f441bf 100644 --- a/src/Ocelot/Configuration/Validator/UnsupportedAuthenticationProviderError.cs +++ b/src/Ocelot/Configuration/Validator/UnsupportedAuthenticationProviderError.cs @@ -1,6 +1,6 @@ -using Ocelot.Library.Errors; +using Ocelot.Errors; -namespace Ocelot.Library.Configuration.Validator +namespace Ocelot.Configuration.Validator { public class UnsupportedAuthenticationProviderError : Error { diff --git a/src/Ocelot/Configuration/Yaml/YamlAuthenticationOptions.cs b/src/Ocelot/Configuration/Yaml/YamlAuthenticationOptions.cs index 2e9e9b27..16faa03e 100644 --- a/src/Ocelot/Configuration/Yaml/YamlAuthenticationOptions.cs +++ b/src/Ocelot/Configuration/Yaml/YamlAuthenticationOptions.cs @@ -1,7 +1,7 @@ -namespace Ocelot.Library.Configuration.Yaml -{ - using System.Collections.Generic; +using System.Collections.Generic; +namespace Ocelot.Configuration.Yaml +{ public class YamlAuthenticationOptions { public string Provider { get; set; } diff --git a/src/Ocelot/Configuration/Yaml/YamlConfiguration.cs b/src/Ocelot/Configuration/Yaml/YamlConfiguration.cs index dd6fb081..2224f7d5 100644 --- a/src/Ocelot/Configuration/Yaml/YamlConfiguration.cs +++ b/src/Ocelot/Configuration/Yaml/YamlConfiguration.cs @@ -1,7 +1,7 @@ -namespace Ocelot.Library.Configuration.Yaml -{ - using System.Collections.Generic; +using System.Collections.Generic; +namespace Ocelot.Configuration.Yaml +{ public class YamlConfiguration { public YamlConfiguration() diff --git a/src/Ocelot/Configuration/Yaml/YamlReRoute.cs b/src/Ocelot/Configuration/Yaml/YamlReRoute.cs index 675044a3..9c18d7a8 100644 --- a/src/Ocelot/Configuration/Yaml/YamlReRoute.cs +++ b/src/Ocelot/Configuration/Yaml/YamlReRoute.cs @@ -1,7 +1,7 @@ -namespace Ocelot.Library.Configuration.Yaml -{ - using System.Collections.Generic; +using System.Collections.Generic; +namespace Ocelot.Configuration.Yaml +{ public class YamlReRoute { public YamlReRoute() diff --git a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs index 1452923b..38dad7ba 100644 --- a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs @@ -1,31 +1,26 @@ -using Ocelot.Library.Authentication.Handler.Creator; -using Ocelot.Library.Authentication.Handler.Factory; -using Ocelot.Library.Configuration.Creator; -using Ocelot.Library.Configuration.Parser; -using Ocelot.Library.Configuration.Provider; -using Ocelot.Library.Configuration.Repository; -using Ocelot.Library.Configuration.Validator; -using Ocelot.Library.DownstreamRouteFinder.Finder; -using Ocelot.Library.DownstreamRouteFinder.UrlMatcher; -using Ocelot.Library.DownstreamUrlCreator.UrlTemplateReplacer; -using Ocelot.Library.HeaderBuilder; -using Ocelot.Library.HeaderBuilder.Parser; -using Ocelot.Library.RequestBuilder.Builder; -using Ocelot.Library.ScopedData; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Ocelot.Authentication.Handler.Creator; +using Ocelot.Authentication.Handler.Factory; +using Ocelot.Configuration.Creator; +using Ocelot.Configuration.Parser; +using Ocelot.Configuration.Provider; +using Ocelot.Configuration.Repository; +using Ocelot.Configuration.Validator; +using Ocelot.Configuration.Yaml; +using Ocelot.DownstreamRouteFinder.Finder; +using Ocelot.DownstreamRouteFinder.UrlMatcher; +using Ocelot.DownstreamUrlCreator.UrlTemplateReplacer; +using Ocelot.HeaderBuilder; +using Ocelot.HeaderBuilder.Parser; +using Ocelot.RequestBuilder.Builder; +using Ocelot.Requester; +using Ocelot.Responder; +using Ocelot.ScopedData; -namespace Ocelot.Library.DependencyInjection +namespace Ocelot.DependencyInjection { - using Authentication; - using Configuration; - using Configuration.Yaml; - using DownstreamRouteFinder; - using Microsoft.AspNetCore.Http; - using Microsoft.Extensions.Configuration; - using Microsoft.Extensions.DependencyInjection; - using RequestBuilder; - using Requester; - using Responder; - public static class ServiceCollectionExtensions { public static IServiceCollection AddOcelotYamlConfiguration(this IServiceCollection services, IConfigurationRoot configurationRoot) diff --git a/src/Ocelot/DownstreamRouteFinder/DownstreamRoute.cs b/src/Ocelot/DownstreamRouteFinder/DownstreamRoute.cs index 7f7fcc61..7e9f0189 100644 --- a/src/Ocelot/DownstreamRouteFinder/DownstreamRoute.cs +++ b/src/Ocelot/DownstreamRouteFinder/DownstreamRoute.cs @@ -1,10 +1,9 @@ -using Ocelot.Library.DownstreamRouteFinder.UrlMatcher; +using System.Collections.Generic; +using Ocelot.Configuration; +using Ocelot.DownstreamRouteFinder.UrlMatcher; -namespace Ocelot.Library.DownstreamRouteFinder +namespace Ocelot.DownstreamRouteFinder { - using System.Collections.Generic; - using Configuration; - public class DownstreamRoute { public DownstreamRoute(List templateVariableNameAndValues, ReRoute reRoute) diff --git a/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs b/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs index 340ca4d7..39164068 100644 --- a/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs +++ b/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs @@ -1,12 +1,12 @@ using System; using System.Collections.Generic; using System.Linq; -using Ocelot.Library.Configuration.Provider; -using Ocelot.Library.DownstreamRouteFinder.UrlMatcher; -using Ocelot.Library.Errors; -using Ocelot.Library.Responses; +using Ocelot.Configuration.Provider; +using Ocelot.DownstreamRouteFinder.UrlMatcher; +using Ocelot.Errors; +using Ocelot.Responses; -namespace Ocelot.Library.DownstreamRouteFinder.Finder +namespace Ocelot.DownstreamRouteFinder.Finder { public class DownstreamRouteFinder : IDownstreamRouteFinder { diff --git a/src/Ocelot/DownstreamRouteFinder/Finder/IDownstreamRouteFinder.cs b/src/Ocelot/DownstreamRouteFinder/Finder/IDownstreamRouteFinder.cs index 3e0cafb4..e351ab2f 100644 --- a/src/Ocelot/DownstreamRouteFinder/Finder/IDownstreamRouteFinder.cs +++ b/src/Ocelot/DownstreamRouteFinder/Finder/IDownstreamRouteFinder.cs @@ -1,6 +1,6 @@ -using Ocelot.Library.Responses; +using Ocelot.Responses; -namespace Ocelot.Library.DownstreamRouteFinder.Finder +namespace Ocelot.DownstreamRouteFinder.Finder { public interface IDownstreamRouteFinder { diff --git a/src/Ocelot/DownstreamRouteFinder/Finder/UnableToFindDownstreamRouteError.cs b/src/Ocelot/DownstreamRouteFinder/Finder/UnableToFindDownstreamRouteError.cs index 92595ea2..d73587b1 100644 --- a/src/Ocelot/DownstreamRouteFinder/Finder/UnableToFindDownstreamRouteError.cs +++ b/src/Ocelot/DownstreamRouteFinder/Finder/UnableToFindDownstreamRouteError.cs @@ -1,6 +1,6 @@ -using Ocelot.Library.Errors; +using Ocelot.Errors; -namespace Ocelot.Library.DownstreamRouteFinder.Finder +namespace Ocelot.DownstreamRouteFinder.Finder { public class UnableToFindDownstreamRouteError : Error { diff --git a/src/Ocelot/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddleware.cs b/src/Ocelot/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddleware.cs index 9dddc81a..e39c3225 100644 --- a/src/Ocelot/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddleware.cs +++ b/src/Ocelot/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddleware.cs @@ -1,10 +1,10 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; -using Ocelot.Library.DownstreamRouteFinder.Finder; -using Ocelot.Library.Middleware; -using Ocelot.Library.ScopedData; +using Ocelot.DownstreamRouteFinder.Finder; +using Ocelot.Middleware; +using Ocelot.ScopedData; -namespace Ocelot.Library.DownstreamRouteFinder.Middleware +namespace Ocelot.DownstreamRouteFinder.Middleware { public class DownstreamRouteFinderMiddleware : OcelotMiddleware { diff --git a/src/Ocelot/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs b/src/Ocelot/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs index e07cbcc5..0cd27758 100644 --- a/src/Ocelot/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs +++ b/src/Ocelot/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddlewareExtensions.cs @@ -1,6 +1,6 @@ using Microsoft.AspNetCore.Builder; -namespace Ocelot.Library.DownstreamRouteFinder.Middleware +namespace Ocelot.DownstreamRouteFinder.Middleware { public static class DownstreamRouteFinderMiddlewareExtensions { diff --git a/src/Ocelot/DownstreamRouteFinder/UrlMatcher/ITemplateVariableNameAndValueFinder.cs b/src/Ocelot/DownstreamRouteFinder/UrlMatcher/ITemplateVariableNameAndValueFinder.cs index 31136199..638b2c40 100644 --- a/src/Ocelot/DownstreamRouteFinder/UrlMatcher/ITemplateVariableNameAndValueFinder.cs +++ b/src/Ocelot/DownstreamRouteFinder/UrlMatcher/ITemplateVariableNameAndValueFinder.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; -using Ocelot.Library.Responses; +using Ocelot.Responses; -namespace Ocelot.Library.DownstreamRouteFinder.UrlMatcher +namespace Ocelot.DownstreamRouteFinder.UrlMatcher { public interface ITemplateVariableNameAndValueFinder { diff --git a/src/Ocelot/DownstreamRouteFinder/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs b/src/Ocelot/DownstreamRouteFinder/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs index 86af26bb..6c8956a2 100644 --- a/src/Ocelot/DownstreamRouteFinder/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs +++ b/src/Ocelot/DownstreamRouteFinder/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs @@ -1,6 +1,6 @@ -using Ocelot.Library.Responses; +using Ocelot.Responses; -namespace Ocelot.Library.DownstreamRouteFinder.UrlMatcher +namespace Ocelot.DownstreamRouteFinder.UrlMatcher { public interface IUrlPathToUrlTemplateMatcher { diff --git a/src/Ocelot/DownstreamRouteFinder/UrlMatcher/RegExUrlMatcher.cs b/src/Ocelot/DownstreamRouteFinder/UrlMatcher/RegExUrlMatcher.cs index 0005c81a..415ee556 100644 --- a/src/Ocelot/DownstreamRouteFinder/UrlMatcher/RegExUrlMatcher.cs +++ b/src/Ocelot/DownstreamRouteFinder/UrlMatcher/RegExUrlMatcher.cs @@ -1,7 +1,7 @@ using System.Text.RegularExpressions; -using Ocelot.Library.Responses; +using Ocelot.Responses; -namespace Ocelot.Library.DownstreamRouteFinder.UrlMatcher +namespace Ocelot.DownstreamRouteFinder.UrlMatcher { public class RegExUrlMatcher : IUrlPathToUrlTemplateMatcher { diff --git a/src/Ocelot/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValue.cs b/src/Ocelot/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValue.cs index c2283720..7ddd2448 100644 --- a/src/Ocelot/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValue.cs +++ b/src/Ocelot/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValue.cs @@ -1,4 +1,4 @@ -namespace Ocelot.Library.DownstreamRouteFinder.UrlMatcher +namespace Ocelot.DownstreamRouteFinder.UrlMatcher { public class TemplateVariableNameAndValue { diff --git a/src/Ocelot/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValueFinder.cs b/src/Ocelot/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValueFinder.cs index cffada4c..f2d3fa79 100644 --- a/src/Ocelot/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValueFinder.cs +++ b/src/Ocelot/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValueFinder.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; -using Ocelot.Library.Responses; +using Ocelot.Responses; -namespace Ocelot.Library.DownstreamRouteFinder.UrlMatcher +namespace Ocelot.DownstreamRouteFinder.UrlMatcher { public class TemplateVariableNameAndValueFinder : ITemplateVariableNameAndValueFinder { diff --git a/src/Ocelot/DownstreamRouteFinder/UrlMatcher/UrlMatch.cs b/src/Ocelot/DownstreamRouteFinder/UrlMatcher/UrlMatch.cs index 55ebb807..aa2a6f06 100644 --- a/src/Ocelot/DownstreamRouteFinder/UrlMatcher/UrlMatch.cs +++ b/src/Ocelot/DownstreamRouteFinder/UrlMatcher/UrlMatch.cs @@ -1,4 +1,4 @@ -namespace Ocelot.Library.DownstreamRouteFinder.UrlMatcher +namespace Ocelot.DownstreamRouteFinder.UrlMatcher { public class UrlMatch { diff --git a/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs b/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs index 604c9132..ff19ccfb 100644 --- a/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs +++ b/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs @@ -1,11 +1,11 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; -using Ocelot.Library.DownstreamRouteFinder; -using Ocelot.Library.DownstreamUrlCreator.UrlTemplateReplacer; -using Ocelot.Library.Middleware; -using Ocelot.Library.ScopedData; +using Ocelot.DownstreamRouteFinder; +using Ocelot.DownstreamUrlCreator.UrlTemplateReplacer; +using Ocelot.Middleware; +using Ocelot.ScopedData; -namespace Ocelot.Library.DownstreamUrlCreator.Middleware +namespace Ocelot.DownstreamUrlCreator.Middleware { public class DownstreamUrlCreatorMiddleware : OcelotMiddleware { diff --git a/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs b/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs index 63d847d2..34bfaa54 100644 --- a/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs +++ b/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddlewareExtensions.cs @@ -1,6 +1,6 @@ using Microsoft.AspNetCore.Builder; -namespace Ocelot.Library.DownstreamUrlCreator.Middleware +namespace Ocelot.DownstreamUrlCreator.Middleware { public static class DownstreamUrlCreatorMiddlewareExtensions { diff --git a/src/Ocelot/DownstreamUrlCreator/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs b/src/Ocelot/DownstreamUrlCreator/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs index b8ff44d9..83570008 100644 --- a/src/Ocelot/DownstreamUrlCreator/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs +++ b/src/Ocelot/DownstreamUrlCreator/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs @@ -1,8 +1,8 @@ using System.Text; -using Ocelot.Library.DownstreamRouteFinder; -using Ocelot.Library.Responses; +using Ocelot.DownstreamRouteFinder; +using Ocelot.Responses; -namespace Ocelot.Library.DownstreamUrlCreator.UrlTemplateReplacer +namespace Ocelot.DownstreamUrlCreator.UrlTemplateReplacer { public class DownstreamUrlTemplateVariableReplacer : IDownstreamUrlTemplateVariableReplacer { diff --git a/src/Ocelot/DownstreamUrlCreator/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs b/src/Ocelot/DownstreamUrlCreator/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs index ba92174a..83b93d00 100644 --- a/src/Ocelot/DownstreamUrlCreator/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs +++ b/src/Ocelot/DownstreamUrlCreator/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs @@ -1,7 +1,7 @@ -using Ocelot.Library.DownstreamRouteFinder; -using Ocelot.Library.Responses; +using Ocelot.DownstreamRouteFinder; +using Ocelot.Responses; -namespace Ocelot.Library.DownstreamUrlCreator.UrlTemplateReplacer +namespace Ocelot.DownstreamUrlCreator.UrlTemplateReplacer { public interface IDownstreamUrlTemplateVariableReplacer { diff --git a/src/Ocelot/Errors/Error.cs b/src/Ocelot/Errors/Error.cs index 4c4d96d5..25a9f5d4 100644 --- a/src/Ocelot/Errors/Error.cs +++ b/src/Ocelot/Errors/Error.cs @@ -1,4 +1,4 @@ -namespace Ocelot.Library.Errors +namespace Ocelot.Errors { public abstract class Error { diff --git a/src/Ocelot/Errors/OcelotErrorCode.cs b/src/Ocelot/Errors/OcelotErrorCode.cs index 643f00ef..28679449 100644 --- a/src/Ocelot/Errors/OcelotErrorCode.cs +++ b/src/Ocelot/Errors/OcelotErrorCode.cs @@ -1,4 +1,4 @@ -namespace Ocelot.Library.Errors +namespace Ocelot.Errors { public enum OcelotErrorCode { diff --git a/src/Ocelot/HeaderBuilder/AddHeadersToRequest.cs b/src/Ocelot/HeaderBuilder/AddHeadersToRequest.cs index 6c2634fa..b6efc334 100644 --- a/src/Ocelot/HeaderBuilder/AddHeadersToRequest.cs +++ b/src/Ocelot/HeaderBuilder/AddHeadersToRequest.cs @@ -2,11 +2,11 @@ using System.Linq; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; -using Ocelot.Library.Configuration; -using Ocelot.Library.HeaderBuilder.Parser; -using Ocelot.Library.Responses; +using Ocelot.Configuration; +using Ocelot.HeaderBuilder.Parser; +using Ocelot.Responses; -namespace Ocelot.Library.HeaderBuilder +namespace Ocelot.HeaderBuilder { public class AddHeadersToRequest : IAddHeadersToRequest { diff --git a/src/Ocelot/HeaderBuilder/IAddHeadersToRequest.cs b/src/Ocelot/HeaderBuilder/IAddHeadersToRequest.cs index c958f199..3c5cf49c 100644 --- a/src/Ocelot/HeaderBuilder/IAddHeadersToRequest.cs +++ b/src/Ocelot/HeaderBuilder/IAddHeadersToRequest.cs @@ -1,9 +1,9 @@ using System.Collections.Generic; using Microsoft.AspNetCore.Http; -using Ocelot.Library.Configuration; -using Ocelot.Library.Responses; +using Ocelot.Configuration; +using Ocelot.Responses; -namespace Ocelot.Library.HeaderBuilder +namespace Ocelot.HeaderBuilder { public interface IAddHeadersToRequest { diff --git a/src/Ocelot/HeaderBuilder/Middleware/HttpRequestHeadersBuilderMiddleware.cs b/src/Ocelot/HeaderBuilder/Middleware/HttpRequestHeadersBuilderMiddleware.cs index 001a424b..a718a7ba 100644 --- a/src/Ocelot/HeaderBuilder/Middleware/HttpRequestHeadersBuilderMiddleware.cs +++ b/src/Ocelot/HeaderBuilder/Middleware/HttpRequestHeadersBuilderMiddleware.cs @@ -1,11 +1,11 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; -using Ocelot.Library.DownstreamRouteFinder; -using Ocelot.Library.Middleware; -using Ocelot.Library.ScopedData; +using Ocelot.DownstreamRouteFinder; +using Ocelot.Middleware; +using Ocelot.ScopedData; -namespace Ocelot.Library.HeaderBuilder.Middleware +namespace Ocelot.HeaderBuilder.Middleware { public class HttpRequestHeadersBuilderMiddleware : OcelotMiddleware { diff --git a/src/Ocelot/HeaderBuilder/Middleware/HttpRequestHeadersBuilderMiddlewareExtensions.cs b/src/Ocelot/HeaderBuilder/Middleware/HttpRequestHeadersBuilderMiddlewareExtensions.cs index acb1cd28..9b58408a 100644 --- a/src/Ocelot/HeaderBuilder/Middleware/HttpRequestHeadersBuilderMiddlewareExtensions.cs +++ b/src/Ocelot/HeaderBuilder/Middleware/HttpRequestHeadersBuilderMiddlewareExtensions.cs @@ -1,6 +1,6 @@ using Microsoft.AspNetCore.Builder; -namespace Ocelot.Library.HeaderBuilder.Middleware +namespace Ocelot.HeaderBuilder.Middleware { public static class HttpRequestHeadersBuilderMiddlewareExtensions { diff --git a/src/Ocelot/HeaderBuilder/Parser/CannotFindClaimError.cs b/src/Ocelot/HeaderBuilder/Parser/CannotFindClaimError.cs index f3270269..88f79075 100644 --- a/src/Ocelot/HeaderBuilder/Parser/CannotFindClaimError.cs +++ b/src/Ocelot/HeaderBuilder/Parser/CannotFindClaimError.cs @@ -1,6 +1,6 @@ -using Ocelot.Library.Errors; +using Ocelot.Errors; -namespace Ocelot.Library.HeaderBuilder.Parser +namespace Ocelot.HeaderBuilder.Parser { public class CannotFindClaimError : Error { diff --git a/src/Ocelot/HeaderBuilder/Parser/ClaimsParser.cs b/src/Ocelot/HeaderBuilder/Parser/ClaimsParser.cs index 5ef6eab6..c54653b1 100644 --- a/src/Ocelot/HeaderBuilder/Parser/ClaimsParser.cs +++ b/src/Ocelot/HeaderBuilder/Parser/ClaimsParser.cs @@ -1,10 +1,10 @@ using System.Collections.Generic; using System.Linq; using System.Security.Claims; -using Ocelot.Library.Errors; -using Ocelot.Library.Responses; +using Ocelot.Errors; +using Ocelot.Responses; -namespace Ocelot.Library.HeaderBuilder.Parser +namespace Ocelot.HeaderBuilder.Parser { public class ClaimsParser : IClaimsParser { diff --git a/src/Ocelot/HeaderBuilder/Parser/IClaimsParser.cs b/src/Ocelot/HeaderBuilder/Parser/IClaimsParser.cs index 7f662d59..7e563be8 100644 --- a/src/Ocelot/HeaderBuilder/Parser/IClaimsParser.cs +++ b/src/Ocelot/HeaderBuilder/Parser/IClaimsParser.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; using System.Security.Claims; -using Ocelot.Library.Responses; +using Ocelot.Responses; -namespace Ocelot.Library.HeaderBuilder.Parser +namespace Ocelot.HeaderBuilder.Parser { public interface IClaimsParser { diff --git a/src/Ocelot/Middleware/OcelotMiddleware.cs b/src/Ocelot/Middleware/OcelotMiddleware.cs index eeccc65e..729493ce 100644 --- a/src/Ocelot/Middleware/OcelotMiddleware.cs +++ b/src/Ocelot/Middleware/OcelotMiddleware.cs @@ -1,10 +1,9 @@ -using Ocelot.Library.ScopedData; +using System.Collections.Generic; +using Ocelot.Errors; +using Ocelot.ScopedData; -namespace Ocelot.Library.Middleware +namespace Ocelot.Middleware { - using System.Collections.Generic; - using Errors; - public abstract class OcelotMiddleware { private readonly IScopedRequestDataRepository _scopedRequestDataRepository; diff --git a/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs b/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs index 3fb320bd..148dc8fe 100644 --- a/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs +++ b/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs @@ -1,15 +1,14 @@ -using Ocelot.Library.Authentication.Middleware; -using Ocelot.Library.DownstreamRouteFinder.Middleware; -using Ocelot.Library.DownstreamUrlCreator.Middleware; -using Ocelot.Library.HeaderBuilder.Middleware; -using Ocelot.Library.RequestBuilder.Middleware; -using Ocelot.Library.Requester.Middleware; -using Ocelot.Library.Responder.Middleware; +using Microsoft.AspNetCore.Builder; +using Ocelot.Authentication.Middleware; +using Ocelot.DownstreamRouteFinder.Middleware; +using Ocelot.DownstreamUrlCreator.Middleware; +using Ocelot.HeaderBuilder.Middleware; +using Ocelot.RequestBuilder.Middleware; +using Ocelot.Requester.Middleware; +using Ocelot.Responder.Middleware; -namespace Ocelot.Library.Middleware +namespace Ocelot.Middleware { - using Microsoft.AspNetCore.Builder; - public static class OcelotMiddlewareExtensions { public static IApplicationBuilder UseOcelot(this IApplicationBuilder builder) diff --git a/src/Ocelot/Middleware/UnauthenticatedError.cs b/src/Ocelot/Middleware/UnauthenticatedError.cs index a8e29033..c8b04039 100644 --- a/src/Ocelot/Middleware/UnauthenticatedError.cs +++ b/src/Ocelot/Middleware/UnauthenticatedError.cs @@ -1,7 +1,7 @@ -namespace Ocelot.Library.Middleware -{ - using Errors; +using Ocelot.Errors; +namespace Ocelot.Middleware +{ public class UnauthenticatedError : Error { public UnauthenticatedError(string message) : base(message, OcelotErrorCode.UnauthenticatedError) diff --git a/src/Ocelot/Properties/AssemblyInfo.cs b/src/Ocelot/Properties/AssemblyInfo.cs index cf59e825..ad12027e 100644 --- a/src/Ocelot/Properties/AssemblyInfo.cs +++ b/src/Ocelot/Properties/AssemblyInfo.cs @@ -7,7 +7,7 @@ using System.Runtime.InteropServices; // associated with an assembly. [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Ocelot.Library")] +[assembly: AssemblyProduct("Ocelot")] [assembly: AssemblyTrademark("")] // Setting ComVisible to false makes the types in this assembly not visible diff --git a/src/Ocelot/RequestBuilder/Builder/HttpRequestBuilder.cs b/src/Ocelot/RequestBuilder/Builder/HttpRequestBuilder.cs index b1846e6e..bda2914d 100644 --- a/src/Ocelot/RequestBuilder/Builder/HttpRequestBuilder.cs +++ b/src/Ocelot/RequestBuilder/Builder/HttpRequestBuilder.cs @@ -5,9 +5,9 @@ using System.Net.Http; using System.Net.Http.Headers; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; -using Ocelot.Library.Responses; +using Ocelot.Responses; -namespace Ocelot.Library.RequestBuilder.Builder +namespace Ocelot.RequestBuilder.Builder { public class HttpRequestBuilder : IRequestBuilder { diff --git a/src/Ocelot/RequestBuilder/Builder/IRequestBuilder.cs b/src/Ocelot/RequestBuilder/Builder/IRequestBuilder.cs index a2c51eb5..7ab5c20b 100644 --- a/src/Ocelot/RequestBuilder/Builder/IRequestBuilder.cs +++ b/src/Ocelot/RequestBuilder/Builder/IRequestBuilder.cs @@ -1,9 +1,9 @@ using System.IO; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; -using Ocelot.Library.Responses; +using Ocelot.Responses; -namespace Ocelot.Library.RequestBuilder.Builder +namespace Ocelot.RequestBuilder.Builder { public interface IRequestBuilder { diff --git a/src/Ocelot/RequestBuilder/Middleware/HttpRequestBuilderMiddleware.cs b/src/Ocelot/RequestBuilder/Middleware/HttpRequestBuilderMiddleware.cs index 3d3be229..3c21413f 100644 --- a/src/Ocelot/RequestBuilder/Middleware/HttpRequestBuilderMiddleware.cs +++ b/src/Ocelot/RequestBuilder/Middleware/HttpRequestBuilderMiddleware.cs @@ -1,10 +1,10 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; -using Ocelot.Library.Middleware; -using Ocelot.Library.RequestBuilder.Builder; -using Ocelot.Library.ScopedData; +using Ocelot.Middleware; +using Ocelot.RequestBuilder.Builder; +using Ocelot.ScopedData; -namespace Ocelot.Library.RequestBuilder.Middleware +namespace Ocelot.RequestBuilder.Middleware { public class HttpRequestBuilderMiddleware : OcelotMiddleware { diff --git a/src/Ocelot/RequestBuilder/Middleware/HttpRequestBuilderMiddlewareExtensions.cs b/src/Ocelot/RequestBuilder/Middleware/HttpRequestBuilderMiddlewareExtensions.cs index b82d437e..3a4c6b26 100644 --- a/src/Ocelot/RequestBuilder/Middleware/HttpRequestBuilderMiddlewareExtensions.cs +++ b/src/Ocelot/RequestBuilder/Middleware/HttpRequestBuilderMiddlewareExtensions.cs @@ -1,6 +1,6 @@ using Microsoft.AspNetCore.Builder; -namespace Ocelot.Library.RequestBuilder.Middleware +namespace Ocelot.RequestBuilder.Middleware { public static class HttpRequestBuilderMiddlewareExtensions { diff --git a/src/Ocelot/RequestBuilder/Request.cs b/src/Ocelot/RequestBuilder/Request.cs index dae1243d..99149497 100644 --- a/src/Ocelot/RequestBuilder/Request.cs +++ b/src/Ocelot/RequestBuilder/Request.cs @@ -1,8 +1,8 @@ -namespace Ocelot.Library.RequestBuilder -{ - using System.Net; - using System.Net.Http; +using System.Net; +using System.Net.Http; +namespace Ocelot.RequestBuilder +{ public class Request { public Request(HttpRequestMessage httpRequestMessage, CookieContainer cookieContainer) diff --git a/src/Ocelot/Requester/HttpClientHttpRequester.cs b/src/Ocelot/Requester/HttpClientHttpRequester.cs index 534244b3..19b3b6fd 100644 --- a/src/Ocelot/Requester/HttpClientHttpRequester.cs +++ b/src/Ocelot/Requester/HttpClientHttpRequester.cs @@ -1,13 +1,13 @@ -namespace Ocelot.Library.Requester -{ - using System; - using System.Collections.Generic; - using System.Net.Http; - using System.Threading.Tasks; - using Errors; - using RequestBuilder; - using Responses; +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Threading.Tasks; +using Ocelot.Errors; +using Ocelot.RequestBuilder; +using Ocelot.Responses; +namespace Ocelot.Requester +{ public class HttpClientHttpRequester : IHttpRequester { public async Task> GetResponse(Request request) diff --git a/src/Ocelot/Requester/IHttpRequester.cs b/src/Ocelot/Requester/IHttpRequester.cs index 8b195fe8..6072b0e5 100644 --- a/src/Ocelot/Requester/IHttpRequester.cs +++ b/src/Ocelot/Requester/IHttpRequester.cs @@ -1,10 +1,10 @@ -namespace Ocelot.Library.Requester -{ - using System.Net.Http; - using System.Threading.Tasks; - using RequestBuilder; - using Responses; +using System.Net.Http; +using System.Threading.Tasks; +using Ocelot.RequestBuilder; +using Ocelot.Responses; +namespace Ocelot.Requester +{ public interface IHttpRequester { Task> GetResponse(Request request); diff --git a/src/Ocelot/Requester/Middleware/HttpRequesterMiddleware.cs b/src/Ocelot/Requester/Middleware/HttpRequesterMiddleware.cs index b24995f4..31f3ea86 100644 --- a/src/Ocelot/Requester/Middleware/HttpRequesterMiddleware.cs +++ b/src/Ocelot/Requester/Middleware/HttpRequesterMiddleware.cs @@ -1,10 +1,10 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; -using Ocelot.Library.Middleware; -using Ocelot.Library.RequestBuilder; -using Ocelot.Library.ScopedData; +using Ocelot.Middleware; +using Ocelot.RequestBuilder; +using Ocelot.ScopedData; -namespace Ocelot.Library.Requester.Middleware +namespace Ocelot.Requester.Middleware { public class HttpRequesterMiddleware : OcelotMiddleware { diff --git a/src/Ocelot/Requester/Middleware/HttpRequesterMiddlewareExtensions.cs b/src/Ocelot/Requester/Middleware/HttpRequesterMiddlewareExtensions.cs index 73af0cd2..6a3d5bb8 100644 --- a/src/Ocelot/Requester/Middleware/HttpRequesterMiddlewareExtensions.cs +++ b/src/Ocelot/Requester/Middleware/HttpRequesterMiddlewareExtensions.cs @@ -1,6 +1,6 @@ using Microsoft.AspNetCore.Builder; -namespace Ocelot.Library.Requester.Middleware +namespace Ocelot.Requester.Middleware { public static class HttpRequesterMiddlewareExtensions { diff --git a/src/Ocelot/Requester/UnableToCompleteRequestError.cs b/src/Ocelot/Requester/UnableToCompleteRequestError.cs index 33d3d18e..d085cd1c 100644 --- a/src/Ocelot/Requester/UnableToCompleteRequestError.cs +++ b/src/Ocelot/Requester/UnableToCompleteRequestError.cs @@ -1,8 +1,8 @@ -namespace Ocelot.Library.Requester -{ - using System; - using Errors; +using System; +using Ocelot.Errors; +namespace Ocelot.Requester +{ public class UnableToCompleteRequestError : Error { public UnableToCompleteRequestError(Exception exception) diff --git a/src/Ocelot/Responder/ErrorsToHttpStatusCodeMapper.cs b/src/Ocelot/Responder/ErrorsToHttpStatusCodeMapper.cs index 902c5ac8..d7ab7090 100644 --- a/src/Ocelot/Responder/ErrorsToHttpStatusCodeMapper.cs +++ b/src/Ocelot/Responder/ErrorsToHttpStatusCodeMapper.cs @@ -1,10 +1,10 @@ -namespace Ocelot.Library.Responder -{ - using System.Collections.Generic; - using System.Linq; - using Errors; - using Responses; +using System.Collections.Generic; +using System.Linq; +using Ocelot.Errors; +using Ocelot.Responses; +namespace Ocelot.Responder +{ public class ErrorsToHttpStatusCodeMapper : IErrorsToHttpStatusCodeMapper { public Response Map(List errors) diff --git a/src/Ocelot/Responder/HttpContextResponder.cs b/src/Ocelot/Responder/HttpContextResponder.cs index d092d36a..46779deb 100644 --- a/src/Ocelot/Responder/HttpContextResponder.cs +++ b/src/Ocelot/Responder/HttpContextResponder.cs @@ -1,9 +1,9 @@ -namespace Ocelot.Library.Responder -{ - using System.Net.Http; - using System.Threading.Tasks; - using Microsoft.AspNetCore.Http; +using System.Net.Http; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +namespace Ocelot.Responder +{ /// /// Cannot unit test things in this class due to methods not being implemented /// on .net concretes used for testing diff --git a/src/Ocelot/Responder/IErrorsToHttpStatusCodeMapper.cs b/src/Ocelot/Responder/IErrorsToHttpStatusCodeMapper.cs index 507b4b24..b4b610d9 100644 --- a/src/Ocelot/Responder/IErrorsToHttpStatusCodeMapper.cs +++ b/src/Ocelot/Responder/IErrorsToHttpStatusCodeMapper.cs @@ -1,9 +1,9 @@ -namespace Ocelot.Library.Responder -{ - using System.Collections.Generic; - using Errors; - using Responses; +using System.Collections.Generic; +using Ocelot.Errors; +using Ocelot.Responses; +namespace Ocelot.Responder +{ public interface IErrorsToHttpStatusCodeMapper { Response Map(List errors); diff --git a/src/Ocelot/Responder/IHttpResponder.cs b/src/Ocelot/Responder/IHttpResponder.cs index 972bb70a..4cf6d1b2 100644 --- a/src/Ocelot/Responder/IHttpResponder.cs +++ b/src/Ocelot/Responder/IHttpResponder.cs @@ -1,9 +1,9 @@ -namespace Ocelot.Library.Responder -{ - using System.Net.Http; - using System.Threading.Tasks; - using Microsoft.AspNetCore.Http; +using System.Net.Http; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +namespace Ocelot.Responder +{ public interface IHttpResponder { Task CreateResponse(HttpContext context, HttpResponseMessage response); diff --git a/src/Ocelot/Responder/Middleware/HttpResponderMiddleware.cs b/src/Ocelot/Responder/Middleware/HttpResponderMiddleware.cs index b822d6b7..a9223a5f 100644 --- a/src/Ocelot/Responder/Middleware/HttpResponderMiddleware.cs +++ b/src/Ocelot/Responder/Middleware/HttpResponderMiddleware.cs @@ -1,10 +1,10 @@ using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; -using Ocelot.Library.Middleware; -using Ocelot.Library.ScopedData; +using Ocelot.Middleware; +using Ocelot.ScopedData; -namespace Ocelot.Library.Responder.Middleware +namespace Ocelot.Responder.Middleware { public class HttpResponderMiddleware : OcelotMiddleware { diff --git a/src/Ocelot/Responder/Middleware/HttpResponderMiddlewareExtensions.cs b/src/Ocelot/Responder/Middleware/HttpResponderMiddlewareExtensions.cs index 7ef7db83..3739efbd 100644 --- a/src/Ocelot/Responder/Middleware/HttpResponderMiddlewareExtensions.cs +++ b/src/Ocelot/Responder/Middleware/HttpResponderMiddlewareExtensions.cs @@ -1,6 +1,6 @@ using Microsoft.AspNetCore.Builder; -namespace Ocelot.Library.Responder.Middleware +namespace Ocelot.Responder.Middleware { public static class HttpResponderMiddlewareExtensions { diff --git a/src/Ocelot/Responses/ErrorResponse.cs b/src/Ocelot/Responses/ErrorResponse.cs index b097d961..9f541507 100644 --- a/src/Ocelot/Responses/ErrorResponse.cs +++ b/src/Ocelot/Responses/ErrorResponse.cs @@ -1,8 +1,8 @@ -namespace Ocelot.Library.Responses -{ - using System.Collections.Generic; - using Errors; +using System.Collections.Generic; +using Ocelot.Errors; +namespace Ocelot.Responses +{ public class ErrorResponse : Response { public ErrorResponse(List errors) : base(errors) diff --git a/src/Ocelot/Responses/ErrorResponseGeneric.cs b/src/Ocelot/Responses/ErrorResponseGeneric.cs index c5f8ef0b..77230503 100644 --- a/src/Ocelot/Responses/ErrorResponseGeneric.cs +++ b/src/Ocelot/Responses/ErrorResponseGeneric.cs @@ -1,8 +1,8 @@ -namespace Ocelot.Library.Responses -{ - using System.Collections.Generic; - using Errors; +using System.Collections.Generic; +using Ocelot.Errors; +namespace Ocelot.Responses +{ public class ErrorResponse : Response { public ErrorResponse(List errors) : base(errors) diff --git a/src/Ocelot/Responses/OkResponse.cs b/src/Ocelot/Responses/OkResponse.cs index 457afced..541d3061 100644 --- a/src/Ocelot/Responses/OkResponse.cs +++ b/src/Ocelot/Responses/OkResponse.cs @@ -1,4 +1,4 @@ -namespace Ocelot.Library.Responses +namespace Ocelot.Responses { public class OkResponse : Response { diff --git a/src/Ocelot/Responses/OkResponseGeneric.cs b/src/Ocelot/Responses/OkResponseGeneric.cs index d768f62f..c979dc91 100644 --- a/src/Ocelot/Responses/OkResponseGeneric.cs +++ b/src/Ocelot/Responses/OkResponseGeneric.cs @@ -1,4 +1,4 @@ -namespace Ocelot.Library.Responses +namespace Ocelot.Responses { public class OkResponse : Response { diff --git a/src/Ocelot/Responses/Response.cs b/src/Ocelot/Responses/Response.cs index c5628ac4..32ff9902 100644 --- a/src/Ocelot/Responses/Response.cs +++ b/src/Ocelot/Responses/Response.cs @@ -1,8 +1,8 @@ -namespace Ocelot.Library.Responses -{ - using System.Collections.Generic; - using Errors; +using System.Collections.Generic; +using Ocelot.Errors; +namespace Ocelot.Responses +{ public abstract class Response { protected Response() diff --git a/src/Ocelot/Responses/ResponseGeneric.cs b/src/Ocelot/Responses/ResponseGeneric.cs index bcebf865..1902b3e1 100644 --- a/src/Ocelot/Responses/ResponseGeneric.cs +++ b/src/Ocelot/Responses/ResponseGeneric.cs @@ -1,8 +1,8 @@ -namespace Ocelot.Library.Responses -{ - using System.Collections.Generic; - using Errors; +using System.Collections.Generic; +using Ocelot.Errors; +namespace Ocelot.Responses +{ public abstract class Response : Response { protected Response(T data) diff --git a/src/Ocelot/ScopedData/CannotAddDataError.cs b/src/Ocelot/ScopedData/CannotAddDataError.cs index bcdd5c28..bc5925e3 100644 --- a/src/Ocelot/ScopedData/CannotAddDataError.cs +++ b/src/Ocelot/ScopedData/CannotAddDataError.cs @@ -1,6 +1,6 @@ -using Ocelot.Library.Errors; +using Ocelot.Errors; -namespace Ocelot.Library.ScopedData +namespace Ocelot.ScopedData { public class CannotAddDataError : Error { diff --git a/src/Ocelot/ScopedData/CannotFindDataError.cs b/src/Ocelot/ScopedData/CannotFindDataError.cs index 9daedcd4..97ae1540 100644 --- a/src/Ocelot/ScopedData/CannotFindDataError.cs +++ b/src/Ocelot/ScopedData/CannotFindDataError.cs @@ -1,6 +1,6 @@ -using Ocelot.Library.Errors; +using Ocelot.Errors; -namespace Ocelot.Library.ScopedData +namespace Ocelot.ScopedData { public class CannotFindDataError : Error { diff --git a/src/Ocelot/ScopedData/IScopedRequestDataRepository.cs b/src/Ocelot/ScopedData/IScopedRequestDataRepository.cs index 852a6121..76630395 100644 --- a/src/Ocelot/ScopedData/IScopedRequestDataRepository.cs +++ b/src/Ocelot/ScopedData/IScopedRequestDataRepository.cs @@ -1,6 +1,6 @@ -using Ocelot.Library.Responses; +using Ocelot.Responses; -namespace Ocelot.Library.ScopedData +namespace Ocelot.ScopedData { public interface IScopedRequestDataRepository { diff --git a/src/Ocelot/ScopedData/ScopedRequestDataRepository.cs b/src/Ocelot/ScopedData/ScopedRequestDataRepository.cs index 928e1ebb..98e22f68 100644 --- a/src/Ocelot/ScopedData/ScopedRequestDataRepository.cs +++ b/src/Ocelot/ScopedData/ScopedRequestDataRepository.cs @@ -1,10 +1,10 @@ using System; using System.Collections.Generic; using Microsoft.AspNetCore.Http; -using Ocelot.Library.Errors; -using Ocelot.Library.Responses; +using Ocelot.Errors; +using Ocelot.Responses; -namespace Ocelot.Library.ScopedData +namespace Ocelot.ScopedData { public class ScopedRequestDataRepository : IScopedRequestDataRepository { diff --git a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs index ab202d70..18f138d3 100644 --- a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs +++ b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs @@ -13,6 +13,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; +using Ocelot.Configuration.Yaml; using Ocelot.ManualTest; using Shouldly; using TestStack.BDDfy; @@ -22,7 +23,6 @@ using YamlDotNet.Serialization; namespace Ocelot.AcceptanceTests { using System.Security.Claims; - using Library.Configuration.Yaml; public class AuthenticationTests : IDisposable { diff --git a/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs b/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs index 44c79872..aea7ec07 100644 --- a/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs +++ b/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs @@ -14,7 +14,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; -using Ocelot.Library.Configuration.Yaml; +using Ocelot.Configuration.Yaml; using Ocelot.ManualTest; using Shouldly; using TestStack.BDDfy; diff --git a/test/Ocelot.AcceptanceTests/ReturnsErrorTests.cs b/test/Ocelot.AcceptanceTests/ReturnsErrorTests.cs index 43dbbdb2..c358e884 100644 --- a/test/Ocelot.AcceptanceTests/ReturnsErrorTests.cs +++ b/test/Ocelot.AcceptanceTests/ReturnsErrorTests.cs @@ -6,7 +6,7 @@ using System.Net.Http; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; -using Ocelot.Library.Configuration.Yaml; +using Ocelot.Configuration.Yaml; using Ocelot.ManualTest; using Shouldly; using TestStack.BDDfy; diff --git a/test/Ocelot.AcceptanceTests/RoutingTests.cs b/test/Ocelot.AcceptanceTests/RoutingTests.cs index 42b9fea5..bef6e1b7 100644 --- a/test/Ocelot.AcceptanceTests/RoutingTests.cs +++ b/test/Ocelot.AcceptanceTests/RoutingTests.cs @@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.TestHost; +using Ocelot.Configuration.Yaml; using Ocelot.ManualTest; using Shouldly; using TestStack.BDDfy; @@ -15,8 +16,6 @@ using YamlDotNet.Serialization; namespace Ocelot.AcceptanceTests { - using Library.Configuration.Yaml; - public class RoutingTests : IDisposable { private TestServer _server; diff --git a/test/Ocelot.ManualTest/Startup.cs b/test/Ocelot.ManualTest/Startup.cs index c8d12f85..8eb7cf9f 100644 --- a/test/Ocelot.ManualTest/Startup.cs +++ b/test/Ocelot.ManualTest/Startup.cs @@ -3,8 +3,8 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Ocelot.Library.DependencyInjection; -using Ocelot.Library.Middleware; +using Ocelot.DependencyInjection; +using Ocelot.Middleware; namespace Ocelot.ManualTest { diff --git a/test/Ocelot.UnitTests/Authentication/AuthenticationHandlerFactoryTests.cs b/test/Ocelot.UnitTests/Authentication/AuthenticationHandlerFactoryTests.cs index 483857c8..e76a2b28 100644 --- a/test/Ocelot.UnitTests/Authentication/AuthenticationHandlerFactoryTests.cs +++ b/test/Ocelot.UnitTests/Authentication/AuthenticationHandlerFactoryTests.cs @@ -3,20 +3,18 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Moq; -using Ocelot.Library.Authentication.Handler; -using Ocelot.Library.Authentication.Handler.Creator; -using Ocelot.Library.Authentication.Handler.Factory; +using Ocelot.Authentication.Handler; +using Ocelot.Authentication.Handler.Creator; +using Ocelot.Authentication.Handler.Factory; +using Ocelot.Errors; +using Ocelot.Responses; using Shouldly; using TestStack.BDDfy; using Xunit; +using AuthenticationOptions = Ocelot.Configuration.AuthenticationOptions; namespace Ocelot.UnitTests.Authentication { - using Library.Authentication; - using Library.Configuration; - using Library.Errors; - using Library.Responses; - public class AuthenticationHandlerFactoryTests { private readonly IAuthenticationHandlerFactory _authenticationHandlerFactory; diff --git a/test/Ocelot.UnitTests/Authentication/AuthenticationMiddlewareTests.cs b/test/Ocelot.UnitTests/Authentication/AuthenticationMiddlewareTests.cs index 89b84a1e..d8ca67ad 100644 --- a/test/Ocelot.UnitTests/Authentication/AuthenticationMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Authentication/AuthenticationMiddlewareTests.cs @@ -6,13 +6,13 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Moq; -using Ocelot.Library.Authentication.Handler.Factory; -using Ocelot.Library.Authentication.Middleware; -using Ocelot.Library.Configuration.Builder; -using Ocelot.Library.DownstreamRouteFinder; -using Ocelot.Library.DownstreamRouteFinder.UrlMatcher; -using Ocelot.Library.Responses; -using Ocelot.Library.ScopedData; +using Ocelot.Authentication.Handler.Factory; +using Ocelot.Authentication.Middleware; +using Ocelot.Configuration.Builder; +using Ocelot.DownstreamRouteFinder; +using Ocelot.DownstreamRouteFinder.UrlMatcher; +using Ocelot.Responses; +using Ocelot.ScopedData; using TestStack.BDDfy; using Xunit; diff --git a/test/Ocelot.UnitTests/Configuration/ConfigurationHeadersExtractorTests.cs b/test/Ocelot.UnitTests/Configuration/ConfigurationHeadersExtractorTests.cs index 29f674be..7b2f37c1 100644 --- a/test/Ocelot.UnitTests/Configuration/ConfigurationHeadersExtractorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/ConfigurationHeadersExtractorTests.cs @@ -1,9 +1,9 @@ using System.Collections.Generic; using System.Linq; -using Ocelot.Library.Configuration; -using Ocelot.Library.Configuration.Parser; -using Ocelot.Library.Errors; -using Ocelot.Library.Responses; +using Ocelot.Configuration; +using Ocelot.Configuration.Parser; +using Ocelot.Errors; +using Ocelot.Responses; using Shouldly; using TestStack.BDDfy; using Xunit; diff --git a/test/Ocelot.UnitTests/Configuration/ConfigurationValidationTests.cs b/test/Ocelot.UnitTests/Configuration/ConfigurationValidationTests.cs index a9395a93..98c45104 100644 --- a/test/Ocelot.UnitTests/Configuration/ConfigurationValidationTests.cs +++ b/test/Ocelot.UnitTests/Configuration/ConfigurationValidationTests.cs @@ -1,14 +1,13 @@ using System.Collections.Generic; -using Ocelot.Library.Configuration.Validator; +using Ocelot.Configuration.Validator; +using Ocelot.Configuration.Yaml; +using Ocelot.Responses; using Shouldly; using TestStack.BDDfy; using Xunit; namespace Ocelot.UnitTests.Configuration { - using Library.Configuration.Yaml; - using Library.Responses; - public class ConfigurationValidationTests { private YamlConfiguration _yamlConfiguration; diff --git a/test/Ocelot.UnitTests/Configuration/InMemoryConfigurationRepositoryTests.cs b/test/Ocelot.UnitTests/Configuration/InMemoryConfigurationRepositoryTests.cs index c46942da..8c1cce52 100644 --- a/test/Ocelot.UnitTests/Configuration/InMemoryConfigurationRepositoryTests.cs +++ b/test/Ocelot.UnitTests/Configuration/InMemoryConfigurationRepositoryTests.cs @@ -2,10 +2,10 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Ocelot.Library.Configuration; -using Ocelot.Library.Configuration.Builder; -using Ocelot.Library.Configuration.Repository; -using Ocelot.Library.Responses; +using Ocelot.Configuration; +using Ocelot.Configuration.Builder; +using Ocelot.Configuration.Repository; +using Ocelot.Responses; using Shouldly; using TestStack.BDDfy; using Xunit; diff --git a/test/Ocelot.UnitTests/Configuration/YamlConfigurationCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/YamlConfigurationCreatorTests.cs index 102b0eae..fd69ba5e 100644 --- a/test/Ocelot.UnitTests/Configuration/YamlConfigurationCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/YamlConfigurationCreatorTests.cs @@ -2,22 +2,19 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Moq; -using Ocelot.Library.Configuration.Builder; -using Ocelot.Library.Configuration.Creator; -using Ocelot.Library.Configuration.Parser; -using Ocelot.Library.Configuration.Repository; -using Ocelot.Library.Configuration.Validator; -using Ocelot.Library.RequestBuilder; +using Ocelot.Configuration; +using Ocelot.Configuration.Builder; +using Ocelot.Configuration.Creator; +using Ocelot.Configuration.Parser; +using Ocelot.Configuration.Validator; +using Ocelot.Configuration.Yaml; +using Ocelot.Responses; using Shouldly; using TestStack.BDDfy; using Xunit; namespace Ocelot.UnitTests.Configuration { - using Library.Configuration; - using Library.Configuration.Yaml; - using Library.Responses; - public class YamlConfigurationCreatorTests { private readonly Mock> _yamlConfig; diff --git a/test/Ocelot.UnitTests/Configuration/YamlConfigurationProviderTests.cs b/test/Ocelot.UnitTests/Configuration/YamlConfigurationProviderTests.cs index ae81c4f7..8beaf159 100644 --- a/test/Ocelot.UnitTests/Configuration/YamlConfigurationProviderTests.cs +++ b/test/Ocelot.UnitTests/Configuration/YamlConfigurationProviderTests.cs @@ -3,13 +3,12 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Moq; -using Ocelot.Library.Configuration; -using Ocelot.Library.Configuration.Creator; -using Ocelot.Library.Configuration.Provider; -using Ocelot.Library.Configuration.Repository; -using Ocelot.Library.Configuration.Yaml; -using Ocelot.Library.Errors; -using Ocelot.Library.Responses; +using Ocelot.Configuration; +using Ocelot.Configuration.Creator; +using Ocelot.Configuration.Provider; +using Ocelot.Configuration.Repository; +using Ocelot.Errors; +using Ocelot.Responses; using Shouldly; using TestStack.BDDfy; using Xunit; diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs index f3ab97cb..b932539a 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs @@ -6,13 +6,13 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Moq; -using Ocelot.Library.Configuration.Builder; -using Ocelot.Library.DownstreamRouteFinder; -using Ocelot.Library.DownstreamRouteFinder.Finder; -using Ocelot.Library.DownstreamRouteFinder.Middleware; -using Ocelot.Library.DownstreamRouteFinder.UrlMatcher; -using Ocelot.Library.Responses; -using Ocelot.Library.ScopedData; +using Ocelot.Configuration.Builder; +using Ocelot.DownstreamRouteFinder; +using Ocelot.DownstreamRouteFinder.Finder; +using Ocelot.DownstreamRouteFinder.Middleware; +using Ocelot.DownstreamRouteFinder.UrlMatcher; +using Ocelot.Responses; +using Ocelot.ScopedData; using TestStack.BDDfy; using Xunit; diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs index 8ea8e581..8f4b57aa 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs @@ -1,19 +1,18 @@ using System.Collections.Generic; using Moq; -using Ocelot.Library.Configuration.Builder; -using Ocelot.Library.Configuration.Provider; -using Ocelot.Library.DownstreamRouteFinder.Finder; -using Ocelot.Library.DownstreamRouteFinder.UrlMatcher; +using Ocelot.Configuration; +using Ocelot.Configuration.Builder; +using Ocelot.Configuration.Provider; +using Ocelot.DownstreamRouteFinder; +using Ocelot.DownstreamRouteFinder.Finder; +using Ocelot.DownstreamRouteFinder.UrlMatcher; +using Ocelot.Responses; using Shouldly; using TestStack.BDDfy; using Xunit; namespace Ocelot.UnitTests.DownstreamRouteFinder { - using Library.Configuration; - using Library.DownstreamRouteFinder; - using Library.Responses; - public class DownstreamRouteFinderTests { private readonly IDownstreamRouteFinder _downstreamRouteFinder; @@ -31,7 +30,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder _mockConfig = new Mock(); _mockMatcher = new Mock(); _finder = new Mock(); - _downstreamRouteFinder = new Library.DownstreamRouteFinder.Finder.DownstreamRouteFinder(_mockConfig.Object, _mockMatcher.Object, _finder.Object); + _downstreamRouteFinder = new Ocelot.DownstreamRouteFinder.Finder.DownstreamRouteFinder(_mockConfig.Object, _mockMatcher.Object, _finder.Object); } [Fact] diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/UrlMatcher/RegExUrlMatcherTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/UrlMatcher/RegExUrlMatcherTests.cs index 0b0c8b50..02e8eb91 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/UrlMatcher/RegExUrlMatcherTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/UrlMatcher/RegExUrlMatcherTests.cs @@ -1,5 +1,5 @@ -using Ocelot.Library.DownstreamRouteFinder.UrlMatcher; -using Ocelot.Library.Responses; +using Ocelot.DownstreamRouteFinder.UrlMatcher; +using Ocelot.Responses; using Shouldly; using TestStack.BDDfy; using Xunit; diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValueFinderTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValueFinderTests.cs index 800f2024..bab6ef7e 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValueFinderTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/UrlMatcher/TemplateVariableNameAndValueFinderTests.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Linq; -using Ocelot.Library.DownstreamRouteFinder.UrlMatcher; -using Ocelot.Library.Responses; +using Ocelot.DownstreamRouteFinder.UrlMatcher; +using Ocelot.Responses; using Shouldly; using TestStack.BDDfy; using Xunit; diff --git a/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs b/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs index 5ba07e06..959e46c5 100644 --- a/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs @@ -6,13 +6,13 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Moq; -using Ocelot.Library.Configuration.Builder; -using Ocelot.Library.DownstreamRouteFinder; -using Ocelot.Library.DownstreamRouteFinder.UrlMatcher; -using Ocelot.Library.DownstreamUrlCreator.Middleware; -using Ocelot.Library.DownstreamUrlCreator.UrlTemplateReplacer; -using Ocelot.Library.Responses; -using Ocelot.Library.ScopedData; +using Ocelot.Configuration.Builder; +using Ocelot.DownstreamRouteFinder; +using Ocelot.DownstreamRouteFinder.UrlMatcher; +using Ocelot.DownstreamUrlCreator.Middleware; +using Ocelot.DownstreamUrlCreator.UrlTemplateReplacer; +using Ocelot.Responses; +using Ocelot.ScopedData; using TestStack.BDDfy; using Xunit; diff --git a/test/Ocelot.UnitTests/DownstreamUrlCreator/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs b/test/Ocelot.UnitTests/DownstreamUrlCreator/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs index c842a223..4bc8f19f 100644 --- a/test/Ocelot.UnitTests/DownstreamUrlCreator/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs +++ b/test/Ocelot.UnitTests/DownstreamUrlCreator/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs @@ -1,9 +1,9 @@ using System.Collections.Generic; -using Ocelot.Library.Configuration.Builder; -using Ocelot.Library.DownstreamRouteFinder; -using Ocelot.Library.DownstreamRouteFinder.UrlMatcher; -using Ocelot.Library.DownstreamUrlCreator.UrlTemplateReplacer; -using Ocelot.Library.Responses; +using Ocelot.Configuration.Builder; +using Ocelot.DownstreamRouteFinder; +using Ocelot.DownstreamRouteFinder.UrlMatcher; +using Ocelot.DownstreamUrlCreator.UrlTemplateReplacer; +using Ocelot.Responses; using Shouldly; using TestStack.BDDfy; using Xunit; diff --git a/test/Ocelot.UnitTests/HeaderBuilder/AddHeadersToRequestTests.cs b/test/Ocelot.UnitTests/HeaderBuilder/AddHeadersToRequestTests.cs index 2e277823..7834558f 100644 --- a/test/Ocelot.UnitTests/HeaderBuilder/AddHeadersToRequestTests.cs +++ b/test/Ocelot.UnitTests/HeaderBuilder/AddHeadersToRequestTests.cs @@ -4,11 +4,11 @@ using System.Security.Claims; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; using Moq; -using Ocelot.Library.Configuration; -using Ocelot.Library.Errors; -using Ocelot.Library.HeaderBuilder; -using Ocelot.Library.HeaderBuilder.Parser; -using Ocelot.Library.Responses; +using Ocelot.Configuration; +using Ocelot.Errors; +using Ocelot.HeaderBuilder; +using Ocelot.HeaderBuilder.Parser; +using Ocelot.Responses; using Shouldly; using TestStack.BDDfy; using Xunit; diff --git a/test/Ocelot.UnitTests/HeaderBuilder/ClaimParserTests.cs b/test/Ocelot.UnitTests/HeaderBuilder/ClaimParserTests.cs index 7be9226b..7b12f150 100644 --- a/test/Ocelot.UnitTests/HeaderBuilder/ClaimParserTests.cs +++ b/test/Ocelot.UnitTests/HeaderBuilder/ClaimParserTests.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; using System.Security.Claims; -using Ocelot.Library.Errors; -using Ocelot.Library.HeaderBuilder.Parser; -using Ocelot.Library.Responses; +using Ocelot.Errors; +using Ocelot.HeaderBuilder.Parser; +using Ocelot.Responses; using Shouldly; using TestStack.BDDfy; using Xunit; diff --git a/test/Ocelot.UnitTests/HeaderBuilder/HttpRequestHeadersBuilderMiddlewareTests.cs b/test/Ocelot.UnitTests/HeaderBuilder/HttpRequestHeadersBuilderMiddlewareTests.cs index d7ab00b6..8fbd7993 100644 --- a/test/Ocelot.UnitTests/HeaderBuilder/HttpRequestHeadersBuilderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/HeaderBuilder/HttpRequestHeadersBuilderMiddlewareTests.cs @@ -7,14 +7,14 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Moq; -using Ocelot.Library.Configuration; -using Ocelot.Library.Configuration.Builder; -using Ocelot.Library.DownstreamRouteFinder; -using Ocelot.Library.DownstreamRouteFinder.UrlMatcher; -using Ocelot.Library.HeaderBuilder; -using Ocelot.Library.HeaderBuilder.Middleware; -using Ocelot.Library.Responses; -using Ocelot.Library.ScopedData; +using Ocelot.Configuration; +using Ocelot.Configuration.Builder; +using Ocelot.DownstreamRouteFinder; +using Ocelot.DownstreamRouteFinder.UrlMatcher; +using Ocelot.HeaderBuilder; +using Ocelot.HeaderBuilder.Middleware; +using Ocelot.Responses; +using Ocelot.ScopedData; using TestStack.BDDfy; using Xunit; diff --git a/test/Ocelot.UnitTests/Repository/ScopedRequestDataRepositoryTests.cs b/test/Ocelot.UnitTests/Repository/ScopedRequestDataRepositoryTests.cs index 53e573ad..196b6a92 100644 --- a/test/Ocelot.UnitTests/Repository/ScopedRequestDataRepositoryTests.cs +++ b/test/Ocelot.UnitTests/Repository/ScopedRequestDataRepositoryTests.cs @@ -1,13 +1,12 @@ using Microsoft.AspNetCore.Http; -using Ocelot.Library.ScopedData; +using Ocelot.Responses; +using Ocelot.ScopedData; using Shouldly; using TestStack.BDDfy; using Xunit; namespace Ocelot.UnitTests.Repository { - using Library.Responses; - public class ScopedRequestDataRepositoryTests { private IScopedRequestDataRepository _scopedRequestDataRepository; diff --git a/test/Ocelot.UnitTests/RequestBuilder/HttpRequestBuilderMiddlewareTests.cs b/test/Ocelot.UnitTests/RequestBuilder/HttpRequestBuilderMiddlewareTests.cs index 03a3d9a1..d7683445 100644 --- a/test/Ocelot.UnitTests/RequestBuilder/HttpRequestBuilderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/RequestBuilder/HttpRequestBuilderMiddlewareTests.cs @@ -7,11 +7,11 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Moq; -using Ocelot.Library.RequestBuilder; -using Ocelot.Library.RequestBuilder.Builder; -using Ocelot.Library.RequestBuilder.Middleware; -using Ocelot.Library.Responses; -using Ocelot.Library.ScopedData; +using Ocelot.RequestBuilder; +using Ocelot.RequestBuilder.Builder; +using Ocelot.RequestBuilder.Middleware; +using Ocelot.Responses; +using Ocelot.ScopedData; using TestStack.BDDfy; using Xunit; diff --git a/test/Ocelot.UnitTests/RequestBuilder/RequestBuilderTests.cs b/test/Ocelot.UnitTests/RequestBuilder/RequestBuilderTests.cs index 224f9624..d7945136 100644 --- a/test/Ocelot.UnitTests/RequestBuilder/RequestBuilderTests.cs +++ b/test/Ocelot.UnitTests/RequestBuilder/RequestBuilderTests.cs @@ -5,16 +5,15 @@ using System.Net; using System.Net.Http; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Internal; -using Ocelot.Library.RequestBuilder.Builder; +using Ocelot.RequestBuilder; +using Ocelot.RequestBuilder.Builder; +using Ocelot.Responses; using Shouldly; using TestStack.BDDfy; using Xunit; namespace Ocelot.UnitTests.RequestBuilder { - using Library.RequestBuilder; - using Library.Responses; - public class RequestBuilderTests { private string _httpMethod; diff --git a/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs b/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs index 2c7bdb8b..34d73b64 100644 --- a/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs @@ -6,11 +6,11 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Moq; -using Ocelot.Library.RequestBuilder; -using Ocelot.Library.Requester; -using Ocelot.Library.Requester.Middleware; -using Ocelot.Library.Responses; -using Ocelot.Library.ScopedData; +using Ocelot.RequestBuilder; +using Ocelot.Requester; +using Ocelot.Requester.Middleware; +using Ocelot.Responses; +using Ocelot.ScopedData; using TestStack.BDDfy; using Xunit; diff --git a/test/Ocelot.UnitTests/Responder/ErrorsToHttpStatusCodeMapperTests.cs b/test/Ocelot.UnitTests/Responder/ErrorsToHttpStatusCodeMapperTests.cs index fdd48842..78f78235 100644 --- a/test/Ocelot.UnitTests/Responder/ErrorsToHttpStatusCodeMapperTests.cs +++ b/test/Ocelot.UnitTests/Responder/ErrorsToHttpStatusCodeMapperTests.cs @@ -2,17 +2,16 @@ using System.IO; using System.Net.Http; using Microsoft.AspNetCore.Http; +using Ocelot.Errors; +using Ocelot.Middleware; +using Ocelot.Responder; +using Ocelot.Responses; using Shouldly; using TestStack.BDDfy; using Xunit; namespace Ocelot.UnitTests.Responder { - using Library.Errors; - using Library.Middleware; - using Library.Responder; - using Library.Responses; - public class ErrorsToHttpStatusCodeMapperTests { private readonly IErrorsToHttpStatusCodeMapper _codeMapper; diff --git a/test/Ocelot.UnitTests/Responder/HttpResponderMiddlewareTests.cs b/test/Ocelot.UnitTests/Responder/HttpResponderMiddlewareTests.cs index b8c3c5eb..0a24907a 100644 --- a/test/Ocelot.UnitTests/Responder/HttpResponderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Responder/HttpResponderMiddlewareTests.cs @@ -6,10 +6,10 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Moq; -using Ocelot.Library.Responder; -using Ocelot.Library.Responder.Middleware; -using Ocelot.Library.Responses; -using Ocelot.Library.ScopedData; +using Ocelot.Responder; +using Ocelot.Responder.Middleware; +using Ocelot.Responses; +using Ocelot.ScopedData; using TestStack.BDDfy; using Xunit; From cb4b000b2195bdad59f91b1d3fb6ecb037f27b86 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Tue, 18 Oct 2016 19:12:53 +0100 Subject: [PATCH 096/183] updated build scripts --- build.bat | 1 - run-tests.bat | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/build.bat b/build.bat index e1de8546..037ad2b4 100644 --- a/build.bat +++ b/build.bat @@ -2,7 +2,6 @@ echo ------------------------- echo Building Ocelot dotnet restore src/Ocelot -dotnet restore src/Ocelot.Library dotnet build src/Ocelot dotnet publish src/Ocelot -o artifacts/ diff --git a/run-tests.bat b/run-tests.bat index 853ea538..ae4856fc 100644 --- a/run-tests.bat +++ b/run-tests.bat @@ -3,8 +3,8 @@ echo ------------------------- echo Restoring Ocelot dotnet restore src/Ocelot -echo Restoring Ocelot -dotnet restore src/Ocelot.Library +echo Restoring Ocelot.ManualTest +dotnet restore test/Ocelot.ManualTest/ echo Running Ocelot.UnitTests dotnet restore test/Ocelot.UnitTests/ From 0221ee9ccbc1316c925e974e89cf3c839df1344f Mon Sep 17 00:00:00 2001 From: TomPallister Date: Tue, 18 Oct 2016 21:38:18 +0100 Subject: [PATCH 097/183] started adding route authorisation --- build.bat | 2 + .../Authorisation/AuthorisationMiddleware.cs | 53 +++++++++++ ...orisationMiddlewareMiddlewareExtensions.cs | 12 +++ src/Ocelot/Authorisation/ClaimsAuthoriser.cs | 12 +++ src/Ocelot/Authorisation/IAuthoriser.cs | 10 ++ .../Authorisation/RouteClaimsRequirement.cs | 11 +++ src/Ocelot/Authorisation/UnauthorisedError.cs | 12 +++ .../ServiceCollectionExtensions.cs | 5 +- src/Ocelot/Errors/OcelotErrorCode.cs | 3 +- .../Middleware/OcelotMiddlewareExtensions.cs | 3 + .../AuthorizationMiddlewareTests.cs | 92 +++++++++++++++++++ 11 files changed, 213 insertions(+), 2 deletions(-) create mode 100644 src/Ocelot/Authorisation/AuthorisationMiddleware.cs create mode 100644 src/Ocelot/Authorisation/AuthorisationMiddlewareMiddlewareExtensions.cs create mode 100644 src/Ocelot/Authorisation/ClaimsAuthoriser.cs create mode 100644 src/Ocelot/Authorisation/IAuthoriser.cs create mode 100644 src/Ocelot/Authorisation/RouteClaimsRequirement.cs create mode 100644 src/Ocelot/Authorisation/UnauthorisedError.cs create mode 100644 test/Ocelot.UnitTests/Authorization/AuthorizationMiddlewareTests.cs diff --git a/build.bat b/build.bat index 037ad2b4..a7866f1d 100644 --- a/build.bat +++ b/build.bat @@ -4,5 +4,7 @@ echo Building Ocelot dotnet restore src/Ocelot dotnet build src/Ocelot dotnet publish src/Ocelot -o artifacts/ +dotnet pack src/Ocelot/project.json --output nupkgs/ + diff --git a/src/Ocelot/Authorisation/AuthorisationMiddleware.cs b/src/Ocelot/Authorisation/AuthorisationMiddleware.cs new file mode 100644 index 00000000..6f3d54e1 --- /dev/null +++ b/src/Ocelot/Authorisation/AuthorisationMiddleware.cs @@ -0,0 +1,53 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Ocelot.DownstreamRouteFinder; +using Ocelot.Errors; +using Ocelot.Middleware; +using Ocelot.ScopedData; + +namespace Ocelot.Authorisation +{ + public class AuthorisationMiddleware : OcelotMiddleware + { + private readonly RequestDelegate _next; + private readonly IScopedRequestDataRepository _scopedRequestDataRepository; + private readonly IAuthoriser _authoriser; + + public AuthorisationMiddleware(RequestDelegate next, + IScopedRequestDataRepository scopedRequestDataRepository, + IAuthoriser authoriser) + : base(scopedRequestDataRepository) + { + _next = next; + _scopedRequestDataRepository = scopedRequestDataRepository; + _authoriser = authoriser; + } + + public async Task Invoke(HttpContext context) + { + var downstreamRoute = _scopedRequestDataRepository.Get("DownstreamRoute"); + + if (downstreamRoute.IsError) + { + SetPipelineError(downstreamRoute.Errors); + return; + } + + var authorised = _authoriser.Authorise(context.User, new RouteClaimsRequirement()); + + if (authorised) + { + await _next.Invoke(context); + } + else + { + //set an error + SetPipelineError(new List + { + new UnauthorisedError($"{context.User.Identity.Name} unable to access {downstreamRoute.Data.ReRoute.UpstreamTemplate}") + }); + } + } + } +} diff --git a/src/Ocelot/Authorisation/AuthorisationMiddlewareMiddlewareExtensions.cs b/src/Ocelot/Authorisation/AuthorisationMiddlewareMiddlewareExtensions.cs new file mode 100644 index 00000000..291a47ad --- /dev/null +++ b/src/Ocelot/Authorisation/AuthorisationMiddlewareMiddlewareExtensions.cs @@ -0,0 +1,12 @@ +using Microsoft.AspNetCore.Builder; + +namespace Ocelot.Authorisation +{ + public static class AuthorisationMiddlewareMiddlewareExtensions + { + public static IApplicationBuilder UseAuthorisationMiddleware(this IApplicationBuilder builder) + { + return builder.UseMiddleware(); + } + } +} \ No newline at end of file diff --git a/src/Ocelot/Authorisation/ClaimsAuthoriser.cs b/src/Ocelot/Authorisation/ClaimsAuthoriser.cs new file mode 100644 index 00000000..631767df --- /dev/null +++ b/src/Ocelot/Authorisation/ClaimsAuthoriser.cs @@ -0,0 +1,12 @@ +using System.Security.Claims; + +namespace Ocelot.Authorisation +{ + public class ClaimsAuthoriser : IAuthoriser + { + public bool Authorise(ClaimsPrincipal claimsPrincipal, RouteClaimsRequirement routeClaimsRequirement) + { + return false; + } + } +} \ No newline at end of file diff --git a/src/Ocelot/Authorisation/IAuthoriser.cs b/src/Ocelot/Authorisation/IAuthoriser.cs new file mode 100644 index 00000000..091eea3f --- /dev/null +++ b/src/Ocelot/Authorisation/IAuthoriser.cs @@ -0,0 +1,10 @@ +using System.Security.Claims; + +namespace Ocelot.Authorisation +{ + public interface IAuthoriser + { + bool Authorise(ClaimsPrincipal claimsPrincipal, + RouteClaimsRequirement routeClaimsRequirement); + } +} diff --git a/src/Ocelot/Authorisation/RouteClaimsRequirement.cs b/src/Ocelot/Authorisation/RouteClaimsRequirement.cs new file mode 100644 index 00000000..bca35bc9 --- /dev/null +++ b/src/Ocelot/Authorisation/RouteClaimsRequirement.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Ocelot.Authorisation +{ + public class RouteClaimsRequirement + { + } +} diff --git a/src/Ocelot/Authorisation/UnauthorisedError.cs b/src/Ocelot/Authorisation/UnauthorisedError.cs new file mode 100644 index 00000000..766c1a7b --- /dev/null +++ b/src/Ocelot/Authorisation/UnauthorisedError.cs @@ -0,0 +1,12 @@ +using Ocelot.Errors; + +namespace Ocelot.Authorisation +{ + public class UnauthorisedError : Error + { + public UnauthorisedError(string message) + : base(message, OcelotErrorCode.UnauthorizedError) + { + } + } +} diff --git a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs index 38dad7ba..20803dcb 100644 --- a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs @@ -1,8 +1,10 @@ -using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Ocelot.Authentication.Handler.Creator; using Ocelot.Authentication.Handler.Factory; +using Ocelot.Authorisation; using Ocelot.Configuration.Creator; using Ocelot.Configuration.Parser; using Ocelot.Configuration.Provider; @@ -45,6 +47,7 @@ namespace Ocelot.DependencyInjection services.AddLogging(); // ocelot services. + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/src/Ocelot/Errors/OcelotErrorCode.cs b/src/Ocelot/Errors/OcelotErrorCode.cs index 28679449..ed15ce2e 100644 --- a/src/Ocelot/Errors/OcelotErrorCode.cs +++ b/src/Ocelot/Errors/OcelotErrorCode.cs @@ -14,6 +14,7 @@ CannotFindClaimError, ParsingConfigurationHeaderError, NoInstructionsError, - InstructionNotForClaimsError + InstructionNotForClaimsError, + UnauthorizedError } } diff --git a/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs b/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs index 148dc8fe..515ac74f 100644 --- a/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs +++ b/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Builder; using Ocelot.Authentication.Middleware; +using Ocelot.Authorisation; using Ocelot.DownstreamRouteFinder.Middleware; using Ocelot.DownstreamUrlCreator.Middleware; using Ocelot.HeaderBuilder.Middleware; @@ -19,6 +20,8 @@ namespace Ocelot.Middleware builder.UseAuthenticationMiddleware(); + //builder.UseAuthorisationMiddleware(); + builder.UseHttpRequestHeadersBuilderMiddleware(); builder.UseDownstreamUrlCreatorMiddleware(); diff --git a/test/Ocelot.UnitTests/Authorization/AuthorizationMiddlewareTests.cs b/test/Ocelot.UnitTests/Authorization/AuthorizationMiddlewareTests.cs new file mode 100644 index 00000000..b9d1746b --- /dev/null +++ b/test/Ocelot.UnitTests/Authorization/AuthorizationMiddlewareTests.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net.Http; +using System.Security.Claims; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using Moq; +using Ocelot.Authorisation; +using Ocelot.Configuration.Builder; +using Ocelot.DownstreamRouteFinder; +using Ocelot.DownstreamRouteFinder.UrlMatcher; +using Ocelot.Responses; +using Ocelot.ScopedData; +using TestStack.BDDfy; +using Xunit; + +namespace Ocelot.UnitTests.Authorization +{ + public class AuthorizationMiddlewareTests : IDisposable + { + private readonly Mock _scopedRepository; + private readonly Mock _authService; + private readonly string _url; + private readonly TestServer _server; + private readonly HttpClient _client; + private HttpResponseMessage _result; + private OkResponse _downstreamRoute; + + public AuthorizationMiddlewareTests() + { + _url = "http://localhost:51879"; + _scopedRepository = new Mock(); + _authService = new Mock(); + var builder = new WebHostBuilder() + .ConfigureServices(x => + { + x.AddSingleton(_authService.Object); + x.AddSingleton(_scopedRepository.Object); + }) + .UseUrls(_url) + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseUrls(_url) + .Configure(app => + { + app.UseAuthorisationMiddleware(); + }); + + _server = new TestServer(builder); + _client = _server.CreateClient(); + } + + [Fact] + public void happy_path() + { + this.Given(x => x.GivenTheDownStreamRouteIs(new DownstreamRoute(new List(), new ReRouteBuilder().Build()))) + .When(x => x.WhenICallTheMiddleware()) + .Then(x => x.ThenTheAuthServiceIsCalledCorrectly()) + .BDDfy(); + } + + private void ThenTheAuthServiceIsCalledCorrectly() + { + _authService + .Verify(x => x.Authorise(It.IsAny(), + It.IsAny()), Times.Once); + } + + private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute) + { + _downstreamRoute = new OkResponse(downstreamRoute); + _scopedRepository + .Setup(x => x.Get(It.IsAny())) + .Returns(_downstreamRoute); + } + + private void WhenICallTheMiddleware() + { + _result = _client.GetAsync(_url).Result; + } + + + public void Dispose() + { + _client.Dispose(); + _server.Dispose(); + } + } +} From 3285be3c735d7e8f3adfd49ae3722040cba73952 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Tue, 18 Oct 2016 22:19:41 +0100 Subject: [PATCH 098/183] more auth stuff...nowhere near done --- src/Ocelot/Authorisation/AddClaims.cs | 45 +++ .../Authorisation/AuthorisationMiddleware.cs | 13 +- .../ClaimValueNotAuthorisedError.cs | 12 + src/Ocelot/Authorisation/ClaimsAuthoriser.cs | 47 ++- src/Ocelot/Authorisation/IAddClaims.cs | 13 + src/Ocelot/Authorisation/IAuthoriser.cs | 3 +- .../Authorisation/RouteClaimsRequirement.cs | 11 +- .../UserDoesNotHaveClaimError.cs | 12 + .../Parser/CannotFindClaimError.cs | 2 +- .../Parser/ClaimsParser.cs | 2 +- .../Parser/IClaimsParser.cs | 2 +- src/Ocelot/Configuration/Yaml/YamlReRoute.cs | 2 + .../ServiceCollectionExtensions.cs | 2 +- src/Ocelot/Errors/OcelotErrorCode.cs | 4 +- .../HeaderBuilder/AddHeadersToRequest.cs | 2 +- .../Middleware/OcelotMiddlewareExtensions.cs | 2 +- .../AuthorisationTests.cs | 297 ++++++++++++++++++ .../AuthorizationMiddlewareTests.cs | 11 +- .../Authorization/ClaimsAuthoriserTests.cs | 78 +++++ .../HeaderBuilder/AddHeadersToRequestTests.cs | 2 +- .../HeaderBuilder/ClaimParserTests.cs | 2 +- 21 files changed, 543 insertions(+), 21 deletions(-) create mode 100644 src/Ocelot/Authorisation/AddClaims.cs create mode 100644 src/Ocelot/Authorisation/ClaimValueNotAuthorisedError.cs create mode 100644 src/Ocelot/Authorisation/IAddClaims.cs create mode 100644 src/Ocelot/Authorisation/UserDoesNotHaveClaimError.cs rename src/Ocelot/{HeaderBuilder => Claims}/Parser/CannotFindClaimError.cs (85%) rename src/Ocelot/{HeaderBuilder => Claims}/Parser/ClaimsParser.cs (97%) rename src/Ocelot/{HeaderBuilder => Claims}/Parser/IClaimsParser.cs (86%) create mode 100644 test/Ocelot.AcceptanceTests/AuthorisationTests.cs create mode 100644 test/Ocelot.UnitTests/Authorization/ClaimsAuthoriserTests.cs diff --git a/src/Ocelot/Authorisation/AddClaims.cs b/src/Ocelot/Authorisation/AddClaims.cs new file mode 100644 index 00000000..4e7f9227 --- /dev/null +++ b/src/Ocelot/Authorisation/AddClaims.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; +using System.Linq; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Primitives; +using Ocelot.Claims.Parser; +using Ocelot.Configuration; +using Ocelot.HeaderBuilder; +using Ocelot.Responses; + +namespace Ocelot.Authorisation +{ + public class AddClaims : IAddHeadersToRequest + { + private readonly IClaimsParser _claimsParser; + + public AddClaims(IClaimsParser claimsParser) + { + _claimsParser = claimsParser; + } + + public Response SetHeadersOnContext(List configurationHeaderExtractorProperties, HttpContext context) + { + foreach (var config in configurationHeaderExtractorProperties) + { + var value = _claimsParser.GetValue(context.User.Claims, config.ClaimKey, config.Delimiter, config.Index); + + if (value.IsError) + { + return new ErrorResponse(value.Errors); + } + + var exists = context.Request.Headers.FirstOrDefault(x => x.Key == config.HeaderKey); + + if (!string.IsNullOrEmpty(exists.Key)) + { + context.Request.Headers.Remove(exists); + } + + context.Request.Headers.Add(config.HeaderKey, new StringValues(value.Data)); + } + + return new OkResponse(); + } + } +} \ No newline at end of file diff --git a/src/Ocelot/Authorisation/AuthorisationMiddleware.cs b/src/Ocelot/Authorisation/AuthorisationMiddleware.cs index 6f3d54e1..53ddb436 100644 --- a/src/Ocelot/Authorisation/AuthorisationMiddleware.cs +++ b/src/Ocelot/Authorisation/AuthorisationMiddleware.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Http; using Ocelot.DownstreamRouteFinder; using Ocelot.Errors; using Ocelot.Middleware; +using Ocelot.Responses; using Ocelot.ScopedData; namespace Ocelot.Authorisation @@ -34,15 +35,21 @@ namespace Ocelot.Authorisation return; } - var authorised = _authoriser.Authorise(context.User, new RouteClaimsRequirement()); + //todo - call authoriser + var authorised = new OkResponse(true); //_authoriser.Authorise(context.User, new RouteClaimsRequirement(new Dictionary())); - if (authorised) + if (authorised.IsError) + { + SetPipelineError(authorised.Errors); + return; + } + + if (authorised.Data) { await _next.Invoke(context); } else { - //set an error SetPipelineError(new List { new UnauthorisedError($"{context.User.Identity.Name} unable to access {downstreamRoute.Data.ReRoute.UpstreamTemplate}") diff --git a/src/Ocelot/Authorisation/ClaimValueNotAuthorisedError.cs b/src/Ocelot/Authorisation/ClaimValueNotAuthorisedError.cs new file mode 100644 index 00000000..166430ed --- /dev/null +++ b/src/Ocelot/Authorisation/ClaimValueNotAuthorisedError.cs @@ -0,0 +1,12 @@ +using Ocelot.Errors; + +namespace Ocelot.Authorisation +{ + public class ClaimValueNotAuthorisedError : Error + { + public ClaimValueNotAuthorisedError(string message) + : base(message, OcelotErrorCode.ClaimValueNotAuthorisedError) + { + } + } +} diff --git a/src/Ocelot/Authorisation/ClaimsAuthoriser.cs b/src/Ocelot/Authorisation/ClaimsAuthoriser.cs index 631767df..52409c82 100644 --- a/src/Ocelot/Authorisation/ClaimsAuthoriser.cs +++ b/src/Ocelot/Authorisation/ClaimsAuthoriser.cs @@ -1,12 +1,53 @@ -using System.Security.Claims; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using Ocelot.Claims.Parser; +using Ocelot.Errors; +using Ocelot.Responses; namespace Ocelot.Authorisation { public class ClaimsAuthoriser : IAuthoriser { - public bool Authorise(ClaimsPrincipal claimsPrincipal, RouteClaimsRequirement routeClaimsRequirement) + private readonly IClaimsParser _claimsParser; + + public ClaimsAuthoriser(IClaimsParser claimsParser) { - return false; + _claimsParser = claimsParser; + } + + public Response Authorise(ClaimsPrincipal claimsPrincipal, RouteClaimsRequirement routeClaimsRequirement) + { + foreach (var required in routeClaimsRequirement.RequiredClaimsAndValues) + { + var value = _claimsParser.GetValue(claimsPrincipal.Claims, required.Key, string.Empty, 0); + + if (value.IsError) + { + return new ErrorResponse(value.Errors); + } + + if (value.Data != null) + { + var authorised = value.Data == required.Value; + if (!authorised) + { + return new ErrorResponse(new List + { + new ClaimValueNotAuthorisedError( + $"claim value: {value.Data} is not the same as required value: {required.Value} for type: {required.Key}") + }); + } + } + else + { + return new ErrorResponse(new List + { + new UserDoesNotHaveClaimError($"user does not have claim {required.Key}") + }); + } + } + return new OkResponse(true); } } } \ No newline at end of file diff --git a/src/Ocelot/Authorisation/IAddClaims.cs b/src/Ocelot/Authorisation/IAddClaims.cs new file mode 100644 index 00000000..d68b0750 --- /dev/null +++ b/src/Ocelot/Authorisation/IAddClaims.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using Microsoft.AspNetCore.Http; +using Ocelot.Configuration; +using Ocelot.Responses; + +namespace Ocelot.Authorisation +{ + public interface IAddClaims + { + Response SetHeadersOnContext(List configurationHeaderExtractorProperties, + HttpContext context); + } +} diff --git a/src/Ocelot/Authorisation/IAuthoriser.cs b/src/Ocelot/Authorisation/IAuthoriser.cs index 091eea3f..96b1291f 100644 --- a/src/Ocelot/Authorisation/IAuthoriser.cs +++ b/src/Ocelot/Authorisation/IAuthoriser.cs @@ -1,10 +1,11 @@ using System.Security.Claims; +using Ocelot.Responses; namespace Ocelot.Authorisation { public interface IAuthoriser { - bool Authorise(ClaimsPrincipal claimsPrincipal, + Response Authorise(ClaimsPrincipal claimsPrincipal, RouteClaimsRequirement routeClaimsRequirement); } } diff --git a/src/Ocelot/Authorisation/RouteClaimsRequirement.cs b/src/Ocelot/Authorisation/RouteClaimsRequirement.cs index bca35bc9..5cc0e412 100644 --- a/src/Ocelot/Authorisation/RouteClaimsRequirement.cs +++ b/src/Ocelot/Authorisation/RouteClaimsRequirement.cs @@ -1,11 +1,14 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using System.Collections.Generic; namespace Ocelot.Authorisation { public class RouteClaimsRequirement { + public RouteClaimsRequirement(Dictionary requiredClaimsAndValues) + { + RequiredClaimsAndValues = requiredClaimsAndValues; + } + + public Dictionary RequiredClaimsAndValues { get; private set; } } } diff --git a/src/Ocelot/Authorisation/UserDoesNotHaveClaimError.cs b/src/Ocelot/Authorisation/UserDoesNotHaveClaimError.cs new file mode 100644 index 00000000..38525f00 --- /dev/null +++ b/src/Ocelot/Authorisation/UserDoesNotHaveClaimError.cs @@ -0,0 +1,12 @@ +using Ocelot.Errors; + +namespace Ocelot.Authorisation +{ + public class UserDoesNotHaveClaimError : Error + { + public UserDoesNotHaveClaimError(string message) + : base(message, OcelotErrorCode.UserDoesNotHaveClaimError) + { + } + } +} diff --git a/src/Ocelot/HeaderBuilder/Parser/CannotFindClaimError.cs b/src/Ocelot/Claims/Parser/CannotFindClaimError.cs similarity index 85% rename from src/Ocelot/HeaderBuilder/Parser/CannotFindClaimError.cs rename to src/Ocelot/Claims/Parser/CannotFindClaimError.cs index 88f79075..37e926e1 100644 --- a/src/Ocelot/HeaderBuilder/Parser/CannotFindClaimError.cs +++ b/src/Ocelot/Claims/Parser/CannotFindClaimError.cs @@ -1,6 +1,6 @@ using Ocelot.Errors; -namespace Ocelot.HeaderBuilder.Parser +namespace Ocelot.Claims.Parser { public class CannotFindClaimError : Error { diff --git a/src/Ocelot/HeaderBuilder/Parser/ClaimsParser.cs b/src/Ocelot/Claims/Parser/ClaimsParser.cs similarity index 97% rename from src/Ocelot/HeaderBuilder/Parser/ClaimsParser.cs rename to src/Ocelot/Claims/Parser/ClaimsParser.cs index c54653b1..a6c8d010 100644 --- a/src/Ocelot/HeaderBuilder/Parser/ClaimsParser.cs +++ b/src/Ocelot/Claims/Parser/ClaimsParser.cs @@ -4,7 +4,7 @@ using System.Security.Claims; using Ocelot.Errors; using Ocelot.Responses; -namespace Ocelot.HeaderBuilder.Parser +namespace Ocelot.Claims.Parser { public class ClaimsParser : IClaimsParser { diff --git a/src/Ocelot/HeaderBuilder/Parser/IClaimsParser.cs b/src/Ocelot/Claims/Parser/IClaimsParser.cs similarity index 86% rename from src/Ocelot/HeaderBuilder/Parser/IClaimsParser.cs rename to src/Ocelot/Claims/Parser/IClaimsParser.cs index 7e563be8..4a2020ec 100644 --- a/src/Ocelot/HeaderBuilder/Parser/IClaimsParser.cs +++ b/src/Ocelot/Claims/Parser/IClaimsParser.cs @@ -2,7 +2,7 @@ using System.Security.Claims; using Ocelot.Responses; -namespace Ocelot.HeaderBuilder.Parser +namespace Ocelot.Claims.Parser { public interface IClaimsParser { diff --git a/src/Ocelot/Configuration/Yaml/YamlReRoute.cs b/src/Ocelot/Configuration/Yaml/YamlReRoute.cs index 9c18d7a8..94daa4a8 100644 --- a/src/Ocelot/Configuration/Yaml/YamlReRoute.cs +++ b/src/Ocelot/Configuration/Yaml/YamlReRoute.cs @@ -7,6 +7,7 @@ namespace Ocelot.Configuration.Yaml public YamlReRoute() { AddHeadersToRequest = new Dictionary(); + AddClaims = new Dictionary(); } public string DownstreamTemplate { get; set; } @@ -14,5 +15,6 @@ namespace Ocelot.Configuration.Yaml public string UpstreamHttpMethod { get; set; } public YamlAuthenticationOptions AuthenticationOptions { get; set; } public Dictionary AddHeadersToRequest { get; set; } + public Dictionary AddClaims { get; set; } } } \ No newline at end of file diff --git a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs index 20803dcb..87c5bb79 100644 --- a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs @@ -5,6 +5,7 @@ using Microsoft.Extensions.DependencyInjection; using Ocelot.Authentication.Handler.Creator; using Ocelot.Authentication.Handler.Factory; using Ocelot.Authorisation; +using Ocelot.Claims.Parser; using Ocelot.Configuration.Creator; using Ocelot.Configuration.Parser; using Ocelot.Configuration.Provider; @@ -15,7 +16,6 @@ using Ocelot.DownstreamRouteFinder.Finder; using Ocelot.DownstreamRouteFinder.UrlMatcher; using Ocelot.DownstreamUrlCreator.UrlTemplateReplacer; using Ocelot.HeaderBuilder; -using Ocelot.HeaderBuilder.Parser; using Ocelot.RequestBuilder.Builder; using Ocelot.Requester; using Ocelot.Responder; diff --git a/src/Ocelot/Errors/OcelotErrorCode.cs b/src/Ocelot/Errors/OcelotErrorCode.cs index ed15ce2e..a4864d1a 100644 --- a/src/Ocelot/Errors/OcelotErrorCode.cs +++ b/src/Ocelot/Errors/OcelotErrorCode.cs @@ -15,6 +15,8 @@ ParsingConfigurationHeaderError, NoInstructionsError, InstructionNotForClaimsError, - UnauthorizedError + UnauthorizedError, + ClaimValueNotAuthorisedError, + UserDoesNotHaveClaimError } } diff --git a/src/Ocelot/HeaderBuilder/AddHeadersToRequest.cs b/src/Ocelot/HeaderBuilder/AddHeadersToRequest.cs index b6efc334..cd96dccf 100644 --- a/src/Ocelot/HeaderBuilder/AddHeadersToRequest.cs +++ b/src/Ocelot/HeaderBuilder/AddHeadersToRequest.cs @@ -2,8 +2,8 @@ using System.Linq; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; +using Ocelot.Claims.Parser; using Ocelot.Configuration; -using Ocelot.HeaderBuilder.Parser; using Ocelot.Responses; namespace Ocelot.HeaderBuilder diff --git a/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs b/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs index 515ac74f..9815388f 100644 --- a/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs +++ b/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs @@ -20,7 +20,7 @@ namespace Ocelot.Middleware builder.UseAuthenticationMiddleware(); - //builder.UseAuthorisationMiddleware(); + builder.UseAuthorisationMiddleware(); builder.UseHttpRequestHeadersBuilderMiddleware(); diff --git a/test/Ocelot.AcceptanceTests/AuthorisationTests.cs b/test/Ocelot.AcceptanceTests/AuthorisationTests.cs new file mode 100644 index 00000000..7a1ec440 --- /dev/null +++ b/test/Ocelot.AcceptanceTests/AuthorisationTests.cs @@ -0,0 +1,297 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Text.Encodings.Web; +using IdentityServer4.Models; +using IdentityServer4.Services.InMemory; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using Newtonsoft.Json; +using Ocelot.Configuration.Yaml; +using Ocelot.ManualTest; +using Shouldly; +using TestStack.BDDfy; +using Xunit; +using YamlDotNet.Serialization; + +namespace Ocelot.AcceptanceTests +{ + using System.Security.Claims; + + public class AuthorisationTests : IDisposable + { + private TestServer _ocelotServer; + private HttpClient _ocelotClient; + private HttpResponseMessage _response; + private readonly string _configurationPath; + private StringContent _postContent; + private IWebHost _servicebuilder; + + // Sadly we need to change this when we update the netcoreapp version to make the test update the config correctly + private double _netCoreAppVersion = 1.4; + private BearerToken _token; + private IWebHost _identityServerBuilder; + + public AuthorisationTests() + { + _configurationPath = $"./bin/Debug/netcoreapp{_netCoreAppVersion}/configuration.yaml"; + } + + [Fact] + public void should_return_response_200_authorising_route() + { + this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Jwt)) + .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura")) + .And(x => x.GivenIHaveAToken("http://localhost:51888")) + .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration + { + ReRoutes = new List + { + new YamlReRoute + { + DownstreamTemplate = "http://localhost:51876/", + UpstreamTemplate = "/", + UpstreamHttpMethod = "Get", + AuthenticationOptions = new YamlAuthenticationOptions + { + AdditionalScopes = new List(), + Provider = "IdentityServer", + ProviderRootUrl = "http://localhost:51888", + RequireHttps = false, + ScopeName = "api", + ScopeSecret = "secret" + }, + AddHeadersToRequest = + { + {"CustomerId", "Claims[CustomerId] > value"}, + {"LocationId", "Claims[LocationId] > value"}, + {"UserType", "Claims[sub] > value[0] > |"}, + {"UserId", "Claims[sub] > value[1] > |"} + }, + AddClaims = + { + {"CustomerId", "Claims[CustomerId] > value"}, + {"UserType", "Claims[sub] > value[0] > |"}, + {"UserId", "Claims[sub] > value[1] > |"} + } + } + } + })) + .And(x => x.GivenTheApiGatewayIsRunning()) + .And(x => x.GivenIHaveAddedATokenToMyRequest()) + .When(x => x.WhenIGetUrlOnTheApiGateway("/")) + .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + .And(x => x.ThenTheResponseBodyShouldBe("Hello from Laura")) + .BDDfy(); + } + + private void WhenIGetUrlOnTheApiGateway(string url) + { + _response = _ocelotClient.GetAsync(url).Result; + } + + private void WhenIPostUrlOnTheApiGateway(string url) + { + _response = _ocelotClient.PostAsync(url, _postContent).Result; + } + + private void ThenTheResponseBodyShouldBe(string expectedBody) + { + _response.Content.ReadAsStringAsync().Result.ShouldBe(expectedBody); + } + + private void GivenThePostHasContent(string postcontent) + { + _postContent = new StringContent(postcontent); + } + + /// + /// This is annoying cos it should be in the constructor but we need to set up the yaml file before calling startup so its a step. + /// + private void GivenTheApiGatewayIsRunning() + { + _ocelotServer = new TestServer(new WebHostBuilder() + .UseStartup()); + + _ocelotClient = _ocelotServer.CreateClient(); + } + + private void GivenThereIsAConfiguration(YamlConfiguration yamlConfiguration) + { + var serializer = new Serializer(); + + if (File.Exists(_configurationPath)) + { + File.Delete(_configurationPath); + } + + using (TextWriter writer = File.CreateText(_configurationPath)) + { + serializer.Serialize(writer, yamlConfiguration); + } + } + + private void GivenThereIsAServiceRunningOn(string url, int statusCode, string responseBody) + { + _servicebuilder = new WebHostBuilder() + .UseUrls(url) + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseUrls(url) + .Configure(app => + { + app.Run(async context => + { + context.Response.StatusCode = statusCode; + await context.Response.WriteAsync(responseBody); + }); + }) + .Build(); + + _servicebuilder.Start(); + } + + private void GivenThereIsAnIdentityServerOn(string url, string scopeName, AccessTokenType tokenType) + { + _identityServerBuilder = new WebHostBuilder() + .UseUrls(url) + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseUrls(url) + .ConfigureServices(services => + { + services.AddLogging(); + services.AddDeveloperIdentityServer() + .AddInMemoryScopes(new List + { + new Scope + { + Name = scopeName, + Description = "My API", + Enabled = true, + AllowUnrestrictedIntrospection = true, + ScopeSecrets = new List() + { + new Secret + { + Value = "secret".Sha256() + } + } + }, + + StandardScopes.OpenId, + StandardScopes.OfflineAccess + }) + .AddInMemoryClients(new List + { + new Client + { + ClientId = "client", + AllowedGrantTypes = GrantTypes.ResourceOwnerPassword, + ClientSecrets = new List {new Secret("secret".Sha256())}, + AllowedScopes = new List { scopeName, "openid", "offline_access" }, + AccessTokenType = tokenType, + Enabled = true, + RequireClientSecret = false + } + }) + .AddInMemoryUsers(new List + { + new InMemoryUser + { + Username = "test", + Password = "test", + Enabled = true, + Subject = "registered|1231231", + Claims = new List + { + new Claim("CustomerId", "123"), + new Claim("LocationId", "321") + } + } + }); + }) + .Configure(app => + { + app.UseIdentityServer(); + }) + .Build(); + + _identityServerBuilder.Start(); + + VerifyIdentiryServerStarted(url); + + } + + private void VerifyIdentiryServerStarted(string url) + { + using (var httpClient = new HttpClient()) + { + var response = httpClient.GetAsync($"{url}/.well-known/openid-configuration").Result; + response.EnsureSuccessStatusCode(); + } + } + + private void GivenIHaveAToken(string url) + { + var tokenUrl = $"{url}/connect/token"; + var formData = new List> + { + new KeyValuePair("client_id", "client"), + new KeyValuePair("client_secret", "secret"), + new KeyValuePair("scope", "api"), + new KeyValuePair("username", "test"), + new KeyValuePair("password", "test"), + new KeyValuePair("grant_type", "password") + }; + var content = new FormUrlEncodedContent(formData); + + using (var httpClient = new HttpClient()) + { + var response = httpClient.PostAsync(tokenUrl, content).Result; + response.EnsureSuccessStatusCode(); + var responseContent = response.Content.ReadAsStringAsync().Result; + _token = JsonConvert.DeserializeObject(responseContent); + } + } + + private void GivenIHaveAddedATokenToMyRequest() + { + _ocelotClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _token.AccessToken); + } + + private void ThenTheStatusCodeShouldBe(HttpStatusCode expectedHttpStatusCode) + { + _response.StatusCode.ShouldBe(expectedHttpStatusCode); + } + + public void Dispose() + { + _servicebuilder?.Dispose(); + _ocelotClient?.Dispose(); + _ocelotServer?.Dispose(); + _identityServerBuilder?.Dispose(); + } + + // ReSharper disable once ClassNeverInstantiated.Local + class BearerToken + { + [JsonProperty("access_token")] + public string AccessToken { get; set; } + + [JsonProperty("expires_in")] + public int ExpiresIn { get; set; } + + [JsonProperty("token_type")] + public string TokenType { get; set; } + } + } +} diff --git a/test/Ocelot.UnitTests/Authorization/AuthorizationMiddlewareTests.cs b/test/Ocelot.UnitTests/Authorization/AuthorizationMiddlewareTests.cs index b9d1746b..d747a41c 100644 --- a/test/Ocelot.UnitTests/Authorization/AuthorizationMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Authorization/AuthorizationMiddlewareTests.cs @@ -57,11 +57,20 @@ namespace Ocelot.UnitTests.Authorization public void happy_path() { this.Given(x => x.GivenTheDownStreamRouteIs(new DownstreamRoute(new List(), new ReRouteBuilder().Build()))) + .And(x => x.GivenTheAuthServiceReturns(new OkResponse(true))) .When(x => x.WhenICallTheMiddleware()) - .Then(x => x.ThenTheAuthServiceIsCalledCorrectly()) + //todo stick this back in + //.Then(x => x.ThenTheAuthServiceIsCalledCorrectly()) .BDDfy(); } + private void GivenTheAuthServiceReturns(Response expected) + { + _authService + .Setup(x => x.Authorise(It.IsAny(), It.IsAny())) + .Returns(expected); + } + private void ThenTheAuthServiceIsCalledCorrectly() { _authService diff --git a/test/Ocelot.UnitTests/Authorization/ClaimsAuthoriserTests.cs b/test/Ocelot.UnitTests/Authorization/ClaimsAuthoriserTests.cs new file mode 100644 index 00000000..15dde43c --- /dev/null +++ b/test/Ocelot.UnitTests/Authorization/ClaimsAuthoriserTests.cs @@ -0,0 +1,78 @@ +using System.Collections.Generic; +using System.Security.Claims; +using Ocelot.Authorisation; +using Ocelot.Claims.Parser; +using Ocelot.Responses; +using Shouldly; +using TestStack.BDDfy; +using Xunit; + +namespace Ocelot.UnitTests.Authorization +{ + public class ClaimsAuthoriserTests + { + private readonly ClaimsAuthoriser _claimsAuthoriser; + private ClaimsPrincipal _claimsPrincipal; + private RouteClaimsRequirement _requirement; + private Response _result; + + public ClaimsAuthoriserTests() + { + _claimsAuthoriser = new ClaimsAuthoriser(new ClaimsParser()); + } + + [Fact] + public void should_authorise_user() + { + this.Given(x => x.GivenAClaimsPrincipal(new ClaimsPrincipal(new ClaimsIdentity(new List + { + new Claim("UserType", "registered") + })))) + .And(x => x.GivenARouteClaimsRequirement(new RouteClaimsRequirement(new Dictionary + { + {"UserType", "registered"} + }))) + .When(x => x.WhenICallTheAuthoriser()) + .Then(x => x.ThenTheUserIsAuthorised()) + .BDDfy(); + } + + [Fact] + public void should_not_authorise_user() + { + this.Given(x => x.GivenAClaimsPrincipal(new ClaimsPrincipal(new ClaimsIdentity(new List())))) + .And(x => x.GivenARouteClaimsRequirement(new RouteClaimsRequirement(new Dictionary + { + { "UserType", "registered" } + }))) + .When(x => x.WhenICallTheAuthoriser()) + .Then(x => x.ThenTheUserIsntAuthorised()) + .BDDfy(); + } + + private void GivenAClaimsPrincipal(ClaimsPrincipal claimsPrincipal) + { + _claimsPrincipal = claimsPrincipal; + } + + private void GivenARouteClaimsRequirement(RouteClaimsRequirement requirement) + { + _requirement = requirement; + } + + private void WhenICallTheAuthoriser() + { + _result = _claimsAuthoriser.Authorise(_claimsPrincipal, _requirement); + } + + private void ThenTheUserIsAuthorised() + { + _result.Data.ShouldBe(true); + } + + private void ThenTheUserIsntAuthorised() + { + _result.Data.ShouldBe(false); + } + } +} diff --git a/test/Ocelot.UnitTests/HeaderBuilder/AddHeadersToRequestTests.cs b/test/Ocelot.UnitTests/HeaderBuilder/AddHeadersToRequestTests.cs index 7834558f..59c111f2 100644 --- a/test/Ocelot.UnitTests/HeaderBuilder/AddHeadersToRequestTests.cs +++ b/test/Ocelot.UnitTests/HeaderBuilder/AddHeadersToRequestTests.cs @@ -4,10 +4,10 @@ using System.Security.Claims; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; using Moq; +using Ocelot.Claims.Parser; using Ocelot.Configuration; using Ocelot.Errors; using Ocelot.HeaderBuilder; -using Ocelot.HeaderBuilder.Parser; using Ocelot.Responses; using Shouldly; using TestStack.BDDfy; diff --git a/test/Ocelot.UnitTests/HeaderBuilder/ClaimParserTests.cs b/test/Ocelot.UnitTests/HeaderBuilder/ClaimParserTests.cs index 7b12f150..189508d8 100644 --- a/test/Ocelot.UnitTests/HeaderBuilder/ClaimParserTests.cs +++ b/test/Ocelot.UnitTests/HeaderBuilder/ClaimParserTests.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Security.Claims; +using Ocelot.Claims.Parser; using Ocelot.Errors; -using Ocelot.HeaderBuilder.Parser; using Ocelot.Responses; using Shouldly; using TestStack.BDDfy; From b8951c4698a7f9d4f9bc234f9e62e397554410cc Mon Sep 17 00:00:00 2001 From: "tom.pallister" Date: Wed, 19 Oct 2016 11:56:05 +0100 Subject: [PATCH 099/183] Can authorise routes based on claims, there is also a claims transformation middleware --- src/Ocelot/Authorisation/AddClaims.cs | 45 ------ .../Authorisation/AuthorisationMiddleware.cs | 60 -------- src/Ocelot/Authorisation/ClaimsAuthoriser.cs | 7 +- src/Ocelot/Authorisation/IAddClaims.cs | 13 -- src/Ocelot/Authorisation/IAuthoriser.cs | 6 +- .../Middleware/AuthorisationMiddleware.cs | 66 ++++++++ ...orisationMiddlewareMiddlewareExtensions.cs | 6 +- .../Authorisation/RouteClaimsRequirement.cs | 14 -- .../ClaimsBuilder/AddClaimsToRequest.cs | 46 ++++++ .../ClaimsBuilder/IAddClaimsToRequest.cs | 13 ++ .../Middleware/ClaimsBuilderMiddleware.cs | 44 ++++++ .../ClaimsBuilderMiddlewareExtensions.cs | 12 ++ .../Configuration/Builder/ReRouteBuilder.cs | 29 +++- src/Ocelot/Configuration/ClaimToHeader.cs | 18 --- src/Ocelot/Configuration/ClaimToThing.cs | 18 +++ .../Creator/YamlOcelotConfigurationCreator.cs | 31 ++-- ....cs => ClaimToThingConfigurationParser.cs} | 16 +- .../IClaimToHeaderConfigurationParser.cs | 9 -- .../IClaimToThingConfigurationParser.cs | 9 ++ src/Ocelot/Configuration/ReRoute.cs | 14 +- src/Ocelot/Configuration/Yaml/YamlReRoute.cs | 6 +- .../ServiceCollectionExtensions.cs | 7 +- .../HeaderBuilder/AddHeadersToRequest.cs | 13 +- .../HeaderBuilder/IAddHeadersToRequest.cs | 2 +- .../Claims/Parser/CannotFindClaimError.cs | 6 +- .../Claims/Parser/ClaimsParser.cs | 14 +- .../Claims/Parser/IClaimsParser.cs | 10 +- .../Middleware/OcelotMiddlewareExtensions.cs | 6 +- .../Responder/ErrorsToHttpStatusCodeMapper.cs | 8 + .../AuthorisationTests.cs | 69 +++++++-- ...sts.cs => AuthorisationMiddlewareTests.cs} | 15 +- .../Authorization/ClaimsAuthoriserTests.cs | 15 +- .../ClaimsBuilder/AddClaimsToRequestTests.cs | 145 ++++++++++++++++++ .../ClaimsBuilderMiddlewareTests.cs | 111 ++++++++++++++ ...> ClaimToThingConfigurationParserTests.cs} | 30 ++-- .../YamlConfigurationCreatorTests.cs | 14 +- .../HeaderBuilder/AddHeadersToRequestTests.cs | 19 +-- ...ttpRequestHeadersBuilderMiddlewareTests.cs | 8 +- .../ClaimParserTests.cs | 20 +-- 39 files changed, 700 insertions(+), 294 deletions(-) delete mode 100644 src/Ocelot/Authorisation/AddClaims.cs delete mode 100644 src/Ocelot/Authorisation/AuthorisationMiddleware.cs delete mode 100644 src/Ocelot/Authorisation/IAddClaims.cs create mode 100644 src/Ocelot/Authorisation/Middleware/AuthorisationMiddleware.cs rename src/Ocelot/Authorisation/{ => Middleware}/AuthorisationMiddlewareMiddlewareExtensions.cs (77%) delete mode 100644 src/Ocelot/Authorisation/RouteClaimsRequirement.cs create mode 100644 src/Ocelot/ClaimsBuilder/AddClaimsToRequest.cs create mode 100644 src/Ocelot/ClaimsBuilder/IAddClaimsToRequest.cs create mode 100644 src/Ocelot/ClaimsBuilder/Middleware/ClaimsBuilderMiddleware.cs create mode 100644 src/Ocelot/ClaimsBuilder/Middleware/ClaimsBuilderMiddlewareExtensions.cs delete mode 100644 src/Ocelot/Configuration/ClaimToHeader.cs create mode 100644 src/Ocelot/Configuration/ClaimToThing.cs rename src/Ocelot/Configuration/Parser/{ClaimToHeaderConfigurationParser.cs => ClaimToThingConfigurationParser.cs} (78%) delete mode 100644 src/Ocelot/Configuration/Parser/IClaimToHeaderConfigurationParser.cs create mode 100644 src/Ocelot/Configuration/Parser/IClaimToThingConfigurationParser.cs rename src/Ocelot/{ => Infrastructure}/Claims/Parser/CannotFindClaimError.cs (75%) rename src/Ocelot/{ => Infrastructure}/Claims/Parser/ClaimsParser.cs (88%) rename src/Ocelot/{ => Infrastructure}/Claims/Parser/IClaimsParser.cs (52%) rename test/Ocelot.UnitTests/Authorization/{AuthorizationMiddlewareTests.cs => AuthorisationMiddlewareTests.cs} (89%) create mode 100644 test/Ocelot.UnitTests/ClaimsBuilder/AddClaimsToRequestTests.cs create mode 100644 test/Ocelot.UnitTests/ClaimsBuilder/ClaimsBuilderMiddlewareTests.cs rename test/Ocelot.UnitTests/Configuration/{ConfigurationHeadersExtractorTests.cs => ClaimToThingConfigurationParserTests.cs} (77%) rename test/Ocelot.UnitTests/{HeaderBuilder => Infrastructure}/ClaimParserTests.cs (93%) diff --git a/src/Ocelot/Authorisation/AddClaims.cs b/src/Ocelot/Authorisation/AddClaims.cs deleted file mode 100644 index 4e7f9227..00000000 --- a/src/Ocelot/Authorisation/AddClaims.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Primitives; -using Ocelot.Claims.Parser; -using Ocelot.Configuration; -using Ocelot.HeaderBuilder; -using Ocelot.Responses; - -namespace Ocelot.Authorisation -{ - public class AddClaims : IAddHeadersToRequest - { - private readonly IClaimsParser _claimsParser; - - public AddClaims(IClaimsParser claimsParser) - { - _claimsParser = claimsParser; - } - - public Response SetHeadersOnContext(List configurationHeaderExtractorProperties, HttpContext context) - { - foreach (var config in configurationHeaderExtractorProperties) - { - var value = _claimsParser.GetValue(context.User.Claims, config.ClaimKey, config.Delimiter, config.Index); - - if (value.IsError) - { - return new ErrorResponse(value.Errors); - } - - var exists = context.Request.Headers.FirstOrDefault(x => x.Key == config.HeaderKey); - - if (!string.IsNullOrEmpty(exists.Key)) - { - context.Request.Headers.Remove(exists); - } - - context.Request.Headers.Add(config.HeaderKey, new StringValues(value.Data)); - } - - return new OkResponse(); - } - } -} \ No newline at end of file diff --git a/src/Ocelot/Authorisation/AuthorisationMiddleware.cs b/src/Ocelot/Authorisation/AuthorisationMiddleware.cs deleted file mode 100644 index 53ddb436..00000000 --- a/src/Ocelot/Authorisation/AuthorisationMiddleware.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using Ocelot.DownstreamRouteFinder; -using Ocelot.Errors; -using Ocelot.Middleware; -using Ocelot.Responses; -using Ocelot.ScopedData; - -namespace Ocelot.Authorisation -{ - public class AuthorisationMiddleware : OcelotMiddleware - { - private readonly RequestDelegate _next; - private readonly IScopedRequestDataRepository _scopedRequestDataRepository; - private readonly IAuthoriser _authoriser; - - public AuthorisationMiddleware(RequestDelegate next, - IScopedRequestDataRepository scopedRequestDataRepository, - IAuthoriser authoriser) - : base(scopedRequestDataRepository) - { - _next = next; - _scopedRequestDataRepository = scopedRequestDataRepository; - _authoriser = authoriser; - } - - public async Task Invoke(HttpContext context) - { - var downstreamRoute = _scopedRequestDataRepository.Get("DownstreamRoute"); - - if (downstreamRoute.IsError) - { - SetPipelineError(downstreamRoute.Errors); - return; - } - - //todo - call authoriser - var authorised = new OkResponse(true); //_authoriser.Authorise(context.User, new RouteClaimsRequirement(new Dictionary())); - - if (authorised.IsError) - { - SetPipelineError(authorised.Errors); - return; - } - - if (authorised.Data) - { - await _next.Invoke(context); - } - else - { - SetPipelineError(new List - { - new UnauthorisedError($"{context.User.Identity.Name} unable to access {downstreamRoute.Data.ReRoute.UpstreamTemplate}") - }); - } - } - } -} diff --git a/src/Ocelot/Authorisation/ClaimsAuthoriser.cs b/src/Ocelot/Authorisation/ClaimsAuthoriser.cs index 52409c82..cb7849e9 100644 --- a/src/Ocelot/Authorisation/ClaimsAuthoriser.cs +++ b/src/Ocelot/Authorisation/ClaimsAuthoriser.cs @@ -1,12 +1,13 @@ using System.Collections.Generic; using System.Linq; using System.Security.Claims; -using Ocelot.Claims.Parser; using Ocelot.Errors; using Ocelot.Responses; namespace Ocelot.Authorisation { + using Infrastructure.Claims.Parser; + public class ClaimsAuthoriser : IAuthoriser { private readonly IClaimsParser _claimsParser; @@ -16,9 +17,9 @@ namespace Ocelot.Authorisation _claimsParser = claimsParser; } - public Response Authorise(ClaimsPrincipal claimsPrincipal, RouteClaimsRequirement routeClaimsRequirement) + public Response Authorise(ClaimsPrincipal claimsPrincipal, Dictionary routeClaimsRequirement) { - foreach (var required in routeClaimsRequirement.RequiredClaimsAndValues) + foreach (var required in routeClaimsRequirement) { var value = _claimsParser.GetValue(claimsPrincipal.Claims, required.Key, string.Empty, 0); diff --git a/src/Ocelot/Authorisation/IAddClaims.cs b/src/Ocelot/Authorisation/IAddClaims.cs deleted file mode 100644 index d68b0750..00000000 --- a/src/Ocelot/Authorisation/IAddClaims.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Collections.Generic; -using Microsoft.AspNetCore.Http; -using Ocelot.Configuration; -using Ocelot.Responses; - -namespace Ocelot.Authorisation -{ - public interface IAddClaims - { - Response SetHeadersOnContext(List configurationHeaderExtractorProperties, - HttpContext context); - } -} diff --git a/src/Ocelot/Authorisation/IAuthoriser.cs b/src/Ocelot/Authorisation/IAuthoriser.cs index 96b1291f..08a7307f 100644 --- a/src/Ocelot/Authorisation/IAuthoriser.cs +++ b/src/Ocelot/Authorisation/IAuthoriser.cs @@ -3,9 +3,11 @@ using Ocelot.Responses; namespace Ocelot.Authorisation { + using System.Collections.Generic; + public interface IAuthoriser { - Response Authorise(ClaimsPrincipal claimsPrincipal, - RouteClaimsRequirement routeClaimsRequirement); + Response Authorise(ClaimsPrincipal claimsPrincipal, + Dictionary routeClaimsRequirement); } } diff --git a/src/Ocelot/Authorisation/Middleware/AuthorisationMiddleware.cs b/src/Ocelot/Authorisation/Middleware/AuthorisationMiddleware.cs new file mode 100644 index 00000000..23c005b6 --- /dev/null +++ b/src/Ocelot/Authorisation/Middleware/AuthorisationMiddleware.cs @@ -0,0 +1,66 @@ +namespace Ocelot.Authorisation.Middleware +{ + using System.Collections.Generic; + using System.Threading.Tasks; + using DownstreamRouteFinder; + using Errors; + using Microsoft.AspNetCore.Http; + using Ocelot.Middleware; + using ScopedData; + + public class AuthorisationMiddleware : OcelotMiddleware + { + private readonly RequestDelegate _next; + private readonly IScopedRequestDataRepository _scopedRequestDataRepository; + private readonly IAuthoriser _authoriser; + + public AuthorisationMiddleware(RequestDelegate next, + IScopedRequestDataRepository scopedRequestDataRepository, + IAuthoriser authoriser) + : base(scopedRequestDataRepository) + { + _next = next; + _scopedRequestDataRepository = scopedRequestDataRepository; + _authoriser = authoriser; + } + + public async Task Invoke(HttpContext context) + { + var downstreamRoute = _scopedRequestDataRepository.Get("DownstreamRoute"); + + if (downstreamRoute.IsError) + { + SetPipelineError(downstreamRoute.Errors); + return; + } + + if (downstreamRoute.Data.ReRoute.IsAuthorised) + { + var authorised = _authoriser.Authorise(context.User, downstreamRoute.Data.ReRoute.RouteClaimsRequirement); + + if (authorised.IsError) + { + SetPipelineError(authorised.Errors); + return; + } + + if (authorised.Data) + { + await _next.Invoke(context); + } + else + { + SetPipelineError(new List + { + new UnauthorisedError( + $"{context.User.Identity.Name} unable to access {downstreamRoute.Data.ReRoute.UpstreamTemplate}") + }); + } + } + else + { + await _next.Invoke(context); + } + } + } +} diff --git a/src/Ocelot/Authorisation/AuthorisationMiddlewareMiddlewareExtensions.cs b/src/Ocelot/Authorisation/Middleware/AuthorisationMiddlewareMiddlewareExtensions.cs similarity index 77% rename from src/Ocelot/Authorisation/AuthorisationMiddlewareMiddlewareExtensions.cs rename to src/Ocelot/Authorisation/Middleware/AuthorisationMiddlewareMiddlewareExtensions.cs index 291a47ad..e2c8af2d 100644 --- a/src/Ocelot/Authorisation/AuthorisationMiddlewareMiddlewareExtensions.cs +++ b/src/Ocelot/Authorisation/Middleware/AuthorisationMiddlewareMiddlewareExtensions.cs @@ -1,7 +1,7 @@ -using Microsoft.AspNetCore.Builder; - -namespace Ocelot.Authorisation +namespace Ocelot.Authorisation.Middleware { + using Microsoft.AspNetCore.Builder; + public static class AuthorisationMiddlewareMiddlewareExtensions { public static IApplicationBuilder UseAuthorisationMiddleware(this IApplicationBuilder builder) diff --git a/src/Ocelot/Authorisation/RouteClaimsRequirement.cs b/src/Ocelot/Authorisation/RouteClaimsRequirement.cs deleted file mode 100644 index 5cc0e412..00000000 --- a/src/Ocelot/Authorisation/RouteClaimsRequirement.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Collections.Generic; - -namespace Ocelot.Authorisation -{ - public class RouteClaimsRequirement - { - public RouteClaimsRequirement(Dictionary requiredClaimsAndValues) - { - RequiredClaimsAndValues = requiredClaimsAndValues; - } - - public Dictionary RequiredClaimsAndValues { get; private set; } - } -} diff --git a/src/Ocelot/ClaimsBuilder/AddClaimsToRequest.cs b/src/Ocelot/ClaimsBuilder/AddClaimsToRequest.cs new file mode 100644 index 00000000..f5be6a9f --- /dev/null +++ b/src/Ocelot/ClaimsBuilder/AddClaimsToRequest.cs @@ -0,0 +1,46 @@ +namespace Ocelot.ClaimsBuilder +{ + using System.Collections.Generic; + using System.Linq; + using System.Security.Claims; + using Configuration; + using Infrastructure.Claims.Parser; + using Microsoft.AspNetCore.Http; + using Responses; + + public class AddClaimsToRequest : IAddClaimsToRequest + { + private readonly IClaimsParser _claimsParser; + + public AddClaimsToRequest(IClaimsParser claimsParser) + { + _claimsParser = claimsParser; + } + + public Response SetClaimsOnContext(List claimsToThings, HttpContext context) + { + foreach (var config in claimsToThings) + { + var value = _claimsParser.GetValue(context.User.Claims, config.NewKey, config.Delimiter, config.Index); + + if (value.IsError) + { + return new ErrorResponse(value.Errors); + } + + var exists = context.User.Claims.FirstOrDefault(x => x.Type == config.ExistingKey); + + var identity = context.User.Identity as ClaimsIdentity; + + if (exists != null) + { + identity?.RemoveClaim(exists); + } + + identity?.AddClaim(new Claim(config.ExistingKey, value.Data)); + } + + return new OkResponse(); + } + } +} \ No newline at end of file diff --git a/src/Ocelot/ClaimsBuilder/IAddClaimsToRequest.cs b/src/Ocelot/ClaimsBuilder/IAddClaimsToRequest.cs new file mode 100644 index 00000000..9069bfe3 --- /dev/null +++ b/src/Ocelot/ClaimsBuilder/IAddClaimsToRequest.cs @@ -0,0 +1,13 @@ +namespace Ocelot.ClaimsBuilder +{ + using System.Collections.Generic; + using Configuration; + using Microsoft.AspNetCore.Http; + using Responses; + + public interface IAddClaimsToRequest + { + Response SetClaimsOnContext(List claimsToThings, + HttpContext context); + } +} diff --git a/src/Ocelot/ClaimsBuilder/Middleware/ClaimsBuilderMiddleware.cs b/src/Ocelot/ClaimsBuilder/Middleware/ClaimsBuilderMiddleware.cs new file mode 100644 index 00000000..570706fa --- /dev/null +++ b/src/Ocelot/ClaimsBuilder/Middleware/ClaimsBuilderMiddleware.cs @@ -0,0 +1,44 @@ +namespace Ocelot.ClaimsBuilder.Middleware +{ + using System.Linq; + using System.Threading.Tasks; + using DownstreamRouteFinder; + using Microsoft.AspNetCore.Http; + using Ocelot.Middleware; + using ScopedData; + + public class ClaimsBuilderMiddleware : OcelotMiddleware + { + private readonly RequestDelegate _next; + private readonly IAddClaimsToRequest _addClaimsToRequest; + private readonly IScopedRequestDataRepository _scopedRequestDataRepository; + + public ClaimsBuilderMiddleware(RequestDelegate next, + IScopedRequestDataRepository scopedRequestDataRepository, + IAddClaimsToRequest addClaimsToRequest) + : base(scopedRequestDataRepository) + { + _next = next; + _addClaimsToRequest = addClaimsToRequest; + _scopedRequestDataRepository = scopedRequestDataRepository; + } + + public async Task Invoke(HttpContext context) + { + var downstreamRoute = _scopedRequestDataRepository.Get("DownstreamRoute"); + + if (downstreamRoute.Data.ReRoute.ClaimsToClaims.Any()) + { + var result = _addClaimsToRequest.SetClaimsOnContext(downstreamRoute.Data.ReRoute.ClaimsToClaims, context); + + if (result.IsError) + { + SetPipelineError(result.Errors); + return; + } + } + + await _next.Invoke(context); + } + } +} diff --git a/src/Ocelot/ClaimsBuilder/Middleware/ClaimsBuilderMiddlewareExtensions.cs b/src/Ocelot/ClaimsBuilder/Middleware/ClaimsBuilderMiddlewareExtensions.cs new file mode 100644 index 00000000..4da29e83 --- /dev/null +++ b/src/Ocelot/ClaimsBuilder/Middleware/ClaimsBuilderMiddlewareExtensions.cs @@ -0,0 +1,12 @@ +namespace Ocelot.ClaimsBuilder.Middleware +{ + using Microsoft.AspNetCore.Builder; + + public static class ClaimsBuilderMiddlewareExtensions + { + public static IApplicationBuilder UseClaimsBuilderMiddleware(this IApplicationBuilder builder) + { + return builder.UseMiddleware(); + } + } +} \ No newline at end of file diff --git a/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs b/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs index e369d78d..db3aa617 100644 --- a/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs +++ b/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs @@ -15,7 +15,10 @@ namespace Ocelot.Configuration.Builder private List _additionalScopes; private bool _requireHttps; private string _scopeSecret; - private List _configHeaderExtractorProperties; + private List _configHeaderExtractorProperties; + private List _claimToClaims; + private Dictionary _routeClaimRequirement; + private bool _isAuthorised; public ReRouteBuilder() { @@ -48,8 +51,14 @@ namespace Ocelot.Configuration.Builder { _isAuthenticated = input; return this; - } + + public ReRouteBuilder WithIsAuthorised(bool input) + { + _isAuthorised = input; + return this; + } + public ReRouteBuilder WithAuthenticationProvider(string input) { _authenticationProvider = input; @@ -86,15 +95,27 @@ namespace Ocelot.Configuration.Builder return this; } - public ReRouteBuilder WithConfigurationHeaderExtractorProperties(List input) + public ReRouteBuilder WithClaimsToHeaders(List input) { _configHeaderExtractorProperties = input; return this; } + public ReRouteBuilder WithClaimsToClaims(List input) + { + _claimToClaims = input; + return this; + } + + public ReRouteBuilder WithRouteClaimsRequirement(Dictionary input) + { + _routeClaimRequirement = input; + return this; + } + public ReRoute Build() { - return new ReRoute(_downstreamTemplate, _upstreamTemplate, _upstreamHttpMethod, _upstreamTemplatePattern, _isAuthenticated, new AuthenticationOptions(_authenticationProvider, _authenticationProviderUrl, _scopeName, _requireHttps, _additionalScopes, _scopeSecret), _configHeaderExtractorProperties); + return new ReRoute(_downstreamTemplate, _upstreamTemplate, _upstreamHttpMethod, _upstreamTemplatePattern, _isAuthenticated, new AuthenticationOptions(_authenticationProvider, _authenticationProviderUrl, _scopeName, _requireHttps, _additionalScopes, _scopeSecret), _configHeaderExtractorProperties, _claimToClaims, _routeClaimRequirement, _isAuthorised); } } } diff --git a/src/Ocelot/Configuration/ClaimToHeader.cs b/src/Ocelot/Configuration/ClaimToHeader.cs deleted file mode 100644 index dce96268..00000000 --- a/src/Ocelot/Configuration/ClaimToHeader.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Ocelot.Configuration -{ - public class ClaimToHeader - { - public ClaimToHeader(string headerKey, string claimKey, string delimiter, int index) - { - ClaimKey = claimKey; - Delimiter = delimiter; - Index = index; - HeaderKey = headerKey; - } - - public string HeaderKey { get; private set; } - public string ClaimKey { get; private set; } - public string Delimiter { get; private set; } - public int Index { get; private set; } - } -} diff --git a/src/Ocelot/Configuration/ClaimToThing.cs b/src/Ocelot/Configuration/ClaimToThing.cs new file mode 100644 index 00000000..5a677667 --- /dev/null +++ b/src/Ocelot/Configuration/ClaimToThing.cs @@ -0,0 +1,18 @@ +namespace Ocelot.Configuration +{ + public class ClaimToThing + { + public ClaimToThing(string existingKey, string newKey, string delimiter, int index) + { + NewKey = newKey; + Delimiter = delimiter; + Index = index; + ExistingKey = existingKey; + } + + public string ExistingKey { get; private set; } + public string NewKey { get; private set; } + public string Delimiter { get; private set; } + public int Index { get; private set; } + } +} diff --git a/src/Ocelot/Configuration/Creator/YamlOcelotConfigurationCreator.cs b/src/Ocelot/Configuration/Creator/YamlOcelotConfigurationCreator.cs index b4ff9d15..e0efd611 100644 --- a/src/Ocelot/Configuration/Creator/YamlOcelotConfigurationCreator.cs +++ b/src/Ocelot/Configuration/Creator/YamlOcelotConfigurationCreator.cs @@ -18,18 +18,18 @@ namespace Ocelot.Configuration.Creator private readonly IConfigurationValidator _configurationValidator; private const string RegExMatchEverything = ".*"; private const string RegExMatchEndString = "$"; - private readonly IClaimToHeaderConfigurationParser _claimToHeaderConfigurationParser; + private readonly IClaimToThingConfigurationParser _claimToThingConfigurationParser; private readonly ILogger _logger; public YamlOcelotConfigurationCreator( IOptions options, IConfigurationValidator configurationValidator, - IClaimToHeaderConfigurationParser claimToHeaderConfigurationParser, + IClaimToThingConfigurationParser claimToThingConfigurationParser, ILogger logger) { _options = options; _configurationValidator = configurationValidator; - _claimToHeaderConfigurationParser = claimToHeaderConfigurationParser; + _claimToThingConfigurationParser = claimToThingConfigurationParser; _logger = logger; } @@ -89,6 +89,8 @@ namespace Ocelot.Configuration.Creator var isAuthenticated = !string.IsNullOrEmpty(reRoute.AuthenticationOptions?.Provider); + var isAuthorised = reRoute.RouteClaimsRequirement?.Count > 0; + if (isAuthenticated) { var authOptionsForRoute = new AuthenticationOptions(reRoute.AuthenticationOptions.Provider, @@ -96,37 +98,38 @@ namespace Ocelot.Configuration.Creator reRoute.AuthenticationOptions.RequireHttps, reRoute.AuthenticationOptions.AdditionalScopes, reRoute.AuthenticationOptions.ScopeSecret); - var configHeaders = GetHeadersToAddToRequest(reRoute); + var claimsToHeaders = GetAddThingsToRequest(reRoute.AddHeadersToRequest); + var claimsToClaims = GetAddThingsToRequest(reRoute.AddClaimsToRequest); return new ReRoute(reRoute.DownstreamTemplate, reRoute.UpstreamTemplate, reRoute.UpstreamHttpMethod, upstreamTemplate, isAuthenticated, - authOptionsForRoute, configHeaders + authOptionsForRoute, claimsToHeaders, claimsToClaims, reRoute.RouteClaimsRequirement, isAuthorised ); } return new ReRoute(reRoute.DownstreamTemplate, reRoute.UpstreamTemplate, reRoute.UpstreamHttpMethod, - upstreamTemplate, isAuthenticated, null, new List()); + upstreamTemplate, isAuthenticated, null, new List(), new List(), reRoute.RouteClaimsRequirement, isAuthorised); } - private List GetHeadersToAddToRequest(YamlReRoute reRoute) + private List GetAddThingsToRequest(Dictionary thingBeingAdded) { - var configHeaders = new List(); + var claimsToTHings = new List(); - foreach (var add in reRoute.AddHeadersToRequest) + foreach (var add in thingBeingAdded) { - var configurationHeader = _claimToHeaderConfigurationParser.Extract(add.Key, add.Value); + var claimToHeader = _claimToThingConfigurationParser.Extract(add.Key, add.Value); - if (configurationHeader.IsError) + if (claimToHeader.IsError) { _logger.LogCritical(new EventId(1, "Application Failed to start"), $"Unable to extract configuration for key: {add.Key} and value: {add.Value} your configuration file is incorrect"); - throw new Exception(configurationHeader.Errors[0].Message); + throw new Exception(claimToHeader.Errors[0].Message); } - configHeaders.Add(configurationHeader.Data); + claimsToTHings.Add(claimToHeader.Data); } - return configHeaders; + return claimsToTHings; } private bool IsPlaceHolder(string upstreamTemplate, int i) diff --git a/src/Ocelot/Configuration/Parser/ClaimToHeaderConfigurationParser.cs b/src/Ocelot/Configuration/Parser/ClaimToThingConfigurationParser.cs similarity index 78% rename from src/Ocelot/Configuration/Parser/ClaimToHeaderConfigurationParser.cs rename to src/Ocelot/Configuration/Parser/ClaimToThingConfigurationParser.cs index 2d81ec1b..45dfe62d 100644 --- a/src/Ocelot/Configuration/Parser/ClaimToHeaderConfigurationParser.cs +++ b/src/Ocelot/Configuration/Parser/ClaimToThingConfigurationParser.cs @@ -6,13 +6,13 @@ using Ocelot.Responses; namespace Ocelot.Configuration.Parser { - public class ClaimToHeaderConfigurationParser : IClaimToHeaderConfigurationParser + public class ClaimToThingConfigurationParser : IClaimToThingConfigurationParser { private readonly Regex _claimRegex = new Regex("Claims\\[.*\\]"); private readonly Regex _indexRegex = new Regex("value\\[.*\\]"); private const string SplitToken = ">"; - public Response Extract(string headerKey, string value) + public Response Extract(string existingKey, string value) { try { @@ -20,7 +20,7 @@ namespace Ocelot.Configuration.Parser if (instructions.Length <= 1) { - return new ErrorResponse( + return new ErrorResponse( new List { new NoInstructionsError(SplitToken) @@ -31,14 +31,14 @@ namespace Ocelot.Configuration.Parser if (!claimMatch) { - return new ErrorResponse( + return new ErrorResponse( new List { new InstructionNotForClaimsError() }); } - var claimKey = GetIndexValue(instructions[0]); + var newKey = GetIndexValue(instructions[0]); var index = 0; var delimiter = string.Empty; @@ -48,12 +48,12 @@ namespace Ocelot.Configuration.Parser delimiter = instructions[2].Trim(); } - return new OkResponse( - new ClaimToHeader(headerKey, claimKey, delimiter, index)); + return new OkResponse( + new ClaimToThing(existingKey, newKey, delimiter, index)); } catch (Exception exception) { - return new ErrorResponse( + return new ErrorResponse( new List { new ParsingConfigurationHeaderError(exception) diff --git a/src/Ocelot/Configuration/Parser/IClaimToHeaderConfigurationParser.cs b/src/Ocelot/Configuration/Parser/IClaimToHeaderConfigurationParser.cs deleted file mode 100644 index d45cd337..00000000 --- a/src/Ocelot/Configuration/Parser/IClaimToHeaderConfigurationParser.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Ocelot.Responses; - -namespace Ocelot.Configuration.Parser -{ - public interface IClaimToHeaderConfigurationParser - { - Response Extract(string headerKey, string value); - } -} \ No newline at end of file diff --git a/src/Ocelot/Configuration/Parser/IClaimToThingConfigurationParser.cs b/src/Ocelot/Configuration/Parser/IClaimToThingConfigurationParser.cs new file mode 100644 index 00000000..a2712994 --- /dev/null +++ b/src/Ocelot/Configuration/Parser/IClaimToThingConfigurationParser.cs @@ -0,0 +1,9 @@ +using Ocelot.Responses; + +namespace Ocelot.Configuration.Parser +{ + public interface IClaimToThingConfigurationParser + { + Response Extract(string existingKey, string value); + } +} \ No newline at end of file diff --git a/src/Ocelot/Configuration/ReRoute.cs b/src/Ocelot/Configuration/ReRoute.cs index 8a67de84..0a8b7ce5 100644 --- a/src/Ocelot/Configuration/ReRoute.cs +++ b/src/Ocelot/Configuration/ReRoute.cs @@ -4,7 +4,7 @@ namespace Ocelot.Configuration { public class ReRoute { - public ReRoute(string downstreamTemplate, string upstreamTemplate, string upstreamHttpMethod, string upstreamTemplatePattern, bool isAuthenticated, AuthenticationOptions authenticationOptions, List configurationHeaderExtractorProperties) + public ReRoute(string downstreamTemplate, string upstreamTemplate, string upstreamHttpMethod, string upstreamTemplatePattern, bool isAuthenticated, AuthenticationOptions authenticationOptions, List configurationHeaderExtractorProperties, List claimsToClaims, Dictionary routeClaimsRequirement, bool isAuthorised) { DownstreamTemplate = downstreamTemplate; UpstreamTemplate = upstreamTemplate; @@ -12,8 +12,12 @@ namespace Ocelot.Configuration UpstreamTemplatePattern = upstreamTemplatePattern; IsAuthenticated = isAuthenticated; AuthenticationOptions = authenticationOptions; + RouteClaimsRequirement = routeClaimsRequirement; + IsAuthorised = isAuthorised; + ClaimsToClaims = claimsToClaims + ?? new List(); ClaimsToHeaders = configurationHeaderExtractorProperties - ?? new List(); + ?? new List(); } public string DownstreamTemplate { get; private set; } @@ -21,7 +25,11 @@ namespace Ocelot.Configuration public string UpstreamTemplatePattern { get; private set; } public string UpstreamHttpMethod { get; private set; } public bool IsAuthenticated { get; private set; } + public bool IsAuthorised { get; private set; } public AuthenticationOptions AuthenticationOptions { get; private set; } - public List ClaimsToHeaders { get; private set; } + public List ClaimsToHeaders { get; private set; } + public List ClaimsToClaims { get; private set; } + public Dictionary RouteClaimsRequirement { get; private set; } + } } \ No newline at end of file diff --git a/src/Ocelot/Configuration/Yaml/YamlReRoute.cs b/src/Ocelot/Configuration/Yaml/YamlReRoute.cs index 94daa4a8..f3297c4c 100644 --- a/src/Ocelot/Configuration/Yaml/YamlReRoute.cs +++ b/src/Ocelot/Configuration/Yaml/YamlReRoute.cs @@ -7,7 +7,8 @@ namespace Ocelot.Configuration.Yaml public YamlReRoute() { AddHeadersToRequest = new Dictionary(); - AddClaims = new Dictionary(); + AddClaimsToRequest = new Dictionary(); + RouteClaimsRequirement = new Dictionary(); } public string DownstreamTemplate { get; set; } @@ -15,6 +16,7 @@ namespace Ocelot.Configuration.Yaml public string UpstreamHttpMethod { get; set; } public YamlAuthenticationOptions AuthenticationOptions { get; set; } public Dictionary AddHeadersToRequest { get; set; } - public Dictionary AddClaims { get; set; } + public Dictionary AddClaimsToRequest { get; set; } + public Dictionary RouteClaimsRequirement { get; set; } } } \ No newline at end of file diff --git a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs index 87c5bb79..6ed8a88d 100644 --- a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs @@ -5,7 +5,6 @@ using Microsoft.Extensions.DependencyInjection; using Ocelot.Authentication.Handler.Creator; using Ocelot.Authentication.Handler.Factory; using Ocelot.Authorisation; -using Ocelot.Claims.Parser; using Ocelot.Configuration.Creator; using Ocelot.Configuration.Parser; using Ocelot.Configuration.Provider; @@ -23,6 +22,9 @@ using Ocelot.ScopedData; namespace Ocelot.DependencyInjection { + using ClaimsBuilder; + using Infrastructure.Claims.Parser; + public static class ServiceCollectionExtensions { public static IServiceCollection AddOcelotYamlConfiguration(this IServiceCollection services, IConfigurationRoot configurationRoot) @@ -34,7 +36,7 @@ namespace Ocelot.DependencyInjection services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); return services; @@ -48,6 +50,7 @@ namespace Ocelot.DependencyInjection // ocelot services. services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/src/Ocelot/HeaderBuilder/AddHeadersToRequest.cs b/src/Ocelot/HeaderBuilder/AddHeadersToRequest.cs index cd96dccf..57ff4103 100644 --- a/src/Ocelot/HeaderBuilder/AddHeadersToRequest.cs +++ b/src/Ocelot/HeaderBuilder/AddHeadersToRequest.cs @@ -2,12 +2,13 @@ using System.Linq; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; -using Ocelot.Claims.Parser; using Ocelot.Configuration; using Ocelot.Responses; namespace Ocelot.HeaderBuilder { + using Infrastructure.Claims.Parser; + public class AddHeadersToRequest : IAddHeadersToRequest { private readonly IClaimsParser _claimsParser; @@ -17,25 +18,25 @@ namespace Ocelot.HeaderBuilder _claimsParser = claimsParser; } - public Response SetHeadersOnContext(List configurationHeaderExtractorProperties, HttpContext context) + public Response SetHeadersOnContext(List claimsToThings, HttpContext context) { - foreach (var config in configurationHeaderExtractorProperties) + foreach (var config in claimsToThings) { - var value = _claimsParser.GetValue(context.User.Claims, config.ClaimKey, config.Delimiter, config.Index); + var value = _claimsParser.GetValue(context.User.Claims, config.NewKey, config.Delimiter, config.Index); if (value.IsError) { return new ErrorResponse(value.Errors); } - var exists = context.Request.Headers.FirstOrDefault(x => x.Key == config.HeaderKey); + var exists = context.Request.Headers.FirstOrDefault(x => x.Key == config.ExistingKey); if (!string.IsNullOrEmpty(exists.Key)) { context.Request.Headers.Remove(exists); } - context.Request.Headers.Add(config.HeaderKey, new StringValues(value.Data)); + context.Request.Headers.Add(config.ExistingKey, new StringValues(value.Data)); } return new OkResponse(); diff --git a/src/Ocelot/HeaderBuilder/IAddHeadersToRequest.cs b/src/Ocelot/HeaderBuilder/IAddHeadersToRequest.cs index 3c5cf49c..f12709ca 100644 --- a/src/Ocelot/HeaderBuilder/IAddHeadersToRequest.cs +++ b/src/Ocelot/HeaderBuilder/IAddHeadersToRequest.cs @@ -7,7 +7,7 @@ namespace Ocelot.HeaderBuilder { public interface IAddHeadersToRequest { - Response SetHeadersOnContext(List configurationHeaderExtractorProperties, + Response SetHeadersOnContext(List claimsToThings, HttpContext context); } } diff --git a/src/Ocelot/Claims/Parser/CannotFindClaimError.cs b/src/Ocelot/Infrastructure/Claims/Parser/CannotFindClaimError.cs similarity index 75% rename from src/Ocelot/Claims/Parser/CannotFindClaimError.cs rename to src/Ocelot/Infrastructure/Claims/Parser/CannotFindClaimError.cs index 37e926e1..64a91cb8 100644 --- a/src/Ocelot/Claims/Parser/CannotFindClaimError.cs +++ b/src/Ocelot/Infrastructure/Claims/Parser/CannotFindClaimError.cs @@ -1,7 +1,7 @@ -using Ocelot.Errors; - -namespace Ocelot.Claims.Parser +namespace Ocelot.Infrastructure.Claims.Parser { + using Errors; + public class CannotFindClaimError : Error { public CannotFindClaimError(string message) diff --git a/src/Ocelot/Claims/Parser/ClaimsParser.cs b/src/Ocelot/Infrastructure/Claims/Parser/ClaimsParser.cs similarity index 88% rename from src/Ocelot/Claims/Parser/ClaimsParser.cs rename to src/Ocelot/Infrastructure/Claims/Parser/ClaimsParser.cs index a6c8d010..e37f48fa 100644 --- a/src/Ocelot/Claims/Parser/ClaimsParser.cs +++ b/src/Ocelot/Infrastructure/Claims/Parser/ClaimsParser.cs @@ -1,11 +1,11 @@ -using System.Collections.Generic; -using System.Linq; -using System.Security.Claims; -using Ocelot.Errors; -using Ocelot.Responses; - -namespace Ocelot.Claims.Parser +namespace Ocelot.Infrastructure.Claims.Parser { + using System.Collections.Generic; + using System.Linq; + using System.Security.Claims; + using Errors; + using Responses; + public class ClaimsParser : IClaimsParser { public Response GetValue(IEnumerable claims, string key, string delimiter, int index) diff --git a/src/Ocelot/Claims/Parser/IClaimsParser.cs b/src/Ocelot/Infrastructure/Claims/Parser/IClaimsParser.cs similarity index 52% rename from src/Ocelot/Claims/Parser/IClaimsParser.cs rename to src/Ocelot/Infrastructure/Claims/Parser/IClaimsParser.cs index 4a2020ec..fa94cd22 100644 --- a/src/Ocelot/Claims/Parser/IClaimsParser.cs +++ b/src/Ocelot/Infrastructure/Claims/Parser/IClaimsParser.cs @@ -1,9 +1,9 @@ -using System.Collections.Generic; -using System.Security.Claims; -using Ocelot.Responses; - -namespace Ocelot.Claims.Parser +namespace Ocelot.Infrastructure.Claims.Parser { + using System.Collections.Generic; + using System.Security.Claims; + using Responses; + public interface IClaimsParser { Response GetValue(IEnumerable claims, string key, string delimiter, int index); diff --git a/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs b/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs index 9815388f..866ac4e8 100644 --- a/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs +++ b/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs @@ -1,6 +1,5 @@ using Microsoft.AspNetCore.Builder; using Ocelot.Authentication.Middleware; -using Ocelot.Authorisation; using Ocelot.DownstreamRouteFinder.Middleware; using Ocelot.DownstreamUrlCreator.Middleware; using Ocelot.HeaderBuilder.Middleware; @@ -10,6 +9,9 @@ using Ocelot.Responder.Middleware; namespace Ocelot.Middleware { + using Authorisation.Middleware; + using ClaimsBuilder.Middleware; + public static class OcelotMiddlewareExtensions { public static IApplicationBuilder UseOcelot(this IApplicationBuilder builder) @@ -20,6 +22,8 @@ namespace Ocelot.Middleware builder.UseAuthenticationMiddleware(); + builder.UseClaimsBuilderMiddleware(); + builder.UseAuthorisationMiddleware(); builder.UseHttpRequestHeadersBuilderMiddleware(); diff --git a/src/Ocelot/Responder/ErrorsToHttpStatusCodeMapper.cs b/src/Ocelot/Responder/ErrorsToHttpStatusCodeMapper.cs index d7ab7090..6ecc20eb 100644 --- a/src/Ocelot/Responder/ErrorsToHttpStatusCodeMapper.cs +++ b/src/Ocelot/Responder/ErrorsToHttpStatusCodeMapper.cs @@ -14,6 +14,14 @@ namespace Ocelot.Responder return new OkResponse(401); } + if (errors.Any(e => e.Code == OcelotErrorCode.UnauthorizedError + || e.Code == OcelotErrorCode.ClaimValueNotAuthorisedError + || e.Code == OcelotErrorCode.UserDoesNotHaveClaimError + || e.Code == OcelotErrorCode.CannotFindClaimError)) + { + return new OkResponse(403); + } + return new OkResponse(404); } } diff --git a/test/Ocelot.AcceptanceTests/AuthorisationTests.cs b/test/Ocelot.AcceptanceTests/AuthorisationTests.cs index 7a1ec440..2bb3a908 100644 --- a/test/Ocelot.AcceptanceTests/AuthorisationTests.cs +++ b/test/Ocelot.AcceptanceTests/AuthorisationTests.cs @@ -74,11 +74,15 @@ namespace Ocelot.AcceptanceTests {"UserType", "Claims[sub] > value[0] > |"}, {"UserId", "Claims[sub] > value[1] > |"} }, - AddClaims = + AddClaimsToRequest = { {"CustomerId", "Claims[CustomerId] > value"}, {"UserType", "Claims[sub] > value[0] > |"}, {"UserId", "Claims[sub] > value[1] > |"} + }, + RouteClaimsRequirement = + { + {"UserType", "registered"} } } } @@ -91,26 +95,66 @@ namespace Ocelot.AcceptanceTests .BDDfy(); } + [Fact] + public void should_return_response_403_authorising_route() + { + this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Jwt)) + .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura")) + .And(x => x.GivenIHaveAToken("http://localhost:51888")) + .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration + { + ReRoutes = new List + { + new YamlReRoute + { + DownstreamTemplate = "http://localhost:51876/", + UpstreamTemplate = "/", + UpstreamHttpMethod = "Get", + AuthenticationOptions = new YamlAuthenticationOptions + { + AdditionalScopes = new List(), + Provider = "IdentityServer", + ProviderRootUrl = "http://localhost:51888", + RequireHttps = false, + ScopeName = "api", + ScopeSecret = "secret" + }, + AddHeadersToRequest = + { + {"CustomerId", "Claims[CustomerId] > value"}, + {"LocationId", "Claims[LocationId] > value"}, + {"UserType", "Claims[sub] > value[0] > |"}, + {"UserId", "Claims[sub] > value[1] > |"} + }, + AddClaimsToRequest = + { + {"CustomerId", "Claims[CustomerId] > value"}, + {"UserId", "Claims[sub] > value[1] > |"} + }, + RouteClaimsRequirement = + { + {"UserType", "registered"} + } + } + } + })) + .And(x => x.GivenTheApiGatewayIsRunning()) + .And(x => x.GivenIHaveAddedATokenToMyRequest()) + .When(x => x.WhenIGetUrlOnTheApiGateway("/")) + .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.Forbidden)) + .BDDfy(); + } + private void WhenIGetUrlOnTheApiGateway(string url) { _response = _ocelotClient.GetAsync(url).Result; } - private void WhenIPostUrlOnTheApiGateway(string url) - { - _response = _ocelotClient.PostAsync(url, _postContent).Result; - } - private void ThenTheResponseBodyShouldBe(string expectedBody) { _response.Content.ReadAsStringAsync().Result.ShouldBe(expectedBody); } - private void GivenThePostHasContent(string postcontent) - { - _postContent = new StringContent(postcontent); - } - /// /// This is annoying cos it should be in the constructor but we need to set up the yaml file before calling startup so its a step. /// @@ -184,7 +228,8 @@ namespace Ocelot.AcceptanceTests { Value = "secret".Sha256() } - } + }, + IncludeAllClaimsForUser = true }, StandardScopes.OpenId, diff --git a/test/Ocelot.UnitTests/Authorization/AuthorizationMiddlewareTests.cs b/test/Ocelot.UnitTests/Authorization/AuthorisationMiddlewareTests.cs similarity index 89% rename from test/Ocelot.UnitTests/Authorization/AuthorizationMiddlewareTests.cs rename to test/Ocelot.UnitTests/Authorization/AuthorisationMiddlewareTests.cs index d747a41c..134a33b8 100644 --- a/test/Ocelot.UnitTests/Authorization/AuthorizationMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Authorization/AuthorisationMiddlewareTests.cs @@ -18,7 +18,9 @@ using Xunit; namespace Ocelot.UnitTests.Authorization { - public class AuthorizationMiddlewareTests : IDisposable + using Authorisation.Middleware; + + public class AuthorisationMiddlewareTests : IDisposable { private readonly Mock _scopedRepository; private readonly Mock _authService; @@ -28,7 +30,7 @@ namespace Ocelot.UnitTests.Authorization private HttpResponseMessage _result; private OkResponse _downstreamRoute; - public AuthorizationMiddlewareTests() + public AuthorisationMiddlewareTests() { _url = "http://localhost:51879"; _scopedRepository = new Mock(); @@ -56,18 +58,17 @@ namespace Ocelot.UnitTests.Authorization [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().WithIsAuthorised(true).Build()))) .And(x => x.GivenTheAuthServiceReturns(new OkResponse(true))) .When(x => x.WhenICallTheMiddleware()) - //todo stick this back in - //.Then(x => x.ThenTheAuthServiceIsCalledCorrectly()) + .Then(x => x.ThenTheAuthServiceIsCalledCorrectly()) .BDDfy(); } private void GivenTheAuthServiceReturns(Response expected) { _authService - .Setup(x => x.Authorise(It.IsAny(), It.IsAny())) + .Setup(x => x.Authorise(It.IsAny(), It.IsAny>())) .Returns(expected); } @@ -75,7 +76,7 @@ namespace Ocelot.UnitTests.Authorization { _authService .Verify(x => x.Authorise(It.IsAny(), - It.IsAny()), Times.Once); + It.IsAny>()), Times.Once); } private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute) diff --git a/test/Ocelot.UnitTests/Authorization/ClaimsAuthoriserTests.cs b/test/Ocelot.UnitTests/Authorization/ClaimsAuthoriserTests.cs index 15dde43c..7b3779a6 100644 --- a/test/Ocelot.UnitTests/Authorization/ClaimsAuthoriserTests.cs +++ b/test/Ocelot.UnitTests/Authorization/ClaimsAuthoriserTests.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; using System.Security.Claims; using Ocelot.Authorisation; -using Ocelot.Claims.Parser; using Ocelot.Responses; using Shouldly; using TestStack.BDDfy; @@ -9,11 +8,13 @@ using Xunit; namespace Ocelot.UnitTests.Authorization { + using Ocelot.Infrastructure.Claims.Parser; + public class ClaimsAuthoriserTests { private readonly ClaimsAuthoriser _claimsAuthoriser; private ClaimsPrincipal _claimsPrincipal; - private RouteClaimsRequirement _requirement; + private Dictionary _requirement; private Response _result; public ClaimsAuthoriserTests() @@ -28,10 +29,10 @@ namespace Ocelot.UnitTests.Authorization { new Claim("UserType", "registered") })))) - .And(x => x.GivenARouteClaimsRequirement(new RouteClaimsRequirement(new Dictionary + .And(x => x.GivenARouteClaimsRequirement(new Dictionary { {"UserType", "registered"} - }))) + })) .When(x => x.WhenICallTheAuthoriser()) .Then(x => x.ThenTheUserIsAuthorised()) .BDDfy(); @@ -41,10 +42,10 @@ namespace Ocelot.UnitTests.Authorization public void should_not_authorise_user() { this.Given(x => x.GivenAClaimsPrincipal(new ClaimsPrincipal(new ClaimsIdentity(new List())))) - .And(x => x.GivenARouteClaimsRequirement(new RouteClaimsRequirement(new Dictionary + .And(x => x.GivenARouteClaimsRequirement(new Dictionary { { "UserType", "registered" } - }))) + })) .When(x => x.WhenICallTheAuthoriser()) .Then(x => x.ThenTheUserIsntAuthorised()) .BDDfy(); @@ -55,7 +56,7 @@ namespace Ocelot.UnitTests.Authorization _claimsPrincipal = claimsPrincipal; } - private void GivenARouteClaimsRequirement(RouteClaimsRequirement requirement) + private void GivenARouteClaimsRequirement(Dictionary requirement) { _requirement = requirement; } diff --git a/test/Ocelot.UnitTests/ClaimsBuilder/AddClaimsToRequestTests.cs b/test/Ocelot.UnitTests/ClaimsBuilder/AddClaimsToRequestTests.cs new file mode 100644 index 00000000..6e4d5339 --- /dev/null +++ b/test/Ocelot.UnitTests/ClaimsBuilder/AddClaimsToRequestTests.cs @@ -0,0 +1,145 @@ +namespace Ocelot.UnitTests.ClaimsBuilder +{ + using System.Collections.Generic; + using System.Linq; + using System.Security.Claims; + using Errors; + using Microsoft.AspNetCore.Http; + using Moq; + using Ocelot.ClaimsBuilder; + using Ocelot.Configuration; + using Ocelot.Infrastructure.Claims.Parser; + using Responses; + using Shouldly; + using TestStack.BDDfy; + using Xunit; + + public class AddClaimsToRequestTests + { + private readonly AddClaimsToRequest _addClaimsToRequest; + private readonly Mock _parser; + private List _claimsToThings; + private HttpContext _context; + private Response _result; + private Response _claimValue; + + public AddClaimsToRequestTests() + { + _parser = new Mock(); + _addClaimsToRequest = new AddClaimsToRequest(_parser.Object); + } + + [Fact] + public void should_add_claims_to_context() + { + var context = new DefaultHttpContext + { + User = new ClaimsPrincipal(new ClaimsIdentity(new List + { + new Claim("test", "data") + })) + }; + + this.Given( + x => x.GivenClaimsToThings(new List + { + new ClaimToThing("claim-key", "", "", 0) + })) + .Given(x => x.GivenHttpContext(context)) + .And(x => x.GivenTheClaimParserReturns(new OkResponse("value"))) + .When(x => x.WhenIAddClaimsToTheRequest()) + .Then(x => x.ThenTheResultIsSuccess()) + .BDDfy(); + } + + [Fact] + public void if_claims_exists_should_replace_it() + { + var context = new DefaultHttpContext + { + User = new ClaimsPrincipal(new ClaimsIdentity(new List + { + new Claim("existing-key", "data"), + new Claim("new-key", "data") + })), + }; + + this.Given( + x => x.GivenClaimsToThings(new List + { + new ClaimToThing("existing-key", "new-key", "", 0) + })) + .Given(x => x.GivenHttpContext(context)) + .And(x => x.GivenTheClaimParserReturns(new OkResponse("value"))) + .When(x => x.WhenIAddClaimsToTheRequest()) + .Then(x => x.ThenTheResultIsSuccess()) + .BDDfy(); + } + + [Fact] + public void should_return_error() + { + this.Given( + x => x.GivenClaimsToThings(new List + { + new ClaimToThing("", "", "", 0) + })) + .Given(x => x.GivenHttpContext(new DefaultHttpContext())) + .And(x => x.GivenTheClaimParserReturns(new ErrorResponse(new List + { + new AnyError() + }))) + .When(x => x.WhenIAddClaimsToTheRequest()) + .Then(x => x.ThenTheResultIsError()) + .BDDfy(); + } + + + private void GivenClaimsToThings(List configuration) + { + _claimsToThings = configuration; + } + + private void GivenHttpContext(HttpContext context) + { + _context = context; + } + + private void GivenTheClaimParserReturns(Response claimValue) + { + _claimValue = claimValue; + _parser + .Setup( + x => + x.GetValue(It.IsAny>(), + It.IsAny(), + It.IsAny(), + It.IsAny())) + .Returns(_claimValue); + } + + private void WhenIAddClaimsToTheRequest() + { + _result = _addClaimsToRequest.SetClaimsOnContext(_claimsToThings, _context); + } + + private void ThenTheResultIsSuccess() + { + _result.IsError.ShouldBe(false); + } + + private void ThenTheResultIsError() + { + + _result.IsError.ShouldBe(true); + } + + class AnyError : Error + { + public AnyError() + : base("blahh", OcelotErrorCode.UnknownError) + { + } + } + } +} diff --git a/test/Ocelot.UnitTests/ClaimsBuilder/ClaimsBuilderMiddlewareTests.cs b/test/Ocelot.UnitTests/ClaimsBuilder/ClaimsBuilderMiddlewareTests.cs new file mode 100644 index 00000000..210bca83 --- /dev/null +++ b/test/Ocelot.UnitTests/ClaimsBuilder/ClaimsBuilderMiddlewareTests.cs @@ -0,0 +1,111 @@ +namespace Ocelot.UnitTests.ClaimsBuilder +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Net.Http; + using Microsoft.AspNetCore.Hosting; + using Microsoft.AspNetCore.Http; + using Microsoft.AspNetCore.TestHost; + using Microsoft.Extensions.DependencyInjection; + using Moq; + using Ocelot.ClaimsBuilder; + using Ocelot.ClaimsBuilder.Middleware; + using Ocelot.Configuration; + using Ocelot.Configuration.Builder; + using Ocelot.DownstreamRouteFinder; + using Ocelot.DownstreamRouteFinder.UrlMatcher; + using Responses; + using ScopedData; + using TestStack.BDDfy; + using Xunit; + + public class ClaimsBuilderMiddlewareTests : IDisposable + { + private readonly Mock _scopedRepository; + private readonly Mock _addHeaders; + private readonly string _url; + private readonly TestServer _server; + private readonly HttpClient _client; + private Response _downstreamRoute; + private HttpResponseMessage _result; + + public ClaimsBuilderMiddlewareTests() + { + _url = "http://localhost:51879"; + _scopedRepository = new Mock(); + _addHeaders = new Mock(); + var builder = new WebHostBuilder() + .ConfigureServices(x => + { + x.AddSingleton(_addHeaders.Object); + x.AddSingleton(_scopedRepository.Object); + }) + .UseUrls(_url) + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseUrls(_url) + .Configure(app => + { + app.UseClaimsBuilderMiddleware(); + }); + + _server = new TestServer(builder); + _client = _server.CreateClient(); + } + + [Fact] + public void happy_path() + { + var downstreamRoute = new DownstreamRoute(new List(), + new ReRouteBuilder() + .WithDownstreamTemplate("any old string") + .WithClaimsToClaims(new List + { + new ClaimToThing("sub", "UserType", "|", 0) + }) + .Build()); + + this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute)) + .And(x => x.GivenTheAddClaimsToRequestReturns()) + .When(x => x.WhenICallTheMiddleware()) + .Then(x => x.ThenTheClaimsToRequestIsCalledCorrectly()) + .BDDfy(); + } + + private void GivenTheAddClaimsToRequestReturns() + { + _addHeaders + .Setup(x => x.SetClaimsOnContext(It.IsAny>(), + It.IsAny())) + .Returns(new OkResponse()); + } + + private void ThenTheClaimsToRequestIsCalledCorrectly() + { + _addHeaders + .Verify(x => x.SetClaimsOnContext(It.IsAny>(), + It.IsAny()), Times.Once); + } + + private void WhenICallTheMiddleware() + { + _result = _client.GetAsync(_url).Result; + } + + private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute) + { + _downstreamRoute = new OkResponse(downstreamRoute); + _scopedRepository + .Setup(x => x.Get(It.IsAny())) + .Returns(_downstreamRoute); + } + + public void Dispose() + { + _client.Dispose(); + _server.Dispose(); + } + } +} diff --git a/test/Ocelot.UnitTests/Configuration/ConfigurationHeadersExtractorTests.cs b/test/Ocelot.UnitTests/Configuration/ClaimToThingConfigurationParserTests.cs similarity index 77% rename from test/Ocelot.UnitTests/Configuration/ConfigurationHeadersExtractorTests.cs rename to test/Ocelot.UnitTests/Configuration/ClaimToThingConfigurationParserTests.cs index 7b2f37c1..1f3ba9bc 100644 --- a/test/Ocelot.UnitTests/Configuration/ConfigurationHeadersExtractorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/ClaimToThingConfigurationParserTests.cs @@ -10,15 +10,15 @@ using Xunit; namespace Ocelot.UnitTests.Configuration { - public class ConfigurationHeadersExtractorTests + public class ClaimToThingConfigurationParserTests { private Dictionary _dictionary; - private readonly IClaimToHeaderConfigurationParser _claimToHeaderConfigurationParser; - private Response _result; + private readonly IClaimToThingConfigurationParser _claimToThingConfigurationParser; + private Response _result; - public ConfigurationHeadersExtractorTests() + public ClaimToThingConfigurationParserTests() { - _claimToHeaderConfigurationParser = new ClaimToHeaderConfigurationParser(); + _claimToThingConfigurationParser = new ClaimToThingConfigurationParser(); } [Fact] @@ -31,7 +31,7 @@ namespace Ocelot.UnitTests.Configuration .When(x => x.WhenICallTheExtractor()) .Then( x => - x.ThenAnErrorIsReturned(new ErrorResponse( + x.ThenAnErrorIsReturned(new ErrorResponse( new List { new NoInstructionsError(">") @@ -49,7 +49,7 @@ namespace Ocelot.UnitTests.Configuration .When(x => x.WhenICallTheExtractor()) .Then( x => - x.ThenAnErrorIsReturned(new ErrorResponse( + x.ThenAnErrorIsReturned(new ErrorResponse( new List { new InstructionNotForClaimsError() @@ -68,8 +68,8 @@ namespace Ocelot.UnitTests.Configuration .Then( x => x.ThenTheClaimParserPropertiesAreReturned( - new OkResponse( - new ClaimToHeader("CustomerId", "CustomerId", "", 0)))) + new OkResponse( + new ClaimToThing("CustomerId", "CustomerId", "", 0)))) .BDDfy(); } @@ -84,20 +84,20 @@ namespace Ocelot.UnitTests.Configuration .Then( x => x.ThenTheClaimParserPropertiesAreReturned( - new OkResponse( - new ClaimToHeader("UserId", "Subject", "|", 0)))) + new OkResponse( + new ClaimToThing("UserId", "Subject", "|", 0)))) .BDDfy(); } - private void ThenAnErrorIsReturned(Response expected) + private void ThenAnErrorIsReturned(Response expected) { _result.IsError.ShouldBe(expected.IsError); _result.Errors[0].ShouldBeOfType(expected.Errors[0].GetType()); } - private void ThenTheClaimParserPropertiesAreReturned(Response expected) + private void ThenTheClaimParserPropertiesAreReturned(Response expected) { - _result.Data.ClaimKey.ShouldBe(expected.Data.ClaimKey); + _result.Data.NewKey.ShouldBe(expected.Data.NewKey); _result.Data.Delimiter.ShouldBe(expected.Data.Delimiter); _result.Data.Index.ShouldBe(expected.Data.Index); _result.IsError.ShouldBe(expected.IsError); @@ -106,7 +106,7 @@ namespace Ocelot.UnitTests.Configuration private void WhenICallTheExtractor() { var first = _dictionary.First(); - _result = _claimToHeaderConfigurationParser.Extract(first.Key, first.Value); + _result = _claimToThingConfigurationParser.Extract(first.Key, first.Value); } private void GivenTheDictionaryIs(Dictionary dictionary) diff --git a/test/Ocelot.UnitTests/Configuration/YamlConfigurationCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/YamlConfigurationCreatorTests.cs index fd69ba5e..36acefc2 100644 --- a/test/Ocelot.UnitTests/Configuration/YamlConfigurationCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/YamlConfigurationCreatorTests.cs @@ -21,14 +21,14 @@ namespace Ocelot.UnitTests.Configuration private readonly Mock _validator; private Response _config; private YamlConfiguration _yamlConfiguration; - private readonly Mock _configParser; + private readonly Mock _configParser; private readonly Mock> _logger; private readonly YamlOcelotConfigurationCreator _ocelotConfigurationCreator; public YamlConfigurationCreatorTests() { _logger = new Mock>(); - _configParser = new Mock(); + _configParser = new Mock(); _validator = new Mock(); _yamlConfig = new Mock>(); _ocelotConfigurationCreator = new YamlOcelotConfigurationCreator( @@ -79,9 +79,9 @@ namespace Ocelot.UnitTests.Configuration .WithRequireHttps(false) .WithScopeSecret("secret") .WithAuthenticationProviderScopeName("api") - .WithConfigurationHeaderExtractorProperties(new List + .WithClaimsToHeaders(new List { - new ClaimToHeader("CustomerId", "CustomerId", "", 0), + new ClaimToThing("CustomerId", "CustomerId", "", 0), }) .Build() }; @@ -112,18 +112,18 @@ namespace Ocelot.UnitTests.Configuration } })) .And(x => x.GivenTheYamlConfigIsValid()) - .And(x => x.GivenTheConfigHeaderExtractorReturns(new ClaimToHeader("CustomerId", "CustomerId", "", 0))) + .And(x => x.GivenTheConfigHeaderExtractorReturns(new ClaimToThing("CustomerId", "CustomerId", "", 0))) .When(x => x.WhenICreateTheConfig()) .Then(x => x.ThenTheReRoutesAre(expected)) .And(x => x.ThenTheAuthenticationOptionsAre(expected)) .BDDfy(); } - private void GivenTheConfigHeaderExtractorReturns(ClaimToHeader expected) + private void GivenTheConfigHeaderExtractorReturns(ClaimToThing expected) { _configParser .Setup(x => x.Extract(It.IsAny(), It.IsAny())) - .Returns(new OkResponse(expected)); + .Returns(new OkResponse(expected)); } [Fact] diff --git a/test/Ocelot.UnitTests/HeaderBuilder/AddHeadersToRequestTests.cs b/test/Ocelot.UnitTests/HeaderBuilder/AddHeadersToRequestTests.cs index 59c111f2..fb12dba4 100644 --- a/test/Ocelot.UnitTests/HeaderBuilder/AddHeadersToRequestTests.cs +++ b/test/Ocelot.UnitTests/HeaderBuilder/AddHeadersToRequestTests.cs @@ -4,7 +4,6 @@ using System.Security.Claims; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; using Moq; -using Ocelot.Claims.Parser; using Ocelot.Configuration; using Ocelot.Errors; using Ocelot.HeaderBuilder; @@ -15,11 +14,13 @@ using Xunit; namespace Ocelot.UnitTests.HeaderBuilder { + using Ocelot.Infrastructure.Claims.Parser; + public class AddHeadersToRequestTests { private readonly AddHeadersToRequest _addHeadersToRequest; private readonly Mock _parser; - private List _configuration; + private List _configuration; private HttpContext _context; private Response _result; private Response _claimValue; @@ -42,9 +43,9 @@ namespace Ocelot.UnitTests.HeaderBuilder }; this.Given( - x => x.GivenConfigurationHeaderExtractorProperties(new List + x => x.GivenConfigurationHeaderExtractorProperties(new List { - new ClaimToHeader("header-key", "", "", 0) + new ClaimToThing("header-key", "", "", 0) })) .Given(x => x.GivenHttpContext(context)) .And(x => x.GivenTheClaimParserReturns(new OkResponse("value"))) @@ -68,9 +69,9 @@ namespace Ocelot.UnitTests.HeaderBuilder context.Request.Headers.Add("header-key", new StringValues("initial")); this.Given( - x => x.GivenConfigurationHeaderExtractorProperties(new List + x => x.GivenConfigurationHeaderExtractorProperties(new List { - new ClaimToHeader("header-key", "", "", 0) + new ClaimToThing("header-key", "", "", 0) })) .Given(x => x.GivenHttpContext(context)) .And(x => x.GivenTheClaimParserReturns(new OkResponse("value"))) @@ -84,9 +85,9 @@ namespace Ocelot.UnitTests.HeaderBuilder public void should_return_error() { this.Given( - x => x.GivenConfigurationHeaderExtractorProperties(new List + x => x.GivenConfigurationHeaderExtractorProperties(new List { - new ClaimToHeader("", "", "", 0) + new ClaimToThing("", "", "", 0) })) .Given(x => x.GivenHttpContext(new DefaultHttpContext())) .And(x => x.GivenTheClaimParserReturns(new ErrorResponse(new List @@ -104,7 +105,7 @@ namespace Ocelot.UnitTests.HeaderBuilder header.Value.First().ShouldBe(_claimValue.Data); } - private void GivenConfigurationHeaderExtractorProperties(List configuration) + private void GivenConfigurationHeaderExtractorProperties(List configuration) { _configuration = configuration; } diff --git a/test/Ocelot.UnitTests/HeaderBuilder/HttpRequestHeadersBuilderMiddlewareTests.cs b/test/Ocelot.UnitTests/HeaderBuilder/HttpRequestHeadersBuilderMiddlewareTests.cs index 8fbd7993..6d28f64c 100644 --- a/test/Ocelot.UnitTests/HeaderBuilder/HttpRequestHeadersBuilderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/HeaderBuilder/HttpRequestHeadersBuilderMiddlewareTests.cs @@ -61,9 +61,9 @@ namespace Ocelot.UnitTests.HeaderBuilder var downstreamRoute = new DownstreamRoute(new List(), new ReRouteBuilder() .WithDownstreamTemplate("any old string") - .WithConfigurationHeaderExtractorProperties(new List + .WithClaimsToHeaders(new List { - new ClaimToHeader("UserId", "Subject", "", 0) + new ClaimToThing("UserId", "Subject", "", 0) }) .Build()); @@ -77,7 +77,7 @@ namespace Ocelot.UnitTests.HeaderBuilder private void GivenTheAddHeadersToRequestReturns(string claimValue) { _addHeaders - .Setup(x => x.SetHeadersOnContext(It.IsAny>(), + .Setup(x => x.SetHeadersOnContext(It.IsAny>(), It.IsAny())) .Returns(new OkResponse()); } @@ -85,7 +85,7 @@ namespace Ocelot.UnitTests.HeaderBuilder private void ThenTheAddHeadersToRequestIsCalledCorrectly() { _addHeaders - .Verify(x => x.SetHeadersOnContext(It.IsAny>(), + .Verify(x => x.SetHeadersOnContext(It.IsAny>(), It.IsAny()), Times.Once); } diff --git a/test/Ocelot.UnitTests/HeaderBuilder/ClaimParserTests.cs b/test/Ocelot.UnitTests/Infrastructure/ClaimParserTests.cs similarity index 93% rename from test/Ocelot.UnitTests/HeaderBuilder/ClaimParserTests.cs rename to test/Ocelot.UnitTests/Infrastructure/ClaimParserTests.cs index 189508d8..5683d636 100644 --- a/test/Ocelot.UnitTests/HeaderBuilder/ClaimParserTests.cs +++ b/test/Ocelot.UnitTests/Infrastructure/ClaimParserTests.cs @@ -1,14 +1,14 @@ -using System.Collections.Generic; -using System.Security.Claims; -using Ocelot.Claims.Parser; -using Ocelot.Errors; -using Ocelot.Responses; -using Shouldly; -using TestStack.BDDfy; -using Xunit; - -namespace Ocelot.UnitTests.HeaderBuilder +namespace Ocelot.UnitTests.Infrastructure { + using System.Collections.Generic; + using System.Security.Claims; + using Errors; + using Ocelot.Infrastructure.Claims.Parser; + using Responses; + using Shouldly; + using TestStack.BDDfy; + using Xunit; + public class ClaimParserTests { private readonly IClaimsParser _claimsParser; From ab5d7fa33da5578a9a0b463016e42b417dd9d55e Mon Sep 17 00:00:00 2001 From: "tom.pallister" Date: Wed, 19 Oct 2016 19:32:05 +0100 Subject: [PATCH 100/183] allowing people to inject functions as custom middleware --- ...ider.cs => OcelotConfigurationProvider.cs} | 24 +-- .../ServiceCollectionExtensions.cs | 2 +- .../OcelotMiddlewareConfiguration.cs | 27 +++ .../Middleware/OcelotMiddlewareExtensions.cs | 68 ++++++ .../CustomMiddlewareTests.cs | 201 ++++++++++++++++++ .../Ocelot.AcceptanceTests/configuration.yaml | 16 +- test/Ocelot.AcceptanceTests/project.json | 2 +- test/Ocelot.ManualTest/project.json | 4 +- test/Ocelot.ManualTest/web.config | 4 +- .../YamlConfigurationProviderTests.cs | 2 +- 10 files changed, 320 insertions(+), 30 deletions(-) rename src/Ocelot/Configuration/Provider/{YamlOcelotConfigurationProvider.cs => OcelotConfigurationProvider.cs} (50%) create mode 100644 src/Ocelot/Middleware/OcelotMiddlewareConfiguration.cs create mode 100644 test/Ocelot.AcceptanceTests/CustomMiddlewareTests.cs diff --git a/src/Ocelot/Configuration/Provider/YamlOcelotConfigurationProvider.cs b/src/Ocelot/Configuration/Provider/OcelotConfigurationProvider.cs similarity index 50% rename from src/Ocelot/Configuration/Provider/YamlOcelotConfigurationProvider.cs rename to src/Ocelot/Configuration/Provider/OcelotConfigurationProvider.cs index 2a92f786..4b6c5fd2 100644 --- a/src/Ocelot/Configuration/Provider/YamlOcelotConfigurationProvider.cs +++ b/src/Ocelot/Configuration/Provider/OcelotConfigurationProvider.cs @@ -7,12 +7,12 @@ namespace Ocelot.Configuration.Provider /// /// Register as singleton /// - public class YamlOcelotConfigurationProvider : IOcelotConfigurationProvider + public class OcelotConfigurationProvider : IOcelotConfigurationProvider { private readonly IOcelotConfigurationRepository _repo; private readonly IOcelotConfigurationCreator _creator; - public YamlOcelotConfigurationProvider(IOcelotConfigurationRepository repo, + public OcelotConfigurationProvider(IOcelotConfigurationRepository repo, IOcelotConfigurationCreator creator) { _repo = repo; @@ -21,28 +21,28 @@ namespace Ocelot.Configuration.Provider public Response Get() { - var config = _repo.Get(); + var repoConfig = _repo.Get(); - if (config.IsError) + if (repoConfig.IsError) { - return new ErrorResponse(config.Errors); + return new ErrorResponse(repoConfig.Errors); } - if (config.Data == null) + if (repoConfig.Data == null) { - var configuration = _creator.Create(); + var creatorConfig = _creator.Create(); - if (configuration.IsError) + if (creatorConfig.IsError) { - return new ErrorResponse(configuration.Errors); + return new ErrorResponse(creatorConfig.Errors); } - _repo.AddOrReplace(configuration.Data); + _repo.AddOrReplace(creatorConfig.Data); - return new OkResponse(configuration.Data); + return new OkResponse(creatorConfig.Data); } - return new OkResponse(config.Data); + return new OkResponse(repoConfig.Data); } } } \ No newline at end of file diff --git a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs index 6ed8a88d..0b943b19 100644 --- a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs @@ -34,7 +34,7 @@ namespace Ocelot.DependencyInjection // ocelot services. services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/src/Ocelot/Middleware/OcelotMiddlewareConfiguration.cs b/src/Ocelot/Middleware/OcelotMiddlewareConfiguration.cs new file mode 100644 index 00000000..798c4577 --- /dev/null +++ b/src/Ocelot/Middleware/OcelotMiddlewareConfiguration.cs @@ -0,0 +1,27 @@ +namespace Ocelot.Middleware +{ + using System; + using System.Threading.Tasks; + using Microsoft.AspNetCore.Http; + + public class OcelotMiddlewareConfiguration + { + public Func, Task> PreHttpResponderMiddleware { get; set; } + public Func, Task> PostHttpResponderMiddleware { get; set; } + public Func, Task> PreDownstreamRouteFinderMiddleware { get; set; } + public Func, Task> PostDownstreamRouteFinderMiddleware { get; set; } + public Func, Task> PreAuthenticationMiddleware { get; set; } + public Func, Task> PostAuthenticationMiddleware { get; set; } + public Func, Task> PreClaimsBuilderMiddleware { get; set; } + public Func, Task> PostClaimsBuilderMiddleware { get; set; } + public Func, Task> PreAuthorisationMiddleware { get; set; } + public Func, Task> PostAuthorisationMiddleware { get; set; } + public Func, Task> PreHttpRequestHeadersBuilderMiddleware { get; set; } + public Func, Task> PostHttpRequestHeadersBuilderMiddleware { get; set; } + public Func, Task> PreDownstreamUrlCreatorMiddleware { get; set; } + public Func, Task> PostDownstreamUrlCreatorMiddleware { get; set; } + public Func, Task> PreHttpRequestBuilderMiddleware { get; set; } + public Func, Task> PostHttpRequestBuilderMiddleware { get; set; } + public Func, Task> PreHttpRequesterMiddleware { get; set; } + } +} \ No newline at end of file diff --git a/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs b/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs index 866ac4e8..8fe0877f 100644 --- a/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs +++ b/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs @@ -9,8 +9,11 @@ using Ocelot.Responder.Middleware; namespace Ocelot.Middleware { + using System; + using System.Threading.Tasks; using Authorisation.Middleware; using ClaimsBuilder.Middleware; + using Microsoft.AspNetCore.Http; public static class OcelotMiddlewareExtensions { @@ -36,5 +39,70 @@ namespace Ocelot.Middleware return builder; } + + public static IApplicationBuilder UseOcelot(this IApplicationBuilder builder, OcelotMiddlewareConfiguration middlewareConfiguration) + { + builder.UseIfNotNull(middlewareConfiguration.PreHttpResponderMiddleware); + + builder.UseHttpResponderMiddleware(); + + builder.UseIfNotNull(middlewareConfiguration.PostHttpResponderMiddleware); + + builder.UseIfNotNull(middlewareConfiguration.PreDownstreamRouteFinderMiddleware); + + builder.UseDownstreamRouteFinderMiddleware(); + + builder.UseIfNotNull(middlewareConfiguration.PostDownstreamRouteFinderMiddleware); + + builder.UseIfNotNull(middlewareConfiguration.PreAuthenticationMiddleware); + + builder.UseAuthenticationMiddleware(); + + builder.UseIfNotNull(middlewareConfiguration.PostAuthenticationMiddleware); + + builder.UseIfNotNull(middlewareConfiguration.PreClaimsBuilderMiddleware); + + builder.UseClaimsBuilderMiddleware(); + + builder.UseIfNotNull(middlewareConfiguration.PostClaimsBuilderMiddleware); + + builder.UseIfNotNull(middlewareConfiguration.PreAuthorisationMiddleware); + + builder.UseAuthorisationMiddleware(); + + builder.UseIfNotNull(middlewareConfiguration.PostAuthorisationMiddleware); + + builder.UseIfNotNull(middlewareConfiguration.PreHttpRequestHeadersBuilderMiddleware); + + builder.UseHttpRequestHeadersBuilderMiddleware(); + + builder.UseIfNotNull(middlewareConfiguration.PostHttpRequestHeadersBuilderMiddleware); + + builder.UseIfNotNull(middlewareConfiguration.PreDownstreamUrlCreatorMiddleware); + + builder.UseDownstreamUrlCreatorMiddleware(); + + builder.UseIfNotNull(middlewareConfiguration.PostDownstreamUrlCreatorMiddleware); + + builder.UseIfNotNull(middlewareConfiguration.PreHttpRequestBuilderMiddleware); + + builder.UseHttpRequestBuilderMiddleware(); + + builder.UseIfNotNull(middlewareConfiguration.PostHttpRequestBuilderMiddleware); + + builder.UseIfNotNull(middlewareConfiguration.PreHttpRequesterMiddleware); + + builder.UseHttpRequesterMiddleware(); + + return builder; + } + + private static void UseIfNotNull(this IApplicationBuilder builder, Func, Task> middleware) + { + if (middleware != null) + { + builder.Use(middleware); + } + } } } diff --git a/test/Ocelot.AcceptanceTests/CustomMiddlewareTests.cs b/test/Ocelot.AcceptanceTests/CustomMiddlewareTests.cs new file mode 100644 index 00000000..d7b680a5 --- /dev/null +++ b/test/Ocelot.AcceptanceTests/CustomMiddlewareTests.cs @@ -0,0 +1,201 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Http; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.TestHost; +using Ocelot.Configuration.Yaml; +using Shouldly; +using TestStack.BDDfy; +using Xunit; +using YamlDotNet.Serialization; + +namespace Ocelot.AcceptanceTests +{ + using System.Linq; + using System.Threading.Tasks; + using DependencyInjection; + using Microsoft.Extensions.Configuration; + using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Logging; + using Microsoft.Extensions.Primitives; + using Middleware; + using ScopedData; + + public class CustomMiddlewareTests : IDisposable + { + private TestServer _server; + private HttpClient _client; + private HttpResponseMessage _response; + private readonly string _configurationPath; + private StringContent _postContent; + private IWebHost _builder; + + // Sadly we need to change this when we update the netcoreapp version to make the test update the config correctly + private double _netCoreAppVersion = 1.4; + + public CustomMiddlewareTests() + { + _configurationPath = $"configuration.yaml"; + } + + [Fact] + public void response_should_come_from_pre_http_responder_middleware() + { + var configuration = new OcelotMiddlewareConfiguration + { + PreHttpResponderMiddleware = async (ctx, next) => + { + await ctx.Response.WriteAsync("PreHttpResponderMiddleware"); + } + }; + + this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:41879", 200)) + .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration + { + ReRoutes = new List + { + new YamlReRoute + { + DownstreamTemplate = "http://localhost:41879/", + UpstreamTemplate = "/", + UpstreamHttpMethod = "Get", + } + } + })) + .And(x => x.GivenTheApiGatewayIsRunning(configuration)) + .When(x => x.WhenIGetUrlOnTheApiGateway("/")) + .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + .And(x => x.ThenTheResponseBodyShouldBe("PreHttpResponderMiddleware")) + .BDDfy(); + } + + [Fact] + public void response_should_come_from_pre_http_requester_middleware() + { + var configuration = new OcelotMiddlewareConfiguration + { + PreHttpRequesterMiddleware = async (ctx, next) => + { + var service = ctx.RequestServices.GetService(); + service.Add("Response", + new HttpResponseMessage {Content = new StringContent("PreHttpRequesterMiddleware")}); + } + }; + + this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:41879", 200)) + .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration + { + ReRoutes = new List + { + new YamlReRoute + { + DownstreamTemplate = "http://localhost:41879/", + UpstreamTemplate = "/", + UpstreamHttpMethod = "Get", + } + } + })) + .And(x => x.GivenTheApiGatewayIsRunning(configuration)) + .When(x => x.WhenIGetUrlOnTheApiGateway("/")) + .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + .And(x => x.ThenTheResponseBodyShouldBe("PreHttpRequesterMiddleware")) + .BDDfy(); + } + + + + /// + /// This is annoying cos it should be in the constructor but we need to set up the yaml file before calling startup so its a step. + /// + private void GivenTheApiGatewayIsRunning(OcelotMiddlewareConfiguration ocelotMiddlewareConfig) + { + var builder = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) + .AddYamlFile("configuration.yaml") + .AddEnvironmentVariables(); + + var configuration = builder.Build(); + + _server = new TestServer(new WebHostBuilder() + .UseConfiguration(configuration) + .ConfigureServices(s => + { + s.AddOcelotYamlConfiguration(configuration); + s.AddOcelot(); + }) + .ConfigureLogging(l => + { + l.AddConsole(configuration.GetSection("Logging")); + l.AddDebug(); + }) + .Configure(a => + { + a.UseOcelot(ocelotMiddlewareConfig); + })); + + _client = _server.CreateClient(); + } + + private void GivenThereIsAConfiguration(YamlConfiguration yamlConfiguration) + { + var serializer = new Serializer(); + + if (File.Exists(_configurationPath)) + { + File.Delete(_configurationPath); + } + + using (TextWriter writer = File.CreateText(_configurationPath)) + { + serializer.Serialize(writer, yamlConfiguration); + } + } + + private void GivenThereIsAServiceRunningOn(string url, int statusCode) + { + _builder = new WebHostBuilder() + .UseUrls(url) + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseUrls(url) + .Configure(app => + { + app.Run(async context => + { + context.Response.StatusCode = statusCode; + }); + }) + .Build(); + + _builder.Start(); + } + + private void WhenIGetUrlOnTheApiGateway(string url) + { + _response = _client.GetAsync(url).Result; + } + + private void ThenTheStatusCodeShouldBe(HttpStatusCode expectedHttpStatusCode) + { + _response.StatusCode.ShouldBe(expectedHttpStatusCode); + } + + private void ThenTheResponseBodyShouldBe(string expectedBody) + { + _response.Content.ReadAsStringAsync().Result.ShouldBe(expectedBody); + } + + public void Dispose() + { + _builder?.Dispose(); + _client.Dispose(); + _server.Dispose(); + } + } +} diff --git a/test/Ocelot.AcceptanceTests/configuration.yaml b/test/Ocelot.AcceptanceTests/configuration.yaml index 29e93d20..feba804e 100644 --- a/test/Ocelot.AcceptanceTests/configuration.yaml +++ b/test/Ocelot.AcceptanceTests/configuration.yaml @@ -1,13 +1,7 @@ ReRoutes: -- DownstreamTemplate: http://localhost:51876/ +- DownstreamTemplate: http://localhost:41879/ UpstreamTemplate: / - UpstreamHttpMethod: Post - AuthenticationOptions: - Provider: IdentityServer - ProviderRootUrl: http://localhost:51888 - ScopeName: api - AdditionalScopes: [] - ScopeSecret: secret - ProxyRequestHeaders: - - CustomerId: Claims[CustomerId] - + UpstreamHttpMethod: Get + AddHeadersToRequest: {} + AddClaimsToRequest: {} + RouteClaimsRequirement: {} diff --git a/test/Ocelot.AcceptanceTests/project.json b/test/Ocelot.AcceptanceTests/project.json index 56f49099..0ff6cf15 100644 --- a/test/Ocelot.AcceptanceTests/project.json +++ b/test/Ocelot.AcceptanceTests/project.json @@ -4,7 +4,7 @@ "buildOptions": { "copyToOutput": { "include": [ - "configuration.yaml" + "middlewareConfiguration.yaml" ] } }, diff --git a/test/Ocelot.ManualTest/project.json b/test/Ocelot.ManualTest/project.json index 39425e9d..921118bd 100644 --- a/test/Ocelot.ManualTest/project.json +++ b/test/Ocelot.ManualTest/project.json @@ -39,7 +39,7 @@ "preserveCompilationContext": true, "copyToOutput": { "include": [ - "configuration.yaml" + "middlewareConfiguration.yaml" ] } }, @@ -57,7 +57,7 @@ "Areas/**/Views", "appsettings.json", "web.config", - "configuration.yaml" + "middlewareConfiguration.yaml" ] }, diff --git a/test/Ocelot.ManualTest/web.config b/test/Ocelot.ManualTest/web.config index dc0514fc..894788ec 100644 --- a/test/Ocelot.ManualTest/web.config +++ b/test/Ocelot.ManualTest/web.config @@ -1,5 +1,5 @@  - +