Added support for query string parameters in upstream path template (#467)

This commit is contained in:
Tom Pallister 2018-07-12 19:26:23 +01:00 committed by GitHub
parent 19ea93d10e
commit 8f4ae03290
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 664 additions and 143 deletions

View File

@ -215,4 +215,33 @@ Ocelot allow's you to specify a querystring as part of the DownstreamPathTemplat
} }
} }
In this example Ocelot will use the value from the {unitId} in the upstream path template and add it to the downstream request as a query string parameter called unitId! Please note you cannot use query string parameters to match routes in the UpstreamPathTemplate. In this example Ocelot will use the value from the {unitId} in the upstream path template and add it to the downstream request as a query string parameter called unitId!
Ocelot will also allow you to put query string parametrs in the UpstreamPathTemplate so you can match certain queries to certain services.
.. code-block:: json
{
"ReRoutes": [
{
"DownstreamPathTemplate": "/api/units/{subscriptionId}/{unitId}/updates",
"UpstreamPathTemplate": "/api/subscriptions/{subscriptionId}/updates?unitId={unitId}",
"UpstreamHttpMethod": [
"Get"
],
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 50110
}
]
}
],
"GlobalConfiguration": {
"UseServiceDiscovery": false
}
}
In this example Ocelot will only match requests that have a matching url path and the querystring starts with unitId=something. You can have other queries after this
but you must start with the matching parameter. Also in this example Ocelot will swap the unitId param from the query string and use it in the downstream request path.

View File

@ -16,6 +16,7 @@ namespace Ocelot.Configuration.Creator
{ {
var upstreamTemplate = reRoute.UpstreamPathTemplate; var upstreamTemplate = reRoute.UpstreamPathTemplate;
var placeholders = new List<string>(); var placeholders = new List<string>();
for (var i = 0; i < upstreamTemplate.Length; i++) for (var i = 0; i < upstreamTemplate.Length; i++)
@ -30,11 +31,19 @@ namespace Ocelot.Configuration.Creator
//hack to handle /{url} case //hack to handle /{url} case
if(ForwardSlashAndOnePlaceHolder(upstreamTemplate, placeholders, postitionOfPlaceHolderClosingBracket)) if(ForwardSlashAndOnePlaceHolder(upstreamTemplate, placeholders, postitionOfPlaceHolderClosingBracket))
{ {
return new UpstreamPathTemplate(RegExForwardSlashAndOnePlaceHolder, 0); return new UpstreamPathTemplate(RegExForwardSlashAndOnePlaceHolder, 0, false);
} }
} }
} }
var containsQueryString = false;
if (upstreamTemplate.Contains("?"))
{
containsQueryString = true;
upstreamTemplate = upstreamTemplate.Replace("?", "\\?");
}
foreach (var placeholder in placeholders) foreach (var placeholder in placeholders)
{ {
upstreamTemplate = upstreamTemplate.Replace(placeholder, RegExMatchOneOrMoreOfEverything); upstreamTemplate = upstreamTemplate.Replace(placeholder, RegExMatchOneOrMoreOfEverything);
@ -42,7 +51,7 @@ namespace Ocelot.Configuration.Creator
if (upstreamTemplate == "/") if (upstreamTemplate == "/")
{ {
return new UpstreamPathTemplate(RegExForwardSlashOnly, reRoute.Priority); return new UpstreamPathTemplate(RegExForwardSlashOnly, reRoute.Priority, containsQueryString);
} }
if(upstreamTemplate.EndsWith("/")) if(upstreamTemplate.EndsWith("/"))
@ -54,7 +63,7 @@ namespace Ocelot.Configuration.Creator
? $"^{upstreamTemplate}{RegExMatchEndString}" ? $"^{upstreamTemplate}{RegExMatchEndString}"
: $"^{RegExIgnoreCase}{upstreamTemplate}{RegExMatchEndString}"; : $"^{RegExIgnoreCase}{upstreamTemplate}{RegExMatchEndString}";
return new UpstreamPathTemplate(route, reRoute.Priority); return new UpstreamPathTemplate(route, reRoute.Priority, containsQueryString);
} }
private bool ForwardSlashAndOnePlaceHolder(string upstreamTemplate, List<string> placeholders, int postitionOfPlaceHolderClosingBracket) private bool ForwardSlashAndOnePlaceHolder(string upstreamTemplate, List<string> placeholders, int postitionOfPlaceHolderClosingBracket)

View File

@ -21,7 +21,7 @@
_cache = new ConcurrentDictionary<string, OkResponse<DownstreamRoute>>(); _cache = new ConcurrentDictionary<string, OkResponse<DownstreamRoute>>();
} }
public Response<DownstreamRoute> Get(string upstreamUrlPath, string upstreamHttpMethod, IInternalConfiguration configuration, string upstreamHost) public Response<DownstreamRoute> Get(string upstreamUrlPath, string upstreamQueryString, string upstreamHttpMethod, IInternalConfiguration configuration, string upstreamHost)
{ {
var serviceName = GetServiceName(upstreamUrlPath); var serviceName = GetServiceName(upstreamUrlPath);

View File

@ -18,7 +18,7 @@ namespace Ocelot.DownstreamRouteFinder.Finder
_placeholderNameAndValueFinder = urlPathPlaceholderNameAndValueFinder; _placeholderNameAndValueFinder = urlPathPlaceholderNameAndValueFinder;
} }
public Response<DownstreamRoute> Get(string path, string httpMethod, IInternalConfiguration configuration, string upstreamHost) public Response<DownstreamRoute> Get(string upstreamUrlPath, string upstreamQueryString, string httpMethod, IInternalConfiguration configuration, string upstreamHost)
{ {
var downstreamRoutes = new List<DownstreamRoute>(); var downstreamRoutes = new List<DownstreamRoute>();
@ -28,11 +28,11 @@ namespace Ocelot.DownstreamRouteFinder.Finder
foreach (var reRoute in applicableReRoutes) foreach (var reRoute in applicableReRoutes)
{ {
var urlMatch = _urlMatcher.Match(path, reRoute.UpstreamTemplatePattern.Template); var urlMatch = _urlMatcher.Match(upstreamUrlPath, upstreamQueryString, reRoute.UpstreamTemplatePattern.Template, reRoute.UpstreamTemplatePattern.ContainsQueryString);
if (urlMatch.Data.Match) if (urlMatch.Data.Match)
{ {
downstreamRoutes.Add(GetPlaceholderNamesAndValues(path, reRoute)); downstreamRoutes.Add(GetPlaceholderNamesAndValues(upstreamUrlPath, upstreamQueryString, reRoute));
} }
} }
@ -44,7 +44,7 @@ namespace Ocelot.DownstreamRouteFinder.Finder
return notNullOption != null ? new OkResponse<DownstreamRoute>(notNullOption) : new OkResponse<DownstreamRoute>(nullOption); return notNullOption != null ? new OkResponse<DownstreamRoute>(notNullOption) : new OkResponse<DownstreamRoute>(nullOption);
} }
return new ErrorResponse<DownstreamRoute>(new UnableToFindDownstreamRouteError(path, httpMethod)); return new ErrorResponse<DownstreamRoute>(new UnableToFindDownstreamRouteError(upstreamUrlPath, httpMethod));
} }
private bool RouteIsApplicableToThisRequest(ReRoute reRoute, string httpMethod, string upstreamHost) private bool RouteIsApplicableToThisRequest(ReRoute reRoute, string httpMethod, string upstreamHost)
@ -53,9 +53,9 @@ namespace Ocelot.DownstreamRouteFinder.Finder
(string.IsNullOrEmpty(reRoute.UpstreamHost) || reRoute.UpstreamHost == upstreamHost); (string.IsNullOrEmpty(reRoute.UpstreamHost) || reRoute.UpstreamHost == upstreamHost);
} }
private DownstreamRoute GetPlaceholderNamesAndValues(string path, ReRoute reRoute) private DownstreamRoute GetPlaceholderNamesAndValues(string path, string query, ReRoute reRoute)
{ {
var templatePlaceholderNameAndValues = _placeholderNameAndValueFinder.Find(path, reRoute.UpstreamPathTemplate.Value); var templatePlaceholderNameAndValues = _placeholderNameAndValueFinder.Find(path, query, reRoute.UpstreamPathTemplate.Value);
return new DownstreamRoute(templatePlaceholderNameAndValues.Data, reRoute); return new DownstreamRoute(templatePlaceholderNameAndValues.Data, reRoute);
} }

View File

@ -6,6 +6,6 @@ namespace Ocelot.DownstreamRouteFinder.Finder
{ {
public interface IDownstreamRouteProvider public interface IDownstreamRouteProvider
{ {
Response<DownstreamRoute> Get(string upstreamUrlPath, string upstreamHttpMethod, IInternalConfiguration configuration, string upstreamHost); Response<DownstreamRoute> Get(string upstreamUrlPath, string upstreamQueryString, string upstreamHttpMethod, IInternalConfiguration configuration, string upstreamHost);
} }
} }

View File

@ -33,13 +33,15 @@ namespace Ocelot.DownstreamRouteFinder.Middleware
{ {
var upstreamUrlPath = context.HttpContext.Request.Path.ToString(); var upstreamUrlPath = context.HttpContext.Request.Path.ToString();
var upstreamQueryString = context.HttpContext.Request.QueryString.ToString();
var upstreamHost = context.HttpContext.Request.Headers["Host"]; var upstreamHost = context.HttpContext.Request.Headers["Host"];
Logger.LogDebug($"Upstream url path is {upstreamUrlPath}"); Logger.LogDebug($"Upstream url path is {upstreamUrlPath}");
var provider = _factory.Get(context.Configuration); var provider = _factory.Get(context.Configuration);
var downstreamRoute = provider.Get(upstreamUrlPath, context.HttpContext.Request.Method, context.Configuration, upstreamHost); var downstreamRoute = provider.Get(upstreamUrlPath, upstreamQueryString, context.HttpContext.Request.Method, context.Configuration, upstreamHost);
if (downstreamRoute.IsError) if (downstreamRoute.IsError)
{ {

View File

@ -5,6 +5,6 @@ namespace Ocelot.DownstreamRouteFinder.UrlMatcher
{ {
public interface IPlaceholderNameAndValueFinder public interface IPlaceholderNameAndValueFinder
{ {
Response<List<PlaceholderNameAndValue>> Find(string path, string pathTemplate); Response<List<PlaceholderNameAndValue>> Find(string path, string query, string pathTemplate);
} }
} }

View File

@ -4,6 +4,6 @@ namespace Ocelot.DownstreamRouteFinder.UrlMatcher
{ {
public interface IUrlPathToUrlTemplateMatcher public interface IUrlPathToUrlTemplateMatcher
{ {
Response<UrlMatch> Match(string upstreamUrlPath, string upstreamUrlPathTemplate); Response<UrlMatch> Match(string upstreamUrlPath, string upstreamQueryString, string upstreamUrlPathTemplate, bool containsQueryString);
} }
} }

View File

@ -5,13 +5,20 @@ namespace Ocelot.DownstreamRouteFinder.UrlMatcher
{ {
public class RegExUrlMatcher : IUrlPathToUrlTemplateMatcher public class RegExUrlMatcher : IUrlPathToUrlTemplateMatcher
{ {
public Response<UrlMatch> Match(string upstreamUrlPath, string upstreamUrlPathTemplate) public Response<UrlMatch> Match(string upstreamUrlPath, string upstreamQueryString, string upstreamUrlPathTemplate, bool containsQueryString)
{ {
var regex = new Regex(upstreamUrlPathTemplate); var regex = new Regex(upstreamUrlPathTemplate);
if (!containsQueryString)
{
return regex.IsMatch(upstreamUrlPath) return regex.IsMatch(upstreamUrlPath)
? new OkResponse<UrlMatch>(new UrlMatch(true)) ? new OkResponse<UrlMatch>(new UrlMatch(true))
: new OkResponse<UrlMatch>(new UrlMatch(false)); : new OkResponse<UrlMatch>(new UrlMatch(false));
} }
return regex.IsMatch($"{upstreamUrlPath}{upstreamQueryString}")
? new OkResponse<UrlMatch>(new UrlMatch(true))
: new OkResponse<UrlMatch>(new UrlMatch(false));
}
} }
} }

View File

@ -5,27 +5,46 @@ namespace Ocelot.DownstreamRouteFinder.UrlMatcher
{ {
public class UrlPathPlaceholderNameAndValueFinder : IPlaceholderNameAndValueFinder public class UrlPathPlaceholderNameAndValueFinder : IPlaceholderNameAndValueFinder
{ {
public Response<List<PlaceholderNameAndValue>> Find(string path, string pathTemplate) public Response<List<PlaceholderNameAndValue>> Find(string path, string query, string pathTemplate)
{ {
var placeHolderNameAndValues = new List<PlaceholderNameAndValue>(); var placeHolderNameAndValues = new List<PlaceholderNameAndValue>();
path = $"{path}{query}";
int counterForPath = 0; int counterForPath = 0;
var delimiter = '/';
var nextDelimiter = '/';
for (int counterForTemplate = 0; counterForTemplate < pathTemplate.Length; counterForTemplate++) for (int counterForTemplate = 0; counterForTemplate < pathTemplate.Length; counterForTemplate++)
{ {
if ((path.Length > counterForPath) && CharactersDontMatch(pathTemplate[counterForTemplate], path[counterForPath]) && ContinueScanningUrl(counterForPath,path.Length)) if ((path.Length > counterForPath) && CharactersDontMatch(pathTemplate[counterForTemplate], path[counterForPath]) && ContinueScanningUrl(counterForPath,path.Length))
{ {
if (IsPlaceholder(pathTemplate[counterForTemplate])) if (IsPlaceholder(pathTemplate[counterForTemplate]))
{ {
//should_find_multiple_query_string make test pass
if (PassedQueryString(pathTemplate, counterForTemplate))
{
delimiter = '&';
nextDelimiter = '&';
}
//should_find_multiple_query_string_and_path makes test pass
if (NotPassedQueryString(pathTemplate, counterForTemplate) && NoMoreForwardSlash(pathTemplate, counterForTemplate))
{
delimiter = '?';
nextDelimiter = '?';
}
var placeholderName = GetPlaceholderName(pathTemplate, counterForTemplate); var placeholderName = GetPlaceholderName(pathTemplate, counterForTemplate);
var placeholderValue = GetPlaceholderValue(pathTemplate, placeholderName, path, counterForPath); var placeholderValue = GetPlaceholderValue(pathTemplate, query, placeholderName, path, counterForPath, delimiter);
placeHolderNameAndValues.Add(new PlaceholderNameAndValue(placeholderName, placeholderValue)); placeHolderNameAndValues.Add(new PlaceholderNameAndValue(placeholderName, placeholderValue));
counterForTemplate = GetNextCounterPosition(pathTemplate, counterForTemplate, '}'); counterForTemplate = GetNextCounterPosition(pathTemplate, counterForTemplate, '}');
counterForPath = GetNextCounterPosition(path, counterForPath, '/'); counterForPath = GetNextCounterPosition(path, counterForPath, nextDelimiter);
continue; continue;
} }
@ -44,7 +63,7 @@ namespace Ocelot.DownstreamRouteFinder.UrlMatcher
} }
else else
{ {
var placeholderValue = GetPlaceholderValue(pathTemplate, placeholderName, path, counterForPath + 1); var placeholderValue = GetPlaceholderValue(pathTemplate, query, placeholderName, path, counterForPath + 1, '/');
placeHolderNameAndValues.Add(new PlaceholderNameAndValue(placeholderName, placeholderValue)); placeHolderNameAndValues.Add(new PlaceholderNameAndValue(placeholderName, placeholderValue));
} }
@ -57,6 +76,21 @@ namespace Ocelot.DownstreamRouteFinder.UrlMatcher
return new OkResponse<List<PlaceholderNameAndValue>>(placeHolderNameAndValues); return new OkResponse<List<PlaceholderNameAndValue>>(placeHolderNameAndValues);
} }
private static bool NoMoreForwardSlash(string pathTemplate, int counterForTemplate)
{
return !pathTemplate.Substring(counterForTemplate).Contains("/");
}
private static bool NotPassedQueryString(string pathTemplate, int counterForTemplate)
{
return !pathTemplate.Substring(0, counterForTemplate).Contains("?");
}
private static bool PassedQueryString(string pathTemplate, int counterForTemplate)
{
return pathTemplate.Substring(0, counterForTemplate).Contains("?");
}
private bool IsCatchAll(string path, int counterForPath, string pathTemplate) private bool IsCatchAll(string path, int counterForPath, string pathTemplate)
{ {
return string.IsNullOrEmpty(path) || (path.Length > counterForPath && path[counterForPath] == '/') && pathTemplate.Length > 1 return string.IsNullOrEmpty(path) || (path.Length > counterForPath && path[counterForPath] == '/') && pathTemplate.Length > 1
@ -69,11 +103,11 @@ namespace Ocelot.DownstreamRouteFinder.UrlMatcher
return path.Length == 1 || path.Length == 0; return path.Length == 1 || path.Length == 0;
} }
private string GetPlaceholderValue(string urlPathTemplate, string variableName, string urlPath, int counterForUrl) private string GetPlaceholderValue(string urlPathTemplate, string query, string variableName, string urlPath, int counterForUrl, char delimiter)
{ {
var positionOfNextSlash = urlPath.IndexOf('/', counterForUrl); var positionOfNextSlash = urlPath.IndexOf(delimiter, counterForUrl);
if (positionOfNextSlash == -1 || urlPathTemplate.Trim('/').EndsWith(variableName)) if (positionOfNextSlash == -1 || (urlPathTemplate.Trim(delimiter).EndsWith(variableName) && string.IsNullOrEmpty(query)))
{ {
positionOfNextSlash = urlPath.Length; positionOfNextSlash = urlPath.Length;
} }

View File

@ -1,17 +1,15 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Ocelot.DownstreamUrlCreator.UrlTemplateReplacer; using Ocelot.DownstreamUrlCreator.UrlTemplateReplacer;
using Ocelot.Infrastructure.RequestData;
using Ocelot.Logging; using Ocelot.Logging;
using Ocelot.Middleware; using Ocelot.Middleware;
using System; using System;
using System.Linq;
using Ocelot.DownstreamRouteFinder.Middleware;
using Ocelot.Responses; using Ocelot.Responses;
using Ocelot.Values; using Ocelot.Values;
namespace Ocelot.DownstreamUrlCreator.Middleware namespace Ocelot.DownstreamUrlCreator.Middleware
{ {
using System.Text.RegularExpressions;
public class DownstreamUrlCreatorMiddleware : OcelotMiddleware public class DownstreamUrlCreatorMiddleware : OcelotMiddleware
{ {
private readonly OcelotRequestDelegate _next; private readonly OcelotRequestDelegate _next;
@ -55,12 +53,11 @@ namespace Ocelot.DownstreamUrlCreator.Middleware
{ {
context.DownstreamRequest.AbsolutePath = GetPath(dsPath); context.DownstreamRequest.AbsolutePath = GetPath(dsPath);
context.DownstreamRequest.Query = GetQueryString(dsPath); context.DownstreamRequest.Query = GetQueryString(dsPath);
// todo - do we need to add anything from the request query string onto the query from the
// templae?
} }
else else
{ {
RemoveQueryStringParametersThatHaveBeenUsedInTemplate(context);
context.DownstreamRequest.AbsolutePath = dsPath.Value; context.DownstreamRequest.AbsolutePath = dsPath.Value;
} }
} }
@ -70,14 +67,37 @@ namespace Ocelot.DownstreamUrlCreator.Middleware
await _next.Invoke(context); await _next.Invoke(context);
} }
private static void RemoveQueryStringParametersThatHaveBeenUsedInTemplate(DownstreamContext context)
{
foreach (var nAndV in context.TemplatePlaceholderNameAndValues)
{
var name = nAndV.Name.Replace("{", "").Replace("}", "");
if (context.DownstreamRequest.Query.Contains(name) &&
context.DownstreamRequest.Query.Contains(nAndV.Value))
{
var questionMarkOrAmpersand = context.DownstreamRequest.Query.IndexOf(name, StringComparison.Ordinal);
context.DownstreamRequest.Query = context.DownstreamRequest.Query.Remove(questionMarkOrAmpersand - 1, 1);
var rgx = new Regex($@"\b{name}={nAndV.Value}\b");
context.DownstreamRequest.Query = rgx.Replace(context.DownstreamRequest.Query, "");
if (!string.IsNullOrEmpty(context.DownstreamRequest.Query))
{
context.DownstreamRequest.Query = '?' + context.DownstreamRequest.Query.Substring(1);
}
}
}
}
private string GetPath(DownstreamPath dsPath) private string GetPath(DownstreamPath dsPath)
{ {
return dsPath.Value.Substring(0, dsPath.Value.IndexOf("?")); return dsPath.Value.Substring(0, dsPath.Value.IndexOf("?", StringComparison.Ordinal));
} }
private string GetQueryString(DownstreamPath dsPath) private string GetQueryString(DownstreamPath dsPath)
{ {
return dsPath.Value.Substring(dsPath.Value.IndexOf("?")); return dsPath.Value.Substring(dsPath.Value.IndexOf("?", StringComparison.Ordinal));
} }
private bool ContainsQueryString(DownstreamPath dsPath) private bool ContainsQueryString(DownstreamPath dsPath)

View File

@ -2,13 +2,12 @@ namespace Ocelot.Request.Creator
{ {
using System.Net.Http; using System.Net.Http;
using Ocelot.Request.Middleware; using Ocelot.Request.Middleware;
using System.Runtime.InteropServices;
using Ocelot.Infrastructure; using Ocelot.Infrastructure;
public class DownstreamRequestCreator : IDownstreamRequestCreator public class DownstreamRequestCreator : IDownstreamRequestCreator
{ {
private readonly IFrameworkDescription _framework; private readonly IFrameworkDescription _framework;
private const string dotNetFramework = ".NET Framework"; private const string DotNetFramework = ".NET Framework";
public DownstreamRequestCreator(IFrameworkDescription framework) public DownstreamRequestCreator(IFrameworkDescription framework)
{ {
@ -24,8 +23,7 @@ namespace Ocelot.Request.Creator
* And MS HttpClient in Full Framework actually rejects it. * And MS HttpClient in Full Framework actually rejects it.
* see #366 issue * see #366 issue
**/ **/
if(_framework.Get().Contains(DotNetFramework))
if(_framework.Get().Contains(dotNetFramework))
{ {
if (request.Method == HttpMethod.Get || if (request.Method == HttpMethod.Get ||
request.Method == HttpMethod.Head || request.Method == HttpMethod.Head ||

View File

@ -28,6 +28,7 @@ namespace Ocelot.Request.Middleware
public async Task Invoke(DownstreamContext context) public async Task Invoke(DownstreamContext context)
{ {
var downstreamRequest = await _requestMapper.Map(context.HttpContext.Request); var downstreamRequest = await _requestMapper.Map(context.HttpContext.Request);
if (downstreamRequest.IsError) if (downstreamRequest.IsError)
{ {
SetPipelineError(context, downstreamRequest.Errors); SetPipelineError(context, downstreamRequest.Errors);

View File

@ -2,14 +2,16 @@ namespace Ocelot.Values
{ {
public class UpstreamPathTemplate public class UpstreamPathTemplate
{ {
public UpstreamPathTemplate(string template, int priority) public UpstreamPathTemplate(string template, int priority, bool containsQueryString)
{ {
Template = template; Template = template;
Priority = priority; Priority = priority;
ContainsQueryString = containsQueryString;
} }
public string Template { get; } public string Template { get; }
public int Priority { get; } public int Priority { get; }
public bool ContainsQueryString { get; }
} }
} }

View File

@ -60,6 +60,152 @@ namespace Ocelot.AcceptanceTests
.BDDfy(); .BDDfy();
} }
[Fact]
public void should_return_response_200_with_query_string_upstream_template()
{
var subscriptionId = Guid.NewGuid().ToString();
var unitId = Guid.NewGuid().ToString();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/api/units/{subscriptionId}/{unitId}/updates",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 64879,
}
},
UpstreamPathTemplate = "/api/subscriptions/{subscriptionId}/updates?unitId={unitId}",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:64879", $"/api/units/{subscriptionId}/{unitId}/updates", "", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway($"/api/subscriptions/{subscriptionId}/updates?unitId={unitId}"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
[Fact]
public void should_return_response_404_with_query_string_upstream_template_no_query_string()
{
var subscriptionId = Guid.NewGuid().ToString();
var unitId = Guid.NewGuid().ToString();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/api/units/{subscriptionId}/{unitId}/updates",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 64879,
}
},
UpstreamPathTemplate = "/api/subscriptions/{subscriptionId}/updates?unitId={unitId}",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:64879", $"/api/units/{subscriptionId}/{unitId}/updates", "", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway($"/api/subscriptions/{subscriptionId}/updates"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound))
.BDDfy();
}
[Fact]
public void should_return_response_404_with_query_string_upstream_template_different_query_string()
{
var subscriptionId = Guid.NewGuid().ToString();
var unitId = Guid.NewGuid().ToString();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/api/units/{subscriptionId}/{unitId}/updates",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 64879,
}
},
UpstreamPathTemplate = "/api/subscriptions/{subscriptionId}/updates?unitId={unitId}",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:64879", $"/api/units/{subscriptionId}/{unitId}/updates", "", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway($"/api/subscriptions/{subscriptionId}/updates?test=1"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound))
.BDDfy();
}
[Fact]
public void should_return_response_200_with_query_string_upstream_template_multiple_params()
{
var subscriptionId = Guid.NewGuid().ToString();
var unitId = Guid.NewGuid().ToString();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/api/units/{subscriptionId}/{unitId}/updates",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 64879,
}
},
UpstreamPathTemplate = "/api/subscriptions/{subscriptionId}/updates?unitId={unitId}",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:64879", $"/api/units/{subscriptionId}/{unitId}/updates", "?productId=1", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway($"/api/subscriptions/{subscriptionId}/updates?unitId={unitId}&productId=1"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, string queryString, int statusCode, string responseBody) private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, string queryString, int statusCode, string responseBody)
{ {
_builder = new WebHostBuilder() _builder = new WebHostBuilder()
@ -72,10 +218,9 @@ namespace Ocelot.AcceptanceTests
app.UsePathBase(basePath); app.UsePathBase(basePath);
app.Run(async context => app.Run(async context =>
{ {
if(context.Request.PathBase.Value != basePath || context.Request.QueryString.Value != queryString) if(context.Request.PathBase.Value != basePath || context.Request.QueryString.Value != queryString)
{ {
context.Response.StatusCode = 404; context.Response.StatusCode = 500;
await context.Response.WriteAsync("downstream path didnt match base path"); await context.Response.WriteAsync("downstream path didnt match base path");
} }
else else

View File

@ -14,6 +14,7 @@ namespace Ocelot.Benchmarks
private RegExUrlMatcher _urlPathMatcher; private RegExUrlMatcher _urlPathMatcher;
private string _downstreamUrlPath; private string _downstreamUrlPath;
private string _downstreamUrlPathTemplate; private string _downstreamUrlPathTemplate;
private string _upstreamQuery;
public UrlPathToUrlPathTemplateMatcherBenchmarks() public UrlPathToUrlPathTemplateMatcherBenchmarks()
{ {
@ -33,7 +34,7 @@ namespace Ocelot.Benchmarks
[Benchmark(Baseline = true)] [Benchmark(Baseline = true)]
public void Baseline() public void Baseline()
{ {
_urlPathMatcher.Match(_downstreamUrlPath, _downstreamUrlPathTemplate); _urlPathMatcher.Match(_downstreamUrlPath, _upstreamQuery, _downstreamUrlPathTemplate, false);
} }
// * Summary * // * Summary *

View File

@ -599,7 +599,7 @@
.WithDownstreamPathTemplate("/products/{productId}") .WithDownstreamPathTemplate("/products/{productId}")
.WithUpstreamPathTemplate("/api/products/{productId}") .WithUpstreamPathTemplate("/api/products/{productId}")
.WithUpstreamHttpMethod(new List<string> {"Get"}) .WithUpstreamHttpMethod(new List<string> {"Get"})
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("(?i)/api/products/.*/$", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("(?i)/api/products/.*/$", 1, false))
.WithLoadBalancerKey("/api/products/{productId}|Get|") .WithLoadBalancerKey("/api/products/{productId}|Get|")
.Build(); .Build();
@ -628,7 +628,7 @@
.WithDownstreamReRoute(downstreamReRoute) .WithDownstreamReRoute(downstreamReRoute)
.WithUpstreamPathTemplate("/api/products/{productId}") .WithUpstreamPathTemplate("/api/products/{productId}")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("(?i)/api/products/.*/$", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("(?i)/api/products/.*/$", 1, false))
.Build() .Build()
})) }))
.BDDfy(); .BDDfy();
@ -922,7 +922,7 @@
{ {
_upstreamTemplatePatternCreator _upstreamTemplatePatternCreator
.Setup(x => x.Create(It.IsAny<FileReRoute>())) .Setup(x => x.Create(It.IsAny<FileReRoute>()))
.Returns(new UpstreamPathTemplate(pattern, 1)); .Returns(new UpstreamPathTemplate(pattern, 1, false));
} }
private void ThenTheRequestIdKeyCreatorIsCalledCorrectly() private void ThenTheRequestIdKeyCreatorIsCalledCorrectly()

View File

@ -10,7 +10,7 @@ namespace Ocelot.UnitTests.Configuration
public class UpstreamTemplatePatternCreatorTests public class UpstreamTemplatePatternCreatorTests
{ {
private FileReRoute _fileReRoute; private FileReRoute _fileReRoute;
private UpstreamTemplatePatternCreator _creator; private readonly UpstreamTemplatePatternCreator _creator;
private UpstreamPathTemplate _result; private UpstreamPathTemplate _result;
public UpstreamTemplatePatternCreatorTests() public UpstreamTemplatePatternCreatorTests()
@ -191,6 +191,36 @@ namespace Ocelot.UnitTests.Configuration
.BDDfy(); .BDDfy();
} }
[Fact]
public void should_create_template_pattern_that_matches_query_string()
{
var fileReRoute = new FileReRoute
{
UpstreamPathTemplate = "/api/subscriptions/{subscriptionId}/updates?unitId={unitId}"
};
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^(?i)/api/subscriptions/.+/updates\\?unitId=.+$"))
.And(x => ThenThePriorityIs(1))
.BDDfy();
}
[Fact]
public void should_create_template_pattern_that_matches_query_string_with_multiple_params()
{
var fileReRoute = new FileReRoute
{
UpstreamPathTemplate = "/api/subscriptions/{subscriptionId}/updates?unitId={unitId}&productId={productId}"
};
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^(?i)/api/subscriptions/.+/updates\\?unitId=.+&productId=.+$"))
.And(x => ThenThePriorityIs(1))
.BDDfy();
}
private void GivenTheFollowingFileReRoute(FileReRoute fileReRoute) private void GivenTheFollowingFileReRoute(FileReRoute fileReRoute)
{ {
_fileReRoute = fileReRoute; _fileReRoute = fileReRoute;

View File

@ -28,6 +28,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
private IInternalConfiguration _configuration; private IInternalConfiguration _configuration;
private Mock<IQoSOptionsCreator> _qosOptionsCreator; private Mock<IQoSOptionsCreator> _qosOptionsCreator;
private Response<DownstreamRoute> _resultTwo; private Response<DownstreamRoute> _resultTwo;
private string _upstreamQuery;
public DownstreamRouteCreatorTests() public DownstreamRouteCreatorTests()
{ {
@ -247,12 +248,12 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
private void WhenICreate() private void WhenICreate()
{ {
_result = _creator.Get(_upstreamUrlPath, _upstreamHttpMethod, _configuration, _upstreamHost); _result = _creator.Get(_upstreamUrlPath, _upstreamQuery, _upstreamHttpMethod, _configuration, _upstreamHost);
} }
private void WhenICreateAgain() private void WhenICreateAgain()
{ {
_resultTwo = _creator.Get(_upstreamUrlPath, _upstreamHttpMethod, _configuration, _upstreamHost); _resultTwo = _creator.Get(_upstreamUrlPath, _upstreamQuery, _upstreamHttpMethod, _configuration, _upstreamHost);
} }
private void ThenTheDownstreamRoutesAreTheSameReference() private void ThenTheDownstreamRoutesAreTheSameReference()

View File

@ -86,7 +86,7 @@
{ {
_downstreamRoute = new OkResponse<DownstreamRoute>(downstreamRoute); _downstreamRoute = new OkResponse<DownstreamRoute>(downstreamRoute);
_finder _finder
.Setup(x => x.Get(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<IInternalConfiguration>(), It.IsAny<string>())) .Setup(x => x.Get(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<IInternalConfiguration>(), It.IsAny<string>()))
.Returns(_downstreamRoute); .Returns(_downstreamRoute);
} }

View File

@ -25,6 +25,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
private Response<UrlMatch> _match; private Response<UrlMatch> _match;
private string _upstreamHttpMethod; private string _upstreamHttpMethod;
private string _upstreamHost; private string _upstreamHost;
private string _upstreamQuery;
public DownstreamRouteFinderTests() public DownstreamRouteFinderTests()
{ {
@ -48,22 +49,22 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Post" }) .WithUpstreamHttpMethod(new List<string> { "Post" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1, false))
.Build()) .Build())
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Post" }) .WithUpstreamHttpMethod(new List<string> { "Post" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1, false))
.Build(), .Build(),
new ReRouteBuilder() new ReRouteBuilder()
.WithDownstreamReRoute(new DownstreamReRouteBuilder() .WithDownstreamReRoute(new DownstreamReRouteBuilder()
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Post" }) .WithUpstreamHttpMethod(new List<string> { "Post" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 0)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 0, false))
.Build()) .Build())
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Post" }) .WithUpstreamHttpMethod(new List<string> { "Post" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 0)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 0, false))
.Build() .Build()
}, string.Empty, serviceProviderConfig)) }, string.Empty, serviceProviderConfig))
.And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true)))) .And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true))))
@ -73,13 +74,13 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
new ReRouteBuilder() new ReRouteBuilder()
.WithDownstreamReRoute(new DownstreamReRouteBuilder() .WithDownstreamReRoute(new DownstreamReRouteBuilder()
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1, false))
.WithUpstreamHttpMethod(new List<string> { "Post" }) .WithUpstreamHttpMethod(new List<string> { "Post" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1, false))
.Build()) .Build())
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1, false))
.WithUpstreamHttpMethod(new List<string> { "Post" }) .WithUpstreamHttpMethod(new List<string> { "Post" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1, false))
.Build() .Build()
))) )))
.BDDfy(); .BDDfy();
@ -100,22 +101,22 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Post" }) .WithUpstreamHttpMethod(new List<string> { "Post" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 0)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 0, false))
.Build()) .Build())
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Post" }) .WithUpstreamHttpMethod(new List<string> { "Post" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 0)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 0, false))
.Build(), .Build(),
new ReRouteBuilder() new ReRouteBuilder()
.WithDownstreamReRoute(new DownstreamReRouteBuilder() .WithDownstreamReRoute(new DownstreamReRouteBuilder()
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Post" }) .WithUpstreamHttpMethod(new List<string> { "Post" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1, false))
.Build()) .Build())
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Post" }) .WithUpstreamHttpMethod(new List<string> { "Post" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1, false))
.Build() .Build()
}, string.Empty, serviceProviderConfig)) }, string.Empty, serviceProviderConfig))
.And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true)))) .And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true))))
@ -125,10 +126,10 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
new ReRouteBuilder() new ReRouteBuilder()
.WithDownstreamReRoute(new DownstreamReRouteBuilder() .WithDownstreamReRoute(new DownstreamReRouteBuilder()
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1, false))
.WithUpstreamHttpMethod(new List<string> { "Post" }) .WithUpstreamHttpMethod(new List<string> { "Post" })
.Build()) .Build())
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1, false))
.WithUpstreamHttpMethod(new List<string> { "Post" }) .WithUpstreamHttpMethod(new List<string> { "Post" })
.Build() .Build()
))) )))
@ -151,11 +152,11 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1, false))
.Build()) .Build())
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1, false))
.Build() .Build()
}, string.Empty, serviceProviderConfig }, string.Empty, serviceProviderConfig
)) ))
@ -169,10 +170,10 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithDownstreamReRoute(new DownstreamReRouteBuilder() .WithDownstreamReRoute(new DownstreamReRouteBuilder()
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1, false))
.Build()) .Build())
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1, false))
.Build() .Build()
))) )))
.And(x => x.ThenTheUrlMatcherIsCalledCorrectly()) .And(x => x.ThenTheUrlMatcherIsCalledCorrectly())
@ -195,11 +196,11 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1, false))
.Build()) .Build())
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1, false))
.Build() .Build()
}, string.Empty, serviceProviderConfig }, string.Empty, serviceProviderConfig
)) ))
@ -213,10 +214,10 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithDownstreamReRoute(new DownstreamReRouteBuilder() .WithDownstreamReRoute(new DownstreamReRouteBuilder()
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1, false))
.Build()) .Build())
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1, false))
.Build() .Build()
))) )))
.And(x => x.ThenTheUrlMatcherIsCalledCorrectly("matchInUrlMatcher")) .And(x => x.ThenTheUrlMatcherIsCalledCorrectly("matchInUrlMatcher"))
@ -240,11 +241,11 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1, false))
.Build()) .Build())
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1, false))
.Build() .Build()
}, string.Empty, serviceProviderConfig }, string.Empty, serviceProviderConfig
)) ))
@ -257,10 +258,10 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithDownstreamReRoute(new DownstreamReRouteBuilder() .WithDownstreamReRoute(new DownstreamReRouteBuilder()
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1, false))
.Build()) .Build())
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1, false))
.Build() .Build()
))) )))
.BDDfy(); .BDDfy();
@ -283,22 +284,22 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1, false))
.Build()) .Build())
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1, false))
.Build(), .Build(),
new ReRouteBuilder() new ReRouteBuilder()
.WithDownstreamReRoute(new DownstreamReRouteBuilder() .WithDownstreamReRoute(new DownstreamReRouteBuilder()
.WithDownstreamPathTemplate("someDownstreamPathForAPost") .WithDownstreamPathTemplate("someDownstreamPathForAPost")
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Post" }) .WithUpstreamHttpMethod(new List<string> { "Post" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1, false))
.Build()) .Build())
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Post" }) .WithUpstreamHttpMethod(new List<string> { "Post" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1, false))
.Build() .Build()
}, string.Empty, serviceProviderConfig }, string.Empty, serviceProviderConfig
)) ))
@ -311,10 +312,10 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithDownstreamReRoute(new DownstreamReRouteBuilder() .WithDownstreamReRoute(new DownstreamReRouteBuilder()
.WithDownstreamPathTemplate("someDownstreamPathForAPost") .WithDownstreamPathTemplate("someDownstreamPathForAPost")
.WithUpstreamHttpMethod(new List<string> { "Post" }) .WithUpstreamHttpMethod(new List<string> { "Post" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1, false))
.Build()) .Build())
.WithUpstreamHttpMethod(new List<string> { "Post" }) .WithUpstreamHttpMethod(new List<string> { "Post" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1, false))
.Build() .Build()
))) )))
.BDDfy(); .BDDfy();
@ -333,11 +334,11 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithDownstreamPathTemplate("somPath") .WithDownstreamPathTemplate("somPath")
.WithUpstreamPathTemplate("somePath") .WithUpstreamPathTemplate("somePath")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("somePath", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("somePath", 1, false))
.Build()) .Build())
.WithUpstreamPathTemplate("somePath") .WithUpstreamPathTemplate("somePath")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("somePath", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("somePath", 1, false))
.Build(), .Build(),
}, string.Empty, serviceProviderConfig }, string.Empty, serviceProviderConfig
)) ))
@ -367,11 +368,11 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get", "Post" }) .WithUpstreamHttpMethod(new List<string> { "Get", "Post" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1, false))
.Build()) .Build())
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get", "Post" }) .WithUpstreamHttpMethod(new List<string> { "Get", "Post" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1, false))
.Build() .Build()
}, string.Empty, serviceProviderConfig }, string.Empty, serviceProviderConfig
)) ))
@ -384,10 +385,10 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithDownstreamReRoute(new DownstreamReRouteBuilder() .WithDownstreamReRoute(new DownstreamReRouteBuilder()
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Post" }) .WithUpstreamHttpMethod(new List<string> { "Post" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1, false))
.Build()) .Build())
.WithUpstreamHttpMethod(new List<string> { "Post" }) .WithUpstreamHttpMethod(new List<string> { "Post" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1, false))
.Build() .Build()
))) )))
.BDDfy(); .BDDfy();
@ -410,11 +411,11 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string>()) .WithUpstreamHttpMethod(new List<string>())
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1, false))
.Build()) .Build())
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string>()) .WithUpstreamHttpMethod(new List<string>())
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1, false))
.Build() .Build()
}, string.Empty, serviceProviderConfig }, string.Empty, serviceProviderConfig
)) ))
@ -427,10 +428,10 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithDownstreamReRoute(new DownstreamReRouteBuilder() .WithDownstreamReRoute(new DownstreamReRouteBuilder()
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Post" }) .WithUpstreamHttpMethod(new List<string> { "Post" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1, false))
.Build()) .Build())
.WithUpstreamHttpMethod(new List<string> { "Post" }) .WithUpstreamHttpMethod(new List<string> { "Post" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1, false))
.Build() .Build()
))) )))
.BDDfy(); .BDDfy();
@ -453,11 +454,11 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get", "Patch", "Delete" }) .WithUpstreamHttpMethod(new List<string> { "Get", "Patch", "Delete" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1, false))
.Build()) .Build())
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get", "Patch", "Delete" }) .WithUpstreamHttpMethod(new List<string> { "Get", "Patch", "Delete" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1, false))
.Build() .Build()
}, string.Empty, serviceProviderConfig }, string.Empty, serviceProviderConfig
)) ))
@ -486,12 +487,12 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1, false))
.WithUpstreamHost("MATCH") .WithUpstreamHost("MATCH")
.Build()) .Build())
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1, false))
.WithUpstreamHost("MATCH") .WithUpstreamHost("MATCH")
.Build() .Build()
}, string.Empty, serviceProviderConfig }, string.Empty, serviceProviderConfig
@ -506,10 +507,10 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithDownstreamReRoute(new DownstreamReRouteBuilder() .WithDownstreamReRoute(new DownstreamReRouteBuilder()
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1, false))
.Build()) .Build())
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1, false))
.Build() .Build()
))) )))
.And(x => x.ThenTheUrlMatcherIsCalledCorrectly()) .And(x => x.ThenTheUrlMatcherIsCalledCorrectly())
@ -533,11 +534,11 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1, false))
.Build()) .Build())
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1, false))
.Build() .Build()
}, string.Empty, serviceProviderConfig }, string.Empty, serviceProviderConfig
)) ))
@ -551,10 +552,10 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithDownstreamReRoute(new DownstreamReRouteBuilder() .WithDownstreamReRoute(new DownstreamReRouteBuilder()
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1, false))
.Build()) .Build())
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1, false))
.Build() .Build()
))) )))
.And(x => x.ThenTheUrlMatcherIsCalledCorrectly()) .And(x => x.ThenTheUrlMatcherIsCalledCorrectly())
@ -576,12 +577,12 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1, false))
.WithUpstreamHost("MATCH") .WithUpstreamHost("MATCH")
.Build()) .Build())
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1, false))
.WithUpstreamHost("MATCH") .WithUpstreamHost("MATCH")
.Build(), .Build(),
new ReRouteBuilder() new ReRouteBuilder()
@ -589,12 +590,12 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { }) // empty list of methods .WithUpstreamHttpMethod(new List<string> { }) // empty list of methods
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1, false))
.WithUpstreamHost("MATCH") .WithUpstreamHost("MATCH")
.Build()) .Build())
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { }) // empty list of methods .WithUpstreamHttpMethod(new List<string> { }) // empty list of methods
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1, false))
.WithUpstreamHost("MATCH") .WithUpstreamHost("MATCH")
.Build() .Build()
}, string.Empty, serviceProviderConfig }, string.Empty, serviceProviderConfig
@ -622,12 +623,12 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string>()) .WithUpstreamHttpMethod(new List<string>())
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1, false))
.WithUpstreamHost("MATCH") .WithUpstreamHost("MATCH")
.Build()) .Build())
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string>()) .WithUpstreamHttpMethod(new List<string>())
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1, false))
.WithUpstreamHost("MATCH") .WithUpstreamHost("MATCH")
.Build() .Build()
}, string.Empty, serviceProviderConfig }, string.Empty, serviceProviderConfig
@ -655,12 +656,12 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string>()) .WithUpstreamHttpMethod(new List<string>())
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1, false))
.WithUpstreamHost("MATCH") .WithUpstreamHost("MATCH")
.Build()) .Build())
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string>()) .WithUpstreamHttpMethod(new List<string>())
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1, false))
.WithUpstreamHost("MATCH") .WithUpstreamHost("MATCH")
.Build() .Build()
}, string.Empty, serviceProviderConfig }, string.Empty, serviceProviderConfig
@ -689,23 +690,23 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithDownstreamPathTemplate("THENULLPATH") .WithDownstreamPathTemplate("THENULLPATH")
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1, false))
.Build()) .Build())
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1, false))
.Build(), .Build(),
new ReRouteBuilder() new ReRouteBuilder()
.WithDownstreamReRoute(new DownstreamReRouteBuilder() .WithDownstreamReRoute(new DownstreamReRouteBuilder()
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1, false))
.WithUpstreamHost("MATCH") .WithUpstreamHost("MATCH")
.Build()) .Build())
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1, false))
.WithUpstreamHost("MATCH") .WithUpstreamHost("MATCH")
.Build() .Build()
}, string.Empty, serviceProviderConfig }, string.Empty, serviceProviderConfig
@ -720,10 +721,10 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithDownstreamReRoute(new DownstreamReRouteBuilder() .WithDownstreamReRoute(new DownstreamReRouteBuilder()
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1, false))
.Build()) .Build())
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1, false))
.Build() .Build()
))) )))
.And(x => x.ThenTheUrlMatcherIsCalledCorrectly(2)) .And(x => x.ThenTheUrlMatcherIsCalledCorrectly(2))
@ -738,7 +739,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
private void GivenTheTemplateVariableAndNameFinderReturns(Response<List<PlaceholderNameAndValue>> response) private void GivenTheTemplateVariableAndNameFinderReturns(Response<List<PlaceholderNameAndValue>> response)
{ {
_finder _finder
.Setup(x => x.Find(It.IsAny<string>(), It.IsAny<string>())) .Setup(x => x.Find(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
.Returns(response); .Returns(response);
} }
@ -755,32 +756,32 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
private void ThenTheUrlMatcherIsCalledCorrectly() private void ThenTheUrlMatcherIsCalledCorrectly()
{ {
_mockMatcher _mockMatcher
.Verify(x => x.Match(_upstreamUrlPath, _reRoutesConfig[0].UpstreamPathTemplate.Value), Times.Once); .Verify(x => x.Match(_upstreamUrlPath, _upstreamQuery, _reRoutesConfig[0].UpstreamPathTemplate.Value, _reRoutesConfig[0].UpstreamTemplatePattern.ContainsQueryString), Times.Once);
} }
private void ThenTheUrlMatcherIsCalledCorrectly(int times) private void ThenTheUrlMatcherIsCalledCorrectly(int times)
{ {
_mockMatcher _mockMatcher
.Verify(x => x.Match(_upstreamUrlPath, _reRoutesConfig[0].UpstreamPathTemplate.Value), Times.Exactly(times)); .Verify(x => x.Match(_upstreamUrlPath, _upstreamQuery, _reRoutesConfig[0].UpstreamPathTemplate.Value, _reRoutesConfig[0].UpstreamTemplatePattern.ContainsQueryString), Times.Exactly(times));
} }
private void ThenTheUrlMatcherIsCalledCorrectly(string expectedUpstreamUrlPath) private void ThenTheUrlMatcherIsCalledCorrectly(string expectedUpstreamUrlPath)
{ {
_mockMatcher _mockMatcher
.Verify(x => x.Match(expectedUpstreamUrlPath, _reRoutesConfig[0].UpstreamPathTemplate.Value), Times.Once); .Verify(x => x.Match(expectedUpstreamUrlPath, _upstreamQuery, _reRoutesConfig[0].UpstreamPathTemplate.Value, _reRoutesConfig[0].UpstreamTemplatePattern.ContainsQueryString), Times.Once);
} }
private void ThenTheUrlMatcherIsNotCalled() private void ThenTheUrlMatcherIsNotCalled()
{ {
_mockMatcher _mockMatcher
.Verify(x => x.Match(_upstreamUrlPath, _reRoutesConfig[0].UpstreamPathTemplate.Value), Times.Never); .Verify(x => x.Match(_upstreamUrlPath, _upstreamQuery, _reRoutesConfig[0].UpstreamPathTemplate.Value, _reRoutesConfig[0].UpstreamTemplatePattern.ContainsQueryString), Times.Never);
} }
private void GivenTheUrlMatcherReturns(Response<UrlMatch> match) private void GivenTheUrlMatcherReturns(Response<UrlMatch> match)
{ {
_match = match; _match = match;
_mockMatcher _mockMatcher
.Setup(x => x.Match(It.IsAny<string>(), It.IsAny<string>())) .Setup(x => x.Match(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<bool>()))
.Returns(_match); .Returns(_match);
} }
@ -797,7 +798,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
private void WhenICallTheFinder() private void WhenICallTheFinder()
{ {
_result = _downstreamRouteFinder.Get(_upstreamUrlPath, _upstreamHttpMethod, _config, _upstreamHost); _result = _downstreamRouteFinder.Get(_upstreamUrlPath, _upstreamQuery, _upstreamHttpMethod, _config, _upstreamHost);
} }
private void ThenTheFollowingIsReturned(DownstreamRoute expected) private void ThenTheFollowingIsReturned(DownstreamRoute expected)

View File

@ -9,22 +9,65 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
public class RegExUrlMatcherTests public class RegExUrlMatcherTests
{ {
private readonly IUrlPathToUrlTemplateMatcher _urlMatcher; private readonly IUrlPathToUrlTemplateMatcher _urlMatcher;
private string _downstreamUrlPath; private string _path;
private string _downstreamPathTemplate; private string _downstreamPathTemplate;
private Response<UrlMatch> _result; private Response<UrlMatch> _result;
private string _queryString;
private bool _containsQueryString;
public RegExUrlMatcherTests() public RegExUrlMatcherTests()
{ {
_urlMatcher = new RegExUrlMatcher(); _urlMatcher = new RegExUrlMatcher();
} }
[Fact]
public void should_match_path_with_no_query_string()
{
const string regExForwardSlashAndOnePlaceHolder = "^(?i)/newThing$";
this.Given(x => x.GivenIHaveAUpstreamPath("/newThing"))
.And(_ => GivenIHaveAQueryString("?DeviceType=IphoneApp&Browser=moonpigIphone&BrowserString=-&CountryCode=123&DeviceName=iPhone 5 (GSM+CDMA)&OperatingSystem=iPhone OS 7.1.2&BrowserVersion=3708AdHoc&ipAddress=-"))
.And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern(regExForwardSlashAndOnePlaceHolder))
.When(x => x.WhenIMatchThePaths())
.And(x => x.ThenTheResultIsTrue())
.BDDfy();
}
[Fact]
public void should_match_query_string()
{
const string regExForwardSlashAndOnePlaceHolder = "^(?i)/api/subscriptions/.+/updates\\?unitId=.+$";
this.Given(x => x.GivenIHaveAUpstreamPath("/api/subscriptions/1/updates"))
.And(_ => GivenIHaveAQueryString("?unitId=2"))
.And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern(regExForwardSlashAndOnePlaceHolder))
.And(_ => GivenThereIsAQueryInTemplate())
.When(x => x.WhenIMatchThePaths())
.And(x => x.ThenTheResultIsTrue())
.BDDfy();
}
[Fact]
public void should_match_query_string_with_multiple_params()
{
const string regExForwardSlashAndOnePlaceHolder = "^(?i)/api/subscriptions/.+/updates\\?unitId=.+&productId=.+$";
this.Given(x => x.GivenIHaveAUpstreamPath("/api/subscriptions/1/updates?unitId=2"))
.And(_ => GivenIHaveAQueryString("?unitId=2&productId=2"))
.And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern(regExForwardSlashAndOnePlaceHolder))
.And(_ => GivenThereIsAQueryInTemplate())
.When(x => x.WhenIMatchThePaths())
.And(x => x.ThenTheResultIsTrue())
.BDDfy();
}
[Fact] [Fact]
public void should_not_match_slash_becaue_we_need_to_match_something_after_it() public void should_not_match_slash_becaue_we_need_to_match_something_after_it()
{ {
const string RegExForwardSlashAndOnePlaceHolder = "^/[0-9a-zA-Z].*"; const string regExForwardSlashAndOnePlaceHolder = "^/[0-9a-zA-Z].+";
this.Given(x => x.GivenIHaveAUpstreamPath("/")) this.Given(x => x.GivenIHaveAUpstreamPath("/"))
.And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern(RegExForwardSlashAndOnePlaceHolder)) .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern(regExForwardSlashAndOnePlaceHolder))
.When(x => x.WhenIMatchThePaths()) .When(x => x.WhenIMatchThePaths())
.And(x => x.ThenTheResultIsFalse()) .And(x => x.ThenTheResultIsFalse())
.BDDfy(); .BDDfy();
@ -44,7 +87,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
public void should_not_match_issue_134() public void should_not_match_issue_134()
{ {
this.Given(x => x.GivenIHaveAUpstreamPath("/api/vacancy/1/")) this.Given(x => x.GivenIHaveAUpstreamPath("/api/vacancy/1/"))
.And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^(?i)/vacancy/.*/$")) .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^(?i)/vacancy/.+/$"))
.When(x => x.WhenIMatchThePaths()) .When(x => x.WhenIMatchThePaths())
.And(x => x.ThenTheResultIsFalse()) .And(x => x.ThenTheResultIsFalse())
.BDDfy(); .BDDfy();
@ -64,7 +107,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
public void should_find_match_when_template_smaller_than_valid_path() public void should_find_match_when_template_smaller_than_valid_path()
{ {
this.Given(x => x.GivenIHaveAUpstreamPath("/api/products/2354325435624623464235")) this.Given(x => x.GivenIHaveAUpstreamPath("/api/products/2354325435624623464235"))
.And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^/api/products/.*$")) .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^/api/products/.+$"))
.When(x => x.WhenIMatchThePaths()) .When(x => x.WhenIMatchThePaths())
.And(x => x.ThenTheResultIsTrue()) .And(x => x.ThenTheResultIsTrue())
.BDDfy(); .BDDfy();
@ -124,7 +167,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
public void can_match_down_stream_url_with_downstream_template_with_one_place_holder() public void can_match_down_stream_url_with_downstream_template_with_one_place_holder()
{ {
this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1")) this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1"))
.Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api/product/products/.*$")) .Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api/product/products/.+$"))
.When(x => x.WhenIMatchThePaths()) .When(x => x.WhenIMatchThePaths())
.Then(x => x.ThenTheResultIsTrue()) .Then(x => x.ThenTheResultIsTrue())
.BDDfy(); .BDDfy();
@ -134,7 +177,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
public void can_match_down_stream_url_with_downstream_template_with_two_place_holders() public void can_match_down_stream_url_with_downstream_template_with_two_place_holders()
{ {
this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/2")) this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/2"))
.Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api/product/products/.*/.*$")) .Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api/product/products/.+/.+$"))
.When(x => x.WhenIMatchThePaths()) .When(x => x.WhenIMatchThePaths())
.Then(x => x.ThenTheResultIsTrue()) .Then(x => x.ThenTheResultIsTrue())
.BDDfy(); .BDDfy();
@ -144,7 +187,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
public void can_match_down_stream_url_with_downstream_template_with_two_place_holders_seperated_by_something() public void can_match_down_stream_url_with_downstream_template_with_two_place_holders_seperated_by_something()
{ {
this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2")) this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2"))
.And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api/product/products/.*/categories/.*$")) .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api/product/products/.+/categories/.+$"))
.When(x => x.WhenIMatchThePaths()) .When(x => x.WhenIMatchThePaths())
.Then(x => x.ThenTheResultIsTrue()) .Then(x => x.ThenTheResultIsTrue())
.BDDfy(); .BDDfy();
@ -154,7 +197,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
public void can_match_down_stream_url_with_downstream_template_with_three_place_holders_seperated_by_something() public void can_match_down_stream_url_with_downstream_template_with_three_place_holders_seperated_by_something()
{ {
this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2/variant/123")) this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2/variant/123"))
.And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api/product/products/.*/categories/.*/variant/.*$")) .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api/product/products/.+/categories/.+/variant/.+$"))
.When(x => x.WhenIMatchThePaths()) .When(x => x.WhenIMatchThePaths())
.Then(x => x.ThenTheResultIsTrue()) .Then(x => x.ThenTheResultIsTrue())
.BDDfy(); .BDDfy();
@ -164,7 +207,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
public void can_match_down_stream_url_with_downstream_template_with_three_place_holders() public void can_match_down_stream_url_with_downstream_template_with_three_place_holders()
{ {
this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2/variant/")) this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2/variant/"))
.And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api/product/products/.*/categories/.*/variant/$")) .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api/product/products/.+/categories/.+/variant/$"))
.When(x => x.WhenIMatchThePaths()) .When(x => x.WhenIMatchThePaths())
.Then(x => x.ThenTheResultIsTrue()) .Then(x => x.ThenTheResultIsTrue())
.BDDfy(); .BDDfy();
@ -174,7 +217,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
public void should_ignore_case_sensitivity() public void should_ignore_case_sensitivity()
{ {
this.Given(x => x.GivenIHaveAUpstreamPath("API/product/products/1/categories/2/variant/")) this.Given(x => x.GivenIHaveAUpstreamPath("API/product/products/1/categories/2/variant/"))
.And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^(?i)api/product/products/.*/categories/.*/variant/$")) .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^(?i)api/product/products/.+/categories/.+/variant/$"))
.When(x => x.WhenIMatchThePaths()) .When(x => x.WhenIMatchThePaths())
.Then(x => x.ThenTheResultIsTrue()) .Then(x => x.ThenTheResultIsTrue())
.BDDfy(); .BDDfy();
@ -184,15 +227,20 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
public void should_respect_case_sensitivity() public void should_respect_case_sensitivity()
{ {
this.Given(x => x.GivenIHaveAUpstreamPath("API/product/products/1/categories/2/variant/")) this.Given(x => x.GivenIHaveAUpstreamPath("API/product/products/1/categories/2/variant/"))
.And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api/product/products/.*/categories/.*/variant/$")) .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api/product/products/.+/categories/.+/variant/$"))
.When(x => x.WhenIMatchThePaths()) .When(x => x.WhenIMatchThePaths())
.Then(x => x.ThenTheResultIsFalse()) .Then(x => x.ThenTheResultIsFalse())
.BDDfy(); .BDDfy();
} }
private void GivenIHaveAUpstreamPath(string downstreamPath) private void GivenIHaveAUpstreamPath(string path)
{ {
_downstreamUrlPath = downstreamPath; _path = path;
}
private void GivenIHaveAQueryString(string queryString)
{
_queryString = queryString;
} }
private void GivenIHaveAnUpstreamUrlTemplatePattern(string downstreamUrlTemplate) private void GivenIHaveAnUpstreamUrlTemplatePattern(string downstreamUrlTemplate)
@ -202,7 +250,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
private void WhenIMatchThePaths() private void WhenIMatchThePaths()
{ {
_result = _urlMatcher.Match(_downstreamUrlPath, _downstreamPathTemplate); _result = _urlMatcher.Match(_path, _queryString, _downstreamPathTemplate, _containsQueryString);
} }
private void ThenTheResultIsTrue() private void ThenTheResultIsTrue()
@ -214,5 +262,10 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
{ {
_result.Data.Match.ShouldBeFalse(); _result.Data.Match.ShouldBeFalse();
} }
private void GivenThereIsAQueryInTemplate()
{
_containsQueryString = true;
}
} }
} }

View File

@ -14,6 +14,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
private string _downstreamUrlPath; private string _downstreamUrlPath;
private string _downstreamPathTemplate; private string _downstreamPathTemplate;
private Response<List<PlaceholderNameAndValue>> _result; private Response<List<PlaceholderNameAndValue>> _result;
private string _query;
public UrlPathPlaceholderNameAndValueFinderTests() public UrlPathPlaceholderNameAndValueFinderTests()
{ {
@ -114,6 +115,91 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
.BDDfy(); .BDDfy();
} }
[Fact]
public void should_find_query_string()
{
var expectedTemplates = new List<PlaceholderNameAndValue>
{
new PlaceholderNameAndValue("{productId}", "1")
};
this.Given(x => x.GivenIHaveAUpstreamPath("/products"))
.And(x => x.GivenIHaveAQuery("?productId=1"))
.And(x => x.GivenIHaveAnUpstreamUrlTemplate("/products?productId={productId}"))
.When(x => x.WhenIFindTheUrlVariableNamesAndValues())
.And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates))
.BDDfy();
}
[Fact]
public void should_find_query_string_dont_include_hardcoded()
{
var expectedTemplates = new List<PlaceholderNameAndValue>
{
new PlaceholderNameAndValue("{productId}", "1")
};
this.Given(x => x.GivenIHaveAUpstreamPath("/products"))
.And(x => x.GivenIHaveAQuery("?productId=1&categoryId=2"))
.And(x => x.GivenIHaveAnUpstreamUrlTemplate("/products?productId={productId}"))
.When(x => x.WhenIFindTheUrlVariableNamesAndValues())
.And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates))
.BDDfy();
}
[Fact]
public void should_find_multiple_query_string()
{
var expectedTemplates = new List<PlaceholderNameAndValue>
{
new PlaceholderNameAndValue("{productId}", "1"),
new PlaceholderNameAndValue("{categoryId}", "2")
};
this.Given(x => x.GivenIHaveAUpstreamPath("/products"))
.And(x => x.GivenIHaveAQuery("?productId=1&categoryId=2"))
.And(x => x.GivenIHaveAnUpstreamUrlTemplate("/products?productId={productId}&categoryId={categoryId}"))
.When(x => x.WhenIFindTheUrlVariableNamesAndValues())
.And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates))
.BDDfy();
}
[Fact]
public void should_find_multiple_query_string_and_path()
{
var expectedTemplates = new List<PlaceholderNameAndValue>
{
new PlaceholderNameAndValue("{productId}", "1"),
new PlaceholderNameAndValue("{categoryId}", "2"),
new PlaceholderNameAndValue("{account}", "3")
};
this.Given(x => x.GivenIHaveAUpstreamPath("/products/3"))
.And(x => x.GivenIHaveAQuery("?productId=1&categoryId=2"))
.And(x => x.GivenIHaveAnUpstreamUrlTemplate("/products/{account}?productId={productId}&categoryId={categoryId}"))
.When(x => x.WhenIFindTheUrlVariableNamesAndValues())
.And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates))
.BDDfy();
}
[Fact]
public void should_find_multiple_query_string_and_path_that_ends_with_slash()
{
var expectedTemplates = new List<PlaceholderNameAndValue>
{
new PlaceholderNameAndValue("{productId}", "1"),
new PlaceholderNameAndValue("{categoryId}", "2"),
new PlaceholderNameAndValue("{account}", "3")
};
this.Given(x => x.GivenIHaveAUpstreamPath("/products/3/"))
.And(x => x.GivenIHaveAQuery("?productId=1&categoryId=2"))
.And(x => x.GivenIHaveAnUpstreamUrlTemplate("/products/{account}/?productId={productId}&categoryId={categoryId}"))
.When(x => x.WhenIFindTheUrlVariableNamesAndValues())
.And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates))
.BDDfy();
}
[Fact] [Fact]
public void can_match_down_stream_url_with_no_slash() public void can_match_down_stream_url_with_no_slash()
{ {
@ -260,7 +346,12 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
private void WhenIFindTheUrlVariableNamesAndValues() private void WhenIFindTheUrlVariableNamesAndValues()
{ {
_result = _finder.Find(_downstreamUrlPath, _downstreamPathTemplate); _result = _finder.Find(_downstreamUrlPath, _query, _downstreamPathTemplate);
}
private void GivenIHaveAQuery(string query)
{
_query = query;
} }
} }
} }

View File

@ -72,6 +72,103 @@
.BDDfy(); .BDDfy();
} }
[Fact]
public void should_replace_query_string()
{
var downstreamReRoute = new DownstreamReRouteBuilder()
.WithDownstreamPathTemplate("/api/units/{subscriptionId}/{unitId}/updates")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.WithDownstreamScheme("https")
.Build();
var config = new ServiceProviderConfigurationBuilder()
.Build();
this.Given(x => x.GivenTheDownStreamRouteIs(
new DownstreamRoute(
new List<PlaceholderNameAndValue>
{
new PlaceholderNameAndValue("{subscriptionId}", "1"),
new PlaceholderNameAndValue("{unitId}", "2")
},
new ReRouteBuilder()
.WithDownstreamReRoute(downstreamReRoute)
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())))
.And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:5000/api/subscriptions/1/updates?unitId=2"))
.And(x => GivenTheServiceProviderConfigIs(config))
.And(x => x.GivenTheUrlReplacerWillReturn("api/units/1/2/updates"))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheDownstreamRequestUriIs("https://localhost:5000/api/units/1/2/updates"))
.And(x => ThenTheQueryStringIs(""))
.BDDfy();
}
[Fact]
public void should_replace_query_string_but_leave_non_placeholder_queries()
{
var downstreamReRoute = new DownstreamReRouteBuilder()
.WithDownstreamPathTemplate("/api/units/{subscriptionId}/{unitId}/updates")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.WithDownstreamScheme("https")
.Build();
var config = new ServiceProviderConfigurationBuilder()
.Build();
this.Given(x => x.GivenTheDownStreamRouteIs(
new DownstreamRoute(
new List<PlaceholderNameAndValue>
{
new PlaceholderNameAndValue("{subscriptionId}", "1"),
new PlaceholderNameAndValue("{unitId}", "2")
},
new ReRouteBuilder()
.WithDownstreamReRoute(downstreamReRoute)
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())))
.And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:5000/api/subscriptions/1/updates?unitId=2&productId=2"))
.And(x => GivenTheServiceProviderConfigIs(config))
.And(x => x.GivenTheUrlReplacerWillReturn("api/units/1/2/updates"))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheDownstreamRequestUriIs("https://localhost:5000/api/units/1/2/updates?productId=2"))
.And(x => ThenTheQueryStringIs("?productId=2"))
.BDDfy();
}
[Fact]
public void should_replace_query_string_exact_match()
{
var downstreamReRoute = new DownstreamReRouteBuilder()
.WithDownstreamPathTemplate("/api/units/{subscriptionId}/{unitId}/updates/{unitIdIty}")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.WithDownstreamScheme("https")
.Build();
var config = new ServiceProviderConfigurationBuilder()
.Build();
this.Given(x => x.GivenTheDownStreamRouteIs(
new DownstreamRoute(
new List<PlaceholderNameAndValue>
{
new PlaceholderNameAndValue("{subscriptionId}", "1"),
new PlaceholderNameAndValue("{unitId}", "2"),
new PlaceholderNameAndValue("{unitIdIty}", "3")
},
new ReRouteBuilder()
.WithDownstreamReRoute(downstreamReRoute)
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())))
.And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:5000/api/subscriptions/1/updates?unitId=2?unitIdIty=3"))
.And(x => GivenTheServiceProviderConfigIs(config))
.And(x => x.GivenTheUrlReplacerWillReturn("api/units/1/2/updates/3"))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheDownstreamRequestUriIs("https://localhost:5000/api/units/1/2/updates/3"))
.And(x => ThenTheQueryStringIs(""))
.BDDfy();
}
[Fact] [Fact]
public void should_not_create_service_fabric_url() public void should_not_create_service_fabric_url()
{ {