mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-11-04 17:30:48 +08:00 
			
		
		
		
	Added support for query string parameters in upstream path template (#467)
This commit is contained in:
		@@ -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. 
 | 
				
			||||||
@@ -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)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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);
 | 
				
			||||||
     }
 | 
					     }
 | 
				
			||||||
} 
 | 
					} 
 | 
				
			||||||
@@ -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));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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 ||
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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 *
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
} 
 | 
					} 
 | 
				
			||||||
@@ -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;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
} 
 | 
					} 
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user