Now defaults to case insensitive routing but you can override with a setting, also global request id setting available

This commit is contained in:
TomPallister 2016-11-06 11:50:33 +00:00
parent 30c668bfdf
commit ff5776613f
11 changed files with 552 additions and 109 deletions

View File

@ -45,6 +45,18 @@ All versions can be found [here](https://www.nuget.org/packages/Ocelot/)
An example configuration can be found [here](https://github.com/TomPallister/Ocelot/blob/develop/test/Ocelot.ManualTest/configuration.json) An example configuration can be found [here](https://github.com/TomPallister/Ocelot/blob/develop/test/Ocelot.ManualTest/configuration.json)
and an explained configuration can be found [here](https://github.com/TomPallister/Ocelot/blob/develop/configuration-explanation.txt). More detailed instructions to come on how to configure this. and an explained configuration can be found [here](https://github.com/TomPallister/Ocelot/blob/develop/configuration-explanation.txt). More detailed instructions to come on how to configure this.
There are two sections to the configuration. An array of ReRoutes and a GlobalConfiguration.
The ReRoutes are the objects that tell Ocelot how to treat an upstream request. The Global
configuration is a bit hacky and allows overrides of ReRoute specific settings. It's useful
if you don't want to manage lots of ReRoute specific settings.
{
"ReRoutes": [],
"GlobalConfiguration": {}
}
More information on how to use these options is below..
## Startup ## Startup
An example startup using a json file for configuration can be seen below. An example startup using a json file for configuration can be seen below.
@ -125,8 +137,14 @@ The placeholder needs to be in both the DownstreamTemplate and UpstreamTemplate.
Ocelot will attempt to replace the placeholder with the correct variable value from the Ocelot will attempt to replace the placeholder with the correct variable value from the
Upstream URL when the request comes in. Upstream URL when the request comes in.
At the moment all Ocelot routing is case sensitive. I think I will turn this off by default At the moment without any configuration Ocelot will default to all ReRoutes being case insensitive.
in the future with an options to make Ocelot case sensitive per ReRoute. In order to change this you can specify on a per ReRoute basis the following setting.
"ReRouteIsCaseSensitive": true
This means that when Ocelot tries to match the incoming upstream url with an upstream template the
evaluation will be case sensitive. This setting defaults to false so only set it if you want
the ReRoute to be case sensitive is my advice!
## Authentication ## Authentication
@ -263,6 +281,13 @@ In order to use the requestid feature in your ReRoute configuration add this set
In this example OcRequestId is the request header that contains the clients request id. In this example OcRequestId is the request header that contains the clients request id.
There is also a setting in the GlobalConfiguration section which will override whatever has been
set at ReRoute level for the request id. The setting is as fllows.
"RequestIdKey": "OcRequestId",
It behaves in exactly the same way as the ReRoute level RequestIdKey settings.
## Caching ## Caching
Ocelot supports some very rudimentary caching at the moment provider by Ocelot supports some very rudimentary caching at the moment provider by
@ -300,6 +325,8 @@ forwarded to the downstream service. Obviously this would break everything :(
and doesnt check the response is OK. I think the fact you can even call stuff and doesnt check the response is OK. I think the fact you can even call stuff
that isnt available is annoying. Let alone it be null. that isnt available is annoying. Let alone it be null.
+ The Ocelot Request Id starts getting logged too late in the pipeline.
## Coming up ## Coming up
You can see what we are working on [here](https://github.com/TomPallister/Ocelot/projects/1) You can see what we are working on [here](https://github.com/TomPallister/Ocelot/projects/1)

View File

@ -1,4 +1,5 @@
"ReRoutes": [ {
"ReRoutes": [
{ {
# The url we are forwarding the request to # The url we are forwarding the request to
"UpstreamTemplate": "/identityserverexample", "UpstreamTemplate": "/identityserverexample",
@ -66,5 +67,14 @@
# a user id or something that would get ignored by the downstream service. This is a hack and I # a user id or something that would get ignored by the downstream service. This is a hack and I
# intend to provide a mechanism the user can specify for the ttl caching. Also want to expand # intend to provide a mechanism the user can specify for the ttl caching. Also want to expand
# the caching a lot. # the caching a lot.
"FileCacheOptions": { "TtlSeconds": 15 } "FileCacheOptions": { "TtlSeconds": 15 },
# The value of this is used when matching the upstream template to an upstream url.
"ReRouteIsCaseSensitive": false
},
# This section is meant to be for global configuration settings
"GlobalConfiguration": {
# If this is set it will override any route specific request id keys, behaves the same
# otherwise
"RequestIdKey": "OcRequestId",
}
} }

View File

@ -19,6 +19,8 @@ namespace Ocelot.Configuration.Creator
private readonly IConfigurationValidator _configurationValidator; private readonly IConfigurationValidator _configurationValidator;
private const string RegExMatchEverything = ".*"; private const string RegExMatchEverything = ".*";
private const string RegExMatchEndString = "$"; private const string RegExMatchEndString = "$";
private const string RegExIgnoreCase = "(?i)";
private readonly IClaimToThingConfigurationParser _claimToThingConfigurationParser; private readonly IClaimToThingConfigurationParser _claimToThingConfigurationParser;
private readonly ILogger<FileOcelotConfigurationCreator> _logger; private readonly ILogger<FileOcelotConfigurationCreator> _logger;
@ -65,14 +67,56 @@ namespace Ocelot.Configuration.Creator
foreach (var reRoute in _options.Value.ReRoutes) foreach (var reRoute in _options.Value.ReRoutes)
{ {
var ocelotReRoute = SetUpReRoute(reRoute); var ocelotReRoute = SetUpReRoute(reRoute, _options.Value.GlobalConfiguration);
reRoutes.Add(ocelotReRoute); reRoutes.Add(ocelotReRoute);
} }
return new OcelotConfiguration(reRoutes); return new OcelotConfiguration(reRoutes);
} }
private ReRoute SetUpReRoute(FileReRoute reRoute) private ReRoute SetUpReRoute(FileReRoute reRoute, FileGlobalConfiguration globalConfiguration)
{
var globalRequestIdConfiguration = !string.IsNullOrEmpty(globalConfiguration?.RequestIdKey);
var upstreamTemplate = BuildUpstreamTemplate(reRoute);
var isAuthenticated = !string.IsNullOrEmpty(reRoute.AuthenticationOptions?.Provider);
var isAuthorised = reRoute.RouteClaimsRequirement?.Count > 0;
var isCached = reRoute.FileCacheOptions.TtlSeconds > 0;
var requestIdKey = globalRequestIdConfiguration
? globalConfiguration.RequestIdKey
: reRoute.RequestIdKey;
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 claimsToHeaders = GetAddThingsToRequest(reRoute.AddHeadersToRequest);
var claimsToClaims = GetAddThingsToRequest(reRoute.AddClaimsToRequest);
var claimsToQueries = GetAddThingsToRequest(reRoute.AddQueriesToRequest);
return new ReRoute(reRoute.DownstreamTemplate, reRoute.UpstreamTemplate,
reRoute.UpstreamHttpMethod, upstreamTemplate, isAuthenticated,
authOptionsForRoute, claimsToHeaders, claimsToClaims,
reRoute.RouteClaimsRequirement, isAuthorised, claimsToQueries,
requestIdKey, isCached, new CacheOptions(reRoute.FileCacheOptions.TtlSeconds));
}
return new ReRoute(reRoute.DownstreamTemplate, reRoute.UpstreamTemplate,
reRoute.UpstreamHttpMethod, upstreamTemplate, isAuthenticated,
null, new List<ClaimToThing>(), new List<ClaimToThing>(),
reRoute.RouteClaimsRequirement, isAuthorised, new List<ClaimToThing>(),
requestIdKey, isCached, new CacheOptions(reRoute.FileCacheOptions.TtlSeconds));
}
private string BuildUpstreamTemplate(FileReRoute reRoute)
{ {
var upstreamTemplate = reRoute.UpstreamTemplate; var upstreamTemplate = reRoute.UpstreamTemplate;
@ -94,38 +138,9 @@ namespace Ocelot.Configuration.Creator
upstreamTemplate = upstreamTemplate.Replace(placeholder, RegExMatchEverything); upstreamTemplate = upstreamTemplate.Replace(placeholder, RegExMatchEverything);
} }
upstreamTemplate = $"{upstreamTemplate}{RegExMatchEndString}"; return reRoute.ReRouteIsCaseSensitive
? $"{upstreamTemplate}{RegExMatchEndString}"
var isAuthenticated = !string.IsNullOrEmpty(reRoute.AuthenticationOptions?.Provider); : $"{RegExIgnoreCase}{upstreamTemplate}{RegExMatchEndString}";
var isAuthorised = reRoute.RouteClaimsRequirement?.Count > 0;
var isCached = reRoute.FileCacheOptions.TtlSeconds > 0;
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 claimsToHeaders = GetAddThingsToRequest(reRoute.AddHeadersToRequest);
var claimsToClaims = GetAddThingsToRequest(reRoute.AddClaimsToRequest);
var claimsToQueries = GetAddThingsToRequest(reRoute.AddQueriesToRequest);
return new ReRoute(reRoute.DownstreamTemplate, reRoute.UpstreamTemplate,
reRoute.UpstreamHttpMethod, upstreamTemplate, isAuthenticated,
authOptionsForRoute, claimsToHeaders, claimsToClaims,
reRoute.RouteClaimsRequirement, isAuthorised, claimsToQueries,
reRoute.RequestIdKey, isCached, new CacheOptions(reRoute.FileCacheOptions.TtlSeconds)
);
}
return new ReRoute(reRoute.DownstreamTemplate, reRoute.UpstreamTemplate,
reRoute.UpstreamHttpMethod, upstreamTemplate, isAuthenticated,
null, new List<ClaimToThing>(), new List<ClaimToThing>(),
reRoute.RouteClaimsRequirement, isAuthorised, new List<ClaimToThing>(),
reRoute.RequestIdKey, isCached, new CacheOptions(reRoute.FileCacheOptions.TtlSeconds));
} }
private List<ClaimToThing> GetAddThingsToRequest(Dictionary<string,string> thingBeingAdded) private List<ClaimToThing> GetAddThingsToRequest(Dictionary<string,string> thingBeingAdded)

View File

@ -7,8 +7,10 @@ namespace Ocelot.Configuration.File
public FileConfiguration() public FileConfiguration()
{ {
ReRoutes = new List<FileReRoute>(); ReRoutes = new List<FileReRoute>();
GlobalConfiguration = new FileGlobalConfiguration();
} }
public List<FileReRoute> ReRoutes { get; set; } public List<FileReRoute> ReRoutes { get; set; }
public FileGlobalConfiguration GlobalConfiguration { get; set; }
} }
} }

View File

@ -0,0 +1,7 @@
namespace Ocelot.Configuration.File
{
public class FileGlobalConfiguration
{
public string RequestIdKey { get; set; }
}
}

View File

@ -24,5 +24,6 @@ namespace Ocelot.Configuration.File
public Dictionary<string, string> AddQueriesToRequest { get; set; } public Dictionary<string, string> AddQueriesToRequest { get; set; }
public string RequestIdKey { get; set; } public string RequestIdKey { get; set; }
public FileCacheOptions FileCacheOptions { get; set; } public FileCacheOptions FileCacheOptions { get; set; }
public bool ReRouteIsCaseSensitive { get; set; }
} }
} }

View File

@ -0,0 +1,200 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Ocelot.Configuration.File;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.AcceptanceTests
{
public class CaseSensitiveRoutingTests : IDisposable
{
private IWebHost _builder;
private readonly Steps _steps;
public CaseSensitiveRoutingTests()
{
_steps = new Steps();
}
[Fact]
public void should_return_response_200_when_global_ignore_case_sensitivity_set()
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamTemplate = "http://localhost:51879/api/products/{productId}",
UpstreamTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get"
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879/api/products/1", 200, "Some Product"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/PRODUCTS/1"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.BDDfy();
}
[Fact]
public void should_return_response_200_when_reroute_ignore_case_sensitivity_set()
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamTemplate = "http://localhost:51879/api/products/{productId}",
UpstreamTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = false
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879/api/products/1", 200, "Some Product"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/PRODUCTS/1"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.BDDfy();
}
[Fact]
public void should_return_response_404_when_reroute_respect_case_sensitivity_set()
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamTemplate = "http://localhost:51879/api/products/{productId}",
UpstreamTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = true
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879/api/products/1", 200, "Some Product"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/PRODUCTS/1"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound))
.BDDfy();
}
[Fact]
public void should_return_response_200_when_reroute_respect_case_sensitivity_set()
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamTemplate = "http://localhost:51879/api/products/{productId}",
UpstreamTemplate = "/PRODUCTS/{productId}",
UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = true
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879/api/products/1", 200, "Some Product"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/PRODUCTS/1"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.BDDfy();
}
[Fact]
public void should_return_response_404_when_global_respect_case_sensitivity_set()
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamTemplate = "http://localhost:51879/api/products/{productId}",
UpstreamTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = true
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879/api/products/1", 200, "Some Product"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/PRODUCTS/1"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound))
.BDDfy();
}
[Fact]
public void should_return_response_200_when_global_respect_case_sensitivity_set()
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamTemplate = "http://localhost:51879/api/products/{productId}",
UpstreamTemplate = "/PRODUCTS/{productId}",
UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = true
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879/api/products/1", 200, "Some Product"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/PRODUCTS/1"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.BDDfy();
}
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();
}
public void Dispose()
{
_builder?.Dispose();
_steps.Dispose();
}
}
}

View File

@ -76,6 +76,36 @@ namespace Ocelot.AcceptanceTests
.BDDfy(); .BDDfy();
} }
[Fact]
public void should_use_global_request_id_and_forward()
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamTemplate = "http://localhost:51879/",
UpstreamTemplate = "/",
UpstreamHttpMethod = "Get",
}
},
GlobalConfiguration = new FileGlobalConfiguration
{
RequestIdKey = _steps.RequestIdKey
}
};
var requestId = Guid.NewGuid().ToString();
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/", requestId))
.Then(x => _steps.ThenTheRequestIdIsReturned(requestId))
.BDDfy();
}
private void GivenThereIsAServiceRunningOn(string url) private void GivenThereIsAServiceRunningOn(string url)
{ {
_builder = new WebHostBuilder() _builder = new WebHostBuilder()

View File

@ -1 +1 @@
{"ReRoutes":[{"DownstreamTemplate":"http://localhost:41879/","UpstreamTemplate":"/","UpstreamHttpMethod":"Get","AuthenticationOptions":{"Provider":null,"ProviderRootUrl":null,"ScopeName":null,"RequireHttps":false,"AdditionalScopes":[],"ScopeSecret":null},"AddHeadersToRequest":{},"AddClaimsToRequest":{},"RouteClaimsRequirement":{},"AddQueriesToRequest":{},"RequestIdKey":null,"FileCacheOptions":{"TtlSeconds":0}}]} {"ReRoutes":[{"DownstreamTemplate":"http://localhost:41879/","UpstreamTemplate":"/","UpstreamHttpMethod":"Get","AuthenticationOptions":{"Provider":null,"ProviderRootUrl":null,"ScopeName":null,"RequireHttps":false,"AdditionalScopes":[],"ScopeSecret":null},"AddHeadersToRequest":{},"AddClaimsToRequest":{},"RouteClaimsRequirement":{},"AddQueriesToRequest":{},"RequestIdKey":null,"FileCacheOptions":{"TtlSeconds":0},"ReRouteIsCaseSensitive":false}],"GlobalConfiguration":{"RequestIdKey":null}}

View File

@ -36,7 +36,37 @@ namespace Ocelot.UnitTests.Configuration
} }
[Fact] [Fact]
public void should_create_template_pattern_that_matches_anything_to_end_of_string() public void should_use_reroute_case_sensitivity_value()
{
this.Given(x => x.GivenTheConfigIs(new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
UpstreamTemplate = "/api/products/{productId}",
DownstreamTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = false
}
}
}))
.And(x => x.GivenTheConfigIsValid())
.When(x => x.WhenICreateTheConfig())
.Then(x => x.ThenTheReRoutesAre(new List<ReRoute>
{
new ReRouteBuilder()
.WithDownstreamTemplate("/products/{productId}")
.WithUpstreamTemplate("/api/products/{productId}")
.WithUpstreamHttpMethod("Get")
.WithUpstreamTemplatePattern("(?i)/api/products/.*$")
.Build()
}))
.BDDfy();
}
[Fact]
public void should_set_upstream_template_pattern_to_ignore_case_sensitivity()
{ {
this.Given(x => x.GivenTheConfigIs(new FileConfiguration this.Given(x => x.GivenTheConfigIs(new FileConfiguration
{ {
@ -49,6 +79,101 @@ namespace Ocelot.UnitTests.Configuration
UpstreamHttpMethod = "Get" UpstreamHttpMethod = "Get"
} }
} }
}))
.And(x => x.GivenTheConfigIsValid())
.When(x => x.WhenICreateTheConfig())
.Then(x => x.ThenTheReRoutesAre(new List<ReRoute>
{
new ReRouteBuilder()
.WithDownstreamTemplate("/products/{productId}")
.WithUpstreamTemplate("/api/products/{productId}")
.WithUpstreamHttpMethod("Get")
.WithUpstreamTemplatePattern("(?i)/api/products/.*$")
.Build()
}))
.BDDfy();
}
[Fact]
public void should_set_upstream_template_pattern_to_respect_case_sensitivity()
{
this.Given(x => x.GivenTheConfigIs(new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
UpstreamTemplate = "/api/products/{productId}",
DownstreamTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = true
}
}
}))
.And(x => x.GivenTheConfigIsValid())
.When(x => x.WhenICreateTheConfig())
.Then(x => x.ThenTheReRoutesAre(new List<ReRoute>
{
new ReRouteBuilder()
.WithDownstreamTemplate("/products/{productId}")
.WithUpstreamTemplate("/api/products/{productId}")
.WithUpstreamHttpMethod("Get")
.WithUpstreamTemplatePattern("/api/products/.*$")
.Build()
}))
.BDDfy();
}
[Fact]
public void should_set_global_request_id_key()
{
this.Given(x => x.GivenTheConfigIs(new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
UpstreamTemplate = "/api/products/{productId}",
DownstreamTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = true
}
},
GlobalConfiguration = new FileGlobalConfiguration
{
RequestIdKey = "blahhhh"
}
}))
.And(x => x.GivenTheConfigIsValid())
.When(x => x.WhenICreateTheConfig())
.Then(x => x.ThenTheReRoutesAre(new List<ReRoute>
{
new ReRouteBuilder()
.WithDownstreamTemplate("/products/{productId}")
.WithUpstreamTemplate("/api/products/{productId}")
.WithUpstreamHttpMethod("Get")
.WithUpstreamTemplatePattern("/api/products/.*$")
.WithRequestIdKey("blahhhh")
.Build()
}))
.BDDfy();
}
[Fact]
public void should_create_template_pattern_that_matches_anything_to_end_of_string()
{
this.Given(x => x.GivenTheConfigIs(new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
UpstreamTemplate = "/api/products/{productId}",
DownstreamTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = true
}
}
})) }))
.And(x => x.GivenTheConfigIsValid()) .And(x => x.GivenTheConfigIsValid())
.When(x => x.WhenICreateTheConfig()) .When(x => x.WhenICreateTheConfig())
@ -95,6 +220,7 @@ namespace Ocelot.UnitTests.Configuration
UpstreamTemplate = "/api/products/{productId}", UpstreamTemplate = "/api/products/{productId}",
DownstreamTemplate = "/products/{productId}", DownstreamTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get", UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = true,
AuthenticationOptions = new FileAuthenticationOptions AuthenticationOptions = new FileAuthenticationOptions
{ {
AdditionalScopes = new List<string>(), AdditionalScopes = new List<string>(),
@ -153,6 +279,7 @@ namespace Ocelot.UnitTests.Configuration
UpstreamTemplate = "/api/products/{productId}", UpstreamTemplate = "/api/products/{productId}",
DownstreamTemplate = "/products/{productId}", DownstreamTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get", UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = true,
AuthenticationOptions = new FileAuthenticationOptions AuthenticationOptions = new FileAuthenticationOptions
{ {
AdditionalScopes = new List<string>(), AdditionalScopes = new List<string>(),
@ -183,7 +310,8 @@ namespace Ocelot.UnitTests.Configuration
{ {
UpstreamTemplate = "/api/products/{productId}/variants/{variantId}", UpstreamTemplate = "/api/products/{productId}/variants/{variantId}",
DownstreamTemplate = "/products/{productId}", DownstreamTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get" UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = true
} }
} }
})) }))
@ -212,7 +340,8 @@ namespace Ocelot.UnitTests.Configuration
{ {
UpstreamTemplate = "/api/products/{productId}/variants/{variantId}/", UpstreamTemplate = "/api/products/{productId}/variants/{variantId}/",
DownstreamTemplate = "/products/{productId}", DownstreamTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get" UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = true
} }
} }
})) }))
@ -241,7 +370,8 @@ namespace Ocelot.UnitTests.Configuration
{ {
UpstreamTemplate = "/", UpstreamTemplate = "/",
DownstreamTemplate = "/api/products/", DownstreamTemplate = "/api/products/",
UpstreamHttpMethod = "Get" UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = true
} }
} }
})) }))

View File

@ -128,6 +128,27 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
.BDDfy(); .BDDfy();
} }
[Fact]
public void should_ignore_case_sensitivity()
{
this.Given(x => x.GivenIHaveAUpstreamPath("API/product/products/1/categories/2/variant/"))
.And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("(?i)api/product/products/.*/categories/.*/variant/$"))
.When(x => x.WhenIMatchThePaths())
.Then(x => x.ThenTheResultIsTrue())
.BDDfy();
}
[Fact]
public void should_respect_case_sensitivity()
{
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.ThenTheResultIsFalse())
.BDDfy();
}
private void GivenIHaveAUpstreamPath(string downstreamPath) private void GivenIHaveAUpstreamPath(string downstreamPath)
{ {
_downstreamUrlPath = downstreamPath; _downstreamUrlPath = downstreamPath;