From caf5cf80fa84f57708b3eadec9cc35a63b448dd6 Mon Sep 17 00:00:00 2001 From: jlukawska Date: Mon, 16 Dec 2019 21:19:31 +0100 Subject: [PATCH] #683 validate if there are duplicated placeholders in UpstreamPathTemplate --- .../FileConfigurationFluentValidator.cs | 13 ++++++++++ .../FileConfigurationFluentValidatorTests.cs | 26 +++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/src/Ocelot/Configuration/Validator/FileConfigurationFluentValidator.cs b/src/Ocelot/Configuration/Validator/FileConfigurationFluentValidator.cs index add4fe0bb..e2f7f24d1 100644 --- a/src/Ocelot/Configuration/Validator/FileConfigurationFluentValidator.cs +++ b/src/Ocelot/Configuration/Validator/FileConfigurationFluentValidator.cs @@ -9,6 +9,7 @@ using System; using System.Collections.Generic; using System.Linq; + using System.Text.RegularExpressions; using System.Threading.Tasks; public class FileConfigurationFluentValidator : AbstractValidator, IConfigurationValidator @@ -35,6 +36,10 @@ public FileConfigurationFluentValidator(IServiceProvider provider, ReRouteFluent .Must((config, reRoute) => HaveServiceDiscoveryProviderRegistered(reRoute, config.GlobalConfiguration.ServiceDiscoveryProvider)) .WithMessage((config, reRoute) => $"Unable to start Ocelot, errors are: Unable to start Ocelot because either a ReRoute or GlobalConfiguration are using ServiceDiscoveryOptions but no ServiceDiscoveryFinderDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Consul and services.AddConsul() or Ocelot.Provider.Eureka and services.AddEureka()?"); + RuleForEach(configuration => configuration.ReRoutes) + .Must((config, reRoute) => IsPlaceholderNotDuplicatedIn(reRoute.UpstreamPathTemplate)) + .WithMessage((config, reRoute) => $"{nameof(reRoute)} {reRoute.UpstreamPathTemplate} has duplicated placeholder"); + RuleFor(configuration => configuration.GlobalConfiguration.ServiceDiscoveryProvider) .Must(HaveServiceDiscoveryProviderRegistered) .WithMessage((config, reRoute) => $"Unable to start Ocelot, errors are: Unable to start Ocelot because either a ReRoute or GlobalConfiguration are using ServiceDiscoveryOptions but no ServiceDiscoveryFinderDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Consul and services.AddConsul() or Ocelot.Provider.Eureka and services.AddEureka()?"); @@ -109,6 +114,14 @@ private bool AllReRoutesForAggregateExist(FileAggregateReRoute fileAggregateReRo return reRoutesForAggregate.Count() == fileAggregateReRoute.ReRouteKeys.Count; } + private bool IsPlaceholderNotDuplicatedIn(string upstreamPathTemplate) + { + Regex regExPlaceholder = new Regex("{[^}]+}"); + var matches = regExPlaceholder.Matches(upstreamPathTemplate); + var upstreamPathPlaceholders = matches.Select(m => m.Value); + return upstreamPathPlaceholders.Count() == upstreamPathPlaceholders.Distinct().Count(); + } + private static bool DoesNotContainReRoutesWithSpecificRequestIdKeys(FileAggregateReRoute fileAggregateReRoute, List reRoutes) { diff --git a/test/Ocelot.UnitTests/Configuration/Validation/FileConfigurationFluentValidatorTests.cs b/test/Ocelot.UnitTests/Configuration/Validation/FileConfigurationFluentValidatorTests.cs index 943001fc6..7055c1ad6 100644 --- a/test/Ocelot.UnitTests/Configuration/Validation/FileConfigurationFluentValidatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/Validation/FileConfigurationFluentValidatorTests.cs @@ -1341,6 +1341,32 @@ public void configuration_is_not_valid_when_host_and_port_is_empty() .BDDfy(); } + [Fact] + public void configuration_is_invalid_when_placeholder_is_used_twice_in_upstream_path_template() + { + this.Given(x => x.GivenAConfiguration(new FileConfiguration + { + ReRoutes = new List + { + new FileReRoute + { + DownstreamPathTemplate = "/bar/{everything}", + DownstreamScheme = "http", + DownstreamHostAndPorts = new List + { + new FileHostAndPort() { Host = "a.b.cd" }, + }, + UpstreamPathTemplate = "/foo/bar/{everything}/{everything}", + UpstreamHttpMethod = new List { "Get" }, + }, + }, + })) + .When(x => x.WhenIValidateTheConfiguration()) + .Then(x => x.ThenTheResultIsNotValid()) + .And(x => x.ThenTheErrorMessageAtPositionIs(0, "reRoute /foo/bar/{everything}/{everything} has duplicated placeholder")) + .BDDfy(); + } + private void GivenAConfiguration(FileConfiguration fileConfiguration) { _fileConfiguration = fileConfiguration;