diff --git a/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs b/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs index 30d9d87a..6839ed13 100644 --- a/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs +++ b/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Net.Http; using Ocelot.Values; +using System.Linq; namespace Ocelot.Configuration.Builder { @@ -11,7 +12,7 @@ namespace Ocelot.Configuration.Builder private string _downstreamPathTemplate; private string _upstreamTemplate; private string _upstreamTemplatePattern; - private string _upstreamHttpMethod; + private List _upstreamHttpMethod; private bool _isAuthenticated; private List _configHeaderExtractorProperties; private List _claimToClaims; @@ -68,7 +69,7 @@ namespace Ocelot.Configuration.Builder } public ReRouteBuilder WithUpstreamHttpMethod(string input) { - _upstreamHttpMethod = input; + _upstreamHttpMethod = string.IsNullOrWhiteSpace(input) ? new List() : input.Split(',').Select(x => new HttpMethod(x.Trim())).ToList(); return this; } public ReRouteBuilder WithIsAuthenticated(bool input) @@ -180,7 +181,7 @@ namespace Ocelot.Configuration.Builder return new ReRoute( new PathTemplate(_downstreamPathTemplate), new PathTemplate(_upstreamTemplate), - new HttpMethod(_upstreamHttpMethod), + _upstreamHttpMethod, _upstreamTemplatePattern, _isAuthenticated, _authenticationOptions, diff --git a/src/Ocelot/Configuration/ReRoute.cs b/src/Ocelot/Configuration/ReRoute.cs index bba8c925..a6673d09 100644 --- a/src/Ocelot/Configuration/ReRoute.cs +++ b/src/Ocelot/Configuration/ReRoute.cs @@ -8,7 +8,7 @@ namespace Ocelot.Configuration { public ReRoute(PathTemplate downstreamPathTemplate, PathTemplate upstreamPathTemplate, - HttpMethod upstreamHttpMethod, + List upstreamHttpMethod, string upstreamTemplatePattern, bool isAuthenticated, AuthenticationOptions authenticationOptions, @@ -64,7 +64,7 @@ namespace Ocelot.Configuration public PathTemplate DownstreamPathTemplate { get; private set; } public PathTemplate UpstreamPathTemplate { get; private set; } public string UpstreamTemplatePattern { get; private set; } - public HttpMethod UpstreamHttpMethod { get; private set; } + public List UpstreamHttpMethod { get; private set; } public bool IsAuthenticated { get; private set; } public bool IsAuthorised { get; private set; } public AuthenticationOptions AuthenticationOptions { get; private set; } diff --git a/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs b/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs index 82a5e7c5..bf0d5a52 100644 --- a/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs +++ b/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs @@ -26,7 +26,7 @@ namespace Ocelot.DownstreamRouteFinder.Finder { var configuration = await _configProvider.Get(); - var applicableReRoutes = configuration.Data.ReRoutes.Where(r => string.Equals(r.UpstreamHttpMethod.Method.ToLower(), upstreamHttpMethod.ToLower(), StringComparison.CurrentCultureIgnoreCase)); + var applicableReRoutes = configuration.Data.ReRoutes.Where(r => r.UpstreamHttpMethod.Count == 0 || r.UpstreamHttpMethod.Select(x => x.Method.ToLower()).Contains(upstreamHttpMethod.ToLower())); foreach (var reRoute in applicableReRoutes) { diff --git a/test/Ocelot.AcceptanceTests/RoutingTests.cs b/test/Ocelot.AcceptanceTests/RoutingTests.cs index 99c11877..ffefd277 100644 --- a/test/Ocelot.AcceptanceTests/RoutingTests.cs +++ b/test/Ocelot.AcceptanceTests/RoutingTests.cs @@ -319,6 +319,62 @@ namespace Ocelot.AcceptanceTests .BDDfy(); } + [Fact] + public void should_return_response_201_with_simple_url_and_multiple_upstream_http_method() + { + var configuration = new FileConfiguration + { + ReRoutes = new List + { + new FileReRoute + { + DownstreamPathTemplate = "/", + DownstreamHost = "localhost", + DownstreamPort = 51879, + DownstreamScheme = "http", + UpstreamPathTemplate = "/", + UpstreamHttpMethod = "Get, Post", + } + } + }; + + this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", 201, string.Empty)) + .And(x => _steps.GivenThereIsAConfiguration(configuration)) + .And(x => _steps.GivenOcelotIsRunning()) + .And(x => _steps.GivenThePostHasContent("postContent")) + .When(x => _steps.WhenIPostUrlOnTheApiGateway("/")) + .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Created)) + .BDDfy(); + } + + [Fact] + public void should_return_response_200_with_simple_url_and_any_upstream_http_method() + { + var configuration = new FileConfiguration + { + ReRoutes = new List + { + new FileReRoute + { + DownstreamPathTemplate = "/", + DownstreamHost = "localhost", + DownstreamPort = 51879, + DownstreamScheme = "http", + UpstreamPathTemplate = "/", + UpstreamHttpMethod = "", + } + } + }; + + this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", 200, "Hello from Laura")) + .And(x => _steps.GivenThereIsAConfiguration(configuration)) + .And(x => _steps.GivenOcelotIsRunning()) + .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) + .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) + .BDDfy(); + } + private void GivenThereIsAServiceRunningOn(string url, int statusCode, string responseBody) { _builder = new WebHostBuilder() diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs index 0d272c63..64c20af0 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs @@ -157,6 +157,95 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .BDDfy(); } + [Fact] + public void should_return_correct_route_for_http_verb_setting_multiple_upstream_http_method() + { + this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath")) + .And( + x => + x.GivenTheTemplateVariableAndNameFinderReturns( + new OkResponse>(new List()))) + .And(x => x.GivenTheConfigurationIs(new List + { + new ReRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") + .WithUpstreamPathTemplate("someUpstreamPath") + .WithUpstreamHttpMethod("Get, Post") + .WithUpstreamTemplatePattern("") + .Build() + }, string.Empty + )) + .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 ReRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") + .WithUpstreamHttpMethod("Post") + .Build() + ))) + .BDDfy(); + } + + [Fact] + public void should_return_correct_route_for_http_verb_setting_all_upstream_http_method() + { + this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath")) + .And( + x => + x.GivenTheTemplateVariableAndNameFinderReturns( + new OkResponse>(new List()))) + .And(x => x.GivenTheConfigurationIs(new List + { + new ReRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") + .WithUpstreamPathTemplate("someUpstreamPath") + .WithUpstreamHttpMethod("") + .WithUpstreamTemplatePattern("") + .Build() + }, string.Empty + )) + .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 ReRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") + .WithUpstreamHttpMethod("Post") + .Build() + ))) + .BDDfy(); + } + + [Fact] + public void should_not_return_route_for_http_verb_not_setting_in_upstream_http_method() + { + this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath")) + .And( + x => + x.GivenTheTemplateVariableAndNameFinderReturns( + new OkResponse>(new List()))) + .And(x => x.GivenTheConfigurationIs(new List + { + new ReRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") + .WithUpstreamPathTemplate("someUpstreamPath") + .WithUpstreamHttpMethod("Get, Patch, Delete") + .WithUpstreamTemplatePattern("") + .Build() + }, string.Empty + )) + .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true)))) + .And(x => x.GivenTheUpstreamHttpMethodIs("Post")) + .When(x => x.WhenICallTheFinder()) + .Then( + x => x.ThenAnErrorResponseIsReturned()) + .And(x => x.ThenTheUrlMatcherIsNotCalled()) + .BDDfy(); + } + private void GivenTheTemplateVariableAndNameFinderReturns(Response> response) { _finder