From 12ea8c9a744472c9dedfe290dbe80afee22953ca Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Thu, 17 Jun 2021 13:02:06 +0000 Subject: [PATCH 01/44] alpha matching: support generic action factory context Prior to this PR the MatchTreeFactory requried a ServerFactoryContext in order to pass this to the action factories. This is not available in all contexts, and there are other possible use cases where we might need to pass additional information to the match tree factory (e.g. the router might need to pass the parent vhost configuration). This PR introduces a paramterized action context, allowing each usage of the MatchTree to define its own data that should be presented to the action factories. This also has the nice benefit of partitioning the action factories per context: each unique ActionFactoryContext defines a new factory type, ensuring that actions defined for a HTTP filter context won't be conflated with actions defined for another context. Signed-off-by: Snow Pettersen --- envoy/matcher/matcher.h | 13 ++++--- source/common/http/filter_manager.cc | 4 +- source/common/http/filter_manager.h | 7 ++-- source/common/http/match_wrapper/BUILD | 1 + source/common/http/match_wrapper/config.cc | 9 +++-- source/common/http/matching/data_impl.h | 4 ++ source/common/http/matching/inputs.h | 6 +-- source/common/matcher/matcher.h | 37 ++++++++++--------- .../extensions/filters/http/composite/BUILD | 1 + .../filters/http/composite/action.cc | 3 +- .../filters/http/composite/action.h | 17 +++++---- .../consistent_hashing/config.cc | 4 +- .../consistent_hashing/config.h | 2 +- .../consistent_hashing/config_test.cc | 12 +++--- 14 files changed, 69 insertions(+), 51 deletions(-) diff --git a/envoy/matcher/matcher.h b/envoy/matcher/matcher.h index 9606d841c1fa..1e3993aeabac 100644 --- a/envoy/matcher/matcher.h +++ b/envoy/matcher/matcher.h @@ -76,11 +76,12 @@ class Action { using ActionPtr = std::unique_ptr; using ActionFactoryCb = std::function; -class ActionFactory : public Config::TypedFactory { +template class ActionFactory : public Config::TypedFactory { public: virtual ActionFactoryCb - createActionFactoryCb(const Protobuf::Message& config, const std::string& stats_prefix, - Server::Configuration::FactoryContext& context) PURE; + createActionFactoryCb(const Protobuf::Message& config, + ActionFactoryContext& action_factory_context, + ProtobufMessage::ValidationVisitor& validation_visitor) PURE; std::string category() const override { return "envoy.matching.action"; } }; @@ -155,7 +156,7 @@ class InputMatcherFactory : public Config::TypedFactory { public: virtual InputMatcherFactoryCb createInputMatcherFactoryCb(const Protobuf::Message& config, - Server::Configuration::FactoryContext& factory_context) PURE; + ProtobufMessage::ValidationVisitor& validation_visitor) PURE; std::string category() const override { return "envoy.matching.input_matchers"; } }; @@ -226,7 +227,7 @@ template class DataInputFactory : public Config::TypedFactory { */ virtual DataInputFactoryCb createDataInputFactoryCb(const Protobuf::Message& config, - Server::Configuration::FactoryContext& factory_context) PURE; + ProtobufMessage::ValidationVisitor& validation_visitor) PURE; /** * The category of this factory depends on the DataType, so we require a name() function to exist @@ -262,7 +263,7 @@ class CommonProtocolInputFactory : public Config::TypedFactory { */ virtual CommonProtocolInputFactoryCb createCommonProtocolInputFactoryCb(const Protobuf::Message& config, - Server::Configuration::FactoryContext& factory_context) PURE; + ProtobufMessage::ValidationVisitor& validation_visitor) PURE; std::string category() const override { return "envoy.matching.common_inputs"; } }; diff --git a/source/common/http/filter_manager.cc b/source/common/http/filter_manager.cc index a68e3207c7a3..cb9ecf49c826 100644 --- a/source/common/http/filter_manager.cc +++ b/source/common/http/filter_manager.cc @@ -13,11 +13,13 @@ #include "source/common/http/header_utility.h" #include "source/common/http/utility.h" +#include "matching/data_impl.h" + namespace Envoy { namespace Http { namespace { -REGISTER_FACTORY(SkipActionFactory, Matcher::ActionFactory); +REGISTER_FACTORY(SkipActionFactory, Matcher::ActionFactory); template using FilterList = std::list>; diff --git a/source/common/http/filter_manager.h b/source/common/http/filter_manager.h index 1e826f1df5d1..f847e71051c3 100644 --- a/source/common/http/filter_manager.h +++ b/source/common/http/filter_manager.h @@ -68,11 +68,12 @@ class FilterMatchState { using FilterMatchStateSharedPtr = std::shared_ptr; -class SkipActionFactory : public Matcher::ActionFactory { +class SkipActionFactory : public Matcher::ActionFactory { public: std::string name() const override { return "skip"; } - Matcher::ActionFactoryCb createActionFactoryCb(const Protobuf::Message&, const std::string&, - Server::Configuration::FactoryContext&) override { + Matcher::ActionFactoryCb createActionFactoryCb(const Protobuf::Message&, + Matching::HttpFilterActionContext&, + ProtobufMessage::ValidationVisitor&) override { return []() { return std::make_unique(); }; } ProtobufTypes::MessagePtr createEmptyConfigProto() override { diff --git a/source/common/http/match_wrapper/BUILD b/source/common/http/match_wrapper/BUILD index 6515bcffe786..43de46e486ba 100644 --- a/source/common/http/match_wrapper/BUILD +++ b/source/common/http/match_wrapper/BUILD @@ -15,6 +15,7 @@ envoy_cc_library( deps = [ "//envoy/registry", "//envoy/server:filter_config_interface", + "//source/common/http/matching:data_impl_lib", "//source/common/matcher:matcher_lib", "//source/extensions/filters/http/common:factory_base_lib", "@envoy_api//envoy/extensions/common/matching/v3:pkg_cc_proto", diff --git a/source/common/http/match_wrapper/config.cc b/source/common/http/match_wrapper/config.cc index 5d9ecd2f1685..68da3b37fd30 100644 --- a/source/common/http/match_wrapper/config.cc +++ b/source/common/http/match_wrapper/config.cc @@ -5,6 +5,7 @@ #include "envoy/registry/registry.h" #include "source/common/config/utility.h" +#include "source/common/http/matching/data_impl.h" #include "source/common/matcher/matcher.h" #include "absl/status/status.h" @@ -103,9 +104,11 @@ Envoy::Http::FilterFactoryCb MatchWrapperConfig::createFilterFactoryFromProtoTyp MatchTreeValidationVisitor validation_visitor(*factory.matchingRequirements()); - auto match_tree = - Matcher::MatchTreeFactory(prefix, context, validation_visitor) - .create(proto_config.matcher()); + Envoy::Http::Matching::HttpFilterActionContext action_context{prefix, context}; + auto match_tree = Matcher::MatchTreeFactory( + action_context, context.messageValidationVisitor(), validation_visitor) + .create(proto_config.matcher()); if (!validation_visitor.errors().empty()) { // TODO(snowp): Output all violations. diff --git a/source/common/http/matching/data_impl.h b/source/common/http/matching/data_impl.h index 136ded312610..5a5042e698b3 100644 --- a/source/common/http/matching/data_impl.h +++ b/source/common/http/matching/data_impl.h @@ -55,6 +55,10 @@ class HttpMatchingDataImpl : public HttpMatchingData { using HttpMatchingDataImplSharedPtr = std::shared_ptr; +struct HttpFilterActionContext { + const std::string& stat_prefix_; + Server::Configuration::FactoryContext& factory_context_; +}; } // namespace Matching } // namespace Http } // namespace Envoy diff --git a/source/common/http/matching/inputs.h b/source/common/http/matching/inputs.h index 052308c5c547..551cab256fb7 100644 --- a/source/common/http/matching/inputs.h +++ b/source/common/http/matching/inputs.h @@ -55,9 +55,9 @@ class HttpHeadersDataInputFactoryBase : public Matcher::DataInputFactory createDataInputFactoryCb(const Protobuf::Message& config, - Server::Configuration::FactoryContext& factory_context) override { - const auto& typed_config = MessageUtil::downcastAndValidate( - config, factory_context.messageValidationVisitor()); + ProtobufMessage::ValidationVisitor& validation_visitor) override { + const auto& typed_config = + MessageUtil::downcastAndValidate(config, validation_visitor); return [header_name = typed_config.header_name()] { return std::make_unique(header_name); diff --git a/source/common/matcher/matcher.h b/source/common/matcher/matcher.h index 376e48606057..ee0dfdc34641 100644 --- a/source/common/matcher/matcher.h +++ b/source/common/matcher/matcher.h @@ -66,13 +66,15 @@ template using DataInputFactoryCb = std::function class MatchTreeFactory { +template class MatchTreeFactory { public: - MatchTreeFactory(const std::string& stats_prefix, - Server::Configuration::FactoryContext& factory_context, + MatchTreeFactory(ActionFactoryContext& context, + ProtobufMessage::ValidationVisitor& proto_validation_visitor, MatchTreeValidationVisitor& validation_visitor) - : stats_prefix_(stats_prefix), factory_context_(factory_context), + : action_factory_context_(context), proto_validation_visitor_(proto_validation_visitor), validation_visitor_(validation_visitor) {} MatchTreeFactoryCb create(const envoy::config::common::matcher::v3::Matcher& config) { @@ -200,12 +202,13 @@ template class MatchTreeFactory { return OnMatch{{}, matcher_factory()}; }; } else if (on_match.has_action()) { - auto& factory = Config::Utility::getAndCheckFactory(on_match.action()); + auto& factory = Config::Utility::getAndCheckFactory>( + on_match.action()); ProtobufTypes::MessagePtr message = Config::Utility::translateAnyToFactoryConfig( - on_match.action().typed_config(), factory_context_.messageValidationVisitor(), factory); + on_match.action().typed_config(), proto_validation_visitor_, factory); - auto action_factory = - factory.createActionFactoryCb(*message, stats_prefix_, factory_context_); + auto action_factory = factory.createActionFactoryCb(*message, action_factory_context_, + proto_validation_visitor_); return [action_factory] { return OnMatch{action_factory, {}}; }; } @@ -234,8 +237,8 @@ template class MatchTreeFactory { validation_visitor_.validateDataInput(*factory, config.typed_config().type_url()); ProtobufTypes::MessagePtr message = Config::Utility::translateAnyToFactoryConfig( - config.typed_config(), factory_context_.messageValidationVisitor(), *factory); - auto data_input = factory->createDataInputFactoryCb(*message, factory_context_); + config.typed_config(), proto_validation_visitor_, *factory); + auto data_input = factory->createDataInputFactoryCb(*message, proto_validation_visitor_); return data_input; } @@ -244,9 +247,9 @@ template class MatchTreeFactory { auto& common_input_factory = Config::Utility::getAndCheckFactory(config); ProtobufTypes::MessagePtr message = Config::Utility::translateAnyToFactoryConfig( - config.typed_config(), factory_context_.messageValidationVisitor(), common_input_factory); - auto common_input = - common_input_factory.createCommonProtocolInputFactoryCb(*message, factory_context_); + config.typed_config(), proto_validation_visitor_, common_input_factory); + auto common_input = common_input_factory.createCommonProtocolInputFactoryCb( + *message, proto_validation_visitor_); return [common_input]() { return std::make_unique(common_input()); }; } @@ -265,9 +268,8 @@ template class MatchTreeFactory { auto& factory = Config::Utility::getAndCheckFactory(predicate.custom_match()); ProtobufTypes::MessagePtr message = Config::Utility::translateAnyToFactoryConfig( - predicate.custom_match().typed_config(), factory_context_.messageValidationVisitor(), - factory); - return factory.createInputMatcherFactoryCb(*message, factory_context_); + predicate.custom_match().typed_config(), proto_validation_visitor_, factory); + return factory.createInputMatcherFactoryCb(*message, proto_validation_visitor_); } default: NOT_REACHED_GCOVR_EXCL_LINE; @@ -275,7 +277,8 @@ template class MatchTreeFactory { } const std::string stats_prefix_; - Server::Configuration::FactoryContext& factory_context_; + ActionFactoryContext& action_factory_context_; + ProtobufMessage::ValidationVisitor& proto_validation_visitor_; MatchTreeValidationVisitor& validation_visitor_; }; } // namespace Matcher diff --git a/source/extensions/filters/http/composite/BUILD b/source/extensions/filters/http/composite/BUILD index e2f0946aa6aa..512c9b054913 100644 --- a/source/extensions/filters/http/composite/BUILD +++ b/source/extensions/filters/http/composite/BUILD @@ -16,6 +16,7 @@ envoy_cc_library( srcs = ["action.cc"], hdrs = ["action.h"], deps = [ + "//source/common/http/matching:data_impl_lib", "//source/common/matcher:matcher_lib", "@envoy_api//envoy/extensions/filters/http/composite/v3:pkg_cc_proto", ], diff --git a/source/extensions/filters/http/composite/action.cc b/source/extensions/filters/http/composite/action.cc index 14935fa819db..743430b5fad3 100644 --- a/source/extensions/filters/http/composite/action.cc +++ b/source/extensions/filters/http/composite/action.cc @@ -7,7 +7,8 @@ namespace Composite { void ExecuteFilterAction::createFilters(Http::FilterChainFactoryCallbacks& callbacks) const { cb_(callbacks); } -REGISTER_FACTORY(ExecuteFilterActionFactory, Matcher::ActionFactory); +REGISTER_FACTORY(ExecuteFilterActionFactory, + Matcher::ActionFactory); } // namespace Composite } // namespace HttpFilters } // namespace Extensions diff --git a/source/extensions/filters/http/composite/action.h b/source/extensions/filters/http/composite/action.h index 1d2b822e7994..f6c69321a1ba 100644 --- a/source/extensions/filters/http/composite/action.h +++ b/source/extensions/filters/http/composite/action.h @@ -2,6 +2,7 @@ #include "envoy/extensions/filters/http/composite/v3/composite.pb.validate.h" +#include "source/common/http/matching/data_impl.h" #include "source/common/matcher/matcher.h" namespace Envoy { @@ -21,23 +22,25 @@ class ExecuteFilterAction Http::FilterFactoryCb cb_; }; -class ExecuteFilterActionFactory : public Matcher::ActionFactory { +class ExecuteFilterActionFactory + : public Matcher::ActionFactory { public: std::string name() const override { return "composite-action"; } Matcher::ActionFactoryCb - createActionFactoryCb(const Protobuf::Message& config, const std::string& stat_prefix, - Server::Configuration::FactoryContext& factory_context) override { + createActionFactoryCb(const Protobuf::Message& config, + Http::Matching::HttpFilterActionContext& context, + ProtobufMessage::ValidationVisitor& validation_visitor) override { const auto& composite_action = MessageUtil::downcastAndValidate< const envoy::extensions::filters::http::composite::v3::ExecuteFilterAction&>( - config, factory_context.messageValidationVisitor()); + config, validation_visitor); auto& factory = Config::Utility::getAndCheckFactory( composite_action.typed_config()); ProtobufTypes::MessagePtr message = Config::Utility::translateAnyToFactoryConfig( - composite_action.typed_config().typed_config(), factory_context.messageValidationVisitor(), - factory); - auto callback = factory.createFilterFactoryFromProto(*message, stat_prefix, factory_context); + composite_action.typed_config().typed_config(), validation_visitor, factory); + auto callback = factory.createFilterFactoryFromProto(*message, context.stat_prefix_, + context.factory_context_); return [cb = std::move(callback)]() -> Matcher::ActionPtr { return std::make_unique(cb); }; diff --git a/source/extensions/matching/input_matchers/consistent_hashing/config.cc b/source/extensions/matching/input_matchers/consistent_hashing/config.cc index cfcac842d366..692026a20f32 100644 --- a/source/extensions/matching/input_matchers/consistent_hashing/config.cc +++ b/source/extensions/matching/input_matchers/consistent_hashing/config.cc @@ -7,11 +7,11 @@ namespace InputMatchers { namespace ConsistentHashing { Envoy::Matcher::InputMatcherFactoryCb ConsistentHashingConfig::createInputMatcherFactoryCb( - const Protobuf::Message& config, Server::Configuration::FactoryContext& factory_context) { + const Protobuf::Message& config, ProtobufMessage::ValidationVisitor& validation_visitor) { const auto& consistent_hashing_config = MessageUtil::downcastAndValidate( - config, factory_context.messageValidationVisitor()); + config, validation_visitor); if (consistent_hashing_config.threshold() > consistent_hashing_config.modulo()) { throw EnvoyException(fmt::format("threshold cannot be greater than modulo: {} > {}", diff --git a/source/extensions/matching/input_matchers/consistent_hashing/config.h b/source/extensions/matching/input_matchers/consistent_hashing/config.h index 1ce2dd628986..fa73fb2f683e 100644 --- a/source/extensions/matching/input_matchers/consistent_hashing/config.h +++ b/source/extensions/matching/input_matchers/consistent_hashing/config.h @@ -18,7 +18,7 @@ class ConsistentHashingConfig : public Envoy::Matcher::InputMatcherFactory { public: Envoy::Matcher::InputMatcherFactoryCb createInputMatcherFactoryCb(const Protobuf::Message& config, - Server::Configuration::FactoryContext& factory_context) override; + ProtobufMessage::ValidationVisitor& validation_visitor) override; std::string name() const override { return "envoy.matching.matchers.consistent_hashing"; } diff --git a/test/extensions/matching/input_matchers/consistent_hashing/config_test.cc b/test/extensions/matching/input_matchers/consistent_hashing/config_test.cc index f70eb2825b9d..3d0fcd28ff46 100644 --- a/test/extensions/matching/input_matchers/consistent_hashing/config_test.cc +++ b/test/extensions/matching/input_matchers/consistent_hashing/config_test.cc @@ -11,8 +11,6 @@ namespace InputMatchers { namespace ConsistentHashing { TEST(ConfigTest, TestConfig) { - NiceMock context; - const std::string yaml_string = R"EOF( name: hashing typed_config: @@ -27,14 +25,13 @@ TEST(ConfigTest, TestConfig) { ConsistentHashingConfig factory; auto message = Config::Utility::translateAnyToFactoryConfig( config.typed_config(), ProtobufMessage::getStrictValidationVisitor(), factory); - auto matcher = factory.createInputMatcherFactoryCb(*message, context); + auto matcher = + factory.createInputMatcherFactoryCb(*message, ProtobufMessage::getStrictValidationVisitor()); ASSERT_NE(nullptr, matcher); matcher(); } TEST(ConfigTest, InvalidConfig) { - NiceMock context; - const std::string yaml_string = R"EOF( name: hashing typed_config: @@ -49,8 +46,9 @@ TEST(ConfigTest, InvalidConfig) { ConsistentHashingConfig factory; auto message = Config::Utility::translateAnyToFactoryConfig( config.typed_config(), ProtobufMessage::getStrictValidationVisitor(), factory); - EXPECT_THROW_WITH_MESSAGE(factory.createInputMatcherFactoryCb(*message, context), EnvoyException, - "threshold cannot be greater than modulo: 200 > 100"); + EXPECT_THROW_WITH_MESSAGE( + factory.createInputMatcherFactoryCb(*message, ProtobufMessage::getStrictValidationVisitor()), + EnvoyException, "threshold cannot be greater than modulo: 200 > 100"); } } // namespace ConsistentHashing } // namespace InputMatchers From 44e162be99ae448021e39bc2b8ed051bc5fdafb3 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Fri, 18 Jun 2021 00:51:01 +0000 Subject: [PATCH 02/44] fix build Signed-off-by: Snow Pettersen --- .../matching/common_inputs/environment_variable/config.cc | 4 ++-- .../matching/common_inputs/environment_variable/config.h | 2 +- .../common_inputs/environment_variable/config_test.cc | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/source/extensions/matching/common_inputs/environment_variable/config.cc b/source/extensions/matching/common_inputs/environment_variable/config.cc index bebbe41a7fd9..be8235c2c5a3 100644 --- a/source/extensions/matching/common_inputs/environment_variable/config.cc +++ b/source/extensions/matching/common_inputs/environment_variable/config.cc @@ -12,10 +12,10 @@ namespace EnvironmentVariable { Envoy::Matcher::CommonProtocolInputFactoryCb Config::createCommonProtocolInputFactoryCb(const Protobuf::Message& config, - Server::Configuration::FactoryContext& factory_context) { + ProtobufMessage::ValidationVisitor& validation_visitor) { const auto& environment_config = MessageUtil::downcastAndValidate< const envoy::extensions::matching::common_inputs::environment_variable::v3::Config&>( - config, factory_context.messageValidationVisitor()); + config, validation_visitor); // We read the env variable at construction time to avoid repeat lookups. // This assumes that the environment remains stable during the process lifetime. diff --git a/source/extensions/matching/common_inputs/environment_variable/config.h b/source/extensions/matching/common_inputs/environment_variable/config.h index 842e7c4bb23f..9db12bdcaf21 100644 --- a/source/extensions/matching/common_inputs/environment_variable/config.h +++ b/source/extensions/matching/common_inputs/environment_variable/config.h @@ -18,7 +18,7 @@ class Config : public Envoy::Matcher::CommonProtocolInputFactory { public: Envoy::Matcher::CommonProtocolInputFactoryCb createCommonProtocolInputFactoryCb( const Protobuf::Message& config, - Server::Configuration::FactoryContext& factory_context) override; + ProtobufMessage::ValidationVisitor& validation_visitor) override; std::string name() const override { return "envoy.matching.common_inputs.environment_variable"; } diff --git a/test/extensions/matching/common_inputs/environment_variable/config_test.cc b/test/extensions/matching/common_inputs/environment_variable/config_test.cc index 86c66037780d..94dd3d0bea24 100644 --- a/test/extensions/matching/common_inputs/environment_variable/config_test.cc +++ b/test/extensions/matching/common_inputs/environment_variable/config_test.cc @@ -13,8 +13,6 @@ namespace CommonInputs { namespace EnvironmentVariable { TEST(ConfigTest, TestConfig) { - NiceMock context; - const std::string yaml_string = R"EOF( name: hashing typed_config: @@ -30,14 +28,16 @@ TEST(ConfigTest, TestConfig) { config.typed_config(), ProtobufMessage::getStrictValidationVisitor(), factory); { - auto input_factory = factory.createCommonProtocolInputFactoryCb(*message, context); + auto input_factory = factory.createCommonProtocolInputFactoryCb( + *message, ProtobufMessage::getStrictValidationVisitor()); EXPECT_NE(nullptr, input_factory); EXPECT_EQ(input_factory()->get(), absl::nullopt); } TestEnvironment::setEnvVar("foo", "bar", 1); { - auto input_factory = factory.createCommonProtocolInputFactoryCb(*message, context); + auto input_factory = factory.createCommonProtocolInputFactoryCb( + *message, ProtobufMessage::getStrictValidationVisitor()); EXPECT_NE(nullptr, input_factory); EXPECT_EQ(input_factory()->get(), absl::make_optional("bar")); } From 7c35634fff2e5ce5aaa2d77f81f82f7c0123bd25 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Fri, 18 Jun 2021 03:04:26 +0000 Subject: [PATCH 03/44] fix more tests Signed-off-by: Snow Pettersen --- test/common/matcher/matcher_test.cc | 37 +++++++++++------------------ test/common/matcher/test_utility.h | 16 ++++++------- 2 files changed, 21 insertions(+), 32 deletions(-) diff --git a/test/common/matcher/matcher_test.cc b/test/common/matcher/matcher_test.cc index 99558fc1af9e..ce768a1e216b 100644 --- a/test/common/matcher/matcher_test.cc +++ b/test/common/matcher/matcher_test.cc @@ -22,12 +22,16 @@ namespace Envoy { namespace Matcher { class MatcherTest : public ::testing::Test { public: - MatcherTest() : inject_action_(action_factory_) {} + MatcherTest() + : inject_action_(action_factory_), + factory_(context_, ProtobufMessage::getStrictValidationVisitor(), validation_visitor_) {} StringActionFactory action_factory_; - Registry::InjectFactory inject_action_; - NiceMock factory_context_; + Registry::InjectFactory> inject_action_; MockMatchTreeValidationVisitor validation_visitor_; + + absl::string_view context_ = ""; + MatchTreeFactory factory_; }; TEST_F(MatcherTest, TestMatcher) { @@ -64,15 +68,13 @@ TEST_F(MatcherTest, TestMatcher) { TestUtility::validate(matcher); - MatchTreeFactory factory("", factory_context_, validation_visitor_); - auto outer_factory = TestDataInputFactory("outer_input", "value"); auto inner_factory = TestDataInputFactory("inner_input", "foo"); EXPECT_CALL(validation_visitor_, performDataInputValidation(_, "type.googleapis.com/google.protobuf.StringValue")) .Times(2); - auto match_tree = factory.create(matcher); + auto match_tree = factory_.create(matcher); const auto result = match_tree()->match(TestData()); EXPECT_EQ(result.match_state_, MatchState::MatchComplete); @@ -104,10 +106,9 @@ TEST_F(MatcherTest, CustomGenericInput) { MessageUtil::loadFromYaml(yaml, matcher, ProtobufMessage::getStrictValidationVisitor()); TestUtility::validate(matcher); - MatchTreeFactory factory("", factory_context_, validation_visitor_); auto common_input_factory = TestCommonProtocolInputFactory("generic", "foo"); - auto match_tree = factory.create(matcher); + auto match_tree = factory_.create(matcher); const auto result = match_tree()->match(TestData()); EXPECT_EQ(result.match_state_, MatchState::MatchComplete); @@ -141,14 +142,12 @@ TEST_F(MatcherTest, CustomMatcher) { TestUtility::validate(matcher); - MatchTreeFactory factory("", factory_context_, validation_visitor_); - auto inner_factory = TestDataInputFactory("inner_input", "foo"); NeverMatchFactory match_factory; EXPECT_CALL(validation_visitor_, performDataInputValidation(_, "type.googleapis.com/google.protobuf.StringValue")); - auto match_tree = factory.create(matcher); + auto match_tree = factory_.create(matcher); const auto result = match_tree()->match(TestData()); EXPECT_EQ(result.match_state_, MatchState::MatchComplete); @@ -198,15 +197,13 @@ TEST_F(MatcherTest, TestAndMatcher) { TestUtility::validate(matcher); - MatchTreeFactory factory("", factory_context_, validation_visitor_); - auto outer_factory = TestDataInputFactory("outer_input", "value"); auto inner_factory = TestDataInputFactory("inner_input", "foo"); EXPECT_CALL(validation_visitor_, performDataInputValidation(_, "type.googleapis.com/google.protobuf.StringValue")) .Times(3); - auto match_tree = factory.create(matcher); + auto match_tree = factory_.create(matcher); const auto result = match_tree()->match(TestData()); EXPECT_EQ(result.match_state_, MatchState::MatchComplete); @@ -257,15 +254,13 @@ TEST_F(MatcherTest, TestOrMatcher) { TestUtility::validate(matcher); - MatchTreeFactory factory("", factory_context_, validation_visitor_); - auto outer_factory = TestDataInputFactory("outer_input", "value"); auto inner_factory = TestDataInputFactory("inner_input", "foo"); EXPECT_CALL(validation_visitor_, performDataInputValidation(_, "type.googleapis.com/google.protobuf.StringValue")) .Times(3); - auto match_tree = factory.create(matcher); + auto match_tree = factory_.create(matcher); const auto result = match_tree()->match(TestData()); EXPECT_EQ(result.match_state_, MatchState::MatchComplete); @@ -299,14 +294,12 @@ TEST_F(MatcherTest, TestNotMatcher) { TestUtility::validate(matcher); - MatchTreeFactory factory("", factory_context_, validation_visitor_); - auto inner_factory = TestDataInputFactory("inner_input", "foo"); NeverMatchFactory match_factory; EXPECT_CALL(validation_visitor_, performDataInputValidation(_, "type.googleapis.com/google.protobuf.StringValue")); - auto match_tree = factory.create(matcher); + auto match_tree = factory_.create(matcher); const auto result = match_tree()->match(TestData()); EXPECT_EQ(result.match_state_, MatchState::MatchComplete); @@ -350,15 +343,13 @@ TEST_F(MatcherTest, TestRecursiveMatcher) { TestUtility::validate(matcher); - MatchTreeFactory factory("", factory_context_, validation_visitor_); - auto outer_factory = TestDataInputFactory("outer_input", "value"); auto inner_factory = TestDataInputFactory("inner_input", "foo"); EXPECT_CALL(validation_visitor_, performDataInputValidation(_, "type.googleapis.com/google.protobuf.StringValue")) .Times(2); - auto match_tree = factory.create(matcher); + auto match_tree = factory_.create(matcher); const auto result = match_tree()->match(TestData()); EXPECT_EQ(result.match_state_, MatchState::MatchComplete); diff --git a/test/common/matcher/test_utility.h b/test/common/matcher/test_utility.h index 08d1debbf0e6..e8ab24fde070 100644 --- a/test/common/matcher/test_utility.h +++ b/test/common/matcher/test_utility.h @@ -30,7 +30,7 @@ class TestCommonProtocolInputFactory : public CommonProtocolInputFactory { CommonProtocolInputFactoryCb createCommonProtocolInputFactoryCb(const Protobuf::Message&, - Server::Configuration::FactoryContext&) override { + ProtobufMessage::ValidationVisitor&) override { return [&]() { return std::make_unique(value_); }; } @@ -60,8 +60,7 @@ class TestDataInputFactory : public DataInputFactory { : factory_name_(std::string(factory_name)), value_(std::string(data)), injection_(*this) {} DataInputFactoryCb - createDataInputFactoryCb(const Protobuf::Message&, - Server::Configuration::FactoryContext&) override { + createDataInputFactoryCb(const Protobuf::Message&, ProtobufMessage::ValidationVisitor&) override { return [&]() { return std::make_unique( DataInputGetResult{DataInputGetResult::DataAvailability::AllDataAvailable, value_}); @@ -108,10 +107,10 @@ struct StringAction : public ActionBase { }; // Factory for StringAction. -class StringActionFactory : public ActionFactory { +class StringActionFactory : public ActionFactory { public: - ActionFactoryCb createActionFactoryCb(const Protobuf::Message& config, const std::string&, - Server::Configuration::FactoryContext&) override { + ActionFactoryCb createActionFactoryCb(const Protobuf::Message& config, absl::string_view&, + ProtobufMessage::ValidationVisitor&) override { const auto& string = dynamic_cast(config); return [string]() { return std::make_unique(string.value()); }; } @@ -135,9 +134,8 @@ class NeverMatchFactory : public InputMatcherFactory { public: NeverMatchFactory() : inject_factory_(*this) {} - InputMatcherFactoryCb - createInputMatcherFactoryCb(const Protobuf::Message&, - Server::Configuration::FactoryContext&) override { + InputMatcherFactoryCb createInputMatcherFactoryCb(const Protobuf::Message&, + ProtobufMessage::ValidationVisitor&) override { return []() { return std::make_unique(); }; } From 0586cb1d813fa5c8266f1aa3a8ee03610d0c05e5 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Fri, 18 Jun 2021 15:36:55 +0000 Subject: [PATCH 04/44] router: poc of integration match api Signed-off-by: Snow Pettersen --- .../config/route/v3/route_components.proto | 7 +- .../route/v4alpha/route_components.proto | 7 +- .../config/route/v3/route_components.proto | 7 +- .../route/v4alpha/route_components.proto | 7 +- source/common/router/BUILD | 3 + source/common/router/config_impl.cc | 194 +++++++++++++----- source/common/router/config_impl.h | 31 +++ test/common/router/config_impl_test.cc | 61 ++++++ 8 files changed, 254 insertions(+), 63 deletions(-) diff --git a/api/envoy/config/route/v3/route_components.proto b/api/envoy/config/route/v3/route_components.proto index ee82e8f73226..797ed1383f06 100644 --- a/api/envoy/config/route/v3/route_components.proto +++ b/api/envoy/config/route/v3/route_components.proto @@ -36,7 +36,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // host header. This allows a single listener to service multiple top level domain path trees. Once // a virtual host is selected based on the domain, the routes are processed in order to see which // upstream cluster to route to or whether to perform a redirect. -// [#next-free-field: 21] +// [#next-free-field: 22] message VirtualHost { option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.route.VirtualHost"; @@ -84,6 +84,9 @@ message VirtualHost { items {string {well_known_regex: HTTP_HEADER_VALUE strict: false}} }]; + // This is mega hacky but gets around the circular dependency between this file and the matcher file. + google.protobuf.Any matcher = 21; + // The list of routes that will be matched, in order, for incoming requests. // The first route that matches will be used. repeated Route routes = 3; @@ -214,7 +217,7 @@ message Route { string name = 14; // Route matching parameters. - RouteMatch match = 1 [(validate.rules).message = {required: true}]; + RouteMatch match = 1; oneof action { option (validate.required) = true; diff --git a/api/envoy/config/route/v4alpha/route_components.proto b/api/envoy/config/route/v4alpha/route_components.proto index 256a3c742ff3..9edd5d9d2edc 100644 --- a/api/envoy/config/route/v4alpha/route_components.proto +++ b/api/envoy/config/route/v4alpha/route_components.proto @@ -34,7 +34,7 @@ option (udpa.annotations.file_status).package_version_status = NEXT_MAJOR_VERSIO // host header. This allows a single listener to service multiple top level domain path trees. Once // a virtual host is selected based on the domain, the routes are processed in order to see which // upstream cluster to route to or whether to perform a redirect. -// [#next-free-field: 21] +// [#next-free-field: 22] message VirtualHost { option (udpa.annotations.versioning).previous_message_type = "envoy.config.route.v3.VirtualHost"; @@ -82,6 +82,9 @@ message VirtualHost { items {string {well_known_regex: HTTP_HEADER_VALUE strict: false}} }]; + // This is mega hacky but gets around the circular dependency between this file and the matcher file. + google.protobuf.Any matcher = 21; + // The list of routes that will be matched, in order, for incoming requests. // The first route that matches will be used. repeated Route routes = 3; @@ -212,7 +215,7 @@ message Route { string name = 14; // Route matching parameters. - RouteMatch match = 1 [(validate.rules).message = {required: true}]; + RouteMatch match = 1; oneof action { option (validate.required) = true; diff --git a/generated_api_shadow/envoy/config/route/v3/route_components.proto b/generated_api_shadow/envoy/config/route/v3/route_components.proto index b8f03cde3a9d..713b172a5cea 100644 --- a/generated_api_shadow/envoy/config/route/v3/route_components.proto +++ b/generated_api_shadow/envoy/config/route/v3/route_components.proto @@ -37,7 +37,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // host header. This allows a single listener to service multiple top level domain path trees. Once // a virtual host is selected based on the domain, the routes are processed in order to see which // upstream cluster to route to or whether to perform a redirect. -// [#next-free-field: 21] +// [#next-free-field: 22] message VirtualHost { option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.route.VirtualHost"; @@ -83,6 +83,9 @@ message VirtualHost { items {string {well_known_regex: HTTP_HEADER_VALUE strict: false}} }]; + // This is mega hacky but gets around the circular dependency between this file and the matcher file. + google.protobuf.Any matcher = 21; + // The list of routes that will be matched, in order, for incoming requests. // The first route that matches will be used. repeated Route routes = 3; @@ -214,7 +217,7 @@ message Route { string name = 14; // Route matching parameters. - RouteMatch match = 1 [(validate.rules).message = {required: true}]; + RouteMatch match = 1; oneof action { option (validate.required) = true; diff --git a/generated_api_shadow/envoy/config/route/v4alpha/route_components.proto b/generated_api_shadow/envoy/config/route/v4alpha/route_components.proto index 6b8c146582a3..fd040956530b 100644 --- a/generated_api_shadow/envoy/config/route/v4alpha/route_components.proto +++ b/generated_api_shadow/envoy/config/route/v4alpha/route_components.proto @@ -35,7 +35,7 @@ option (udpa.annotations.file_status).package_version_status = NEXT_MAJOR_VERSIO // host header. This allows a single listener to service multiple top level domain path trees. Once // a virtual host is selected based on the domain, the routes are processed in order to see which // upstream cluster to route to or whether to perform a redirect. -// [#next-free-field: 21] +// [#next-free-field: 22] message VirtualHost { option (udpa.annotations.versioning).previous_message_type = "envoy.config.route.v3.VirtualHost"; @@ -83,6 +83,9 @@ message VirtualHost { items {string {well_known_regex: HTTP_HEADER_VALUE strict: false}} }]; + // This is mega hacky but gets around the circular dependency between this file and the matcher file. + google.protobuf.Any matcher = 21; + // The list of routes that will be matched, in order, for incoming requests. // The first route that matches will be used. repeated Route routes = 3; @@ -213,7 +216,7 @@ message Route { string name = 14; // Route matching parameters. - RouteMatch match = 1 [(validate.rules).message = {required: true}]; + RouteMatch match = 1; oneof action { option (validate.required) = true; diff --git a/source/common/router/BUILD b/source/common/router/BUILD index 524bd27213f1..64f697f01baf 100644 --- a/source/common/router/BUILD +++ b/source/common/router/BUILD @@ -61,9 +61,12 @@ envoy_cc_library( "//source/common/http:headers_lib", "//source/common/http:path_utility_lib", "//source/common/http:utility_lib", + "//source/common/http/matching:data_impl_lib", + "//source/common/matcher:matcher_lib", "//source/common/protobuf:utility_lib", "//source/common/tracing:http_tracer_lib", "//source/extensions/filters/http/common:utility_lib", + "@envoy_api//envoy/config/common/matcher/v3:pkg_cc_proto", "@envoy_api//envoy/config/core/v3:pkg_cc_proto", "@envoy_api//envoy/config/route/v3:pkg_cc_proto", "@envoy_api//envoy/type/matcher/v3:pkg_cc_proto", diff --git a/source/common/router/config_impl.cc b/source/common/router/config_impl.cc index 325b77ef4c0b..43725e2352b6 100644 --- a/source/common/router/config_impl.cc +++ b/source/common/router/config_impl.cc @@ -8,6 +8,8 @@ #include #include +#include "envoy/config/common/matcher/v3/matcher.pb.h" +#include "envoy/config/common/matcher/v3/matcher.pb.validate.h" #include "envoy/config/core/v3/base.pb.h" #include "envoy/config/route/v3/route.pb.h" #include "envoy/config/route/v3/route_components.pb.h" @@ -29,8 +31,10 @@ #include "source/common/config/utility.h" #include "source/common/config/well_known_names.h" #include "source/common/http/headers.h" +#include "source/common/http/matching/data_impl.h" #include "source/common/http/path_utility.h" #include "source/common/http/utility.h" +#include "source/common/matcher/matcher.h" #include "source/common/protobuf/protobuf.h" #include "source/common/protobuf/utility.h" #include "source/common/router/reset_header_parser.h" @@ -59,6 +63,78 @@ void mergeTransforms(Http::HeaderTransforms& dest, const Http::HeaderTransforms& src.headers_to_remove.end()); } +class MatchTreeRouteEntryImpl : public RouteEntryImplBase { +public: + using RouteEntryImplBase::RouteEntryImplBase; + + virtual absl::optional + currentUrlPathAfterRewrite(const Http::RequestHeaderMap&) const override { + return absl::nullopt; + } + RouteConstSharedPtr matches(const Http::RequestHeaderMap&, const StreamInfo::StreamInfo&, + uint64_t) const override { + NOT_REACHED_GCOVR_EXCL_LINE; + } + PathMatchType matchType() const override { return PathMatchType::None; } + const std::string& matcher() const override { NOT_REACHED_GCOVR_EXCL_LINE; } +}; + +RouteEntryImplBaseConstSharedPtr createAndValidateRoute( + const envoy::config::route::v3::Route& route_config, const VirtualHostImpl& vhost, + const OptionalHttpFilters& optional_http_filters, + Server::Configuration::ServerFactoryContext& factory_context, + ProtobufMessage::ValidationVisitor& validator, + const absl::optional& validation_clusters) { + + RouteEntryImplBaseConstSharedPtr route; + switch (route_config.match().path_specifier_case()) { + case envoy::config::route::v3::RouteMatch::PathSpecifierCase::kPrefix: { + route = std::make_shared(vhost, route_config, optional_http_filters, + factory_context, validator); + break; + } + case envoy::config::route::v3::RouteMatch::PathSpecifierCase::kPath: { + route = std::make_shared(vhost, route_config, optional_http_filters, + factory_context, validator); + break; + } + case envoy::config::route::v3::RouteMatch::PathSpecifierCase::kHiddenEnvoyDeprecatedRegex: + case envoy::config::route::v3::RouteMatch::PathSpecifierCase::kSafeRegex: { + route = std::make_shared(vhost, route_config, optional_http_filters, + factory_context, validator); + break; + } + case envoy::config::route::v3::RouteMatch::PathSpecifierCase::kConnectMatcher: { + route = std::make_shared(vhost, route_config, optional_http_filters, + factory_context, validator); + break; + } + default: + NOT_REACHED_GCOVR_EXCL_LINE; + } + + if (validation_clusters.has_value()) { + route->validateClusters(*validation_clusters); + for (const auto& shadow_policy : route->shadowPolicies()) { + ASSERT(!shadow_policy->cluster().empty()); + if (!validation_clusters->hasCluster(shadow_policy->cluster())) { + throw EnvoyException( + fmt::format("route: unknown shadow cluster '{}'", shadow_policy->cluster())); + } + } + } + + return route; +} + +class RouteActionValidationVisitor + : public Matcher::MatchTreeValidationVisitor { +public: + absl::Status performDataInputValidation(const Matcher::DataInputFactory&, + absl::string_view) override { + return absl::OkStatus(); + } +}; } // namespace const std::string& OriginalConnectPort::key() { @@ -1226,42 +1302,23 @@ VirtualHostImpl::VirtualHostImpl( hedge_policy_ = virtual_host.hedge_policy(); } - for (const auto& route : virtual_host.routes()) { - switch (route.match().path_specifier_case()) { - case envoy::config::route::v3::RouteMatch::PathSpecifierCase::kPrefix: { - routes_.emplace_back(new PrefixRouteEntryImpl(*this, route, optional_http_filters, - factory_context, validator)); - break; - } - case envoy::config::route::v3::RouteMatch::PathSpecifierCase::kPath: { - routes_.emplace_back( - new PathRouteEntryImpl(*this, route, optional_http_filters, factory_context, validator)); - break; - } - case envoy::config::route::v3::RouteMatch::PathSpecifierCase::kHiddenEnvoyDeprecatedRegex: - case envoy::config::route::v3::RouteMatch::PathSpecifierCase::kSafeRegex: { - routes_.emplace_back( - new RegexRouteEntryImpl(*this, route, optional_http_filters, factory_context, validator)); - break; - } - case envoy::config::route::v3::RouteMatch::PathSpecifierCase::kConnectMatcher: { - routes_.emplace_back(new ConnectRouteEntryImpl(*this, route, optional_http_filters, - factory_context, validator)); - break; - } - default: - NOT_REACHED_GCOVR_EXCL_LINE; - } + if (virtual_host.has_matcher()) { + envoy::config::common::matcher::v3::Matcher matcher; + MessageUtil::anyConvertAndValidate(virtual_host.matcher(), matcher, validator); - if (validation_clusters.has_value()) { - routes_.back()->validateClusters(*validation_clusters); - for (const auto& shadow_policy : routes_.back()->shadowPolicies()) { - ASSERT(!shadow_policy->cluster().empty()); - if (!validation_clusters->hasCluster(shadow_policy->cluster())) { - throw EnvoyException( - fmt::format("route: unknown shadow cluster '{}'", shadow_policy->cluster())); - } + RouteActionContext context{*this, optional_http_filters, factory_context}; + RouteActionValidationVisitor validation_visitor; + Matcher::MatchTreeFactory factory( + context, validator, validation_visitor); + + matcher_ = factory.create(matcher)(); + } else { + for (const auto& route : virtual_host.routes()) { + if (!route.has_match()) { + throw EnvoyException("RouteValidationError.Match"); } + routes_.emplace_back(createAndValidateRoute(route, *this, optional_http_filters, + factory_context, validator, validation_clusters)); } } @@ -1382,33 +1439,46 @@ RouteConstSharedPtr VirtualHostImpl::getRouteFromEntries(const RouteCallback& cb return SSL_REDIRECT_ROUTE; } - // Check for a route that matches the request. - for (auto route = routes_.begin(); route != routes_.end(); ++route) { - if (!headers.Path() && !(*route)->supportsPathlessHeaders()) { - continue; - } + if (matcher_) { + Http::Matching::HttpMatchingDataImpl data; + data.onRequestHeaders(headers); - RouteConstSharedPtr route_entry = (*route)->matches(headers, stream_info, random_value); - if (nullptr == route_entry) { - continue; + auto match = Matcher::evaluateMatch(*matcher_, data); + + if (match.result_) { + return dynamic_cast(*match.result_).route(); } - if (cb) { - RouteEvalStatus eval_status = (std::next(route) == routes_.end()) - ? RouteEvalStatus::NoMoreRoutes - : RouteEvalStatus::HasMoreRoutes; - RouteMatchStatus match_status = cb(route_entry, eval_status); - if (match_status == RouteMatchStatus::Accept) { - return route_entry; + return nullptr; + } else { + // Check for a route that matches the request. + for (auto route = routes_.begin(); route != routes_.end(); ++route) { + if (!headers.Path() && !(*route)->supportsPathlessHeaders()) { + continue; } - if (match_status == RouteMatchStatus::Continue && - eval_status == RouteEvalStatus::NoMoreRoutes) { - return nullptr; + + RouteConstSharedPtr route_entry = (*route)->matches(headers, stream_info, random_value); + if (nullptr == route_entry) { + continue; } - continue; - } - return route_entry; + if (cb) { + RouteEvalStatus eval_status = (std::next(route) == routes_.end()) + ? RouteEvalStatus::NoMoreRoutes + : RouteEvalStatus::HasMoreRoutes; + RouteMatchStatus match_status = cb(route_entry, eval_status); + if (match_status == RouteMatchStatus::Accept) { + return route_entry; + } + if (match_status == RouteMatchStatus::Continue && + eval_status == RouteEvalStatus::NoMoreRoutes) { + return nullptr; + } + continue; + } + + return route_entry; + } } return nullptr; @@ -1592,5 +1662,19 @@ const RouteSpecificFilterConfig* PerFilterConfigs::get(const std::string& name) return it == configs_.end() ? nullptr : it->second.get(); } +Matcher::ActionFactoryCb RouteMatchActionFactory::createActionFactoryCb( + const Protobuf::Message& config, RouteActionContext& context, + ProtobufMessage::ValidationVisitor& validation_visitor) { + const auto& route_config = + MessageUtil::downcastAndValidate(config, + validation_visitor); + auto route = std::make_shared( + context.vhost, route_config, context.optional_http_filters, context.factory_context, + validation_visitor); + + return [route]() { return std::make_unique(route); }; +} +REGISTER_FACTORY(RouteMatchActionFactory, Matcher::ActionFactory); + } // namespace Router } // namespace Envoy diff --git a/source/common/router/config_impl.h b/source/common/router/config_impl.h index e367683e092e..e084170dbbee 100644 --- a/source/common/router/config_impl.h +++ b/source/common/router/config_impl.h @@ -13,6 +13,7 @@ #include "envoy/config/core/v3/base.pb.h" #include "envoy/config/route/v3/route.pb.h" #include "envoy/config/route/v3/route_components.pb.h" +#include "envoy/config/route/v3/route_components.pb.validate.h" #include "envoy/router/router.h" #include "envoy/runtime/runtime.h" #include "envoy/server/filter_config.h" @@ -23,6 +24,7 @@ #include "source/common/config/metadata.h" #include "source/common/http/hash_policy.h" #include "source/common/http/header_utility.h" +#include "source/common/matcher/matcher.h" #include "source/common/router/config_utility.h" #include "source/common/router/header_formatter.h" #include "source/common/router/header_parser.h" @@ -276,6 +278,7 @@ class VirtualHostImpl : public VirtualHost { absl::optional retry_policy_; absl::optional hedge_policy_; const CatchAllVirtualCluster virtual_cluster_catch_all_; + Matcher::MatchTreeSharedPtr matcher_; }; using VirtualHostSharedPtr = std::shared_ptr; @@ -1011,6 +1014,34 @@ class ConnectRouteEntryImpl : public RouteEntryImplBase { bool supportsPathlessHeaders() const override { return true; } }; + +struct RouteActionContext { + const VirtualHostImpl& vhost; + const OptionalHttpFilters& optional_http_filters; + Server::Configuration::ServerFactoryContext& factory_context; +}; + +class RouteMatchAction : public Matcher::ActionBase { +public: + explicit RouteMatchAction(RouteConstSharedPtr route) : route_(std::move(route)) {} + + RouteConstSharedPtr route() const { return route_; } + +private: + const RouteConstSharedPtr route_; +}; + +class RouteMatchActionFactory : public Matcher::ActionFactory { +public: + Matcher::ActionFactoryCb + createActionFactoryCb(const Protobuf::Message& config, RouteActionContext& context, + ProtobufMessage::ValidationVisitor& validation_visitor) override; + std::string name() const override { return "route"; } + ProtobufTypes::MessagePtr createEmptyConfigProto() override { + return std::make_unique(); + } +}; + /** * Wraps the route configuration which matches an incoming request headers to a backend cluster. * This is split out mainly to help with unit testing. diff --git a/test/common/router/config_impl_test.cc b/test/common/router/config_impl_test.cc index 38f3f0d65387..97b9423850b6 100644 --- a/test/common/router/config_impl_test.cc +++ b/test/common/router/config_impl_test.cc @@ -1209,6 +1209,67 @@ TEST_F(RouteMatcherTest, TestRoutesWithInvalidVirtualCluster) { "virtual clusters must define 'headers'"); } +// Validates behavior of request_headers_to_add at router, vhost, and route levels. +TEST_F(RouteMatcherTest, TestMatchTree) { + const std::string yaml = R"EOF( +virtual_hosts: +- name: www2 + domains: + - lyft.com + matcher: + "@type": type.googleapis.com/envoy.config.common.matcher.v3.Matcher + matcher_tree: + input: + name: request-headers + typed_config: + "@type": type.googleapis.com/envoy.type.matcher.v3.HttpRequestHeaderMatchInput + header_name: :path + exact_match_map: + map: + "/new_endpoint/foo": + action: + name: route + typed_config: + "@type": type.googleapis.com/envoy.config.route.v3.Route + route: + cluster: root_ww2 + request_headers_to_add: + - header: + key: x-route-header + value: match_tree + "/new_endpoint/bar": + action: + name: route + typed_config: + "@type": type.googleapis.com/envoy.config.route.v3.Route + route: + cluster: root_ww2 + request_headers_to_add: + - header: + key: x-route-header + value: match_tree_2 + )EOF"; + + NiceMock stream_info; + factory_context_.cluster_manager_.initializeClusters( + {"www2", "root_www2", "www2_staging", "instant-server"}, {}); + TestConfigImpl config(parseRouteConfigurationFromYaml(yaml), factory_context_, true); + + { + Http::TestRequestHeaderMapImpl headers = genHeaders("lyft.com", "/new_endpoint/foo", "GET"); + const RouteEntry* route = config.route(headers, 0)->routeEntry(); + route->finalizeRequestHeaders(headers, stream_info, true); + EXPECT_EQ("match_tree", headers.get_("x-route-header")); + } + + { + Http::TestRequestHeaderMapImpl headers = genHeaders("lyft.com", "/new_endpoint/bar", "GET"); + const RouteEntry* route = config.route(headers, 0)->routeEntry(); + route->finalizeRequestHeaders(headers, stream_info, true); + EXPECT_EQ("match_tree_2", headers.get_("x-route-header")); + } +} + // Validates behavior of request_headers_to_add at router, vhost, and route levels. TEST_F(RouteMatcherTest, TestAddRemoveRequestHeaders) { const std::string yaml = R"EOF( From 50fe3e8246476939e8b2db6bf4d81433eef23f59 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Wed, 23 Jun 2021 02:35:52 +0000 Subject: [PATCH 05/44] api: move generic matcher proto to its own package Signed-off-by: Snow Pettersen --- api/BUILD | 1 + .../config/common/matcher/generic/v3/BUILD | 13 ++ .../common/matcher/generic/v3/matcher.proto | 142 +++++++++++++++ .../common/matcher/generic/v4alpha/BUILD | 14 ++ .../matcher/generic/v4alpha/matcher.proto | 170 ++++++++++++++++++ api/versioning/BUILD | 1 + generated_api_shadow/BUILD | 1 + .../config/common/matcher/generic/v3/BUILD | 13 ++ .../common/matcher/generic/v3/matcher.proto | 142 +++++++++++++++ .../common/matcher/generic/v4alpha/BUILD | 14 ++ .../matcher/generic/v4alpha/matcher.proto | 170 ++++++++++++++++++ 11 files changed, 681 insertions(+) create mode 100644 api/envoy/config/common/matcher/generic/v3/BUILD create mode 100644 api/envoy/config/common/matcher/generic/v3/matcher.proto create mode 100644 api/envoy/config/common/matcher/generic/v4alpha/BUILD create mode 100644 api/envoy/config/common/matcher/generic/v4alpha/matcher.proto create mode 100644 generated_api_shadow/envoy/config/common/matcher/generic/v3/BUILD create mode 100644 generated_api_shadow/envoy/config/common/matcher/generic/v3/matcher.proto create mode 100644 generated_api_shadow/envoy/config/common/matcher/generic/v4alpha/BUILD create mode 100644 generated_api_shadow/envoy/config/common/matcher/generic/v4alpha/matcher.proto diff --git a/api/BUILD b/api/BUILD index cb40c29c8e40..fdce26cec69c 100644 --- a/api/BUILD +++ b/api/BUILD @@ -68,6 +68,7 @@ proto_library( "//envoy/config/accesslog/v3:pkg", "//envoy/config/bootstrap/v3:pkg", "//envoy/config/cluster/v3:pkg", + "//envoy/config/common/matcher/generic/v3:pkg", "//envoy/config/common/matcher/v3:pkg", "//envoy/config/core/v3:pkg", "//envoy/config/endpoint/v3:pkg", diff --git a/api/envoy/config/common/matcher/generic/v3/BUILD b/api/envoy/config/common/matcher/generic/v3/BUILD new file mode 100644 index 000000000000..3f3a5395d2aa --- /dev/null +++ b/api/envoy/config/common/matcher/generic/v3/BUILD @@ -0,0 +1,13 @@ +# DO NOT EDIT. This file is generated by tools/proto_format/proto_sync.py. + +load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") + +licenses(["notice"]) # Apache 2 + +api_proto_package( + deps = [ + "//envoy/config/core/v3:pkg", + "//envoy/type/matcher/v3:pkg", + "@com_github_cncf_udpa//udpa/annotations:pkg", + ], +) diff --git a/api/envoy/config/common/matcher/generic/v3/matcher.proto b/api/envoy/config/common/matcher/generic/v3/matcher.proto new file mode 100644 index 000000000000..1113fa07adf3 --- /dev/null +++ b/api/envoy/config/common/matcher/generic/v3/matcher.proto @@ -0,0 +1,142 @@ +syntax = "proto3"; + +package envoy.config.common.matcher.generic.v3; + +import "envoy/config/core/v3/extension.proto"; +import "envoy/type/matcher/v3/string.proto"; + +import "udpa/annotations/status.proto"; +import "validate/validate.proto"; + +option java_package = "io.envoyproxy.envoy.config.common.matcher.generic.v3"; +option java_outer_classname = "MatcherProto"; +option java_multiple_files = true; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#protodoc-title: Unified Matcher API] + +// A matcher, which may traverse a matching tree in order to result in a match action. +// During matching, the tree will be traversed until a match is found, or if no match +// is found the action specified by the most specific on_no_match will be evaluated. +// As an on_no_match might result in another matching tree being evaluated, this process +// might repeat several times until the final OnMatch (or no match) is decided. +// +// [#alpha:] +message Matcher { + // What to do if a match is successful. + message OnMatch { + oneof on_match { + option (validate.required) = true; + + // Nested matcher to evaluate. + // If the nested matcher does not match and does not specify + // on_no_match, then this matcher is considered not to have + // matched, even if a predicate at this level or above returned + // true. + Matcher matcher = 1; + + // Protocol-specific action to take. + core.v3.TypedExtensionConfig action = 2; + } + } + + // A linear list of field matchers. + // The field matchers are evaluated in order, and the first match + // wins. + message MatcherList { + // Predicate to determine if a match is successful. + message Predicate { + // Predicate for a single input field. + message SinglePredicate { + // Protocol-specific specification of input field to match on. + // [#extension-category: envoy.matching.common_inputs] + core.v3.TypedExtensionConfig input = 1 [(validate.rules).message = {required: true}]; + + oneof matcher { + option (validate.required) = true; + + // Built-in string matcher. + type.matcher.v3.StringMatcher value_match = 2; + + // Extension for custom matching logic. + // [#extension-category: envoy.matching.input_matchers] + core.v3.TypedExtensionConfig custom_match = 3; + } + } + + // A list of two or more matchers. Used to allow using a list within a oneof. + message PredicateList { + repeated Predicate predicate = 1 [(validate.rules).repeated = {min_items: 2}]; + } + + oneof match_type { + option (validate.required) = true; + + // A single predicate to evaluate. + SinglePredicate single_predicate = 1; + + // A list of predicates to be OR-ed together. + PredicateList or_matcher = 2; + + // A list of predicates to be AND-ed together. + PredicateList and_matcher = 3; + + // The invert of a predicate + Predicate not_matcher = 4; + } + } + + // An individual matcher. + message FieldMatcher { + // Determines if the match succeeds. + Predicate predicate = 1 [(validate.rules).message = {required: true}]; + + // What to do if the match succeeds. + OnMatch on_match = 2 [(validate.rules).message = {required: true}]; + } + + // A list of matchers. First match wins. + repeated FieldMatcher matchers = 1 [(validate.rules).repeated = {min_items: 1}]; + } + + message MatcherTree { + // A map of configured matchers. Used to allow using a map within a oneof. + message MatchMap { + map map = 1 [(validate.rules).map = {min_pairs: 1}]; + } + + // Protocol-specific specification of input field to match on. + core.v3.TypedExtensionConfig input = 1 [(validate.rules).message = {required: true}]; + + // Exact or prefix match maps in which to look up the input value. + // If the lookup succeeds, the match is considered successful, and + // the corresponding OnMatch is used. + oneof tree_type { + option (validate.required) = true; + + MatchMap exact_match_map = 2; + + // Longest matching prefix wins. + MatchMap prefix_match_map = 3; + + // Extension for custom matching logic. + core.v3.TypedExtensionConfig custom_match = 4; + } + } + + oneof matcher_type { + option (validate.required) = true; + + // A linear list of matchers to evaluate. + MatcherList matcher_list = 1; + + // A match tree to evaluate. + MatcherTree matcher_tree = 2; + } + + // Optional OnMatch to use if the matcher failed. + // If specified, the OnMatch is used, and the matcher is considered + // to have matched. + // If not specified, the matcher is considered not to have matched. + OnMatch on_no_match = 3; +} diff --git a/api/envoy/config/common/matcher/generic/v4alpha/BUILD b/api/envoy/config/common/matcher/generic/v4alpha/BUILD new file mode 100644 index 000000000000..09cd119d3a62 --- /dev/null +++ b/api/envoy/config/common/matcher/generic/v4alpha/BUILD @@ -0,0 +1,14 @@ +# DO NOT EDIT. This file is generated by tools/proto_format/proto_sync.py. + +load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") + +licenses(["notice"]) # Apache 2 + +api_proto_package( + deps = [ + "//envoy/config/common/matcher/generic/v3:pkg", + "//envoy/config/core/v4alpha:pkg", + "//envoy/type/matcher/v4alpha:pkg", + "@com_github_cncf_udpa//udpa/annotations:pkg", + ], +) diff --git a/api/envoy/config/common/matcher/generic/v4alpha/matcher.proto b/api/envoy/config/common/matcher/generic/v4alpha/matcher.proto new file mode 100644 index 000000000000..f90fcc6e0927 --- /dev/null +++ b/api/envoy/config/common/matcher/generic/v4alpha/matcher.proto @@ -0,0 +1,170 @@ +syntax = "proto3"; + +package envoy.config.common.matcher.generic.v4alpha; + +import "envoy/config/core/v4alpha/extension.proto"; +import "envoy/type/matcher/v4alpha/string.proto"; + +import "udpa/annotations/status.proto"; +import "udpa/annotations/versioning.proto"; +import "validate/validate.proto"; + +option java_package = "io.envoyproxy.envoy.config.common.matcher.generic.v4alpha"; +option java_outer_classname = "MatcherProto"; +option java_multiple_files = true; +option (udpa.annotations.file_status).package_version_status = NEXT_MAJOR_VERSION_CANDIDATE; + +// [#protodoc-title: Unified Matcher API] + +// A matcher, which may traverse a matching tree in order to result in a match action. +// During matching, the tree will be traversed until a match is found, or if no match +// is found the action specified by the most specific on_no_match will be evaluated. +// As an on_no_match might result in another matching tree being evaluated, this process +// might repeat several times until the final OnMatch (or no match) is decided. +// +// [#alpha:] +message Matcher { + option (udpa.annotations.versioning).previous_message_type = + "envoy.config.common.matcher.generic.v3.Matcher"; + + // What to do if a match is successful. + message OnMatch { + option (udpa.annotations.versioning).previous_message_type = + "envoy.config.common.matcher.generic.v3.Matcher.OnMatch"; + + oneof on_match { + option (validate.required) = true; + + // Nested matcher to evaluate. + // If the nested matcher does not match and does not specify + // on_no_match, then this matcher is considered not to have + // matched, even if a predicate at this level or above returned + // true. + Matcher matcher = 1; + + // Protocol-specific action to take. + core.v4alpha.TypedExtensionConfig action = 2; + } + } + + // A linear list of field matchers. + // The field matchers are evaluated in order, and the first match + // wins. + message MatcherList { + option (udpa.annotations.versioning).previous_message_type = + "envoy.config.common.matcher.generic.v3.Matcher.MatcherList"; + + // Predicate to determine if a match is successful. + message Predicate { + option (udpa.annotations.versioning).previous_message_type = + "envoy.config.common.matcher.generic.v3.Matcher.MatcherList.Predicate"; + + // Predicate for a single input field. + message SinglePredicate { + option (udpa.annotations.versioning).previous_message_type = + "envoy.config.common.matcher.generic.v3.Matcher.MatcherList.Predicate.SinglePredicate"; + + // Protocol-specific specification of input field to match on. + // [#extension-category: envoy.matching.common_inputs] + core.v4alpha.TypedExtensionConfig input = 1 [(validate.rules).message = {required: true}]; + + oneof matcher { + option (validate.required) = true; + + // Built-in string matcher. + type.matcher.v4alpha.StringMatcher value_match = 2; + + // Extension for custom matching logic. + // [#extension-category: envoy.matching.input_matchers] + core.v4alpha.TypedExtensionConfig custom_match = 3; + } + } + + // A list of two or more matchers. Used to allow using a list within a oneof. + message PredicateList { + option (udpa.annotations.versioning).previous_message_type = + "envoy.config.common.matcher.generic.v3.Matcher.MatcherList.Predicate.PredicateList"; + + repeated Predicate predicate = 1 [(validate.rules).repeated = {min_items: 2}]; + } + + oneof match_type { + option (validate.required) = true; + + // A single predicate to evaluate. + SinglePredicate single_predicate = 1; + + // A list of predicates to be OR-ed together. + PredicateList or_matcher = 2; + + // A list of predicates to be AND-ed together. + PredicateList and_matcher = 3; + + // The invert of a predicate + Predicate not_matcher = 4; + } + } + + // An individual matcher. + message FieldMatcher { + option (udpa.annotations.versioning).previous_message_type = + "envoy.config.common.matcher.generic.v3.Matcher.MatcherList.FieldMatcher"; + + // Determines if the match succeeds. + Predicate predicate = 1 [(validate.rules).message = {required: true}]; + + // What to do if the match succeeds. + OnMatch on_match = 2 [(validate.rules).message = {required: true}]; + } + + // A list of matchers. First match wins. + repeated FieldMatcher matchers = 1 [(validate.rules).repeated = {min_items: 1}]; + } + + message MatcherTree { + option (udpa.annotations.versioning).previous_message_type = + "envoy.config.common.matcher.generic.v3.Matcher.MatcherTree"; + + // A map of configured matchers. Used to allow using a map within a oneof. + message MatchMap { + option (udpa.annotations.versioning).previous_message_type = + "envoy.config.common.matcher.generic.v3.Matcher.MatcherTree.MatchMap"; + + map map = 1 [(validate.rules).map = {min_pairs: 1}]; + } + + // Protocol-specific specification of input field to match on. + core.v4alpha.TypedExtensionConfig input = 1 [(validate.rules).message = {required: true}]; + + // Exact or prefix match maps in which to look up the input value. + // If the lookup succeeds, the match is considered successful, and + // the corresponding OnMatch is used. + oneof tree_type { + option (validate.required) = true; + + MatchMap exact_match_map = 2; + + // Longest matching prefix wins. + MatchMap prefix_match_map = 3; + + // Extension for custom matching logic. + core.v4alpha.TypedExtensionConfig custom_match = 4; + } + } + + oneof matcher_type { + option (validate.required) = true; + + // A linear list of matchers to evaluate. + MatcherList matcher_list = 1; + + // A match tree to evaluate. + MatcherTree matcher_tree = 2; + } + + // Optional OnMatch to use if the matcher failed. + // If specified, the OnMatch is used, and the matcher is considered + // to have matched. + // If not specified, the matcher is considered not to have matched. + OnMatch on_no_match = 3; +} diff --git a/api/versioning/BUILD b/api/versioning/BUILD index eb4267263f3f..6e11e399d844 100644 --- a/api/versioning/BUILD +++ b/api/versioning/BUILD @@ -13,6 +13,7 @@ proto_library( "//envoy/config/accesslog/v3:pkg", "//envoy/config/bootstrap/v3:pkg", "//envoy/config/cluster/v3:pkg", + "//envoy/config/common/matcher/generic/v3:pkg", "//envoy/config/common/matcher/v3:pkg", "//envoy/config/core/v3:pkg", "//envoy/config/endpoint/v3:pkg", diff --git a/generated_api_shadow/BUILD b/generated_api_shadow/BUILD index cb40c29c8e40..fdce26cec69c 100644 --- a/generated_api_shadow/BUILD +++ b/generated_api_shadow/BUILD @@ -68,6 +68,7 @@ proto_library( "//envoy/config/accesslog/v3:pkg", "//envoy/config/bootstrap/v3:pkg", "//envoy/config/cluster/v3:pkg", + "//envoy/config/common/matcher/generic/v3:pkg", "//envoy/config/common/matcher/v3:pkg", "//envoy/config/core/v3:pkg", "//envoy/config/endpoint/v3:pkg", diff --git a/generated_api_shadow/envoy/config/common/matcher/generic/v3/BUILD b/generated_api_shadow/envoy/config/common/matcher/generic/v3/BUILD new file mode 100644 index 000000000000..3f3a5395d2aa --- /dev/null +++ b/generated_api_shadow/envoy/config/common/matcher/generic/v3/BUILD @@ -0,0 +1,13 @@ +# DO NOT EDIT. This file is generated by tools/proto_format/proto_sync.py. + +load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") + +licenses(["notice"]) # Apache 2 + +api_proto_package( + deps = [ + "//envoy/config/core/v3:pkg", + "//envoy/type/matcher/v3:pkg", + "@com_github_cncf_udpa//udpa/annotations:pkg", + ], +) diff --git a/generated_api_shadow/envoy/config/common/matcher/generic/v3/matcher.proto b/generated_api_shadow/envoy/config/common/matcher/generic/v3/matcher.proto new file mode 100644 index 000000000000..1113fa07adf3 --- /dev/null +++ b/generated_api_shadow/envoy/config/common/matcher/generic/v3/matcher.proto @@ -0,0 +1,142 @@ +syntax = "proto3"; + +package envoy.config.common.matcher.generic.v3; + +import "envoy/config/core/v3/extension.proto"; +import "envoy/type/matcher/v3/string.proto"; + +import "udpa/annotations/status.proto"; +import "validate/validate.proto"; + +option java_package = "io.envoyproxy.envoy.config.common.matcher.generic.v3"; +option java_outer_classname = "MatcherProto"; +option java_multiple_files = true; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#protodoc-title: Unified Matcher API] + +// A matcher, which may traverse a matching tree in order to result in a match action. +// During matching, the tree will be traversed until a match is found, or if no match +// is found the action specified by the most specific on_no_match will be evaluated. +// As an on_no_match might result in another matching tree being evaluated, this process +// might repeat several times until the final OnMatch (or no match) is decided. +// +// [#alpha:] +message Matcher { + // What to do if a match is successful. + message OnMatch { + oneof on_match { + option (validate.required) = true; + + // Nested matcher to evaluate. + // If the nested matcher does not match and does not specify + // on_no_match, then this matcher is considered not to have + // matched, even if a predicate at this level or above returned + // true. + Matcher matcher = 1; + + // Protocol-specific action to take. + core.v3.TypedExtensionConfig action = 2; + } + } + + // A linear list of field matchers. + // The field matchers are evaluated in order, and the first match + // wins. + message MatcherList { + // Predicate to determine if a match is successful. + message Predicate { + // Predicate for a single input field. + message SinglePredicate { + // Protocol-specific specification of input field to match on. + // [#extension-category: envoy.matching.common_inputs] + core.v3.TypedExtensionConfig input = 1 [(validate.rules).message = {required: true}]; + + oneof matcher { + option (validate.required) = true; + + // Built-in string matcher. + type.matcher.v3.StringMatcher value_match = 2; + + // Extension for custom matching logic. + // [#extension-category: envoy.matching.input_matchers] + core.v3.TypedExtensionConfig custom_match = 3; + } + } + + // A list of two or more matchers. Used to allow using a list within a oneof. + message PredicateList { + repeated Predicate predicate = 1 [(validate.rules).repeated = {min_items: 2}]; + } + + oneof match_type { + option (validate.required) = true; + + // A single predicate to evaluate. + SinglePredicate single_predicate = 1; + + // A list of predicates to be OR-ed together. + PredicateList or_matcher = 2; + + // A list of predicates to be AND-ed together. + PredicateList and_matcher = 3; + + // The invert of a predicate + Predicate not_matcher = 4; + } + } + + // An individual matcher. + message FieldMatcher { + // Determines if the match succeeds. + Predicate predicate = 1 [(validate.rules).message = {required: true}]; + + // What to do if the match succeeds. + OnMatch on_match = 2 [(validate.rules).message = {required: true}]; + } + + // A list of matchers. First match wins. + repeated FieldMatcher matchers = 1 [(validate.rules).repeated = {min_items: 1}]; + } + + message MatcherTree { + // A map of configured matchers. Used to allow using a map within a oneof. + message MatchMap { + map map = 1 [(validate.rules).map = {min_pairs: 1}]; + } + + // Protocol-specific specification of input field to match on. + core.v3.TypedExtensionConfig input = 1 [(validate.rules).message = {required: true}]; + + // Exact or prefix match maps in which to look up the input value. + // If the lookup succeeds, the match is considered successful, and + // the corresponding OnMatch is used. + oneof tree_type { + option (validate.required) = true; + + MatchMap exact_match_map = 2; + + // Longest matching prefix wins. + MatchMap prefix_match_map = 3; + + // Extension for custom matching logic. + core.v3.TypedExtensionConfig custom_match = 4; + } + } + + oneof matcher_type { + option (validate.required) = true; + + // A linear list of matchers to evaluate. + MatcherList matcher_list = 1; + + // A match tree to evaluate. + MatcherTree matcher_tree = 2; + } + + // Optional OnMatch to use if the matcher failed. + // If specified, the OnMatch is used, and the matcher is considered + // to have matched. + // If not specified, the matcher is considered not to have matched. + OnMatch on_no_match = 3; +} diff --git a/generated_api_shadow/envoy/config/common/matcher/generic/v4alpha/BUILD b/generated_api_shadow/envoy/config/common/matcher/generic/v4alpha/BUILD new file mode 100644 index 000000000000..09cd119d3a62 --- /dev/null +++ b/generated_api_shadow/envoy/config/common/matcher/generic/v4alpha/BUILD @@ -0,0 +1,14 @@ +# DO NOT EDIT. This file is generated by tools/proto_format/proto_sync.py. + +load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") + +licenses(["notice"]) # Apache 2 + +api_proto_package( + deps = [ + "//envoy/config/common/matcher/generic/v3:pkg", + "//envoy/config/core/v4alpha:pkg", + "//envoy/type/matcher/v4alpha:pkg", + "@com_github_cncf_udpa//udpa/annotations:pkg", + ], +) diff --git a/generated_api_shadow/envoy/config/common/matcher/generic/v4alpha/matcher.proto b/generated_api_shadow/envoy/config/common/matcher/generic/v4alpha/matcher.proto new file mode 100644 index 000000000000..f90fcc6e0927 --- /dev/null +++ b/generated_api_shadow/envoy/config/common/matcher/generic/v4alpha/matcher.proto @@ -0,0 +1,170 @@ +syntax = "proto3"; + +package envoy.config.common.matcher.generic.v4alpha; + +import "envoy/config/core/v4alpha/extension.proto"; +import "envoy/type/matcher/v4alpha/string.proto"; + +import "udpa/annotations/status.proto"; +import "udpa/annotations/versioning.proto"; +import "validate/validate.proto"; + +option java_package = "io.envoyproxy.envoy.config.common.matcher.generic.v4alpha"; +option java_outer_classname = "MatcherProto"; +option java_multiple_files = true; +option (udpa.annotations.file_status).package_version_status = NEXT_MAJOR_VERSION_CANDIDATE; + +// [#protodoc-title: Unified Matcher API] + +// A matcher, which may traverse a matching tree in order to result in a match action. +// During matching, the tree will be traversed until a match is found, or if no match +// is found the action specified by the most specific on_no_match will be evaluated. +// As an on_no_match might result in another matching tree being evaluated, this process +// might repeat several times until the final OnMatch (or no match) is decided. +// +// [#alpha:] +message Matcher { + option (udpa.annotations.versioning).previous_message_type = + "envoy.config.common.matcher.generic.v3.Matcher"; + + // What to do if a match is successful. + message OnMatch { + option (udpa.annotations.versioning).previous_message_type = + "envoy.config.common.matcher.generic.v3.Matcher.OnMatch"; + + oneof on_match { + option (validate.required) = true; + + // Nested matcher to evaluate. + // If the nested matcher does not match and does not specify + // on_no_match, then this matcher is considered not to have + // matched, even if a predicate at this level or above returned + // true. + Matcher matcher = 1; + + // Protocol-specific action to take. + core.v4alpha.TypedExtensionConfig action = 2; + } + } + + // A linear list of field matchers. + // The field matchers are evaluated in order, and the first match + // wins. + message MatcherList { + option (udpa.annotations.versioning).previous_message_type = + "envoy.config.common.matcher.generic.v3.Matcher.MatcherList"; + + // Predicate to determine if a match is successful. + message Predicate { + option (udpa.annotations.versioning).previous_message_type = + "envoy.config.common.matcher.generic.v3.Matcher.MatcherList.Predicate"; + + // Predicate for a single input field. + message SinglePredicate { + option (udpa.annotations.versioning).previous_message_type = + "envoy.config.common.matcher.generic.v3.Matcher.MatcherList.Predicate.SinglePredicate"; + + // Protocol-specific specification of input field to match on. + // [#extension-category: envoy.matching.common_inputs] + core.v4alpha.TypedExtensionConfig input = 1 [(validate.rules).message = {required: true}]; + + oneof matcher { + option (validate.required) = true; + + // Built-in string matcher. + type.matcher.v4alpha.StringMatcher value_match = 2; + + // Extension for custom matching logic. + // [#extension-category: envoy.matching.input_matchers] + core.v4alpha.TypedExtensionConfig custom_match = 3; + } + } + + // A list of two or more matchers. Used to allow using a list within a oneof. + message PredicateList { + option (udpa.annotations.versioning).previous_message_type = + "envoy.config.common.matcher.generic.v3.Matcher.MatcherList.Predicate.PredicateList"; + + repeated Predicate predicate = 1 [(validate.rules).repeated = {min_items: 2}]; + } + + oneof match_type { + option (validate.required) = true; + + // A single predicate to evaluate. + SinglePredicate single_predicate = 1; + + // A list of predicates to be OR-ed together. + PredicateList or_matcher = 2; + + // A list of predicates to be AND-ed together. + PredicateList and_matcher = 3; + + // The invert of a predicate + Predicate not_matcher = 4; + } + } + + // An individual matcher. + message FieldMatcher { + option (udpa.annotations.versioning).previous_message_type = + "envoy.config.common.matcher.generic.v3.Matcher.MatcherList.FieldMatcher"; + + // Determines if the match succeeds. + Predicate predicate = 1 [(validate.rules).message = {required: true}]; + + // What to do if the match succeeds. + OnMatch on_match = 2 [(validate.rules).message = {required: true}]; + } + + // A list of matchers. First match wins. + repeated FieldMatcher matchers = 1 [(validate.rules).repeated = {min_items: 1}]; + } + + message MatcherTree { + option (udpa.annotations.versioning).previous_message_type = + "envoy.config.common.matcher.generic.v3.Matcher.MatcherTree"; + + // A map of configured matchers. Used to allow using a map within a oneof. + message MatchMap { + option (udpa.annotations.versioning).previous_message_type = + "envoy.config.common.matcher.generic.v3.Matcher.MatcherTree.MatchMap"; + + map map = 1 [(validate.rules).map = {min_pairs: 1}]; + } + + // Protocol-specific specification of input field to match on. + core.v4alpha.TypedExtensionConfig input = 1 [(validate.rules).message = {required: true}]; + + // Exact or prefix match maps in which to look up the input value. + // If the lookup succeeds, the match is considered successful, and + // the corresponding OnMatch is used. + oneof tree_type { + option (validate.required) = true; + + MatchMap exact_match_map = 2; + + // Longest matching prefix wins. + MatchMap prefix_match_map = 3; + + // Extension for custom matching logic. + core.v4alpha.TypedExtensionConfig custom_match = 4; + } + } + + oneof matcher_type { + option (validate.required) = true; + + // A linear list of matchers to evaluate. + MatcherList matcher_list = 1; + + // A match tree to evaluate. + MatcherTree matcher_tree = 2; + } + + // Optional OnMatch to use if the matcher failed. + // If specified, the OnMatch is used, and the matcher is considered + // to have matched. + // If not specified, the matcher is considered not to have matched. + OnMatch on_no_match = 3; +} From 81aa2bc924b4697e22d4fc71a7a2e726d1184bd6 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Wed, 23 Jun 2021 02:38:18 +0000 Subject: [PATCH 06/44] deprecation note Signed-off-by: Snow Pettersen --- docs/root/version_history/current.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/root/version_history/current.rst b/docs/root/version_history/current.rst index 7dd83c3a9791..8052b548a954 100644 --- a/docs/root/version_history/current.rst +++ b/docs/root/version_history/current.rst @@ -121,6 +121,7 @@ New Features Deprecated ---------- +* api: the :ref:`generic matching API ` is deprecated in favor of :ref:`dns_resolution_config ` which aggregates all of the DNS resolver configuration in a single message. * cluster: the fields :ref:`use_tcp_for_dns_lookups ` and :ref:`dns_resolvers ` are deprecated in favor of :ref:`dns_resolution_config ` which aggregates all of the DNS resolver configuration in a single message. * dns_filter: the field :ref:`known_suffixes ` is deprecated. The internal data management of the filter has changed and the filter no longer uses the known_suffixes field. From 7acbde0950a8d71235575afeedbc2d64ebf6dab0 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Wed, 7 Jul 2021 13:55:52 +0000 Subject: [PATCH 07/44] add new file, make factory generic, add test Signed-off-by: Snow Pettersen --- api/envoy/extensions/common/matching/v3/BUILD | 2 + .../matching/v3/extension_matcher.proto | 8 ++- .../extensions/common/matching/v4alpha/BUILD | 2 +- .../matching/v4alpha/extension_matcher.proto | 8 ++- .../envoy/extensions/common/matching/v3/BUILD | 2 + .../matching/v3/extension_matcher.proto | 8 ++- .../extensions/common/matching/v4alpha/BUILD | 2 + .../matching/v4alpha/extension_matcher.proto | 8 ++- source/common/http/match_wrapper/config.cc | 17 +++-- source/common/matcher/matcher.h | 67 +++++++++---------- test/integration/integration_test.cc | 67 +++++++++++++++++++ 11 files changed, 146 insertions(+), 45 deletions(-) diff --git a/api/envoy/extensions/common/matching/v3/BUILD b/api/envoy/extensions/common/matching/v3/BUILD index 5fa93360e655..3a05a6fb527d 100644 --- a/api/envoy/extensions/common/matching/v3/BUILD +++ b/api/envoy/extensions/common/matching/v3/BUILD @@ -6,6 +6,8 @@ licenses(["notice"]) # Apache 2 api_proto_package( deps = [ + "//envoy/annotations:pkg", + "//envoy/config/common/matcher/generic/v3:pkg", "//envoy/config/common/matcher/v3:pkg", "//envoy/config/core/v3:pkg", "@com_github_cncf_udpa//udpa/annotations:pkg", diff --git a/api/envoy/extensions/common/matching/v3/extension_matcher.proto b/api/envoy/extensions/common/matching/v3/extension_matcher.proto index e317d885af39..e28f474b8098 100644 --- a/api/envoy/extensions/common/matching/v3/extension_matcher.proto +++ b/api/envoy/extensions/common/matching/v3/extension_matcher.proto @@ -2,9 +2,11 @@ syntax = "proto3"; package envoy.extensions.common.matching.v3; +import "envoy/config/common/matcher/generic/v3/matcher.proto"; import "envoy/config/common/matcher/v3/matcher.proto"; import "envoy/config/core/v3/extension.proto"; +import "envoy/annotations/deprecation.proto"; import "udpa/annotations/status.proto"; import "validate/validate.proto"; @@ -21,8 +23,12 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // // [#alpha:] message ExtensionWithMatcher { + // The associated matcher. This is deprecated in favor of matcher_tree. + config.common.matcher.v3.Matcher matcher = 1 + [deprecated = true, (envoy.annotations.deprecated_at_minor_version) = "3.0"]; + // The associated matcher. - config.common.matcher.v3.Matcher matcher = 1 [(validate.rules).message = {required: true}]; + config.common.matcher.generic.v3.Matcher matcher_tree = 3; // The underlying extension config. config.core.v3.TypedExtensionConfig extension_config = 2 diff --git a/api/envoy/extensions/common/matching/v4alpha/BUILD b/api/envoy/extensions/common/matching/v4alpha/BUILD index 95ccc22a554a..3bbf02df7781 100644 --- a/api/envoy/extensions/common/matching/v4alpha/BUILD +++ b/api/envoy/extensions/common/matching/v4alpha/BUILD @@ -6,7 +6,7 @@ licenses(["notice"]) # Apache 2 api_proto_package( deps = [ - "//envoy/config/common/matcher/v4alpha:pkg", + "//envoy/config/common/matcher/generic/v4alpha:pkg", "//envoy/config/core/v4alpha:pkg", "//envoy/extensions/common/matching/v3:pkg", "@com_github_cncf_udpa//udpa/annotations:pkg", diff --git a/api/envoy/extensions/common/matching/v4alpha/extension_matcher.proto b/api/envoy/extensions/common/matching/v4alpha/extension_matcher.proto index 88ac7c7570f8..61e71e5f1cfd 100644 --- a/api/envoy/extensions/common/matching/v4alpha/extension_matcher.proto +++ b/api/envoy/extensions/common/matching/v4alpha/extension_matcher.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package envoy.extensions.common.matching.v4alpha; -import "envoy/config/common/matcher/v4alpha/matcher.proto"; +import "envoy/config/common/matcher/generic/v4alpha/matcher.proto"; import "envoy/config/core/v4alpha/extension.proto"; import "udpa/annotations/status.proto"; @@ -25,8 +25,12 @@ message ExtensionWithMatcher { option (udpa.annotations.versioning).previous_message_type = "envoy.extensions.common.matching.v3.ExtensionWithMatcher"; + reserved 1; + + reserved "matcher"; + // The associated matcher. - config.common.matcher.v4alpha.Matcher matcher = 1 [(validate.rules).message = {required: true}]; + config.common.matcher.generic.v4alpha.Matcher matcher_tree = 3; // The underlying extension config. config.core.v4alpha.TypedExtensionConfig extension_config = 2 diff --git a/generated_api_shadow/envoy/extensions/common/matching/v3/BUILD b/generated_api_shadow/envoy/extensions/common/matching/v3/BUILD index 5fa93360e655..3a05a6fb527d 100644 --- a/generated_api_shadow/envoy/extensions/common/matching/v3/BUILD +++ b/generated_api_shadow/envoy/extensions/common/matching/v3/BUILD @@ -6,6 +6,8 @@ licenses(["notice"]) # Apache 2 api_proto_package( deps = [ + "//envoy/annotations:pkg", + "//envoy/config/common/matcher/generic/v3:pkg", "//envoy/config/common/matcher/v3:pkg", "//envoy/config/core/v3:pkg", "@com_github_cncf_udpa//udpa/annotations:pkg", diff --git a/generated_api_shadow/envoy/extensions/common/matching/v3/extension_matcher.proto b/generated_api_shadow/envoy/extensions/common/matching/v3/extension_matcher.proto index e317d885af39..e28f474b8098 100644 --- a/generated_api_shadow/envoy/extensions/common/matching/v3/extension_matcher.proto +++ b/generated_api_shadow/envoy/extensions/common/matching/v3/extension_matcher.proto @@ -2,9 +2,11 @@ syntax = "proto3"; package envoy.extensions.common.matching.v3; +import "envoy/config/common/matcher/generic/v3/matcher.proto"; import "envoy/config/common/matcher/v3/matcher.proto"; import "envoy/config/core/v3/extension.proto"; +import "envoy/annotations/deprecation.proto"; import "udpa/annotations/status.proto"; import "validate/validate.proto"; @@ -21,8 +23,12 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // // [#alpha:] message ExtensionWithMatcher { + // The associated matcher. This is deprecated in favor of matcher_tree. + config.common.matcher.v3.Matcher matcher = 1 + [deprecated = true, (envoy.annotations.deprecated_at_minor_version) = "3.0"]; + // The associated matcher. - config.common.matcher.v3.Matcher matcher = 1 [(validate.rules).message = {required: true}]; + config.common.matcher.generic.v3.Matcher matcher_tree = 3; // The underlying extension config. config.core.v3.TypedExtensionConfig extension_config = 2 diff --git a/generated_api_shadow/envoy/extensions/common/matching/v4alpha/BUILD b/generated_api_shadow/envoy/extensions/common/matching/v4alpha/BUILD index 95ccc22a554a..26b3a0ed9ac9 100644 --- a/generated_api_shadow/envoy/extensions/common/matching/v4alpha/BUILD +++ b/generated_api_shadow/envoy/extensions/common/matching/v4alpha/BUILD @@ -6,6 +6,8 @@ licenses(["notice"]) # Apache 2 api_proto_package( deps = [ + "//envoy/annotations:pkg", + "//envoy/config/common/matcher/generic/v4alpha:pkg", "//envoy/config/common/matcher/v4alpha:pkg", "//envoy/config/core/v4alpha:pkg", "//envoy/extensions/common/matching/v3:pkg", diff --git a/generated_api_shadow/envoy/extensions/common/matching/v4alpha/extension_matcher.proto b/generated_api_shadow/envoy/extensions/common/matching/v4alpha/extension_matcher.proto index 88ac7c7570f8..ccb30cbf03f3 100644 --- a/generated_api_shadow/envoy/extensions/common/matching/v4alpha/extension_matcher.proto +++ b/generated_api_shadow/envoy/extensions/common/matching/v4alpha/extension_matcher.proto @@ -2,9 +2,11 @@ syntax = "proto3"; package envoy.extensions.common.matching.v4alpha; +import "envoy/config/common/matcher/generic/v4alpha/matcher.proto"; import "envoy/config/common/matcher/v4alpha/matcher.proto"; import "envoy/config/core/v4alpha/extension.proto"; +import "envoy/annotations/deprecation.proto"; import "udpa/annotations/status.proto"; import "udpa/annotations/versioning.proto"; import "validate/validate.proto"; @@ -25,8 +27,12 @@ message ExtensionWithMatcher { option (udpa.annotations.versioning).previous_message_type = "envoy.extensions.common.matching.v3.ExtensionWithMatcher"; + // The associated matcher. This is deprecated in favor of matcher_tree. + config.common.matcher.v4alpha.Matcher hidden_envoy_deprecated_matcher = 1 + [deprecated = true, (envoy.annotations.deprecated_at_minor_version) = "3.0"]; + // The associated matcher. - config.common.matcher.v4alpha.Matcher matcher = 1 [(validate.rules).message = {required: true}]; + config.common.matcher.generic.v4alpha.Matcher matcher_tree = 3; // The underlying extension config. config.core.v4alpha.TypedExtensionConfig extension_config = 2 diff --git a/source/common/http/match_wrapper/config.cc b/source/common/http/match_wrapper/config.cc index 5d9ecd2f1685..8c34d83d56b9 100644 --- a/source/common/http/match_wrapper/config.cc +++ b/source/common/http/match_wrapper/config.cc @@ -103,9 +103,16 @@ Envoy::Http::FilterFactoryCb MatchWrapperConfig::createFilterFactoryFromProtoTyp MatchTreeValidationVisitor validation_visitor(*factory.matchingRequirements()); - auto match_tree = - Matcher::MatchTreeFactory(prefix, context, validation_visitor) - .create(proto_config.matcher()); + Matcher::MatchTreeFactory matcher_factory(prefix, context, + validation_visitor); + Matcher::MatchTreeFactoryCb factory_cb; + if (proto_config.has_matcher_tree()) { + factory_cb = matcher_factory.create(proto_config.matcher_tree()); + } else if (proto_config.has_matcher()) { + factory_cb = matcher_factory.create(proto_config.matcher()); + } else { + throw EnvoyException("one of `matcher` and `matcher_tree` must be set."); + } if (!validation_visitor.errors().empty()) { // TODO(snowp): Output all violations. @@ -113,8 +120,8 @@ Envoy::Http::FilterFactoryCb MatchWrapperConfig::createFilterFactoryFromProtoTyp validation_visitor.errors()[0])); } - return [filter_factory, match_tree](Envoy::Http::FilterChainFactoryCallbacks& callbacks) -> void { - DelegatingFactoryCallbacks delegated_callbacks(callbacks, match_tree()); + return [filter_factory, factory_cb](Envoy::Http::FilterChainFactoryCallbacks& callbacks) -> void { + DelegatingFactoryCallbacks delegated_callbacks(callbacks, factory_cb()); return filter_factory(delegated_callbacks); }; diff --git a/source/common/matcher/matcher.h b/source/common/matcher/matcher.h index 376e48606057..d865d34d6aa1 100644 --- a/source/common/matcher/matcher.h +++ b/source/common/matcher/matcher.h @@ -75,11 +75,12 @@ template class MatchTreeFactory { : stats_prefix_(stats_prefix), factory_context_(factory_context), validation_visitor_(validation_visitor) {} - MatchTreeFactoryCb create(const envoy::config::common::matcher::v3::Matcher& config) { + // TODO(snowp): Remove this type parameter once we only have one Matcher proto. + template MatchTreeFactoryCb create(const MatcherType& config) { switch (config.matcher_type_case()) { - case envoy::config::common::matcher::v3::Matcher::kMatcherTree: + case MatcherType::kMatcherTree: return createTreeMatcher(config); - case envoy::config::common::matcher::v3::Matcher::kMatcherList: + case MatcherType::kMatcherList: return createListMatcher(config); default: NOT_REACHED_GCOVR_EXCL_LINE; @@ -88,14 +89,15 @@ template class MatchTreeFactory { } private: - MatchTreeFactoryCb - createListMatcher(const envoy::config::common::matcher::v3::Matcher& config) { + template + MatchTreeFactoryCb createListMatcher(const MatcherType& config) { std::vector, OnMatchFactoryCb>> matcher_factories; matcher_factories.reserve(config.matcher_list().matchers().size()); for (const auto& matcher : config.matcher_list().matchers()) { - matcher_factories.push_back(std::make_pair(createFieldMatcher(matcher.predicate()), - *createOnMatch(matcher.on_match()))); + matcher_factories.push_back(std::make_pair( + createFieldMatcher(matcher.predicate()), + *createOnMatch(matcher.on_match()))); } auto on_no_match = createOnMatch(config.on_no_match()); @@ -112,13 +114,12 @@ template class MatchTreeFactory { }; } - template + template FieldMatcherFactoryCb createAggregateFieldMatcherFactoryCb( - const Protobuf::RepeatedPtrField< - envoy::config::common::matcher::v3::Matcher::MatcherList::Predicate>& predicates) { + const Protobuf::RepeatedPtrField& predicates) { std::vector> sub_matchers; for (const auto& predicate : predicates) { - sub_matchers.emplace_back(createFieldMatcher(predicate)); + sub_matchers.emplace_back(createFieldMatcher(predicate)); } return [sub_matchers]() { @@ -132,10 +133,10 @@ template class MatchTreeFactory { }; } - FieldMatcherFactoryCb createFieldMatcher( - const envoy::config::common::matcher::v3::Matcher::MatcherList::Predicate& field_predicate) { + template + FieldMatcherFactoryCb createFieldMatcher(const FieldMatcherType& field_predicate) { switch (field_predicate.match_type_case()) { - case (envoy::config::common::matcher::v3::Matcher::MatcherList::Predicate::kSinglePredicate): { + case (PredicateType::kSinglePredicate): { auto data_input = createDataInput(field_predicate.single_predicate().input()); auto input_matcher = createInputMatcher(field_predicate.single_predicate()); @@ -143,14 +144,14 @@ template class MatchTreeFactory { return std::make_unique>(data_input(), input_matcher()); }; } - case (envoy::config::common::matcher::v3::Matcher::MatcherList::Predicate::kOrMatcher): - return createAggregateFieldMatcherFactoryCb>( + case (PredicateType::kOrMatcher): + return createAggregateFieldMatcherFactoryCb, PredicateType>( field_predicate.or_matcher().predicate()); - case (envoy::config::common::matcher::v3::Matcher::MatcherList::Predicate::kAndMatcher): - return createAggregateFieldMatcherFactoryCb>( + case (PredicateType::kAndMatcher): + return createAggregateFieldMatcherFactoryCb, PredicateType>( field_predicate.and_matcher().predicate()); - case (envoy::config::common::matcher::v3::Matcher::MatcherList::Predicate::kNotMatcher): { - auto matcher_factory = createFieldMatcher(field_predicate.not_matcher()); + case (PredicateType::kNotMatcher): { + auto matcher_factory = createFieldMatcher(field_predicate.not_matcher()); return [matcher_factory]() { return std::make_unique>(matcher_factory()); @@ -161,10 +162,10 @@ template class MatchTreeFactory { } } - MatchTreeFactoryCb - createTreeMatcher(const envoy::config::common::matcher::v3::Matcher& matcher) { + template + MatchTreeFactoryCb createTreeMatcher(const MatcherType& matcher) { switch (matcher.matcher_tree().tree_type_case()) { - case envoy::config::common::matcher::v3::Matcher_MatcherTree::kExactMatchMap: { + case MatcherType::MatcherTree::kExactMatchMap: { std::vector>> match_children; match_children.reserve(matcher.matcher_tree().exact_match_map().map().size()); @@ -185,16 +186,17 @@ template class MatchTreeFactory { return multimap_matcher; }; } - case envoy::config::common::matcher::v3::Matcher_MatcherTree::kPrefixMatchMap: + case MatcherType::MatcherTree::kPrefixMatchMap: NOT_IMPLEMENTED_GCOVR_EXCL_LINE; - case envoy::config::common::matcher::v3::Matcher_MatcherTree::kCustomMatch: + case MatcherType::MatcherTree::kCustomMatch: NOT_IMPLEMENTED_GCOVR_EXCL_LINE; default: NOT_REACHED_GCOVR_EXCL_LINE; } } - absl::optional> - createOnMatch(const envoy::config::common::matcher::v3::Matcher::OnMatch& on_match) { + + template + absl::optional> createOnMatch(const OnMatchType& on_match) { if (on_match.has_matcher()) { return [matcher_factory = create(on_match.matcher())]() { return OnMatch{{}, matcher_factory()}; @@ -251,17 +253,14 @@ template class MatchTreeFactory { [common_input]() { return std::make_unique(common_input()); }; } - InputMatcherFactoryCb createInputMatcher( - const envoy::config::common::matcher::v3::Matcher::MatcherList::Predicate::SinglePredicate& - predicate) { + template + InputMatcherFactoryCb createInputMatcher(const SinglePredicateType& predicate) { switch (predicate.matcher_case()) { - case envoy::config::common::matcher::v3::Matcher::MatcherList::Predicate::SinglePredicate:: - kValueMatch: + case SinglePredicateType::kValueMatch: return [value_match = predicate.value_match()]() { return std::make_unique(value_match); }; - case envoy::config::common::matcher::v3::Matcher::MatcherList::Predicate::SinglePredicate:: - kCustomMatch: { + case SinglePredicateType::kCustomMatch: { auto& factory = Config::Utility::getAndCheckFactory(predicate.custom_match()); ProtobufTypes::MessagePtr message = Config::Utility::translateAnyToFactoryConfig( diff --git a/test/integration/integration_test.cc b/test/integration/integration_test.cc index 10c57fa1fac6..f86c0aaf6ef0 100644 --- a/test/integration/integration_test.cc +++ b/test/integration/integration_test.cc @@ -433,6 +433,73 @@ name: matcher second_codec->close(); } +// Verifies that we can construct a match tree with a filter using the new matcher tree proto, and +// that we are able to skip filter invocation through the match tree. +TEST_P(IntegrationTest, MatchingHttpFilterConstructionNewProto) { + concurrency_ = 2; + config_helper_.addRuntimeOverride("envoy.reloadable_features.experimental_matching_api", "true"); + + config_helper_.addFilter(R"EOF( +name: matcher +typed_config: + "@type": type.googleapis.com/envoy.extensions.common.matching.v3.ExtensionWithMatcher + extension_config: + name: set-response-code + typed_config: + "@type": type.googleapis.com/test.integration.filters.SetResponseCodeFilterConfig + code: 403 + matcher_tree: + matcher_tree: + input: + name: request-headers + typed_config: + "@type": type.googleapis.com/envoy.type.matcher.v3.HttpRequestHeaderMatchInput + header_name: match-header + exact_match_map: + map: + match: + action: + name: skip + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.common.matcher.action.v3.SkipFilter +)EOF"); + + initialize(); + + codec_client_ = makeHttpConnection(lookupPort("http")); + + { + auto response = codec_client_->makeRequestWithBody(default_request_headers_, 1024); + ASSERT_TRUE(response->waitForEndStream()); + EXPECT_THAT(response->headers(), HttpStatusIs("403")); + } + + { + codec_client_ = makeHttpConnection(lookupPort("http")); + Http::TestRequestHeaderMapImpl request_headers{ + {":method", "POST"}, {":path", "/test/long/url"}, {":scheme", "http"}, + {":authority", "host"}, {"match-header", "match"}, {"content-type", "application/grpc"}}; + auto response = codec_client_->makeRequestWithBody(request_headers, 1024); + waitForNextUpstreamRequest(); + upstream_request_->encodeHeaders(default_response_headers_, true); + + ASSERT_TRUE(response->waitForEndStream()); + EXPECT_THAT(response->headers(), HttpStatusIs("200")); + } + + auto second_codec = makeHttpConnection(lookupPort("http")); + Http::TestRequestHeaderMapImpl request_headers{ + {":method", "POST"}, {":path", "/test/long/url"}, {":scheme", "http"}, + {":authority", "host"}, {"match-header", "not-match"}, {"content-type", "application/grpc"}}; + auto response = second_codec->makeRequestWithBody(request_headers, 1024); + + ASSERT_TRUE(response->waitForEndStream()); + EXPECT_THAT(response->headers(), HttpStatusIs("200")); + + codec_client_->close(); + second_codec->close(); +} + // This is a regression for https://github.com/envoyproxy/envoy/issues/2715 and validates that a // pending request is not sent on a connection that has been half-closed. TEST_P(IntegrationTest, UpstreamDisconnectWithTwoRequests) { From 98100c7f3fbcc1b04ee20bd6bcde7c26b271f0bb Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Wed, 7 Jul 2021 17:06:29 +0000 Subject: [PATCH 08/44] fix docs Signed-off-by: Snow Pettersen --- docs/root/api-v3/common_messages/common_messages.rst | 1 + docs/root/version_history/current.rst | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/root/api-v3/common_messages/common_messages.rst b/docs/root/api-v3/common_messages/common_messages.rst index ea123c074ca1..b12f61b91cca 100644 --- a/docs/root/api-v3/common_messages/common_messages.rst +++ b/docs/root/api-v3/common_messages/common_messages.rst @@ -5,6 +5,7 @@ Common messages :glob: :maxdepth: 2 + ../config/common/matcher/generic/v3/matcher.proto ../config/core/v3/base.proto ../config/core/v3/extension.proto ../config/core/v3/address.proto diff --git a/docs/root/version_history/current.rst b/docs/root/version_history/current.rst index 4a072f7fa84a..3286eb1b60c3 100644 --- a/docs/root/version_history/current.rst +++ b/docs/root/version_history/current.rst @@ -127,7 +127,8 @@ New Features Deprecated ---------- -* api: the :ref:`generic matching API ` field has been deprecated in favor of + :ref:`matcher ` in order to break a build dependency. * bootstrap: the field :ref:`use_tcp_for_dns_lookups ` is deprecated in favor of :ref:`dns_resolution_config ` which aggregates all of the DNS resolver configuration in a single message. * cluster: the fields :ref:`use_tcp_for_dns_lookups ` and :ref:`dns_resolvers ` are deprecated in favor of :ref:`dns_resolution_config ` which aggregates all of the DNS resolver configuration in a single message. * dns_filter: the field :ref:`known_suffixes ` is deprecated. The internal data management of the filter has changed and the filter no longer uses the known_suffixes field. From fd009246985fbc09d326b8c3b79862a61a720485 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Wed, 7 Jul 2021 17:11:10 +0000 Subject: [PATCH 09/44] add alpha exception Signed-off-by: Snow Pettersen --- api/API_VERSIONING.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/api/API_VERSIONING.md b/api/API_VERSIONING.md index 3f5d41e710a9..8f8b72665d96 100644 --- a/api/API_VERSIONING.md +++ b/api/API_VERSIONING.md @@ -67,6 +67,8 @@ experience a backward compatible break on a change. Specifically: may be granted for scenarios in which these stricter conditions model behavior already implied structurally or by documentation. +* Messages marked as [#alpha:] are excluded from the backwards compatibility guarantees. + An exception to the above policy exists for: * Changes made within 14 days of the introduction of a new API field or message. * API versions tagged `vNalpha`. Within an alpha major version, arbitrary breaking changes are allowed. From 28bf418879f05cb234407518af44778eaf814fd9 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Fri, 9 Jul 2021 03:20:38 +0000 Subject: [PATCH 10/44] fix examples Signed-off-by: Snow Pettersen --- .../arch_overview/advanced/matching/_include/complicated.yaml | 2 +- .../advanced/matching/_include/request_response.yaml | 2 +- .../intro/arch_overview/advanced/matching/_include/simple.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/root/intro/arch_overview/advanced/matching/_include/complicated.yaml b/docs/root/intro/arch_overview/advanced/matching/_include/complicated.yaml index 9efc4cbf217e..afc33ba6948d 100644 --- a/docs/root/intro/arch_overview/advanced/matching/_include/complicated.yaml +++ b/docs/root/intro/arch_overview/advanced/matching/_include/complicated.yaml @@ -29,7 +29,7 @@ static_resources: percentage: numerator: 0 denominator: HUNDRED - matcher: + matcher_tree: # The top level matcher is a matcher tree which conceptually selects one of several subtrees. matcher_tree: input: diff --git a/docs/root/intro/arch_overview/advanced/matching/_include/request_response.yaml b/docs/root/intro/arch_overview/advanced/matching/_include/request_response.yaml index bf4721e48e24..a33f49f84de2 100644 --- a/docs/root/intro/arch_overview/advanced/matching/_include/request_response.yaml +++ b/docs/root/intro/arch_overview/advanced/matching/_include/request_response.yaml @@ -29,7 +29,7 @@ static_resources: percentage: numerator: 0 denominator: HUNDRED - matcher: + matcher_tree: matcher_list: matchers: - predicate: diff --git a/docs/root/intro/arch_overview/advanced/matching/_include/simple.yaml b/docs/root/intro/arch_overview/advanced/matching/_include/simple.yaml index 836deb819182..a55be6eedc8a 100644 --- a/docs/root/intro/arch_overview/advanced/matching/_include/simple.yaml +++ b/docs/root/intro/arch_overview/advanced/matching/_include/simple.yaml @@ -29,7 +29,7 @@ static_resources: percentage: numerator: 0 denominator: HUNDRED - matcher: + matcher_tree: matcher_tree: input: name: request-headers From a4b752b82277eac3fcba947f55f64bfe8060a514 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Fri, 9 Jul 2021 19:22:46 +0000 Subject: [PATCH 11/44] use udpa version Signed-off-by: Snow Pettersen --- api/BUILD | 1 - api/bazel/repository_locations.bzl | 4 +- .../config/common/matcher/generic/v3/BUILD | 13 -- .../common/matcher/generic/v3/matcher.proto | 142 --------------- .../common/matcher/generic/v4alpha/BUILD | 14 -- .../matcher/generic/v4alpha/matcher.proto | 170 ------------------ api/envoy/extensions/common/matching/v3/BUILD | 2 +- .../matching/v3/extension_matcher.proto | 7 +- .../extensions/common/matching/v4alpha/BUILD | 2 +- .../matching/v4alpha/extension_matcher.proto | 5 +- api/versioning/BUILD | 1 - generated_api_shadow/BUILD | 1 - .../bazel/repository_locations.bzl | 4 +- .../config/common/matcher/generic/v3/BUILD | 13 -- .../common/matcher/generic/v3/matcher.proto | 142 --------------- .../common/matcher/generic/v4alpha/BUILD | 14 -- .../matcher/generic/v4alpha/matcher.proto | 170 ------------------ .../envoy/extensions/common/matching/v3/BUILD | 2 +- .../matching/v3/extension_matcher.proto | 7 +- .../extensions/common/matching/v4alpha/BUILD | 2 +- .../matching/v4alpha/extension_matcher.proto | 7 +- source/common/common/BUILD | 1 + source/common/common/matchers.cc | 62 +------ source/common/common/matchers.h | 68 ++++++- source/common/common/regex.cc | 121 +++++-------- source/common/common/regex.h | 40 ++++- source/common/http/match_wrapper/config.cc | 4 +- source/common/matcher/matcher.h | 7 +- source/common/matcher/value_input_matcher.h | 7 +- source/common/router/config_impl.cc | 4 +- source/common/router/config_utility.cc | 2 +- source/common/router/config_utility.h | 3 +- source/common/stats/histogram_impl.h | 3 +- source/common/stats/stats_matcher_impl.h | 2 +- source/common/upstream/health_checker_impl.h | 3 +- .../tls/cert_validator/default_validator.cc | 7 +- .../tls/cert_validator/default_validator.h | 17 +- test/integration/integration_test.cc | 2 +- tools/proto_format/proto_sync.py | 3 + 39 files changed, 211 insertions(+), 868 deletions(-) delete mode 100644 api/envoy/config/common/matcher/generic/v3/BUILD delete mode 100644 api/envoy/config/common/matcher/generic/v3/matcher.proto delete mode 100644 api/envoy/config/common/matcher/generic/v4alpha/BUILD delete mode 100644 api/envoy/config/common/matcher/generic/v4alpha/matcher.proto delete mode 100644 generated_api_shadow/envoy/config/common/matcher/generic/v3/BUILD delete mode 100644 generated_api_shadow/envoy/config/common/matcher/generic/v3/matcher.proto delete mode 100644 generated_api_shadow/envoy/config/common/matcher/generic/v4alpha/BUILD delete mode 100644 generated_api_shadow/envoy/config/common/matcher/generic/v4alpha/matcher.proto diff --git a/api/BUILD b/api/BUILD index 94fea47904d4..4b11cc147633 100644 --- a/api/BUILD +++ b/api/BUILD @@ -68,7 +68,6 @@ proto_library( "//envoy/config/accesslog/v3:pkg", "//envoy/config/bootstrap/v3:pkg", "//envoy/config/cluster/v3:pkg", - "//envoy/config/common/matcher/generic/v3:pkg", "//envoy/config/common/matcher/v3:pkg", "//envoy/config/core/v3:pkg", "//envoy/config/endpoint/v3:pkg", diff --git a/api/bazel/repository_locations.bzl b/api/bazel/repository_locations.bzl index 968c6a9ffa28..6f5f50941052 100644 --- a/api/bazel/repository_locations.bzl +++ b/api/bazel/repository_locations.bzl @@ -44,8 +44,8 @@ REPOSITORY_LOCATIONS_SPEC = dict( project_desc = "xDS API Working Group (xDS-WG)", project_url = "https://github.com/cncf/xds", # During the UDPA -> xDS migration, we aren't working with releases. - version = "b88cc788a63e5b38ee334a2e702c67901355ae2c", - sha256 = "3220df8564f217665b6e17776569c5f748178c2b9cbf83bb55a13ddc0a3738f0", + version = "2e5c007c8982836cda87a125fb95fc0b5057fe3a", + sha256 = "e9c751599f69549027aacd8cdc30c0e7b55d9b61ba351739abed705ed667d2b1", release_date = "2021-03-23", strip_prefix = "xds-{version}", urls = ["https://github.com/cncf/xds/archive/{version}.tar.gz"], diff --git a/api/envoy/config/common/matcher/generic/v3/BUILD b/api/envoy/config/common/matcher/generic/v3/BUILD deleted file mode 100644 index 3f3a5395d2aa..000000000000 --- a/api/envoy/config/common/matcher/generic/v3/BUILD +++ /dev/null @@ -1,13 +0,0 @@ -# DO NOT EDIT. This file is generated by tools/proto_format/proto_sync.py. - -load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") - -licenses(["notice"]) # Apache 2 - -api_proto_package( - deps = [ - "//envoy/config/core/v3:pkg", - "//envoy/type/matcher/v3:pkg", - "@com_github_cncf_udpa//udpa/annotations:pkg", - ], -) diff --git a/api/envoy/config/common/matcher/generic/v3/matcher.proto b/api/envoy/config/common/matcher/generic/v3/matcher.proto deleted file mode 100644 index 1113fa07adf3..000000000000 --- a/api/envoy/config/common/matcher/generic/v3/matcher.proto +++ /dev/null @@ -1,142 +0,0 @@ -syntax = "proto3"; - -package envoy.config.common.matcher.generic.v3; - -import "envoy/config/core/v3/extension.proto"; -import "envoy/type/matcher/v3/string.proto"; - -import "udpa/annotations/status.proto"; -import "validate/validate.proto"; - -option java_package = "io.envoyproxy.envoy.config.common.matcher.generic.v3"; -option java_outer_classname = "MatcherProto"; -option java_multiple_files = true; -option (udpa.annotations.file_status).package_version_status = ACTIVE; - -// [#protodoc-title: Unified Matcher API] - -// A matcher, which may traverse a matching tree in order to result in a match action. -// During matching, the tree will be traversed until a match is found, or if no match -// is found the action specified by the most specific on_no_match will be evaluated. -// As an on_no_match might result in another matching tree being evaluated, this process -// might repeat several times until the final OnMatch (or no match) is decided. -// -// [#alpha:] -message Matcher { - // What to do if a match is successful. - message OnMatch { - oneof on_match { - option (validate.required) = true; - - // Nested matcher to evaluate. - // If the nested matcher does not match and does not specify - // on_no_match, then this matcher is considered not to have - // matched, even if a predicate at this level or above returned - // true. - Matcher matcher = 1; - - // Protocol-specific action to take. - core.v3.TypedExtensionConfig action = 2; - } - } - - // A linear list of field matchers. - // The field matchers are evaluated in order, and the first match - // wins. - message MatcherList { - // Predicate to determine if a match is successful. - message Predicate { - // Predicate for a single input field. - message SinglePredicate { - // Protocol-specific specification of input field to match on. - // [#extension-category: envoy.matching.common_inputs] - core.v3.TypedExtensionConfig input = 1 [(validate.rules).message = {required: true}]; - - oneof matcher { - option (validate.required) = true; - - // Built-in string matcher. - type.matcher.v3.StringMatcher value_match = 2; - - // Extension for custom matching logic. - // [#extension-category: envoy.matching.input_matchers] - core.v3.TypedExtensionConfig custom_match = 3; - } - } - - // A list of two or more matchers. Used to allow using a list within a oneof. - message PredicateList { - repeated Predicate predicate = 1 [(validate.rules).repeated = {min_items: 2}]; - } - - oneof match_type { - option (validate.required) = true; - - // A single predicate to evaluate. - SinglePredicate single_predicate = 1; - - // A list of predicates to be OR-ed together. - PredicateList or_matcher = 2; - - // A list of predicates to be AND-ed together. - PredicateList and_matcher = 3; - - // The invert of a predicate - Predicate not_matcher = 4; - } - } - - // An individual matcher. - message FieldMatcher { - // Determines if the match succeeds. - Predicate predicate = 1 [(validate.rules).message = {required: true}]; - - // What to do if the match succeeds. - OnMatch on_match = 2 [(validate.rules).message = {required: true}]; - } - - // A list of matchers. First match wins. - repeated FieldMatcher matchers = 1 [(validate.rules).repeated = {min_items: 1}]; - } - - message MatcherTree { - // A map of configured matchers. Used to allow using a map within a oneof. - message MatchMap { - map map = 1 [(validate.rules).map = {min_pairs: 1}]; - } - - // Protocol-specific specification of input field to match on. - core.v3.TypedExtensionConfig input = 1 [(validate.rules).message = {required: true}]; - - // Exact or prefix match maps in which to look up the input value. - // If the lookup succeeds, the match is considered successful, and - // the corresponding OnMatch is used. - oneof tree_type { - option (validate.required) = true; - - MatchMap exact_match_map = 2; - - // Longest matching prefix wins. - MatchMap prefix_match_map = 3; - - // Extension for custom matching logic. - core.v3.TypedExtensionConfig custom_match = 4; - } - } - - oneof matcher_type { - option (validate.required) = true; - - // A linear list of matchers to evaluate. - MatcherList matcher_list = 1; - - // A match tree to evaluate. - MatcherTree matcher_tree = 2; - } - - // Optional OnMatch to use if the matcher failed. - // If specified, the OnMatch is used, and the matcher is considered - // to have matched. - // If not specified, the matcher is considered not to have matched. - OnMatch on_no_match = 3; -} diff --git a/api/envoy/config/common/matcher/generic/v4alpha/BUILD b/api/envoy/config/common/matcher/generic/v4alpha/BUILD deleted file mode 100644 index 09cd119d3a62..000000000000 --- a/api/envoy/config/common/matcher/generic/v4alpha/BUILD +++ /dev/null @@ -1,14 +0,0 @@ -# DO NOT EDIT. This file is generated by tools/proto_format/proto_sync.py. - -load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") - -licenses(["notice"]) # Apache 2 - -api_proto_package( - deps = [ - "//envoy/config/common/matcher/generic/v3:pkg", - "//envoy/config/core/v4alpha:pkg", - "//envoy/type/matcher/v4alpha:pkg", - "@com_github_cncf_udpa//udpa/annotations:pkg", - ], -) diff --git a/api/envoy/config/common/matcher/generic/v4alpha/matcher.proto b/api/envoy/config/common/matcher/generic/v4alpha/matcher.proto deleted file mode 100644 index f90fcc6e0927..000000000000 --- a/api/envoy/config/common/matcher/generic/v4alpha/matcher.proto +++ /dev/null @@ -1,170 +0,0 @@ -syntax = "proto3"; - -package envoy.config.common.matcher.generic.v4alpha; - -import "envoy/config/core/v4alpha/extension.proto"; -import "envoy/type/matcher/v4alpha/string.proto"; - -import "udpa/annotations/status.proto"; -import "udpa/annotations/versioning.proto"; -import "validate/validate.proto"; - -option java_package = "io.envoyproxy.envoy.config.common.matcher.generic.v4alpha"; -option java_outer_classname = "MatcherProto"; -option java_multiple_files = true; -option (udpa.annotations.file_status).package_version_status = NEXT_MAJOR_VERSION_CANDIDATE; - -// [#protodoc-title: Unified Matcher API] - -// A matcher, which may traverse a matching tree in order to result in a match action. -// During matching, the tree will be traversed until a match is found, or if no match -// is found the action specified by the most specific on_no_match will be evaluated. -// As an on_no_match might result in another matching tree being evaluated, this process -// might repeat several times until the final OnMatch (or no match) is decided. -// -// [#alpha:] -message Matcher { - option (udpa.annotations.versioning).previous_message_type = - "envoy.config.common.matcher.generic.v3.Matcher"; - - // What to do if a match is successful. - message OnMatch { - option (udpa.annotations.versioning).previous_message_type = - "envoy.config.common.matcher.generic.v3.Matcher.OnMatch"; - - oneof on_match { - option (validate.required) = true; - - // Nested matcher to evaluate. - // If the nested matcher does not match and does not specify - // on_no_match, then this matcher is considered not to have - // matched, even if a predicate at this level or above returned - // true. - Matcher matcher = 1; - - // Protocol-specific action to take. - core.v4alpha.TypedExtensionConfig action = 2; - } - } - - // A linear list of field matchers. - // The field matchers are evaluated in order, and the first match - // wins. - message MatcherList { - option (udpa.annotations.versioning).previous_message_type = - "envoy.config.common.matcher.generic.v3.Matcher.MatcherList"; - - // Predicate to determine if a match is successful. - message Predicate { - option (udpa.annotations.versioning).previous_message_type = - "envoy.config.common.matcher.generic.v3.Matcher.MatcherList.Predicate"; - - // Predicate for a single input field. - message SinglePredicate { - option (udpa.annotations.versioning).previous_message_type = - "envoy.config.common.matcher.generic.v3.Matcher.MatcherList.Predicate.SinglePredicate"; - - // Protocol-specific specification of input field to match on. - // [#extension-category: envoy.matching.common_inputs] - core.v4alpha.TypedExtensionConfig input = 1 [(validate.rules).message = {required: true}]; - - oneof matcher { - option (validate.required) = true; - - // Built-in string matcher. - type.matcher.v4alpha.StringMatcher value_match = 2; - - // Extension for custom matching logic. - // [#extension-category: envoy.matching.input_matchers] - core.v4alpha.TypedExtensionConfig custom_match = 3; - } - } - - // A list of two or more matchers. Used to allow using a list within a oneof. - message PredicateList { - option (udpa.annotations.versioning).previous_message_type = - "envoy.config.common.matcher.generic.v3.Matcher.MatcherList.Predicate.PredicateList"; - - repeated Predicate predicate = 1 [(validate.rules).repeated = {min_items: 2}]; - } - - oneof match_type { - option (validate.required) = true; - - // A single predicate to evaluate. - SinglePredicate single_predicate = 1; - - // A list of predicates to be OR-ed together. - PredicateList or_matcher = 2; - - // A list of predicates to be AND-ed together. - PredicateList and_matcher = 3; - - // The invert of a predicate - Predicate not_matcher = 4; - } - } - - // An individual matcher. - message FieldMatcher { - option (udpa.annotations.versioning).previous_message_type = - "envoy.config.common.matcher.generic.v3.Matcher.MatcherList.FieldMatcher"; - - // Determines if the match succeeds. - Predicate predicate = 1 [(validate.rules).message = {required: true}]; - - // What to do if the match succeeds. - OnMatch on_match = 2 [(validate.rules).message = {required: true}]; - } - - // A list of matchers. First match wins. - repeated FieldMatcher matchers = 1 [(validate.rules).repeated = {min_items: 1}]; - } - - message MatcherTree { - option (udpa.annotations.versioning).previous_message_type = - "envoy.config.common.matcher.generic.v3.Matcher.MatcherTree"; - - // A map of configured matchers. Used to allow using a map within a oneof. - message MatchMap { - option (udpa.annotations.versioning).previous_message_type = - "envoy.config.common.matcher.generic.v3.Matcher.MatcherTree.MatchMap"; - - map map = 1 [(validate.rules).map = {min_pairs: 1}]; - } - - // Protocol-specific specification of input field to match on. - core.v4alpha.TypedExtensionConfig input = 1 [(validate.rules).message = {required: true}]; - - // Exact or prefix match maps in which to look up the input value. - // If the lookup succeeds, the match is considered successful, and - // the corresponding OnMatch is used. - oneof tree_type { - option (validate.required) = true; - - MatchMap exact_match_map = 2; - - // Longest matching prefix wins. - MatchMap prefix_match_map = 3; - - // Extension for custom matching logic. - core.v4alpha.TypedExtensionConfig custom_match = 4; - } - } - - oneof matcher_type { - option (validate.required) = true; - - // A linear list of matchers to evaluate. - MatcherList matcher_list = 1; - - // A match tree to evaluate. - MatcherTree matcher_tree = 2; - } - - // Optional OnMatch to use if the matcher failed. - // If specified, the OnMatch is used, and the matcher is considered - // to have matched. - // If not specified, the matcher is considered not to have matched. - OnMatch on_no_match = 3; -} diff --git a/api/envoy/extensions/common/matching/v3/BUILD b/api/envoy/extensions/common/matching/v3/BUILD index 3a05a6fb527d..42b094a2dcd8 100644 --- a/api/envoy/extensions/common/matching/v3/BUILD +++ b/api/envoy/extensions/common/matching/v3/BUILD @@ -7,9 +7,9 @@ licenses(["notice"]) # Apache 2 api_proto_package( deps = [ "//envoy/annotations:pkg", - "//envoy/config/common/matcher/generic/v3:pkg", "//envoy/config/common/matcher/v3:pkg", "//envoy/config/core/v3:pkg", "@com_github_cncf_udpa//udpa/annotations:pkg", + "@com_github_cncf_udpa//udpa/type/matcher/v1:pkg", ], ) diff --git a/api/envoy/extensions/common/matching/v3/extension_matcher.proto b/api/envoy/extensions/common/matching/v3/extension_matcher.proto index e28f474b8098..251848705e1e 100644 --- a/api/envoy/extensions/common/matching/v3/extension_matcher.proto +++ b/api/envoy/extensions/common/matching/v3/extension_matcher.proto @@ -2,10 +2,11 @@ syntax = "proto3"; package envoy.extensions.common.matching.v3; -import "envoy/config/common/matcher/generic/v3/matcher.proto"; import "envoy/config/common/matcher/v3/matcher.proto"; import "envoy/config/core/v3/extension.proto"; +import "udpa/type/matcher/v1/matcher.proto"; + import "envoy/annotations/deprecation.proto"; import "udpa/annotations/status.proto"; import "validate/validate.proto"; @@ -23,12 +24,12 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // // [#alpha:] message ExtensionWithMatcher { - // The associated matcher. This is deprecated in favor of matcher_tree. + // The associated matcher. This is deprecated in favor of udpa_matcher. config.common.matcher.v3.Matcher matcher = 1 [deprecated = true, (envoy.annotations.deprecated_at_minor_version) = "3.0"]; // The associated matcher. - config.common.matcher.generic.v3.Matcher matcher_tree = 3; + udpa.type.matcher.v1.Matcher udpa_matcher = 3; // The underlying extension config. config.core.v3.TypedExtensionConfig extension_config = 2 diff --git a/api/envoy/extensions/common/matching/v4alpha/BUILD b/api/envoy/extensions/common/matching/v4alpha/BUILD index 3bbf02df7781..f3cc645b10ee 100644 --- a/api/envoy/extensions/common/matching/v4alpha/BUILD +++ b/api/envoy/extensions/common/matching/v4alpha/BUILD @@ -6,9 +6,9 @@ licenses(["notice"]) # Apache 2 api_proto_package( deps = [ - "//envoy/config/common/matcher/generic/v4alpha:pkg", "//envoy/config/core/v4alpha:pkg", "//envoy/extensions/common/matching/v3:pkg", "@com_github_cncf_udpa//udpa/annotations:pkg", + "@com_github_cncf_udpa//udpa/type/matcher/v1:pkg", ], ) diff --git a/api/envoy/extensions/common/matching/v4alpha/extension_matcher.proto b/api/envoy/extensions/common/matching/v4alpha/extension_matcher.proto index 61e71e5f1cfd..c361fcd0e823 100644 --- a/api/envoy/extensions/common/matching/v4alpha/extension_matcher.proto +++ b/api/envoy/extensions/common/matching/v4alpha/extension_matcher.proto @@ -2,9 +2,10 @@ syntax = "proto3"; package envoy.extensions.common.matching.v4alpha; -import "envoy/config/common/matcher/generic/v4alpha/matcher.proto"; import "envoy/config/core/v4alpha/extension.proto"; +import "udpa/type/matcher/v1/matcher.proto"; + import "udpa/annotations/status.proto"; import "udpa/annotations/versioning.proto"; import "validate/validate.proto"; @@ -30,7 +31,7 @@ message ExtensionWithMatcher { reserved "matcher"; // The associated matcher. - config.common.matcher.generic.v4alpha.Matcher matcher_tree = 3; + udpa.type.matcher.v1.Matcher udpa_matcher = 3; // The underlying extension config. config.core.v4alpha.TypedExtensionConfig extension_config = 2 diff --git a/api/versioning/BUILD b/api/versioning/BUILD index e297f3b55d25..51bc63183a1c 100644 --- a/api/versioning/BUILD +++ b/api/versioning/BUILD @@ -13,7 +13,6 @@ proto_library( "//envoy/config/accesslog/v3:pkg", "//envoy/config/bootstrap/v3:pkg", "//envoy/config/cluster/v3:pkg", - "//envoy/config/common/matcher/generic/v3:pkg", "//envoy/config/common/matcher/v3:pkg", "//envoy/config/core/v3:pkg", "//envoy/config/endpoint/v3:pkg", diff --git a/generated_api_shadow/BUILD b/generated_api_shadow/BUILD index 94fea47904d4..4b11cc147633 100644 --- a/generated_api_shadow/BUILD +++ b/generated_api_shadow/BUILD @@ -68,7 +68,6 @@ proto_library( "//envoy/config/accesslog/v3:pkg", "//envoy/config/bootstrap/v3:pkg", "//envoy/config/cluster/v3:pkg", - "//envoy/config/common/matcher/generic/v3:pkg", "//envoy/config/common/matcher/v3:pkg", "//envoy/config/core/v3:pkg", "//envoy/config/endpoint/v3:pkg", diff --git a/generated_api_shadow/bazel/repository_locations.bzl b/generated_api_shadow/bazel/repository_locations.bzl index 968c6a9ffa28..6f5f50941052 100644 --- a/generated_api_shadow/bazel/repository_locations.bzl +++ b/generated_api_shadow/bazel/repository_locations.bzl @@ -44,8 +44,8 @@ REPOSITORY_LOCATIONS_SPEC = dict( project_desc = "xDS API Working Group (xDS-WG)", project_url = "https://github.com/cncf/xds", # During the UDPA -> xDS migration, we aren't working with releases. - version = "b88cc788a63e5b38ee334a2e702c67901355ae2c", - sha256 = "3220df8564f217665b6e17776569c5f748178c2b9cbf83bb55a13ddc0a3738f0", + version = "2e5c007c8982836cda87a125fb95fc0b5057fe3a", + sha256 = "e9c751599f69549027aacd8cdc30c0e7b55d9b61ba351739abed705ed667d2b1", release_date = "2021-03-23", strip_prefix = "xds-{version}", urls = ["https://github.com/cncf/xds/archive/{version}.tar.gz"], diff --git a/generated_api_shadow/envoy/config/common/matcher/generic/v3/BUILD b/generated_api_shadow/envoy/config/common/matcher/generic/v3/BUILD deleted file mode 100644 index 3f3a5395d2aa..000000000000 --- a/generated_api_shadow/envoy/config/common/matcher/generic/v3/BUILD +++ /dev/null @@ -1,13 +0,0 @@ -# DO NOT EDIT. This file is generated by tools/proto_format/proto_sync.py. - -load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") - -licenses(["notice"]) # Apache 2 - -api_proto_package( - deps = [ - "//envoy/config/core/v3:pkg", - "//envoy/type/matcher/v3:pkg", - "@com_github_cncf_udpa//udpa/annotations:pkg", - ], -) diff --git a/generated_api_shadow/envoy/config/common/matcher/generic/v3/matcher.proto b/generated_api_shadow/envoy/config/common/matcher/generic/v3/matcher.proto deleted file mode 100644 index 1113fa07adf3..000000000000 --- a/generated_api_shadow/envoy/config/common/matcher/generic/v3/matcher.proto +++ /dev/null @@ -1,142 +0,0 @@ -syntax = "proto3"; - -package envoy.config.common.matcher.generic.v3; - -import "envoy/config/core/v3/extension.proto"; -import "envoy/type/matcher/v3/string.proto"; - -import "udpa/annotations/status.proto"; -import "validate/validate.proto"; - -option java_package = "io.envoyproxy.envoy.config.common.matcher.generic.v3"; -option java_outer_classname = "MatcherProto"; -option java_multiple_files = true; -option (udpa.annotations.file_status).package_version_status = ACTIVE; - -// [#protodoc-title: Unified Matcher API] - -// A matcher, which may traverse a matching tree in order to result in a match action. -// During matching, the tree will be traversed until a match is found, or if no match -// is found the action specified by the most specific on_no_match will be evaluated. -// As an on_no_match might result in another matching tree being evaluated, this process -// might repeat several times until the final OnMatch (or no match) is decided. -// -// [#alpha:] -message Matcher { - // What to do if a match is successful. - message OnMatch { - oneof on_match { - option (validate.required) = true; - - // Nested matcher to evaluate. - // If the nested matcher does not match and does not specify - // on_no_match, then this matcher is considered not to have - // matched, even if a predicate at this level or above returned - // true. - Matcher matcher = 1; - - // Protocol-specific action to take. - core.v3.TypedExtensionConfig action = 2; - } - } - - // A linear list of field matchers. - // The field matchers are evaluated in order, and the first match - // wins. - message MatcherList { - // Predicate to determine if a match is successful. - message Predicate { - // Predicate for a single input field. - message SinglePredicate { - // Protocol-specific specification of input field to match on. - // [#extension-category: envoy.matching.common_inputs] - core.v3.TypedExtensionConfig input = 1 [(validate.rules).message = {required: true}]; - - oneof matcher { - option (validate.required) = true; - - // Built-in string matcher. - type.matcher.v3.StringMatcher value_match = 2; - - // Extension for custom matching logic. - // [#extension-category: envoy.matching.input_matchers] - core.v3.TypedExtensionConfig custom_match = 3; - } - } - - // A list of two or more matchers. Used to allow using a list within a oneof. - message PredicateList { - repeated Predicate predicate = 1 [(validate.rules).repeated = {min_items: 2}]; - } - - oneof match_type { - option (validate.required) = true; - - // A single predicate to evaluate. - SinglePredicate single_predicate = 1; - - // A list of predicates to be OR-ed together. - PredicateList or_matcher = 2; - - // A list of predicates to be AND-ed together. - PredicateList and_matcher = 3; - - // The invert of a predicate - Predicate not_matcher = 4; - } - } - - // An individual matcher. - message FieldMatcher { - // Determines if the match succeeds. - Predicate predicate = 1 [(validate.rules).message = {required: true}]; - - // What to do if the match succeeds. - OnMatch on_match = 2 [(validate.rules).message = {required: true}]; - } - - // A list of matchers. First match wins. - repeated FieldMatcher matchers = 1 [(validate.rules).repeated = {min_items: 1}]; - } - - message MatcherTree { - // A map of configured matchers. Used to allow using a map within a oneof. - message MatchMap { - map map = 1 [(validate.rules).map = {min_pairs: 1}]; - } - - // Protocol-specific specification of input field to match on. - core.v3.TypedExtensionConfig input = 1 [(validate.rules).message = {required: true}]; - - // Exact or prefix match maps in which to look up the input value. - // If the lookup succeeds, the match is considered successful, and - // the corresponding OnMatch is used. - oneof tree_type { - option (validate.required) = true; - - MatchMap exact_match_map = 2; - - // Longest matching prefix wins. - MatchMap prefix_match_map = 3; - - // Extension for custom matching logic. - core.v3.TypedExtensionConfig custom_match = 4; - } - } - - oneof matcher_type { - option (validate.required) = true; - - // A linear list of matchers to evaluate. - MatcherList matcher_list = 1; - - // A match tree to evaluate. - MatcherTree matcher_tree = 2; - } - - // Optional OnMatch to use if the matcher failed. - // If specified, the OnMatch is used, and the matcher is considered - // to have matched. - // If not specified, the matcher is considered not to have matched. - OnMatch on_no_match = 3; -} diff --git a/generated_api_shadow/envoy/config/common/matcher/generic/v4alpha/BUILD b/generated_api_shadow/envoy/config/common/matcher/generic/v4alpha/BUILD deleted file mode 100644 index 09cd119d3a62..000000000000 --- a/generated_api_shadow/envoy/config/common/matcher/generic/v4alpha/BUILD +++ /dev/null @@ -1,14 +0,0 @@ -# DO NOT EDIT. This file is generated by tools/proto_format/proto_sync.py. - -load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") - -licenses(["notice"]) # Apache 2 - -api_proto_package( - deps = [ - "//envoy/config/common/matcher/generic/v3:pkg", - "//envoy/config/core/v4alpha:pkg", - "//envoy/type/matcher/v4alpha:pkg", - "@com_github_cncf_udpa//udpa/annotations:pkg", - ], -) diff --git a/generated_api_shadow/envoy/config/common/matcher/generic/v4alpha/matcher.proto b/generated_api_shadow/envoy/config/common/matcher/generic/v4alpha/matcher.proto deleted file mode 100644 index f90fcc6e0927..000000000000 --- a/generated_api_shadow/envoy/config/common/matcher/generic/v4alpha/matcher.proto +++ /dev/null @@ -1,170 +0,0 @@ -syntax = "proto3"; - -package envoy.config.common.matcher.generic.v4alpha; - -import "envoy/config/core/v4alpha/extension.proto"; -import "envoy/type/matcher/v4alpha/string.proto"; - -import "udpa/annotations/status.proto"; -import "udpa/annotations/versioning.proto"; -import "validate/validate.proto"; - -option java_package = "io.envoyproxy.envoy.config.common.matcher.generic.v4alpha"; -option java_outer_classname = "MatcherProto"; -option java_multiple_files = true; -option (udpa.annotations.file_status).package_version_status = NEXT_MAJOR_VERSION_CANDIDATE; - -// [#protodoc-title: Unified Matcher API] - -// A matcher, which may traverse a matching tree in order to result in a match action. -// During matching, the tree will be traversed until a match is found, or if no match -// is found the action specified by the most specific on_no_match will be evaluated. -// As an on_no_match might result in another matching tree being evaluated, this process -// might repeat several times until the final OnMatch (or no match) is decided. -// -// [#alpha:] -message Matcher { - option (udpa.annotations.versioning).previous_message_type = - "envoy.config.common.matcher.generic.v3.Matcher"; - - // What to do if a match is successful. - message OnMatch { - option (udpa.annotations.versioning).previous_message_type = - "envoy.config.common.matcher.generic.v3.Matcher.OnMatch"; - - oneof on_match { - option (validate.required) = true; - - // Nested matcher to evaluate. - // If the nested matcher does not match and does not specify - // on_no_match, then this matcher is considered not to have - // matched, even if a predicate at this level or above returned - // true. - Matcher matcher = 1; - - // Protocol-specific action to take. - core.v4alpha.TypedExtensionConfig action = 2; - } - } - - // A linear list of field matchers. - // The field matchers are evaluated in order, and the first match - // wins. - message MatcherList { - option (udpa.annotations.versioning).previous_message_type = - "envoy.config.common.matcher.generic.v3.Matcher.MatcherList"; - - // Predicate to determine if a match is successful. - message Predicate { - option (udpa.annotations.versioning).previous_message_type = - "envoy.config.common.matcher.generic.v3.Matcher.MatcherList.Predicate"; - - // Predicate for a single input field. - message SinglePredicate { - option (udpa.annotations.versioning).previous_message_type = - "envoy.config.common.matcher.generic.v3.Matcher.MatcherList.Predicate.SinglePredicate"; - - // Protocol-specific specification of input field to match on. - // [#extension-category: envoy.matching.common_inputs] - core.v4alpha.TypedExtensionConfig input = 1 [(validate.rules).message = {required: true}]; - - oneof matcher { - option (validate.required) = true; - - // Built-in string matcher. - type.matcher.v4alpha.StringMatcher value_match = 2; - - // Extension for custom matching logic. - // [#extension-category: envoy.matching.input_matchers] - core.v4alpha.TypedExtensionConfig custom_match = 3; - } - } - - // A list of two or more matchers. Used to allow using a list within a oneof. - message PredicateList { - option (udpa.annotations.versioning).previous_message_type = - "envoy.config.common.matcher.generic.v3.Matcher.MatcherList.Predicate.PredicateList"; - - repeated Predicate predicate = 1 [(validate.rules).repeated = {min_items: 2}]; - } - - oneof match_type { - option (validate.required) = true; - - // A single predicate to evaluate. - SinglePredicate single_predicate = 1; - - // A list of predicates to be OR-ed together. - PredicateList or_matcher = 2; - - // A list of predicates to be AND-ed together. - PredicateList and_matcher = 3; - - // The invert of a predicate - Predicate not_matcher = 4; - } - } - - // An individual matcher. - message FieldMatcher { - option (udpa.annotations.versioning).previous_message_type = - "envoy.config.common.matcher.generic.v3.Matcher.MatcherList.FieldMatcher"; - - // Determines if the match succeeds. - Predicate predicate = 1 [(validate.rules).message = {required: true}]; - - // What to do if the match succeeds. - OnMatch on_match = 2 [(validate.rules).message = {required: true}]; - } - - // A list of matchers. First match wins. - repeated FieldMatcher matchers = 1 [(validate.rules).repeated = {min_items: 1}]; - } - - message MatcherTree { - option (udpa.annotations.versioning).previous_message_type = - "envoy.config.common.matcher.generic.v3.Matcher.MatcherTree"; - - // A map of configured matchers. Used to allow using a map within a oneof. - message MatchMap { - option (udpa.annotations.versioning).previous_message_type = - "envoy.config.common.matcher.generic.v3.Matcher.MatcherTree.MatchMap"; - - map map = 1 [(validate.rules).map = {min_pairs: 1}]; - } - - // Protocol-specific specification of input field to match on. - core.v4alpha.TypedExtensionConfig input = 1 [(validate.rules).message = {required: true}]; - - // Exact or prefix match maps in which to look up the input value. - // If the lookup succeeds, the match is considered successful, and - // the corresponding OnMatch is used. - oneof tree_type { - option (validate.required) = true; - - MatchMap exact_match_map = 2; - - // Longest matching prefix wins. - MatchMap prefix_match_map = 3; - - // Extension for custom matching logic. - core.v4alpha.TypedExtensionConfig custom_match = 4; - } - } - - oneof matcher_type { - option (validate.required) = true; - - // A linear list of matchers to evaluate. - MatcherList matcher_list = 1; - - // A match tree to evaluate. - MatcherTree matcher_tree = 2; - } - - // Optional OnMatch to use if the matcher failed. - // If specified, the OnMatch is used, and the matcher is considered - // to have matched. - // If not specified, the matcher is considered not to have matched. - OnMatch on_no_match = 3; -} diff --git a/generated_api_shadow/envoy/extensions/common/matching/v3/BUILD b/generated_api_shadow/envoy/extensions/common/matching/v3/BUILD index 3a05a6fb527d..42b094a2dcd8 100644 --- a/generated_api_shadow/envoy/extensions/common/matching/v3/BUILD +++ b/generated_api_shadow/envoy/extensions/common/matching/v3/BUILD @@ -7,9 +7,9 @@ licenses(["notice"]) # Apache 2 api_proto_package( deps = [ "//envoy/annotations:pkg", - "//envoy/config/common/matcher/generic/v3:pkg", "//envoy/config/common/matcher/v3:pkg", "//envoy/config/core/v3:pkg", "@com_github_cncf_udpa//udpa/annotations:pkg", + "@com_github_cncf_udpa//udpa/type/matcher/v1:pkg", ], ) diff --git a/generated_api_shadow/envoy/extensions/common/matching/v3/extension_matcher.proto b/generated_api_shadow/envoy/extensions/common/matching/v3/extension_matcher.proto index e28f474b8098..251848705e1e 100644 --- a/generated_api_shadow/envoy/extensions/common/matching/v3/extension_matcher.proto +++ b/generated_api_shadow/envoy/extensions/common/matching/v3/extension_matcher.proto @@ -2,10 +2,11 @@ syntax = "proto3"; package envoy.extensions.common.matching.v3; -import "envoy/config/common/matcher/generic/v3/matcher.proto"; import "envoy/config/common/matcher/v3/matcher.proto"; import "envoy/config/core/v3/extension.proto"; +import "udpa/type/matcher/v1/matcher.proto"; + import "envoy/annotations/deprecation.proto"; import "udpa/annotations/status.proto"; import "validate/validate.proto"; @@ -23,12 +24,12 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // // [#alpha:] message ExtensionWithMatcher { - // The associated matcher. This is deprecated in favor of matcher_tree. + // The associated matcher. This is deprecated in favor of udpa_matcher. config.common.matcher.v3.Matcher matcher = 1 [deprecated = true, (envoy.annotations.deprecated_at_minor_version) = "3.0"]; // The associated matcher. - config.common.matcher.generic.v3.Matcher matcher_tree = 3; + udpa.type.matcher.v1.Matcher udpa_matcher = 3; // The underlying extension config. config.core.v3.TypedExtensionConfig extension_config = 2 diff --git a/generated_api_shadow/envoy/extensions/common/matching/v4alpha/BUILD b/generated_api_shadow/envoy/extensions/common/matching/v4alpha/BUILD index 26b3a0ed9ac9..d3e725e6398c 100644 --- a/generated_api_shadow/envoy/extensions/common/matching/v4alpha/BUILD +++ b/generated_api_shadow/envoy/extensions/common/matching/v4alpha/BUILD @@ -7,10 +7,10 @@ licenses(["notice"]) # Apache 2 api_proto_package( deps = [ "//envoy/annotations:pkg", - "//envoy/config/common/matcher/generic/v4alpha:pkg", "//envoy/config/common/matcher/v4alpha:pkg", "//envoy/config/core/v4alpha:pkg", "//envoy/extensions/common/matching/v3:pkg", "@com_github_cncf_udpa//udpa/annotations:pkg", + "@com_github_cncf_udpa//udpa/type/matcher/v1:pkg", ], ) diff --git a/generated_api_shadow/envoy/extensions/common/matching/v4alpha/extension_matcher.proto b/generated_api_shadow/envoy/extensions/common/matching/v4alpha/extension_matcher.proto index ccb30cbf03f3..004b0deec0dc 100644 --- a/generated_api_shadow/envoy/extensions/common/matching/v4alpha/extension_matcher.proto +++ b/generated_api_shadow/envoy/extensions/common/matching/v4alpha/extension_matcher.proto @@ -2,10 +2,11 @@ syntax = "proto3"; package envoy.extensions.common.matching.v4alpha; -import "envoy/config/common/matcher/generic/v4alpha/matcher.proto"; import "envoy/config/common/matcher/v4alpha/matcher.proto"; import "envoy/config/core/v4alpha/extension.proto"; +import "udpa/type/matcher/v1/matcher.proto"; + import "envoy/annotations/deprecation.proto"; import "udpa/annotations/status.proto"; import "udpa/annotations/versioning.proto"; @@ -27,12 +28,12 @@ message ExtensionWithMatcher { option (udpa.annotations.versioning).previous_message_type = "envoy.extensions.common.matching.v3.ExtensionWithMatcher"; - // The associated matcher. This is deprecated in favor of matcher_tree. + // The associated matcher. This is deprecated in favor of udpa_matcher. config.common.matcher.v4alpha.Matcher hidden_envoy_deprecated_matcher = 1 [deprecated = true, (envoy.annotations.deprecated_at_minor_version) = "3.0"]; // The associated matcher. - config.common.matcher.generic.v4alpha.Matcher matcher_tree = 3; + udpa.type.matcher.v1.Matcher udpa_matcher = 3; // The underlying extension config. config.core.v4alpha.TypedExtensionConfig extension_config = 2 diff --git a/source/common/common/BUILD b/source/common/common/BUILD index 5614a214ba5a..87d8c015d193 100644 --- a/source/common/common/BUILD +++ b/source/common/common/BUILD @@ -301,6 +301,7 @@ envoy_cc_library( "//envoy/common:regex_interface", "//source/common/protobuf:utility_lib", "//source/common/stats:symbol_table_lib", + "@com_github_cncf_udpa//udpa/type/matcher/v1:pkg_cc_proto", "@com_googlesource_code_re2//:re2", "@envoy_api//envoy/type/matcher/v3:pkg_cc_proto", ], diff --git a/source/common/common/matchers.cc b/source/common/common/matchers.cc index ec93e4bbf11c..cb57af2869f3 100644 --- a/source/common/common/matchers.cc +++ b/source/common/common/matchers.cc @@ -23,7 +23,8 @@ ValueMatcherConstSharedPtr ValueMatcher::create(const envoy::type::matcher::v3:: case envoy::type::matcher::v3::ValueMatcher::MatchPatternCase::kDoubleMatch: return std::make_shared(v.double_match()); case envoy::type::matcher::v3::ValueMatcher::MatchPatternCase::kStringMatch: - return std::make_shared(v.string_match()); + return std::make_shared>>( + v.string_match()); case envoy::type::matcher::v3::ValueMatcher::MatchPatternCase::kBoolMatch: return std::make_shared(v.bool_match()); case envoy::type::matcher::v3::ValueMatcher::MatchPatternCase::kPresentMatch: @@ -63,65 +64,6 @@ bool DoubleMatcher::match(const ProtobufWkt::Value& value) const { }; } -StringMatcherImpl::StringMatcherImpl(const envoy::type::matcher::v3::StringMatcher& matcher) - : matcher_(matcher) { - if (matcher.match_pattern_case() == - envoy::type::matcher::v3::StringMatcher::MatchPatternCase::kSafeRegex) { - if (matcher.ignore_case()) { - throw EnvoyException("ignore_case has no effect for safe_regex."); - } - regex_ = Regex::Utility::parseRegex(matcher_.safe_regex()); - } else if (matcher.match_pattern_case() == - envoy::type::matcher::v3::StringMatcher::MatchPatternCase::kContains) { - if (matcher_.ignore_case()) { - // Cache the lowercase conversion of the Contains matcher for future use - lowercase_contains_match_ = absl::AsciiStrToLower(matcher_.contains()); - } - } -} - -bool StringMatcherImpl::match(const ProtobufWkt::Value& value) const { - if (value.kind_case() != ProtobufWkt::Value::kStringValue) { - return false; - } - - return match(value.string_value()); -} - -bool StringMatcherImpl::match(const absl::string_view value) const { - switch (matcher_.match_pattern_case()) { - case envoy::type::matcher::v3::StringMatcher::MatchPatternCase::kExact: - return matcher_.ignore_case() ? absl::EqualsIgnoreCase(value, matcher_.exact()) - : value == matcher_.exact(); - case envoy::type::matcher::v3::StringMatcher::MatchPatternCase::kPrefix: - return matcher_.ignore_case() ? absl::StartsWithIgnoreCase(value, matcher_.prefix()) - : absl::StartsWith(value, matcher_.prefix()); - case envoy::type::matcher::v3::StringMatcher::MatchPatternCase::kSuffix: - return matcher_.ignore_case() ? absl::EndsWithIgnoreCase(value, matcher_.suffix()) - : absl::EndsWith(value, matcher_.suffix()); - case envoy::type::matcher::v3::StringMatcher::MatchPatternCase::kContains: - return matcher_.ignore_case() - ? absl::StrContains(absl::AsciiStrToLower(value), lowercase_contains_match_) - : absl::StrContains(value, matcher_.contains()); - case envoy::type::matcher::v3::StringMatcher::MatchPatternCase::kHiddenEnvoyDeprecatedRegex: - FALLTHRU; - case envoy::type::matcher::v3::StringMatcher::MatchPatternCase::kSafeRegex: - return regex_->match(value); - default: - NOT_REACHED_GCOVR_EXCL_LINE; - } -} - -bool StringMatcherImpl::getCaseSensitivePrefixMatch(std::string& prefix) const { - if (matcher_.match_pattern_case() == - envoy::type::matcher::v3::StringMatcher::MatchPatternCase::kPrefix && - !matcher_.ignore_case()) { - prefix = matcher_.prefix(); - return true; - } - return false; -} - ListMatcher::ListMatcher(const envoy::type::matcher::v3::ListMatcher& matcher) : matcher_(matcher) { ASSERT(matcher_.match_pattern_case() == envoy::type::matcher::v3::ListMatcher::MatchPatternCase::kOneOf); diff --git a/source/common/common/matchers.h b/source/common/common/matchers.h index 3bcf1a88bf12..6d04de854df8 100644 --- a/source/common/common/matchers.h +++ b/source/common/common/matchers.h @@ -2,6 +2,7 @@ #include +#include "envoy/common/exception.h" #include "envoy/common/matchers.h" #include "envoy/common/regex.h" #include "envoy/config/core/v3/base.pb.h" @@ -11,9 +12,12 @@ #include "envoy/type/matcher/v3/string.pb.h" #include "envoy/type/matcher/v3/value.pb.h" +#include "source/common/common/regex.h" #include "source/common/common/utility.h" #include "source/common/protobuf/protobuf.h" +#include "absl/strings/match.h" + namespace Envoy { namespace Matchers { @@ -81,15 +85,55 @@ class UniversalStringMatcher : public StringMatcher { bool match(absl::string_view) const override { return true; } }; +template class StringMatcherImpl : public ValueMatcher, public StringMatcher { public: - explicit StringMatcherImpl(const envoy::type::matcher::v3::StringMatcher& matcher); + explicit StringMatcherImpl(const StringMatcherType& matcher) : matcher_(matcher) { + if (matcher.match_pattern_case() == StringMatcherType::MatchPatternCase::kSafeRegex) { + if (matcher.ignore_case()) { + throw EnvoyException("ignore_case has no effect for safe_regex."); + } + regex_ = Regex::Utility::parseRegex(matcher_.safe_regex()); + } else if (matcher.match_pattern_case() == StringMatcherType::MatchPatternCase::kContains) { + if (matcher_.ignore_case()) { + // Cache the lowercase conversion of the Contains matcher for future use + lowercase_contains_match_ = absl::AsciiStrToLower(matcher_.contains()); + } + } + } // StringMatcher - bool match(const absl::string_view value) const override; - bool match(const ProtobufWkt::Value& value) const override; - - const envoy::type::matcher::v3::StringMatcher& matcher() const { return matcher_; } + bool match(const absl::string_view value) const override { + switch (matcher_.match_pattern_case()) { + case StringMatcherType::MatchPatternCase::kExact: + return matcher_.ignore_case() ? absl::EqualsIgnoreCase(value, matcher_.exact()) + : value == matcher_.exact(); + case StringMatcherType::MatchPatternCase::kPrefix: + return matcher_.ignore_case() ? absl::StartsWithIgnoreCase(value, matcher_.prefix()) + : absl::StartsWith(value, matcher_.prefix()); + case StringMatcherType::MatchPatternCase::kSuffix: + return matcher_.ignore_case() ? absl::EndsWithIgnoreCase(value, matcher_.suffix()) + : absl::EndsWith(value, matcher_.suffix()); + case StringMatcherType::MatchPatternCase::kContains: + return matcher_.ignore_case() + ? absl::StrContains(absl::AsciiStrToLower(value), lowercase_contains_match_) + : absl::StrContains(value, matcher_.contains()); + case StringMatcherType::MatchPatternCase::kSafeRegex: + return regex_->match(value); + default: + NOT_REACHED_GCOVR_EXCL_LINE; + } + } + bool match(const ProtobufWkt::Value& value) const override { + + if (value.kind_case() != ProtobufWkt::Value::kStringValue) { + return false; + } + + return match(value.string_value()); + } + + const StringMatcherType& matcher() const { return matcher_; } /** * Helps applications optimize the case where a matcher is a case-sensitive @@ -98,10 +142,18 @@ class StringMatcherImpl : public ValueMatcher, public StringMatcher { * @param prefix the returned prefix string * @return true if the matcher is a case-sensitive prefix-match. */ - bool getCaseSensitivePrefixMatch(std::string& prefix) const; + bool getCaseSensitivePrefixMatch(std::string& prefix) const { + if (matcher_.match_pattern_case() == + envoy::type::matcher::v3::StringMatcher::MatchPatternCase::kPrefix && + !matcher_.ignore_case()) { + prefix = matcher_.prefix(); + return true; + } + return false; + } private: - const envoy::type::matcher::v3::StringMatcher matcher_; + const StringMatcherType matcher_; Regex::CompiledMatcherPtr regex_; std::string lowercase_contains_match_; }; @@ -149,7 +201,7 @@ class PathMatcher : public StringMatcher { bool match(const absl::string_view path) const override; private: - const StringMatcherImpl matcher_; + const StringMatcherImpl matcher_; }; } // namespace Matchers diff --git a/source/common/common/regex.cc b/source/common/common/regex.cc index 6b2e0050b487..7b0196b0dfca 100644 --- a/source/common/common/regex.cc +++ b/source/common/common/regex.cc @@ -1,28 +1,65 @@ #include "source/common/common/regex.h" #include "envoy/common/exception.h" -#include "envoy/runtime/runtime.h" #include "envoy/type/matcher/v3/regex.pb.h" #include "source/common/common/assert.h" #include "source/common/common/fmt.h" -#include "source/common/protobuf/utility.h" -#include "source/common/stats/symbol_table_impl.h" - -#include "re2/re2.h" namespace Envoy { namespace Regex { -namespace { -class CompiledGoogleReMatcher : public CompiledMatcher { -public: - CompiledGoogleReMatcher(const envoy::type::matcher::v3::RegexMatcher& config) - : regex_(config.regex(), re2::RE2::Quiet) { +CompiledGoogleReMatcher::CompiledGoogleReMatcher(const std::string& regex, bool do_program_size_check) + : regex_(regex, re2::RE2::Quiet) { if (!regex_.ok()) { throw EnvoyException(regex_.error()); } + if (do_program_size_check) { + Runtime::Loader* runtime = Runtime::LoaderSingleton::getExisting(); + if (runtime) { + Stats::Scope& root_scope = runtime->getRootScope(); + + const uint32_t regex_program_size = static_cast(regex_.ProgramSize()); + // TODO(perf): It would be more efficient to create the stats (program size histogram, + // warning counter) on startup and not with each regex match. + Stats::StatNameManagedStorage program_size_stat_name("re2.program_size", + root_scope.symbolTable()); + Stats::Histogram& program_size_stat = root_scope.histogramFromStatName( + program_size_stat_name.statName(), Stats::Histogram::Unit::Unspecified); + program_size_stat.recordValue(regex_program_size); + + Stats::StatNameManagedStorage warn_count_stat_name("re2.exceeded_warn_level", + root_scope.symbolTable()); + Stats::Counter& warn_count = + root_scope.counterFromStatName(warn_count_stat_name.statName()); + + const uint32_t max_program_size_error_level = + runtime->snapshot().getInteger("re2.max_program_size.error_level", 100); + if (regex_program_size > max_program_size_error_level) { + throw EnvoyException( + fmt::format("regex '{}' RE2 program size of {} > max program size of " + "{} set for the error level threshold. Increase " + "configured max program size if necessary.", + regex, regex_program_size, max_program_size_error_level)); + } + + const uint32_t max_program_size_warn_level = + runtime->snapshot().getInteger("re2.max_program_size.warn_level", UINT32_MAX); + if (regex_program_size > max_program_size_warn_level) { + warn_count.inc(); + ENVOY_LOG_MISC( + warn, + "regex '{}' RE2 program size of {} > max program size of {} set for the warn " + "level threshold. Increase configured max program size if necessary.", + regex, regex_program_size, max_program_size_warn_level); + } + } + } + } + +CompiledGoogleReMatcher::CompiledGoogleReMatcher(const envoy::type::matcher::v3::RegexMatcher& config) + : CompiledGoogleReMatcher(config.regex(), !config.google_re2().has_max_program_size()) { const uint32_t regex_program_size = static_cast(regex_.ProgramSize()); // Check if the deprecated field max_program_size is set first, and follow the old logic if so. @@ -34,73 +71,9 @@ class CompiledGoogleReMatcher : public CompiledMatcher { "{}. Increase configured max program size if necessary.", config.regex(), regex_program_size, max_program_size)); } - return; - } - - Runtime::Loader* runtime = Runtime::LoaderSingleton::getExisting(); - if (runtime) { - Stats::Scope& root_scope = runtime->getRootScope(); - - // TODO(perf): It would be more efficient to create the stats (program size histogram, warning - // counter) on startup and not with each regex match. - Stats::StatNameManagedStorage program_size_stat_name("re2.program_size", - root_scope.symbolTable()); - Stats::Histogram& program_size_stat = root_scope.histogramFromStatName( - program_size_stat_name.statName(), Stats::Histogram::Unit::Unspecified); - program_size_stat.recordValue(regex_program_size); - - Stats::StatNameManagedStorage warn_count_stat_name("re2.exceeded_warn_level", - root_scope.symbolTable()); - Stats::Counter& warn_count = root_scope.counterFromStatName(warn_count_stat_name.statName()); - - const uint32_t max_program_size_error_level = - runtime->snapshot().getInteger("re2.max_program_size.error_level", 100); - if (regex_program_size > max_program_size_error_level) { - throw EnvoyException(fmt::format("regex '{}' RE2 program size of {} > max program size of " - "{} set for the error level threshold. Increase " - "configured max program size if necessary.", - config.regex(), regex_program_size, - max_program_size_error_level)); - } - - const uint32_t max_program_size_warn_level = - runtime->snapshot().getInteger("re2.max_program_size.warn_level", UINT32_MAX); - if (regex_program_size > max_program_size_warn_level) { - warn_count.inc(); - ENVOY_LOG_MISC( - warn, - "regex '{}' RE2 program size of {} > max program size of {} set for the warn " - "level threshold. Increase configured max program size if necessary.", - config.regex(), regex_program_size, max_program_size_warn_level); - } } } - // CompiledMatcher - bool match(absl::string_view value) const override { - return re2::RE2::FullMatch(re2::StringPiece(value.data(), value.size()), regex_); - } - - // CompiledMatcher - std::string replaceAll(absl::string_view value, absl::string_view substitution) const override { - std::string result = std::string(value); - re2::RE2::GlobalReplace(&result, regex_, - re2::StringPiece(substitution.data(), substitution.size())); - return result; - } - -private: - const re2::RE2 regex_; -}; - -} // namespace - -CompiledMatcherPtr Utility::parseRegex(const envoy::type::matcher::v3::RegexMatcher& matcher) { - // Google Re is the only currently supported engine. - ASSERT(matcher.has_google_re2()); - return std::make_unique(matcher); -} - std::regex Utility::parseStdRegex(const std::string& regex, std::regex::flag_type flags) { // TODO(zuercher): In the future, PGV (https://github.com/envoyproxy/protoc-gen-validate) // annotations may allow us to remove this in favor of direct validation of regular diff --git a/source/common/common/regex.h b/source/common/common/regex.h index e360cab01b96..c46579e39539 100644 --- a/source/common/common/regex.h +++ b/source/common/common/regex.h @@ -4,11 +4,44 @@ #include #include "envoy/common/regex.h" +#include "envoy/runtime/runtime.h" #include "envoy/type/matcher/v3/regex.pb.h" +#include "source/common/common/assert.h" +#include "source/common/protobuf/utility.h" +#include "source/common/stats/symbol_table_impl.h" + +#include "re2/re2.h" +#include "udpa/type/matcher/v1/regex.pb.h" + namespace Envoy { namespace Regex { +class CompiledGoogleReMatcher : public CompiledMatcher { +public: + explicit CompiledGoogleReMatcher(const std::string& regex, bool do_program_size_check); + + explicit CompiledGoogleReMatcher(const udpa::type::matcher::v1::RegexMatcher& config) + : CompiledGoogleReMatcher(config.regex(), false) {} + + explicit CompiledGoogleReMatcher(const envoy::type::matcher::v3::RegexMatcher& config); + + // CompiledMatcher + bool match(absl::string_view value) const override { + return re2::RE2::FullMatch(re2::StringPiece(value.data(), value.size()), regex_); + } + + // CompiledMatcher + std::string replaceAll(absl::string_view value, absl::string_view substitution) const override { + std::string result = std::string(value); + re2::RE2::GlobalReplace(&result, regex_, + re2::StringPiece(substitution.data(), substitution.size())); + return result; + } + +private: + const re2::RE2 regex_; +}; enum class Type { Re2, StdRegex }; /** @@ -29,7 +62,12 @@ class Utility { /** * Construct a compiled regex matcher from a match config. */ - static CompiledMatcherPtr parseRegex(const envoy::type::matcher::v3::RegexMatcher& matcher); + template + static CompiledMatcherPtr parseRegex(const RegexMatcherType& matcher) { + // Google Re is the only currently supported engine. + ASSERT(matcher.has_google_re2()); + return std::make_unique(matcher); + } }; } // namespace Regex diff --git a/source/common/http/match_wrapper/config.cc b/source/common/http/match_wrapper/config.cc index 096c6d14833c..c6a300db0265 100644 --- a/source/common/http/match_wrapper/config.cc +++ b/source/common/http/match_wrapper/config.cc @@ -109,8 +109,8 @@ Envoy::Http::FilterFactoryCb MatchWrapperConfig::createFilterFactoryFromProtoTyp Envoy::Http::Matching::HttpFilterActionContext> matcher_factory(action_context, context.getServerFactoryContext(), validation_visitor); Matcher::MatchTreeFactoryCb factory_cb; - if (proto_config.has_matcher_tree()) { - factory_cb = matcher_factory.create(proto_config.matcher_tree()); + if (proto_config.has_udpa_matcher()) { + factory_cb = matcher_factory.create(proto_config.udpa_matcher()); } else if (proto_config.has_matcher()) { factory_cb = matcher_factory.create(proto_config.matcher()); } else { diff --git a/source/common/matcher/matcher.h b/source/common/matcher/matcher.h index c3d306b73972..8afa2a0b9639 100644 --- a/source/common/matcher/matcher.h +++ b/source/common/matcher/matcher.h @@ -233,8 +233,8 @@ template class MatchTreeFactory { const CommonProtocolInputPtr common_protocol_input_; }; - DataInputFactoryCb - createDataInput(const envoy::config::core::v3::TypedExtensionConfig& config) { + template + DataInputFactoryCb createDataInput(const TypedExtensionConfigType& config) { auto* factory = Config::Utility::getFactory>(config); if (factory != nullptr) { validation_visitor_.validateDataInput(*factory, config.typed_config().type_url()); @@ -264,7 +264,8 @@ template class MatchTreeFactory { switch (predicate.matcher_case()) { case SinglePredicateType::kValueMatch: return [value_match = predicate.value_match()]() { - return std::make_unique(value_match); + return std::make_unique>>( + value_match); }; case SinglePredicateType::kCustomMatch: { auto& factory = diff --git a/source/common/matcher/value_input_matcher.h b/source/common/matcher/value_input_matcher.h index e381f393550c..0cfdb3a39ba7 100644 --- a/source/common/matcher/value_input_matcher.h +++ b/source/common/matcher/value_input_matcher.h @@ -7,10 +7,9 @@ namespace Envoy { namespace Matcher { -class StringInputMatcher : public InputMatcher { +template class StringInputMatcher : public InputMatcher { public: - explicit StringInputMatcher(const envoy::type::matcher::v3::StringMatcher& matcher) - : matcher_(matcher) {} + explicit StringInputMatcher(const StringMatcherType& matcher) : matcher_(matcher) {} bool match(absl::optional input) override { if (!input) { @@ -21,7 +20,7 @@ class StringInputMatcher : public InputMatcher { } private: - const Matchers::StringMatcherImpl matcher_; + const Matchers::StringMatcherImpl matcher_; }; } // namespace Matcher diff --git a/source/common/router/config_impl.cc b/source/common/router/config_impl.cc index b1432fa02bbf..a2e22e1fddbb 100644 --- a/source/common/router/config_impl.cc +++ b/source/common/router/config_impl.cc @@ -223,7 +223,9 @@ CorsPolicyImpl::CorsPolicyImpl(const envoy::config::route::v3::CorsPolicy& confi ? config.hidden_envoy_deprecated_enabled().value() : true) { for (const auto& string_match : config.allow_origin_string_match()) { - allow_origins_.push_back(std::make_unique(string_match)); + allow_origins_.push_back( + std::make_unique>( + string_match)); } if (config.has_allow_credentials()) { allow_credentials_ = PROTOBUF_GET_WRAPPED_REQUIRED(config, allow_credentials); diff --git a/source/common/router/config_utility.cc b/source/common/router/config_utility.cc index f94d6b68a19e..0c618ffd70cf 100644 --- a/source/common/router/config_utility.cc +++ b/source/common/router/config_utility.cc @@ -14,7 +14,7 @@ namespace Envoy { namespace Router { namespace { -absl::optional +absl::optional> maybeCreateStringMatcher(const envoy::config::route::v3::QueryParameterMatcher& config) { switch (config.query_parameter_match_specifier_case()) { case envoy::config::route::v3::QueryParameterMatcher::QueryParameterMatchSpecifierCase:: diff --git a/source/common/router/config_utility.h b/source/common/router/config_utility.h index 3c8167c2faa3..4895f103de3a 100644 --- a/source/common/router/config_utility.h +++ b/source/common/router/config_utility.h @@ -43,7 +43,8 @@ class ConfigUtility { private: const std::string name_; - const absl::optional matcher_; + const absl::optional> + matcher_; }; using QueryParameterMatcherPtr = std::unique_ptr; diff --git a/source/common/stats/histogram_impl.h b/source/common/stats/histogram_impl.h index 4090434f46ed..03992a06cd7b 100644 --- a/source/common/stats/histogram_impl.h +++ b/source/common/stats/histogram_impl.h @@ -28,7 +28,8 @@ class HistogramSettingsImpl : public HistogramSettings { static ConstSupportedBuckets& defaultBuckets(); private: - using Config = std::pair; + using Config = std::pair, + ConstSupportedBuckets>; const std::vector configs_{}; }; diff --git a/source/common/stats/stats_matcher_impl.h b/source/common/stats/stats_matcher_impl.h index b9cad0fa35da..a0d3a085cc3f 100644 --- a/source/common/stats/stats_matcher_impl.h +++ b/source/common/stats/stats_matcher_impl.h @@ -52,7 +52,7 @@ class StatsMatcherImpl : public StatsMatcher { OptRef symbol_table_; std::unique_ptr stat_name_pool_; - std::vector matchers_; + std::vector> matchers_; std::vector prefixes_; }; diff --git a/source/common/upstream/health_checker_impl.h b/source/common/upstream/health_checker_impl.h index ec3b615ea5ab..a4000fc2ecc5 100644 --- a/source/common/upstream/health_checker_impl.h +++ b/source/common/upstream/health_checker_impl.h @@ -163,7 +163,8 @@ class HttpHealthCheckerImpl : public HealthCheckerImplBase { const std::string path_; const std::string host_value_; - absl::optional service_name_matcher_; + absl::optional> + service_name_matcher_; Router::HeaderParserPtr request_headers_parser_; const HttpStatusChecker http_status_checker_; diff --git a/source/extensions/transport_sockets/tls/cert_validator/default_validator.cc b/source/extensions/transport_sockets/tls/cert_validator/default_validator.cc index 06fa51331293..25029c7196f8 100644 --- a/source/extensions/transport_sockets/tls/cert_validator/default_validator.cc +++ b/source/extensions/transport_sockets/tls/cert_validator/default_validator.cc @@ -221,7 +221,8 @@ int DefaultCertValidator::doVerifyCertChain( Envoy::Ssl::ClientValidationStatus DefaultCertValidator::verifyCertificate( X509* cert, const std::vector& verify_san_list, - const std::vector& subject_alt_name_matchers) { + const std::vector>& + subject_alt_name_matchers) { Envoy::Ssl::ClientValidationStatus validated = Envoy::Ssl::ClientValidationStatus::NotValidated; if (!verify_san_list.empty()) { @@ -300,7 +301,9 @@ bool DefaultCertValidator::dnsNameMatch(const absl::string_view dns_name, } bool DefaultCertValidator::matchSubjectAltName( - X509* cert, const std::vector& subject_alt_name_matchers) { + X509* cert, + const std::vector>& + subject_alt_name_matchers) { bssl::UniquePtr san_names( static_cast(X509_get_ext_d2i(cert, NID_subject_alt_name, nullptr, nullptr))); if (san_names == nullptr) { diff --git a/source/extensions/transport_sockets/tls/cert_validator/default_validator.h b/source/extensions/transport_sockets/tls/cert_validator/default_validator.h index fb7e7acab1f4..4d5daaf0205e 100644 --- a/source/extensions/transport_sockets/tls/cert_validator/default_validator.h +++ b/source/extensions/transport_sockets/tls/cert_validator/default_validator.h @@ -52,9 +52,10 @@ class DefaultCertValidator : public CertValidator { Envoy::Ssl::CertificateDetailsPtr getCaCertInformation() const override; // Utility functions. - Envoy::Ssl::ClientValidationStatus - verifyCertificate(X509* cert, const std::vector& verify_san_list, - const std::vector& subject_alt_name_matchers); + Envoy::Ssl::ClientValidationStatus verifyCertificate( + X509* cert, const std::vector& verify_san_list, + const std::vector>& + subject_alt_name_matchers); /** * Verifies certificate hash for pinning. The hash is a hex-encoded SHA-256 of the DER-encoded @@ -101,9 +102,10 @@ class DefaultCertValidator : public CertValidator { * @param subject_alt_name_matchers the configured matchers to match * @return true if the verification succeeds */ - static bool - matchSubjectAltName(X509* cert, - const std::vector& subject_alt_name_matchers); + static bool matchSubjectAltName( + X509* cert, + const std::vector>& + subject_alt_name_matchers); private: const Envoy::Ssl::CertificateValidationContextConfig* config_; @@ -113,7 +115,8 @@ class DefaultCertValidator : public CertValidator { bool allow_untrusted_certificate_{false}; bssl::UniquePtr ca_cert_; std::string ca_file_path_; - std::vector subject_alt_name_matchers_; + std::vector> + subject_alt_name_matchers_; std::vector> verify_certificate_hash_list_; std::vector> verify_certificate_spki_list_; bool verify_trusted_ca_{false}; diff --git a/test/integration/integration_test.cc b/test/integration/integration_test.cc index f86c0aaf6ef0..582675d96c88 100644 --- a/test/integration/integration_test.cc +++ b/test/integration/integration_test.cc @@ -448,7 +448,7 @@ name: matcher typed_config: "@type": type.googleapis.com/test.integration.filters.SetResponseCodeFilterConfig code: 403 - matcher_tree: + udpa_matcher: matcher_tree: input: name: request-headers diff --git a/tools/proto_format/proto_sync.py b/tools/proto_format/proto_sync.py index 9dd232a4fae3..dd6ee81ef54b 100755 --- a/tools/proto_format/proto_sync.py +++ b/tools/proto_format/proto_sync.py @@ -268,6 +268,9 @@ def get_import_deps(proto_path): if import_path.startswith('udpa/annotations/'): imports.append('@com_github_cncf_udpa//udpa/annotations:pkg') continue + if import_path.startswith('udpa/type/matcher/v1/'): + imports.append('@com_github_cncf_udpa//udpa/type/matcher/v1:pkg') + continue # Special case handling for UDPA core. if import_path.startswith('xds/core/v3/'): imports.append('@com_github_cncf_udpa//xds/core/v3:pkg') From 41f07e47afe317828efc0484b889996760aad30e Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Fri, 9 Jul 2021 19:55:37 +0000 Subject: [PATCH 12/44] fix examples Signed-off-by: Snow Pettersen --- .../arch_overview/advanced/matching/_include/complicated.yaml | 2 +- .../advanced/matching/_include/request_response.yaml | 2 +- .../intro/arch_overview/advanced/matching/_include/simple.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/root/intro/arch_overview/advanced/matching/_include/complicated.yaml b/docs/root/intro/arch_overview/advanced/matching/_include/complicated.yaml index afc33ba6948d..c5cceb22841e 100644 --- a/docs/root/intro/arch_overview/advanced/matching/_include/complicated.yaml +++ b/docs/root/intro/arch_overview/advanced/matching/_include/complicated.yaml @@ -29,7 +29,7 @@ static_resources: percentage: numerator: 0 denominator: HUNDRED - matcher_tree: + udpa_matcher: # The top level matcher is a matcher tree which conceptually selects one of several subtrees. matcher_tree: input: diff --git a/docs/root/intro/arch_overview/advanced/matching/_include/request_response.yaml b/docs/root/intro/arch_overview/advanced/matching/_include/request_response.yaml index a33f49f84de2..60c4ca77757c 100644 --- a/docs/root/intro/arch_overview/advanced/matching/_include/request_response.yaml +++ b/docs/root/intro/arch_overview/advanced/matching/_include/request_response.yaml @@ -29,7 +29,7 @@ static_resources: percentage: numerator: 0 denominator: HUNDRED - matcher_tree: + udpa_matcher: matcher_list: matchers: - predicate: diff --git a/docs/root/intro/arch_overview/advanced/matching/_include/simple.yaml b/docs/root/intro/arch_overview/advanced/matching/_include/simple.yaml index a55be6eedc8a..3f1fd1a6e279 100644 --- a/docs/root/intro/arch_overview/advanced/matching/_include/simple.yaml +++ b/docs/root/intro/arch_overview/advanced/matching/_include/simple.yaml @@ -29,7 +29,7 @@ static_resources: percentage: numerator: 0 denominator: HUNDRED - matcher_tree: + udpa_matcher: matcher_tree: input: name: request-headers From ba371e8bcd51fb2da3e47bd27b9829e36076694a Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Fri, 9 Jul 2021 19:56:31 +0000 Subject: [PATCH 13/44] update versioning Signed-off-by: Snow Pettersen --- api/API_VERSIONING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/API_VERSIONING.md b/api/API_VERSIONING.md index 8f8b72665d96..33f953134831 100644 --- a/api/API_VERSIONING.md +++ b/api/API_VERSIONING.md @@ -67,13 +67,13 @@ experience a backward compatible break on a change. Specifically: may be granted for scenarios in which these stricter conditions model behavior already implied structurally or by documentation. -* Messages marked as [#alpha:] are excluded from the backwards compatibility guarantees. An exception to the above policy exists for: * Changes made within 14 days of the introduction of a new API field or message. * API versions tagged `vNalpha`. Within an alpha major version, arbitrary breaking changes are allowed. * Any field, message or enum with a `[#not-implemented-hide:..` comment. * Any proto with a `(udpa.annotations.file_status).work_in_progress` option annotation. +* Any proto marked as [#alpha:]. Note that changes to default values for wrapped types, e.g. `google.protobuf.UInt32Value` are not governed by the above policy. Any management server requiring stability across Envoy API or From 0fb80baaa4dbdcfc7a1551dd25084089d8c3a5cf Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Wed, 14 Jul 2021 12:17:45 +0000 Subject: [PATCH 14/44] format Signed-off-by: Snow Pettersen --- source/common/common/regex.cc | 104 +++++++++++++++++----------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/source/common/common/regex.cc b/source/common/common/regex.cc index 7b0196b0dfca..0cc34cf7e5e9 100644 --- a/source/common/common/regex.cc +++ b/source/common/common/regex.cc @@ -9,70 +9,70 @@ namespace Envoy { namespace Regex { -CompiledGoogleReMatcher::CompiledGoogleReMatcher(const std::string& regex, bool do_program_size_check) - : regex_(regex, re2::RE2::Quiet) { - if (!regex_.ok()) { - throw EnvoyException(regex_.error()); - } - - if (do_program_size_check) { - Runtime::Loader* runtime = Runtime::LoaderSingleton::getExisting(); - if (runtime) { - Stats::Scope& root_scope = runtime->getRootScope(); +CompiledGoogleReMatcher::CompiledGoogleReMatcher(const std::string& regex, + bool do_program_size_check) + : regex_(regex, re2::RE2::Quiet) { + if (!regex_.ok()) { + throw EnvoyException(regex_.error()); + } - const uint32_t regex_program_size = static_cast(regex_.ProgramSize()); - // TODO(perf): It would be more efficient to create the stats (program size histogram, - // warning counter) on startup and not with each regex match. - Stats::StatNameManagedStorage program_size_stat_name("re2.program_size", - root_scope.symbolTable()); - Stats::Histogram& program_size_stat = root_scope.histogramFromStatName( - program_size_stat_name.statName(), Stats::Histogram::Unit::Unspecified); - program_size_stat.recordValue(regex_program_size); + if (do_program_size_check) { + Runtime::Loader* runtime = Runtime::LoaderSingleton::getExisting(); + if (runtime) { + Stats::Scope& root_scope = runtime->getRootScope(); - Stats::StatNameManagedStorage warn_count_stat_name("re2.exceeded_warn_level", + const uint32_t regex_program_size = static_cast(regex_.ProgramSize()); + // TODO(perf): It would be more efficient to create the stats (program size histogram, + // warning counter) on startup and not with each regex match. + Stats::StatNameManagedStorage program_size_stat_name("re2.program_size", root_scope.symbolTable()); - Stats::Counter& warn_count = - root_scope.counterFromStatName(warn_count_stat_name.statName()); + Stats::Histogram& program_size_stat = root_scope.histogramFromStatName( + program_size_stat_name.statName(), Stats::Histogram::Unit::Unspecified); + program_size_stat.recordValue(regex_program_size); - const uint32_t max_program_size_error_level = - runtime->snapshot().getInteger("re2.max_program_size.error_level", 100); - if (regex_program_size > max_program_size_error_level) { - throw EnvoyException( - fmt::format("regex '{}' RE2 program size of {} > max program size of " - "{} set for the error level threshold. Increase " - "configured max program size if necessary.", - regex, regex_program_size, max_program_size_error_level)); - } + Stats::StatNameManagedStorage warn_count_stat_name("re2.exceeded_warn_level", + root_scope.symbolTable()); + Stats::Counter& warn_count = root_scope.counterFromStatName(warn_count_stat_name.statName()); + + const uint32_t max_program_size_error_level = + runtime->snapshot().getInteger("re2.max_program_size.error_level", 100); + if (regex_program_size > max_program_size_error_level) { + throw EnvoyException(fmt::format("regex '{}' RE2 program size of {} > max program size of " + "{} set for the error level threshold. Increase " + "configured max program size if necessary.", + regex, regex_program_size, max_program_size_error_level)); + } - const uint32_t max_program_size_warn_level = - runtime->snapshot().getInteger("re2.max_program_size.warn_level", UINT32_MAX); - if (regex_program_size > max_program_size_warn_level) { - warn_count.inc(); - ENVOY_LOG_MISC( - warn, - "regex '{}' RE2 program size of {} > max program size of {} set for the warn " - "level threshold. Increase configured max program size if necessary.", - regex, regex_program_size, max_program_size_warn_level); - } + const uint32_t max_program_size_warn_level = + runtime->snapshot().getInteger("re2.max_program_size.warn_level", UINT32_MAX); + if (regex_program_size > max_program_size_warn_level) { + warn_count.inc(); + ENVOY_LOG_MISC( + warn, + "regex '{}' RE2 program size of {} > max program size of {} set for the warn " + "level threshold. Increase configured max program size if necessary.", + regex, regex_program_size, max_program_size_warn_level); } } } +} -CompiledGoogleReMatcher::CompiledGoogleReMatcher(const envoy::type::matcher::v3::RegexMatcher& config) - : CompiledGoogleReMatcher(config.regex(), !config.google_re2().has_max_program_size()) { - const uint32_t regex_program_size = static_cast(regex_.ProgramSize()); +CompiledGoogleReMatcher::CompiledGoogleReMatcher( + const envoy::type::matcher::v3::RegexMatcher& config) + : CompiledGoogleReMatcher(config.regex(), !config.google_re2().has_max_program_size()) { + const uint32_t regex_program_size = static_cast(regex_.ProgramSize()); - // Check if the deprecated field max_program_size is set first, and follow the old logic if so. - if (config.google_re2().has_max_program_size()) { - const uint32_t max_program_size = - PROTOBUF_GET_WRAPPED_OR_DEFAULT(config.google_re2(), max_program_size, 100); - if (regex_program_size > max_program_size) { - throw EnvoyException(fmt::format("regex '{}' RE2 program size of {} > max program size of " - "{}. Increase configured max program size if necessary.", - config.regex(), regex_program_size, max_program_size)); - } + // Check if the deprecated field max_program_size is set first, and follow the old logic if so. + if (config.google_re2().has_max_program_size()) { + const uint32_t max_program_size = + PROTOBUF_GET_WRAPPED_OR_DEFAULT(config.google_re2(), max_program_size, 100); + if (regex_program_size > max_program_size) { + throw EnvoyException(fmt::format("regex '{}' RE2 program size of {} > max program size of " + "{}. Increase configured max program size if necessary.", + config.regex(), regex_program_size, max_program_size)); } } +} std::regex Utility::parseStdRegex(const std::string& regex, std::regex::flag_type flags) { // TODO(zuercher): In the future, PGV (https://github.com/envoyproxy/protoc-gen-validate) From 9d24e1fb23a03c473c76b3ea3d53258be93ed680 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Wed, 14 Jul 2021 12:54:09 +0000 Subject: [PATCH 15/44] update to use xds namespaced protos Signed-off-by: Snow Pettersen --- api/bazel/repository_locations.bzl | 4 ++-- api/envoy/extensions/common/matching/v3/BUILD | 2 +- .../extensions/common/matching/v3/extension_matcher.proto | 6 +++--- api/envoy/extensions/common/matching/v4alpha/BUILD | 2 +- .../common/matching/v4alpha/extension_matcher.proto | 4 ++-- .../advanced/matching/_include/complicated.yaml | 2 +- .../advanced/matching/_include/request_response.yaml | 2 +- .../arch_overview/advanced/matching/_include/simple.yaml | 2 +- generated_api_shadow/bazel/repository_locations.bzl | 4 ++-- .../envoy/extensions/common/matching/v3/BUILD | 2 +- .../extensions/common/matching/v3/extension_matcher.proto | 6 +++--- .../envoy/extensions/common/matching/v4alpha/BUILD | 2 +- .../common/matching/v4alpha/extension_matcher.proto | 6 +++--- source/common/common/BUILD | 2 +- source/common/common/matchers.h | 2 +- source/common/common/regex.h | 4 ++-- source/common/http/match_wrapper/config.cc | 4 ++-- test/integration/integration_test.cc | 2 +- tools/proto_format/proto_sync.py | 4 ++-- 19 files changed, 31 insertions(+), 31 deletions(-) diff --git a/api/bazel/repository_locations.bzl b/api/bazel/repository_locations.bzl index 6f5f50941052..479d9c8cf700 100644 --- a/api/bazel/repository_locations.bzl +++ b/api/bazel/repository_locations.bzl @@ -44,8 +44,8 @@ REPOSITORY_LOCATIONS_SPEC = dict( project_desc = "xDS API Working Group (xDS-WG)", project_url = "https://github.com/cncf/xds", # During the UDPA -> xDS migration, we aren't working with releases. - version = "2e5c007c8982836cda87a125fb95fc0b5057fe3a", - sha256 = "e9c751599f69549027aacd8cdc30c0e7b55d9b61ba351739abed705ed667d2b1", + version = "b4d4f75666b03252210862d1d61a08567a22f36d", + sha256 = "d79c3aaca0b14518661dc62c333d2e9fe1c4e8ff179eaf33d5b125cc78f892d8", release_date = "2021-03-23", strip_prefix = "xds-{version}", urls = ["https://github.com/cncf/xds/archive/{version}.tar.gz"], diff --git a/api/envoy/extensions/common/matching/v3/BUILD b/api/envoy/extensions/common/matching/v3/BUILD index 42b094a2dcd8..1afd4545d960 100644 --- a/api/envoy/extensions/common/matching/v3/BUILD +++ b/api/envoy/extensions/common/matching/v3/BUILD @@ -10,6 +10,6 @@ api_proto_package( "//envoy/config/common/matcher/v3:pkg", "//envoy/config/core/v3:pkg", "@com_github_cncf_udpa//udpa/annotations:pkg", - "@com_github_cncf_udpa//udpa/type/matcher/v1:pkg", + "@com_github_cncf_udpa//xds/type/matcher/v3:pkg", ], ) diff --git a/api/envoy/extensions/common/matching/v3/extension_matcher.proto b/api/envoy/extensions/common/matching/v3/extension_matcher.proto index 251848705e1e..eee82a381633 100644 --- a/api/envoy/extensions/common/matching/v3/extension_matcher.proto +++ b/api/envoy/extensions/common/matching/v3/extension_matcher.proto @@ -5,7 +5,7 @@ package envoy.extensions.common.matching.v3; import "envoy/config/common/matcher/v3/matcher.proto"; import "envoy/config/core/v3/extension.proto"; -import "udpa/type/matcher/v1/matcher.proto"; +import "xds/type/matcher/v3/matcher.proto"; import "envoy/annotations/deprecation.proto"; import "udpa/annotations/status.proto"; @@ -24,12 +24,12 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // // [#alpha:] message ExtensionWithMatcher { - // The associated matcher. This is deprecated in favor of udpa_matcher. + // The associated matcher. This is deprecated in favor of xds_matcher. config.common.matcher.v3.Matcher matcher = 1 [deprecated = true, (envoy.annotations.deprecated_at_minor_version) = "3.0"]; // The associated matcher. - udpa.type.matcher.v1.Matcher udpa_matcher = 3; + xds.type.matcher.v3.Matcher xds_matcher = 3; // The underlying extension config. config.core.v3.TypedExtensionConfig extension_config = 2 diff --git a/api/envoy/extensions/common/matching/v4alpha/BUILD b/api/envoy/extensions/common/matching/v4alpha/BUILD index f3cc645b10ee..8082008a9d98 100644 --- a/api/envoy/extensions/common/matching/v4alpha/BUILD +++ b/api/envoy/extensions/common/matching/v4alpha/BUILD @@ -9,6 +9,6 @@ api_proto_package( "//envoy/config/core/v4alpha:pkg", "//envoy/extensions/common/matching/v3:pkg", "@com_github_cncf_udpa//udpa/annotations:pkg", - "@com_github_cncf_udpa//udpa/type/matcher/v1:pkg", + "@com_github_cncf_udpa//xds/type/matcher/v3:pkg", ], ) diff --git a/api/envoy/extensions/common/matching/v4alpha/extension_matcher.proto b/api/envoy/extensions/common/matching/v4alpha/extension_matcher.proto index c361fcd0e823..9077facc29a4 100644 --- a/api/envoy/extensions/common/matching/v4alpha/extension_matcher.proto +++ b/api/envoy/extensions/common/matching/v4alpha/extension_matcher.proto @@ -4,7 +4,7 @@ package envoy.extensions.common.matching.v4alpha; import "envoy/config/core/v4alpha/extension.proto"; -import "udpa/type/matcher/v1/matcher.proto"; +import "xds/type/matcher/v3/matcher.proto"; import "udpa/annotations/status.proto"; import "udpa/annotations/versioning.proto"; @@ -31,7 +31,7 @@ message ExtensionWithMatcher { reserved "matcher"; // The associated matcher. - udpa.type.matcher.v1.Matcher udpa_matcher = 3; + xds.type.matcher.v3.Matcher xds_matcher = 3; // The underlying extension config. config.core.v4alpha.TypedExtensionConfig extension_config = 2 diff --git a/docs/root/intro/arch_overview/advanced/matching/_include/complicated.yaml b/docs/root/intro/arch_overview/advanced/matching/_include/complicated.yaml index c5cceb22841e..6111adfd23ee 100644 --- a/docs/root/intro/arch_overview/advanced/matching/_include/complicated.yaml +++ b/docs/root/intro/arch_overview/advanced/matching/_include/complicated.yaml @@ -29,7 +29,7 @@ static_resources: percentage: numerator: 0 denominator: HUNDRED - udpa_matcher: + xds_matcher: # The top level matcher is a matcher tree which conceptually selects one of several subtrees. matcher_tree: input: diff --git a/docs/root/intro/arch_overview/advanced/matching/_include/request_response.yaml b/docs/root/intro/arch_overview/advanced/matching/_include/request_response.yaml index 60c4ca77757c..5fc3a5c3e8ec 100644 --- a/docs/root/intro/arch_overview/advanced/matching/_include/request_response.yaml +++ b/docs/root/intro/arch_overview/advanced/matching/_include/request_response.yaml @@ -29,7 +29,7 @@ static_resources: percentage: numerator: 0 denominator: HUNDRED - udpa_matcher: + xds_matcher: matcher_list: matchers: - predicate: diff --git a/docs/root/intro/arch_overview/advanced/matching/_include/simple.yaml b/docs/root/intro/arch_overview/advanced/matching/_include/simple.yaml index 3f1fd1a6e279..1433fa75d108 100644 --- a/docs/root/intro/arch_overview/advanced/matching/_include/simple.yaml +++ b/docs/root/intro/arch_overview/advanced/matching/_include/simple.yaml @@ -29,7 +29,7 @@ static_resources: percentage: numerator: 0 denominator: HUNDRED - udpa_matcher: + xds_matcher: matcher_tree: input: name: request-headers diff --git a/generated_api_shadow/bazel/repository_locations.bzl b/generated_api_shadow/bazel/repository_locations.bzl index 6f5f50941052..479d9c8cf700 100644 --- a/generated_api_shadow/bazel/repository_locations.bzl +++ b/generated_api_shadow/bazel/repository_locations.bzl @@ -44,8 +44,8 @@ REPOSITORY_LOCATIONS_SPEC = dict( project_desc = "xDS API Working Group (xDS-WG)", project_url = "https://github.com/cncf/xds", # During the UDPA -> xDS migration, we aren't working with releases. - version = "2e5c007c8982836cda87a125fb95fc0b5057fe3a", - sha256 = "e9c751599f69549027aacd8cdc30c0e7b55d9b61ba351739abed705ed667d2b1", + version = "b4d4f75666b03252210862d1d61a08567a22f36d", + sha256 = "d79c3aaca0b14518661dc62c333d2e9fe1c4e8ff179eaf33d5b125cc78f892d8", release_date = "2021-03-23", strip_prefix = "xds-{version}", urls = ["https://github.com/cncf/xds/archive/{version}.tar.gz"], diff --git a/generated_api_shadow/envoy/extensions/common/matching/v3/BUILD b/generated_api_shadow/envoy/extensions/common/matching/v3/BUILD index 42b094a2dcd8..1afd4545d960 100644 --- a/generated_api_shadow/envoy/extensions/common/matching/v3/BUILD +++ b/generated_api_shadow/envoy/extensions/common/matching/v3/BUILD @@ -10,6 +10,6 @@ api_proto_package( "//envoy/config/common/matcher/v3:pkg", "//envoy/config/core/v3:pkg", "@com_github_cncf_udpa//udpa/annotations:pkg", - "@com_github_cncf_udpa//udpa/type/matcher/v1:pkg", + "@com_github_cncf_udpa//xds/type/matcher/v3:pkg", ], ) diff --git a/generated_api_shadow/envoy/extensions/common/matching/v3/extension_matcher.proto b/generated_api_shadow/envoy/extensions/common/matching/v3/extension_matcher.proto index 251848705e1e..eee82a381633 100644 --- a/generated_api_shadow/envoy/extensions/common/matching/v3/extension_matcher.proto +++ b/generated_api_shadow/envoy/extensions/common/matching/v3/extension_matcher.proto @@ -5,7 +5,7 @@ package envoy.extensions.common.matching.v3; import "envoy/config/common/matcher/v3/matcher.proto"; import "envoy/config/core/v3/extension.proto"; -import "udpa/type/matcher/v1/matcher.proto"; +import "xds/type/matcher/v3/matcher.proto"; import "envoy/annotations/deprecation.proto"; import "udpa/annotations/status.proto"; @@ -24,12 +24,12 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // // [#alpha:] message ExtensionWithMatcher { - // The associated matcher. This is deprecated in favor of udpa_matcher. + // The associated matcher. This is deprecated in favor of xds_matcher. config.common.matcher.v3.Matcher matcher = 1 [deprecated = true, (envoy.annotations.deprecated_at_minor_version) = "3.0"]; // The associated matcher. - udpa.type.matcher.v1.Matcher udpa_matcher = 3; + xds.type.matcher.v3.Matcher xds_matcher = 3; // The underlying extension config. config.core.v3.TypedExtensionConfig extension_config = 2 diff --git a/generated_api_shadow/envoy/extensions/common/matching/v4alpha/BUILD b/generated_api_shadow/envoy/extensions/common/matching/v4alpha/BUILD index d3e725e6398c..5337b3622aa7 100644 --- a/generated_api_shadow/envoy/extensions/common/matching/v4alpha/BUILD +++ b/generated_api_shadow/envoy/extensions/common/matching/v4alpha/BUILD @@ -11,6 +11,6 @@ api_proto_package( "//envoy/config/core/v4alpha:pkg", "//envoy/extensions/common/matching/v3:pkg", "@com_github_cncf_udpa//udpa/annotations:pkg", - "@com_github_cncf_udpa//udpa/type/matcher/v1:pkg", + "@com_github_cncf_udpa//xds/type/matcher/v3:pkg", ], ) diff --git a/generated_api_shadow/envoy/extensions/common/matching/v4alpha/extension_matcher.proto b/generated_api_shadow/envoy/extensions/common/matching/v4alpha/extension_matcher.proto index 004b0deec0dc..2fdfab931775 100644 --- a/generated_api_shadow/envoy/extensions/common/matching/v4alpha/extension_matcher.proto +++ b/generated_api_shadow/envoy/extensions/common/matching/v4alpha/extension_matcher.proto @@ -5,7 +5,7 @@ package envoy.extensions.common.matching.v4alpha; import "envoy/config/common/matcher/v4alpha/matcher.proto"; import "envoy/config/core/v4alpha/extension.proto"; -import "udpa/type/matcher/v1/matcher.proto"; +import "xds/type/matcher/v3/matcher.proto"; import "envoy/annotations/deprecation.proto"; import "udpa/annotations/status.proto"; @@ -28,12 +28,12 @@ message ExtensionWithMatcher { option (udpa.annotations.versioning).previous_message_type = "envoy.extensions.common.matching.v3.ExtensionWithMatcher"; - // The associated matcher. This is deprecated in favor of udpa_matcher. + // The associated matcher. This is deprecated in favor of xds_matcher. config.common.matcher.v4alpha.Matcher hidden_envoy_deprecated_matcher = 1 [deprecated = true, (envoy.annotations.deprecated_at_minor_version) = "3.0"]; // The associated matcher. - udpa.type.matcher.v1.Matcher udpa_matcher = 3; + xds.type.matcher.v3.Matcher xds_matcher = 3; // The underlying extension config. config.core.v4alpha.TypedExtensionConfig extension_config = 2 diff --git a/source/common/common/BUILD b/source/common/common/BUILD index 87d8c015d193..ae549efefb82 100644 --- a/source/common/common/BUILD +++ b/source/common/common/BUILD @@ -301,7 +301,7 @@ envoy_cc_library( "//envoy/common:regex_interface", "//source/common/protobuf:utility_lib", "//source/common/stats:symbol_table_lib", - "@com_github_cncf_udpa//udpa/type/matcher/v1:pkg_cc_proto", + "@com_github_cncf_udpa//xds/type/matcher/v3:pkg_cc_proto", "@com_googlesource_code_re2//:re2", "@envoy_api//envoy/type/matcher/v3:pkg_cc_proto", ], diff --git a/source/common/common/matchers.h b/source/common/common/matchers.h index 6d04de854df8..486d8dbb875d 100644 --- a/source/common/common/matchers.h +++ b/source/common/common/matchers.h @@ -91,7 +91,7 @@ class StringMatcherImpl : public ValueMatcher, public StringMatcher { explicit StringMatcherImpl(const StringMatcherType& matcher) : matcher_(matcher) { if (matcher.match_pattern_case() == StringMatcherType::MatchPatternCase::kSafeRegex) { if (matcher.ignore_case()) { - throw EnvoyException("ignore_case has no effect for safe_regex."); + ExceptionUtil::throwEnvoyException("ignore_case has no effect for safe_regex."); } regex_ = Regex::Utility::parseRegex(matcher_.safe_regex()); } else if (matcher.match_pattern_case() == StringMatcherType::MatchPatternCase::kContains) { diff --git a/source/common/common/regex.h b/source/common/common/regex.h index c46579e39539..e2aee56170ab 100644 --- a/source/common/common/regex.h +++ b/source/common/common/regex.h @@ -12,7 +12,7 @@ #include "source/common/stats/symbol_table_impl.h" #include "re2/re2.h" -#include "udpa/type/matcher/v1/regex.pb.h" +#include "xds/type/matcher/v3/regex.pb.h" namespace Envoy { namespace Regex { @@ -21,7 +21,7 @@ class CompiledGoogleReMatcher : public CompiledMatcher { public: explicit CompiledGoogleReMatcher(const std::string& regex, bool do_program_size_check); - explicit CompiledGoogleReMatcher(const udpa::type::matcher::v1::RegexMatcher& config) + explicit CompiledGoogleReMatcher(const xds::type::matcher::v3::RegexMatcher& config) : CompiledGoogleReMatcher(config.regex(), false) {} explicit CompiledGoogleReMatcher(const envoy::type::matcher::v3::RegexMatcher& config); diff --git a/source/common/http/match_wrapper/config.cc b/source/common/http/match_wrapper/config.cc index c6a300db0265..30c70adb2fac 100644 --- a/source/common/http/match_wrapper/config.cc +++ b/source/common/http/match_wrapper/config.cc @@ -109,8 +109,8 @@ Envoy::Http::FilterFactoryCb MatchWrapperConfig::createFilterFactoryFromProtoTyp Envoy::Http::Matching::HttpFilterActionContext> matcher_factory(action_context, context.getServerFactoryContext(), validation_visitor); Matcher::MatchTreeFactoryCb factory_cb; - if (proto_config.has_udpa_matcher()) { - factory_cb = matcher_factory.create(proto_config.udpa_matcher()); + if (proto_config.has_xds_matcher()) { + factory_cb = matcher_factory.create(proto_config.xds_matcher()); } else if (proto_config.has_matcher()) { factory_cb = matcher_factory.create(proto_config.matcher()); } else { diff --git a/test/integration/integration_test.cc b/test/integration/integration_test.cc index 582675d96c88..1d52144b6fbc 100644 --- a/test/integration/integration_test.cc +++ b/test/integration/integration_test.cc @@ -448,7 +448,7 @@ name: matcher typed_config: "@type": type.googleapis.com/test.integration.filters.SetResponseCodeFilterConfig code: 403 - udpa_matcher: + xds_matcher: matcher_tree: input: name: request-headers diff --git a/tools/proto_format/proto_sync.py b/tools/proto_format/proto_sync.py index dd6ee81ef54b..1d4b816159d8 100755 --- a/tools/proto_format/proto_sync.py +++ b/tools/proto_format/proto_sync.py @@ -268,8 +268,8 @@ def get_import_deps(proto_path): if import_path.startswith('udpa/annotations/'): imports.append('@com_github_cncf_udpa//udpa/annotations:pkg') continue - if import_path.startswith('udpa/type/matcher/v1/'): - imports.append('@com_github_cncf_udpa//udpa/type/matcher/v1:pkg') + if import_path.startswith('xds/type/matcher/v3/'): + imports.append('@com_github_cncf_udpa//xds/type/matcher/v3:pkg') continue # Special case handling for UDPA core. if import_path.startswith('xds/core/v3/'): From f6d9af7854f4c9aaedd787675c0aebbd6c02e38a Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Wed, 14 Jul 2021 13:12:22 +0000 Subject: [PATCH 16/44] fix docs Signed-off-by: Snow Pettersen --- docs/root/api-v3/common_messages/common_messages.rst | 1 - docs/root/version_history/current.rst | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/root/api-v3/common_messages/common_messages.rst b/docs/root/api-v3/common_messages/common_messages.rst index b12f61b91cca..ea123c074ca1 100644 --- a/docs/root/api-v3/common_messages/common_messages.rst +++ b/docs/root/api-v3/common_messages/common_messages.rst @@ -5,7 +5,6 @@ Common messages :glob: :maxdepth: 2 - ../config/common/matcher/generic/v3/matcher.proto ../config/core/v3/base.proto ../config/core/v3/extension.proto ../config/core/v3/address.proto diff --git a/docs/root/version_history/current.rst b/docs/root/version_history/current.rst index f79208ae0357..edb9ad3a9728 100644 --- a/docs/root/version_history/current.rst +++ b/docs/root/version_history/current.rst @@ -134,7 +134,7 @@ Deprecated ---------- * api: the :ref:`matcher ` field has been deprecated in favor of - :ref:`matcher ` in order to break a build dependency. + :ref:`matcher ` in order to break a build dependency. * bootstrap: the field :ref:`use_tcp_for_dns_lookups ` is deprecated in favor of :ref:`dns_resolution_config ` which aggregates all of the DNS resolver configuration in a single message. * cluster: the fields :ref:`use_tcp_for_dns_lookups ` and :ref:`dns_resolvers ` are deprecated in favor of :ref:`dns_resolution_config ` which aggregates all of the DNS resolver configuration in a single message. * dns_filter: the field :ref:`known_suffixes ` is deprecated. The internal data management of the filter has changed and the filter no longer uses the known_suffixes field. From 02dc3f09cabd6f6442f86e48bed3b99b9c0d7d02 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Mon, 26 Jul 2021 13:35:51 +0000 Subject: [PATCH 17/44] use xds latest main Signed-off-by: Snow Pettersen --- api/bazel/repository_locations.bzl | 6 +++--- generated_api_shadow/bazel/repository_locations.bzl | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/api/bazel/repository_locations.bzl b/api/bazel/repository_locations.bzl index f2685aaeb014..0885d4f970c2 100644 --- a/api/bazel/repository_locations.bzl +++ b/api/bazel/repository_locations.bzl @@ -44,9 +44,9 @@ REPOSITORY_LOCATIONS_SPEC = dict( project_desc = "xDS API Working Group (xDS-WG)", project_url = "https://github.com/cncf/xds", # During the UDPA -> xDS migration, we aren't working with releases. - version = "b88cc788a63e5b38ee334a2e702c67901355ae2c", - sha256 = "3220df8564f217665b6e17776569c5f748178c2b9cbf83bb55a13ddc0a3738f0", - release_date = "2021-03-23", + version = "dd25fe81a44506ab21ea666fb70b3b1c4bb183ee", + sha256 = "9184235cd31272679e4c7f9232c341d4ea75351ded74d3fbba28b05c290bfa71", + release_date = "2021-07-21", strip_prefix = "xds-{version}", urls = ["https://github.com/cncf/xds/archive/{version}.tar.gz"], use_category = ["api"], diff --git a/generated_api_shadow/bazel/repository_locations.bzl b/generated_api_shadow/bazel/repository_locations.bzl index f2685aaeb014..0885d4f970c2 100644 --- a/generated_api_shadow/bazel/repository_locations.bzl +++ b/generated_api_shadow/bazel/repository_locations.bzl @@ -44,9 +44,9 @@ REPOSITORY_LOCATIONS_SPEC = dict( project_desc = "xDS API Working Group (xDS-WG)", project_url = "https://github.com/cncf/xds", # During the UDPA -> xDS migration, we aren't working with releases. - version = "b88cc788a63e5b38ee334a2e702c67901355ae2c", - sha256 = "3220df8564f217665b6e17776569c5f748178c2b9cbf83bb55a13ddc0a3738f0", - release_date = "2021-03-23", + version = "dd25fe81a44506ab21ea666fb70b3b1c4bb183ee", + sha256 = "9184235cd31272679e4c7f9232c341d4ea75351ded74d3fbba28b05c290bfa71", + release_date = "2021-07-21", strip_prefix = "xds-{version}", urls = ["https://github.com/cncf/xds/archive/{version}.tar.gz"], use_category = ["api"], From 853a1bd1f974f5d7a63c1cc7985f07b192633168 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Mon, 26 Jul 2021 13:51:42 +0000 Subject: [PATCH 18/44] use xds main Signed-off-by: Snow Pettersen --- api/bazel/repository_locations.bzl | 6 +++--- generated_api_shadow/bazel/repository_locations.bzl | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/api/bazel/repository_locations.bzl b/api/bazel/repository_locations.bzl index 479d9c8cf700..b0941cb5eb6b 100644 --- a/api/bazel/repository_locations.bzl +++ b/api/bazel/repository_locations.bzl @@ -44,9 +44,9 @@ REPOSITORY_LOCATIONS_SPEC = dict( project_desc = "xDS API Working Group (xDS-WG)", project_url = "https://github.com/cncf/xds", # During the UDPA -> xDS migration, we aren't working with releases. - version = "b4d4f75666b03252210862d1d61a08567a22f36d", - sha256 = "d79c3aaca0b14518661dc62c333d2e9fe1c4e8ff179eaf33d5b125cc78f892d8", - release_date = "2021-03-23", + version = "dd25fe81a44506ab21ea666fb70b3b1c4bb183ee", + sha256 = "9184235cd31272679e4c7f9232c341d4ea75351ded74d3fbba28b05c290bfa71", + release_date = "2021-07-21", strip_prefix = "xds-{version}", urls = ["https://github.com/cncf/xds/archive/{version}.tar.gz"], use_category = ["api"], diff --git a/generated_api_shadow/bazel/repository_locations.bzl b/generated_api_shadow/bazel/repository_locations.bzl index 479d9c8cf700..b0941cb5eb6b 100644 --- a/generated_api_shadow/bazel/repository_locations.bzl +++ b/generated_api_shadow/bazel/repository_locations.bzl @@ -44,9 +44,9 @@ REPOSITORY_LOCATIONS_SPEC = dict( project_desc = "xDS API Working Group (xDS-WG)", project_url = "https://github.com/cncf/xds", # During the UDPA -> xDS migration, we aren't working with releases. - version = "b4d4f75666b03252210862d1d61a08567a22f36d", - sha256 = "d79c3aaca0b14518661dc62c333d2e9fe1c4e8ff179eaf33d5b125cc78f892d8", - release_date = "2021-03-23", + version = "dd25fe81a44506ab21ea666fb70b3b1c4bb183ee", + sha256 = "9184235cd31272679e4c7f9232c341d4ea75351ded74d3fbba28b05c290bfa71", + release_date = "2021-07-21", strip_prefix = "xds-{version}", urls = ["https://github.com/cncf/xds/archive/{version}.tar.gz"], use_category = ["api"], From 7863b17286d36b83101e7906d680f8cffa368452 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Mon, 26 Jul 2021 15:10:29 +0000 Subject: [PATCH 19/44] fix release date Signed-off-by: Snow Pettersen --- api/bazel/repository_locations.bzl | 2 +- generated_api_shadow/bazel/repository_locations.bzl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/api/bazel/repository_locations.bzl b/api/bazel/repository_locations.bzl index b0941cb5eb6b..bb35ff7754b8 100644 --- a/api/bazel/repository_locations.bzl +++ b/api/bazel/repository_locations.bzl @@ -46,7 +46,7 @@ REPOSITORY_LOCATIONS_SPEC = dict( # During the UDPA -> xDS migration, we aren't working with releases. version = "dd25fe81a44506ab21ea666fb70b3b1c4bb183ee", sha256 = "9184235cd31272679e4c7f9232c341d4ea75351ded74d3fbba28b05c290bfa71", - release_date = "2021-07-21", + release_date = "2021-07-22", strip_prefix = "xds-{version}", urls = ["https://github.com/cncf/xds/archive/{version}.tar.gz"], use_category = ["api"], diff --git a/generated_api_shadow/bazel/repository_locations.bzl b/generated_api_shadow/bazel/repository_locations.bzl index b0941cb5eb6b..bb35ff7754b8 100644 --- a/generated_api_shadow/bazel/repository_locations.bzl +++ b/generated_api_shadow/bazel/repository_locations.bzl @@ -46,7 +46,7 @@ REPOSITORY_LOCATIONS_SPEC = dict( # During the UDPA -> xDS migration, we aren't working with releases. version = "dd25fe81a44506ab21ea666fb70b3b1c4bb183ee", sha256 = "9184235cd31272679e4c7f9232c341d4ea75351ded74d3fbba28b05c290bfa71", - release_date = "2021-07-21", + release_date = "2021-07-22", strip_prefix = "xds-{version}", urls = ["https://github.com/cncf/xds/archive/{version}.tar.gz"], use_category = ["api"], From 4ebb008923ff1e856dadb9003cbdcce99e58ede1 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Tue, 27 Jul 2021 15:57:15 +0000 Subject: [PATCH 20/44] fix more stringmatcherimpl ctors Signed-off-by: Snow Pettersen --- source/common/http/header_utility.cc | 4 +++- .../filters/http/cache/cache_headers_utils.cc | 4 +++- .../http/cache/cache_headers_utils_test.cc | 20 ++++++++++++++----- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/source/common/http/header_utility.cc b/source/common/http/header_utility.cc index b0fc8d02fe5e..b8fb6d43617a 100644 --- a/source/common/http/header_utility.cc +++ b/source/common/http/header_utility.cc @@ -69,7 +69,9 @@ HeaderUtility::HeaderData::HeaderData(const envoy::config::route::v3::HeaderMatc break; case envoy::config::route::v3::HeaderMatcher::HeaderMatchSpecifierCase::kStringMatch: header_match_type_ = HeaderMatchType::StringMatch; - string_match_ = std::make_unique(config.string_match()); + string_match_ = + std::make_unique>( + config.string_match()); break; case envoy::config::route::v3::HeaderMatcher::HeaderMatchSpecifierCase:: HEADER_MATCH_SPECIFIER_NOT_SET: diff --git a/source/extensions/filters/http/cache/cache_headers_utils.cc b/source/extensions/filters/http/cache/cache_headers_utils.cc index 73a9c5b5625a..c020828f6a63 100644 --- a/source/extensions/filters/http/cache/cache_headers_utils.cc +++ b/source/extensions/filters/http/cache/cache_headers_utils.cc @@ -234,7 +234,9 @@ VaryHeader::VaryHeader( const Protobuf::RepeatedPtrField& allow_list) { for (const auto& rule : allow_list) { - allow_list_.emplace_back(std::make_unique(rule)); + allow_list_.emplace_back( + std::make_unique>( + rule)); } } diff --git a/test/extensions/filters/http/cache/cache_headers_utils_test.cc b/test/extensions/filters/http/cache/cache_headers_utils_test.cc index 2c0795195efe..b0c2007a04ae 100644 --- a/test/extensions/filters/http/cache/cache_headers_utils_test.cc +++ b/test/extensions/filters/http/cache/cache_headers_utils_test.cc @@ -463,7 +463,9 @@ TEST(GetAllMatchingHeaderNames, EmptyHeaderMap) { envoy::type::matcher::v3::StringMatcher matcher; matcher.set_exact("accept"); - ruleset.emplace_back(std::make_unique(matcher)); + ruleset.emplace_back( + std::make_unique>( + matcher)); CacheHeadersUtils::getAllMatchingHeaderNames(headers, ruleset, result); @@ -477,7 +479,9 @@ TEST(GetAllMatchingHeaderNames, SingleMatchSingleValue) { envoy::type::matcher::v3::StringMatcher matcher; matcher.set_exact("accept"); - ruleset.emplace_back(std::make_unique(matcher)); + ruleset.emplace_back( + std::make_unique>( + matcher)); CacheHeadersUtils::getAllMatchingHeaderNames(headers, ruleset, result); @@ -492,7 +496,9 @@ TEST(GetAllMatchingHeaderNames, SingleMatchMultiValue) { envoy::type::matcher::v3::StringMatcher matcher; matcher.set_exact("accept"); - ruleset.emplace_back(std::make_unique(matcher)); + ruleset.emplace_back( + std::make_unique>( + matcher)); CacheHeadersUtils::getAllMatchingHeaderNames(headers, ruleset, result); @@ -507,9 +513,13 @@ TEST(GetAllMatchingHeaderNames, MultipleMatches) { envoy::type::matcher::v3::StringMatcher matcher; matcher.set_exact("accept"); - ruleset.emplace_back(std::make_unique(matcher)); + ruleset.emplace_back( + std::make_unique>( + matcher)); matcher.set_exact("accept-language"); - ruleset.emplace_back(std::make_unique(matcher)); + ruleset.emplace_back( + std::make_unique>( + matcher)); CacheHeadersUtils::getAllMatchingHeaderNames(headers, ruleset, result); From 199a8b1940dfe4127fee0dcce59fc37100195cd9 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Fri, 30 Jul 2021 18:43:11 +0000 Subject: [PATCH 21/44] more fixes Signed-off-by: Snow Pettersen --- .../filters/common/ext_authz/ext_authz_http_impl.cc | 8 ++++---- source/extensions/filters/common/rbac/matchers.h | 8 ++++---- source/extensions/filters/http/csrf/csrf_filter.h | 2 +- .../filters/network/dubbo_proxy/router/route_matcher.h | 2 +- .../filters/network/rocketmq_proxy/router/route_matcher.h | 2 +- .../tls/cert_validator/spiffe/spiffe_validator.h | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/source/extensions/filters/common/ext_authz/ext_authz_http_impl.cc b/source/extensions/filters/common/ext_authz/ext_authz_http_impl.cc index f80b3022080a..52e2b3518c5d 100644 --- a/source/extensions/filters/common/ext_authz/ext_authz_http_impl.cc +++ b/source/extensions/filters/common/ext_authz/ext_authz_http_impl.cc @@ -86,7 +86,7 @@ std::vector createStringMatchers(const envoy::type::matcher::v3::ListStringMatcher& list) { std::vector matchers; for (const auto& matcher : list.patterns()) { - matchers.push_back(std::make_unique(matcher)); + matchers.push_back(std::make_unique>(matcher)); } return matchers; } @@ -136,7 +136,7 @@ ClientConfig::toRequestMatchers(const envoy::type::matcher::v3::ListStringMatche for (const auto& key : keys) { envoy::type::matcher::v3::StringMatcher matcher; matcher.set_exact(key.get()); - matchers.push_back(std::make_unique(matcher)); + matchers.push_back(std::make_unique>(matcher)); } return std::make_shared(std::move(matchers)); @@ -157,7 +157,7 @@ ClientConfig::toClientMatchers(const envoy::type::matcher::v3::ListStringMatcher if (matchers.empty()) { envoy::type::matcher::v3::StringMatcher matcher; matcher.set_exact(Http::Headers::get().Host.get()); - matchers.push_back(std::make_unique(matcher)); + matchers.push_back(std::make_unique>(matcher)); return std::make_shared(std::move(matchers)); } @@ -171,7 +171,7 @@ ClientConfig::toClientMatchers(const envoy::type::matcher::v3::ListStringMatcher for (const auto& key : keys) { envoy::type::matcher::v3::StringMatcher matcher; matcher.set_exact(key.get()); - matchers.push_back(std::make_unique(matcher)); + matchers.push_back(std::make_unique>(matcher)); } return std::make_shared(std::move(matchers)); diff --git a/source/extensions/filters/common/rbac/matchers.h b/source/extensions/filters/common/rbac/matchers.h index 472b4a2c9c17..3717e1b32ffa 100644 --- a/source/extensions/filters/common/rbac/matchers.h +++ b/source/extensions/filters/common/rbac/matchers.h @@ -171,14 +171,14 @@ class AuthenticatedMatcher : public Matcher { public: AuthenticatedMatcher(const envoy::config::rbac::v3::Principal::Authenticated& auth) : matcher_(auth.has_principal_name() - ? absl::make_optional(auth.principal_name()) + ? absl::make_optional>(auth.principal_name()) : absl::nullopt) {} bool matches(const Network::Connection& connection, const Envoy::Http::RequestHeaderMap& headers, const StreamInfo::StreamInfo&) const override; private: - const absl::optional matcher_; + const absl::optional> matcher_; }; /** @@ -222,10 +222,10 @@ class MetadataMatcher : public Matcher { * Perform a match against the request server from the client's connection * request. This is typically TLS SNI. */ -class RequestedServerNameMatcher : public Matcher, Envoy::Matchers::StringMatcherImpl { +class RequestedServerNameMatcher : public Matcher, Envoy::Matchers::StringMatcherImpl { public: RequestedServerNameMatcher(const envoy::type::matcher::v3::StringMatcher& requested_server_name) - : Envoy::Matchers::StringMatcherImpl(requested_server_name) {} + : Envoy::Matchers::StringMatcherImpl(requested_server_name) {} bool matches(const Network::Connection& connection, const Envoy::Http::RequestHeaderMap& headers, const StreamInfo::StreamInfo&) const override; diff --git a/source/extensions/filters/http/csrf/csrf_filter.h b/source/extensions/filters/http/csrf/csrf_filter.h index 5697cf99f59e..1aeba738e58b 100644 --- a/source/extensions/filters/http/csrf/csrf_filter.h +++ b/source/extensions/filters/http/csrf/csrf_filter.h @@ -39,7 +39,7 @@ class CsrfPolicy : public Router::RouteSpecificFilterConfig { : policy_(policy), runtime_(runtime) { for (const auto& additional_origin : policy.additional_origins()) { additional_origins_.emplace_back( - std::make_unique(additional_origin)); + std::make_unique>(additional_origin)); } } diff --git a/source/extensions/filters/network/dubbo_proxy/router/route_matcher.h b/source/extensions/filters/network/dubbo_proxy/router/route_matcher.h index 1a36230b8c5b..f19f7b9d13eb 100644 --- a/source/extensions/filters/network/dubbo_proxy/router/route_matcher.h +++ b/source/extensions/filters/network/dubbo_proxy/router/route_matcher.h @@ -123,7 +123,7 @@ class MethodRouteEntryImpl : public RouteEntryImplBase { uint64_t random_value) const override; private: - const Matchers::StringMatcherImpl method_name_; + const Matchers::StringMatcherImpl method_name_; std::shared_ptr parameter_route_; }; diff --git a/source/extensions/filters/network/rocketmq_proxy/router/route_matcher.h b/source/extensions/filters/network/rocketmq_proxy/router/route_matcher.h index 06aec7221d25..bb2d40d9e59f 100644 --- a/source/extensions/filters/network/rocketmq_proxy/router/route_matcher.h +++ b/source/extensions/filters/network/rocketmq_proxy/router/route_matcher.h @@ -42,7 +42,7 @@ class RouteEntryImpl : public RouteEntry, private: bool headersMatch(const Http::HeaderMap& headers) const; - const Matchers::StringMatcherImpl topic_name_; + const Matchers::StringMatcherImpl topic_name_; const std::string cluster_name_; const std::vector config_headers_; Envoy::Router::MetadataMatchCriteriaConstPtr metadata_match_criteria_; diff --git a/source/extensions/transport_sockets/tls/cert_validator/spiffe/spiffe_validator.h b/source/extensions/transport_sockets/tls/cert_validator/spiffe/spiffe_validator.h index fc3a045d0255..9721e3227165 100644 --- a/source/extensions/transport_sockets/tls/cert_validator/spiffe/spiffe_validator.h +++ b/source/extensions/transport_sockets/tls/cert_validator/spiffe/spiffe_validator.h @@ -67,7 +67,7 @@ class SPIFFEValidator : public CertValidator { bool allow_expired_certificate_{false}; std::vector> ca_certs_; std::string ca_file_name_; - std::vector subject_alt_name_matchers_{}; + std::vector> subject_alt_name_matchers_{}; absl::flat_hash_map trust_bundle_stores_; SslStats& stats_; From 73e1848e36732f52aca6ffe48113a7310debab37 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Thu, 5 Aug 2021 13:31:29 +0000 Subject: [PATCH 22/44] more build fixes Signed-off-by: Snow Pettersen --- .../common/ext_authz/ext_authz_http_impl.cc | 16 +++++++++++---- .../extensions/filters/common/rbac/matchers.h | 14 +++++++++---- .../filters/http/csrf/csrf_filter.h | 3 ++- .../cert_validator/spiffe/spiffe_validator.h | 3 ++- .../filters/http/cors/cors_filter_test.cc | 6 ++++-- .../cert_validator/default_validator_test.cc | 20 ++++++++++++------- 6 files changed, 43 insertions(+), 19 deletions(-) diff --git a/source/extensions/filters/common/ext_authz/ext_authz_http_impl.cc b/source/extensions/filters/common/ext_authz/ext_authz_http_impl.cc index 52e2b3518c5d..4dba952fede7 100644 --- a/source/extensions/filters/common/ext_authz/ext_authz_http_impl.cc +++ b/source/extensions/filters/common/ext_authz/ext_authz_http_impl.cc @@ -86,7 +86,9 @@ std::vector createStringMatchers(const envoy::type::matcher::v3::ListStringMatcher& list) { std::vector matchers; for (const auto& matcher : list.patterns()) { - matchers.push_back(std::make_unique>(matcher)); + matchers.push_back( + std::make_unique>( + matcher)); } return matchers; } @@ -136,7 +138,9 @@ ClientConfig::toRequestMatchers(const envoy::type::matcher::v3::ListStringMatche for (const auto& key : keys) { envoy::type::matcher::v3::StringMatcher matcher; matcher.set_exact(key.get()); - matchers.push_back(std::make_unique>(matcher)); + matchers.push_back( + std::make_unique>( + matcher)); } return std::make_shared(std::move(matchers)); @@ -157,7 +161,9 @@ ClientConfig::toClientMatchers(const envoy::type::matcher::v3::ListStringMatcher if (matchers.empty()) { envoy::type::matcher::v3::StringMatcher matcher; matcher.set_exact(Http::Headers::get().Host.get()); - matchers.push_back(std::make_unique>(matcher)); + matchers.push_back( + std::make_unique>( + matcher)); return std::make_shared(std::move(matchers)); } @@ -171,7 +177,9 @@ ClientConfig::toClientMatchers(const envoy::type::matcher::v3::ListStringMatcher for (const auto& key : keys) { envoy::type::matcher::v3::StringMatcher matcher; matcher.set_exact(key.get()); - matchers.push_back(std::make_unique>(matcher)); + matchers.push_back( + std::make_unique>( + matcher)); } return std::make_shared(std::move(matchers)); diff --git a/source/extensions/filters/common/rbac/matchers.h b/source/extensions/filters/common/rbac/matchers.h index 3717e1b32ffa..8b8c4d87bc15 100644 --- a/source/extensions/filters/common/rbac/matchers.h +++ b/source/extensions/filters/common/rbac/matchers.h @@ -171,14 +171,17 @@ class AuthenticatedMatcher : public Matcher { public: AuthenticatedMatcher(const envoy::config::rbac::v3::Principal::Authenticated& auth) : matcher_(auth.has_principal_name() - ? absl::make_optional>(auth.principal_name()) + ? absl::make_optional< + Matchers::StringMatcherImpl>( + auth.principal_name()) : absl::nullopt) {} bool matches(const Network::Connection& connection, const Envoy::Http::RequestHeaderMap& headers, const StreamInfo::StreamInfo&) const override; private: - const absl::optional> matcher_; + const absl::optional> + matcher_; }; /** @@ -222,10 +225,13 @@ class MetadataMatcher : public Matcher { * Perform a match against the request server from the client's connection * request. This is typically TLS SNI. */ -class RequestedServerNameMatcher : public Matcher, Envoy::Matchers::StringMatcherImpl { +class RequestedServerNameMatcher + : public Matcher, + Envoy::Matchers::StringMatcherImpl { public: RequestedServerNameMatcher(const envoy::type::matcher::v3::StringMatcher& requested_server_name) - : Envoy::Matchers::StringMatcherImpl(requested_server_name) {} + : Envoy::Matchers::StringMatcherImpl( + requested_server_name) {} bool matches(const Network::Connection& connection, const Envoy::Http::RequestHeaderMap& headers, const StreamInfo::StreamInfo&) const override; diff --git a/source/extensions/filters/http/csrf/csrf_filter.h b/source/extensions/filters/http/csrf/csrf_filter.h index 1aeba738e58b..b52b9473a884 100644 --- a/source/extensions/filters/http/csrf/csrf_filter.h +++ b/source/extensions/filters/http/csrf/csrf_filter.h @@ -39,7 +39,8 @@ class CsrfPolicy : public Router::RouteSpecificFilterConfig { : policy_(policy), runtime_(runtime) { for (const auto& additional_origin : policy.additional_origins()) { additional_origins_.emplace_back( - std::make_unique>(additional_origin)); + std::make_unique>( + additional_origin)); } } diff --git a/source/extensions/transport_sockets/tls/cert_validator/spiffe/spiffe_validator.h b/source/extensions/transport_sockets/tls/cert_validator/spiffe/spiffe_validator.h index 9721e3227165..b4cc068e908e 100644 --- a/source/extensions/transport_sockets/tls/cert_validator/spiffe/spiffe_validator.h +++ b/source/extensions/transport_sockets/tls/cert_validator/spiffe/spiffe_validator.h @@ -67,7 +67,8 @@ class SPIFFEValidator : public CertValidator { bool allow_expired_certificate_{false}; std::vector> ca_certs_; std::string ca_file_name_; - std::vector> subject_alt_name_matchers_{}; + std::vector> + subject_alt_name_matchers_{}; absl::flat_hash_map trust_bundle_stores_; SslStats& stats_; diff --git a/test/extensions/filters/http/cors/cors_filter_test.cc b/test/extensions/filters/http/cors/cors_filter_test.cc index 116b45c00ae2..8f7da8e21446 100644 --- a/test/extensions/filters/http/cors/cors_filter_test.cc +++ b/test/extensions/filters/http/cors/cors_filter_test.cc @@ -25,13 +25,15 @@ namespace { Matchers::StringMatcherPtr makeExactStringMatcher(const std::string& exact_match) { envoy::type::matcher::v3::StringMatcher config; config.set_exact(exact_match); - return std::make_unique(config); + return std::make_unique>( + config); } Matchers::StringMatcherPtr makeStdRegexStringMatcher(const std::string& regex) { envoy::type::matcher::v3::StringMatcher config; config.MergeFrom(TestUtility::createRegexMatcher(regex)); - return std::make_unique(config); + return std::make_unique>( + config); } } // namespace diff --git a/test/extensions/transport_sockets/tls/cert_validator/default_validator_test.cc b/test/extensions/transport_sockets/tls/cert_validator/default_validator_test.cc index fee175872bd6..5034bfa9ce2d 100644 --- a/test/extensions/transport_sockets/tls/cert_validator/default_validator_test.cc +++ b/test/extensions/transport_sockets/tls/cert_validator/default_validator_test.cc @@ -43,7 +43,8 @@ TEST(DefaultCertValidatorTest, TestMatchSubjectAltNameDNSMatched) { "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_cert.pem")); envoy::type::matcher::v3::StringMatcher matcher; matcher.MergeFrom(TestUtility::createRegexMatcher(".*.example.com")); - std::vector subject_alt_name_matchers; + std::vector> + subject_alt_name_matchers; subject_alt_name_matchers.push_back(Matchers::StringMatcherImpl(matcher)); EXPECT_TRUE(DefaultCertValidator::matchSubjectAltName(cert.get(), subject_alt_name_matchers)); } @@ -54,7 +55,8 @@ TEST(DefaultCertValidatorTest, TestMatchSubjectAltNameWildcardDNSMatched) { "}}/test/extensions/transport_sockets/tls/test_data/san_multiple_dns_cert.pem")); envoy::type::matcher::v3::StringMatcher matcher; matcher.set_exact("api.example.com"); - std::vector subject_alt_name_matchers; + std::vector> + subject_alt_name_matchers; subject_alt_name_matchers.push_back(Matchers::StringMatcherImpl(matcher)); EXPECT_TRUE(DefaultCertValidator::matchSubjectAltName(cert.get(), subject_alt_name_matchers)); } @@ -66,7 +68,8 @@ TEST(DefaultCertValidatorTest, TestMultiLevelMatch) { "}}/test/extensions/transport_sockets/tls/test_data/san_multiple_dns_cert.pem")); envoy::type::matcher::v3::StringMatcher matcher; matcher.set_exact("foo.api.example.com"); - std::vector subject_alt_name_matchers; + std::vector> + subject_alt_name_matchers; subject_alt_name_matchers.push_back(Matchers::StringMatcherImpl(matcher)); EXPECT_FALSE(DefaultCertValidator::matchSubjectAltName(cert.get(), subject_alt_name_matchers)); } @@ -93,7 +96,8 @@ TEST(DefaultCertValidatorTest, TestMatchSubjectAltNameURIMatched) { "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_uri_cert.pem")); envoy::type::matcher::v3::StringMatcher matcher; matcher.MergeFrom(TestUtility::createRegexMatcher("spiffe://lyft.com/.*-team")); - std::vector subject_alt_name_matchers; + std::vector> + subject_alt_name_matchers; subject_alt_name_matchers.push_back(Matchers::StringMatcherImpl(matcher)); EXPECT_TRUE(DefaultCertValidator::matchSubjectAltName(cert.get(), subject_alt_name_matchers)); } @@ -111,7 +115,8 @@ TEST(DefaultCertValidatorTest, TestMatchSubjectAltNameNotMatched) { "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_cert.pem")); envoy::type::matcher::v3::StringMatcher matcher; matcher.MergeFrom(TestUtility::createRegexMatcher(".*.foo.com")); - std::vector subject_alt_name_matchers; + std::vector> + subject_alt_name_matchers; subject_alt_name_matchers.push_back(Matchers::StringMatcherImpl(matcher)); EXPECT_FALSE(DefaultCertValidator::matchSubjectAltName(cert.get(), subject_alt_name_matchers)); } @@ -129,7 +134,7 @@ TEST(DefaultCertValidatorTest, TestCertificateVerificationWithSANMatcher) { "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_cert.pem")); envoy::type::matcher::v3::StringMatcher matcher; matcher.MergeFrom(TestUtility::createRegexMatcher(".*.example.com")); - std::vector san_matchers; + std::vector> san_matchers; san_matchers.push_back(Matchers::StringMatcherImpl(matcher)); // Verify the certificate with correct SAN regex matcher. EXPECT_EQ(default_validator->verifyCertificate(cert.get(), /*verify_san_list=*/{}, san_matchers), @@ -137,7 +142,8 @@ TEST(DefaultCertValidatorTest, TestCertificateVerificationWithSANMatcher) { EXPECT_EQ(stats.fail_verify_san_.value(), 0); matcher.MergeFrom(TestUtility::createExactMatcher("hello.example.com")); - std::vector invalid_san_matchers; + std::vector> + invalid_san_matchers; invalid_san_matchers.push_back(Matchers::StringMatcherImpl(matcher)); // Verify the certificate with incorrect SAN exact matcher. EXPECT_EQ(default_validator->verifyCertificate(cert.get(), /*verify_san_list=*/{}, From 4c9f5e6f6d6ccbf671c9570c7773ecd413e27db4 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Thu, 5 Aug 2021 15:21:55 +0000 Subject: [PATCH 23/44] cleanups, fix composite example Signed-off-by: Snow Pettersen --- api/API_VERSIONING.md | 1 - .../configuration/http/http_filters/_include/composite.yaml | 2 +- docs/root/version_history/current.rst | 5 ----- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/api/API_VERSIONING.md b/api/API_VERSIONING.md index 33f953134831..f1bf6a8912e0 100644 --- a/api/API_VERSIONING.md +++ b/api/API_VERSIONING.md @@ -67,7 +67,6 @@ experience a backward compatible break on a change. Specifically: may be granted for scenarios in which these stricter conditions model behavior already implied structurally or by documentation. - An exception to the above policy exists for: * Changes made within 14 days of the introduction of a new API field or message. * API versions tagged `vNalpha`. Within an alpha major version, arbitrary breaking changes are allowed. diff --git a/docs/root/configuration/http/http_filters/_include/composite.yaml b/docs/root/configuration/http/http_filters/_include/composite.yaml index d45969ba4361..256647da314d 100644 --- a/docs/root/configuration/http/http_filters/_include/composite.yaml +++ b/docs/root/configuration/http/http_filters/_include/composite.yaml @@ -33,7 +33,7 @@ static_resources: name: composite typed_config: "@type": type.googleapis.com/envoy.extensions.filters.http.composite.v3.Composite - matcher: + xds_matcher: matcher_tree: input: name: request-headers diff --git a/docs/root/version_history/current.rst b/docs/root/version_history/current.rst index eec3ffa5e58d..cb50b34621ed 100644 --- a/docs/root/version_history/current.rst +++ b/docs/root/version_history/current.rst @@ -63,11 +63,6 @@ Deprecated * api: the :ref:`matcher ` field has been deprecated in favor of :ref:`matcher ` in order to break a build dependency. -* bootstrap: the field :ref:`use_tcp_for_dns_lookups ` is deprecated in favor of :ref:`dns_resolution_config ` which aggregates all of the DNS resolver configuration in a single message. -* cluster: the fields :ref:`use_tcp_for_dns_lookups ` and :ref:`dns_resolvers ` are deprecated in favor of :ref:`dns_resolution_config ` which aggregates all of the DNS resolver configuration in a single message. -* dns_filter: the field :ref:`known_suffixes ` is deprecated. The internal data management of the filter has changed and the filter no longer uses the known_suffixes field. -* dynamic_forward_proxy: the field :ref:`use_tcp_for_dns_lookups ` is deprecated in favor of :ref:`dns_resolution_config ` which aggregates all of the DNS resolver configuration in a single message. -* http: :ref:`xff_num_trusted_hops ` is deprecated in favor of :ref:`original IP detection extensions`. * cluster: :ref:`max_requests_per_connection ` is deprecated in favor of :ref:`max_requests_per_connection `. * http: the HeaderMatcher fields :ref:`exact_match `, :ref:`safe_regex_match `, :ref:`prefix_match `, :ref:`suffix_match ` and From 6e5177e7c90d51bd13f676b915f6ae86861c47c9 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Mon, 9 Aug 2021 13:38:31 +0000 Subject: [PATCH 24/44] fix merges, start docs Signed-off-by: Snow Pettersen --- .../intro/arch_overview/http/http_routing.rst | 9 +++ source/common/matcher/matcher.h | 4 +- source/common/router/config_impl.cc | 2 +- test/integration/integration_test.cc | 67 ------------------- 4 files changed, 12 insertions(+), 70 deletions(-) diff --git a/docs/root/intro/arch_overview/http/http_routing.rst b/docs/root/intro/arch_overview/http/http_routing.rst index 816218721590..a76eb3d7b356 100644 --- a/docs/root/intro/arch_overview/http/http_routing.rst +++ b/docs/root/intro/arch_overview/http/http_routing.rst @@ -192,3 +192,12 @@ upon configuration load and cache the contents. If **response_headers_to_add** has been set for the Route or the enclosing Virtual Host, Envoy will include the specified headers in the direct HTTP response. + +Routing Via Generic Matching +---------------------------- + +Envoy recently added support for utilzing a :ref:`generic match tree ` to +specify the route table. This is a more expressive matching engine than the original one, allowing +for sublinear matching on arbitrary headers (unlike the original matching engine which could only +do this for :authority in some cases). + diff --git a/source/common/matcher/matcher.h b/source/common/matcher/matcher.h index 6391b63bf56a..2055e460aad0 100644 --- a/source/common/matcher/matcher.h +++ b/source/common/matcher/matcher.h @@ -72,9 +72,9 @@ template using DataInputFactoryCb = std::function class MatchTreeFactory { public: MatchTreeFactory(ActionFactoryContext& context, - ProtobufMessage::ValidationVisitor& proto_validation_visitor, + Server::Configuration::ServerFactoryContext& factory_context, MatchTreeValidationVisitor& validation_visitor) - : action_factory_context_(context), proto_validation_visitor_(proto_validation_visitor), + : action_factory_context_(context), server_factory_context_(factory_context), validation_visitor_(validation_visitor) {} // TODO(snowp): Remove this type parameter once we only have one Matcher proto. diff --git a/source/common/router/config_impl.cc b/source/common/router/config_impl.cc index 8124d373252d..7a22a8f71ec6 100644 --- a/source/common/router/config_impl.cc +++ b/source/common/router/config_impl.cc @@ -1338,7 +1338,7 @@ VirtualHostImpl::VirtualHostImpl( RouteActionContext context{*this, optional_http_filters, factory_context}; RouteActionValidationVisitor validation_visitor; Matcher::MatchTreeFactory factory( - context, validator, validation_visitor); + context, factory_context, validation_visitor); matcher_ = factory.create(matcher)(); } else { diff --git a/test/integration/integration_test.cc b/test/integration/integration_test.cc index 962405807c2c..8f1bbe82554f 100644 --- a/test/integration/integration_test.cc +++ b/test/integration/integration_test.cc @@ -561,73 +561,6 @@ name: matcher second_codec->close(); } -// Verifies that we can construct a match tree with a filter using the new matcher tree proto, and -// that we are able to skip filter invocation through the match tree. -TEST_P(IntegrationTest, MatchingHttpFilterConstructionNewProto) { - concurrency_ = 2; - config_helper_.addRuntimeOverride("envoy.reloadable_features.experimental_matching_api", "true"); - - config_helper_.addFilter(R"EOF( -name: matcher -typed_config: - "@type": type.googleapis.com/envoy.extensions.common.matching.v3.ExtensionWithMatcher - extension_config: - name: set-response-code - typed_config: - "@type": type.googleapis.com/test.integration.filters.SetResponseCodeFilterConfig - code: 403 - xds_matcher: - matcher_tree: - input: - name: request-headers - typed_config: - "@type": type.googleapis.com/envoy.type.matcher.v3.HttpRequestHeaderMatchInput - header_name: match-header - exact_match_map: - map: - match: - action: - name: skip - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.common.matcher.action.v3.SkipFilter -)EOF"); - - initialize(); - - codec_client_ = makeHttpConnection(lookupPort("http")); - - { - auto response = codec_client_->makeRequestWithBody(default_request_headers_, 1024); - ASSERT_TRUE(response->waitForEndStream()); - EXPECT_THAT(response->headers(), HttpStatusIs("403")); - } - - { - codec_client_ = makeHttpConnection(lookupPort("http")); - Http::TestRequestHeaderMapImpl request_headers{ - {":method", "POST"}, {":path", "/test/long/url"}, {":scheme", "http"}, - {":authority", "host"}, {"match-header", "match"}, {"content-type", "application/grpc"}}; - auto response = codec_client_->makeRequestWithBody(request_headers, 1024); - waitForNextUpstreamRequest(); - upstream_request_->encodeHeaders(default_response_headers_, true); - - ASSERT_TRUE(response->waitForEndStream()); - EXPECT_THAT(response->headers(), HttpStatusIs("200")); - } - - auto second_codec = makeHttpConnection(lookupPort("http")); - Http::TestRequestHeaderMapImpl request_headers{ - {":method", "POST"}, {":path", "/test/long/url"}, {":scheme", "http"}, - {":authority", "host"}, {"match-header", "not-match"}, {"content-type", "application/grpc"}}; - auto response = second_codec->makeRequestWithBody(request_headers, 1024); - - ASSERT_TRUE(response->waitForEndStream()); - EXPECT_THAT(response->headers(), HttpStatusIs("200")); - - codec_client_->close(); - second_codec->close(); -} - // This is a regression for https://github.com/envoyproxy/envoy/issues/2715 and validates that a // pending request is not sent on a connection that has been half-closed. TEST_P(IntegrationTest, UpstreamDisconnectWithTwoRequests) { From 0071dc822487d3ff917fcb455783f092cea86730 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Mon, 9 Aug 2021 14:21:15 +0000 Subject: [PATCH 25/44] clean up Signed-off-by: Snow Pettersen --- api/envoy/config/route/v3/BUILD | 1 + .../config/route/v3/route_components.proto | 9 ++-- api/envoy/config/route/v4alpha/BUILD | 1 + .../route/v4alpha/route_components.proto | 9 ++-- .../intro/arch_overview/http/http_routing.rst | 44 +++++++++++++++++++ .../envoy/config/route/v3/BUILD | 1 + .../config/route/v3/route_components.proto | 9 ++-- .../envoy/config/route/v4alpha/BUILD | 1 + .../route/v4alpha/route_components.proto | 9 ++-- source/common/router/config_impl.cc | 29 ++++++++---- test/common/router/config_impl_test.cc | 2 +- 11 files changed, 93 insertions(+), 22 deletions(-) diff --git a/api/envoy/config/route/v3/BUILD b/api/envoy/config/route/v3/BUILD index 81cdfdf8a93a..730789f9801d 100644 --- a/api/envoy/config/route/v3/BUILD +++ b/api/envoy/config/route/v3/BUILD @@ -15,5 +15,6 @@ api_proto_package( "//envoy/type/tracing/v3:pkg", "//envoy/type/v3:pkg", "@com_github_cncf_udpa//udpa/annotations:pkg", + "@com_github_cncf_udpa//xds/type/matcher/v3:pkg", ], ) diff --git a/api/envoy/config/route/v3/route_components.proto b/api/envoy/config/route/v3/route_components.proto index 192e776e3c11..4957bebc7ba5 100644 --- a/api/envoy/config/route/v3/route_components.proto +++ b/api/envoy/config/route/v3/route_components.proto @@ -16,6 +16,8 @@ import "google/protobuf/any.proto"; import "google/protobuf/duration.proto"; import "google/protobuf/wrappers.proto"; +import "xds/type/matcher/v3/matcher.proto"; + import "envoy/annotations/deprecation.proto"; import "udpa/annotations/migrate.proto"; import "udpa/annotations/status.proto"; @@ -84,13 +86,14 @@ message VirtualHost { items {string {well_known_regex: HTTP_HEADER_VALUE strict: false}} }]; - // This is mega hacky but gets around the circular dependency between this file and the matcher file. - google.protobuf.Any matcher = 21; - // The list of routes that will be matched, in order, for incoming requests. // The first route that matches will be used. repeated Route routes = 3; + // The match tree to use when resolving route actions for incoming requests. Onle one of this and `routes` + // can be specified. + xds.type.matcher.v3.Matcher matcher = 21; + // Specifies the type of TLS enforcement the virtual host expects. If this option is not // specified, there is no TLS requirement for the virtual host. TlsRequirementType require_tls = 4 [(validate.rules).enum = {defined_only: true}]; diff --git a/api/envoy/config/route/v4alpha/BUILD b/api/envoy/config/route/v4alpha/BUILD index 89fa4149b879..c4c4cd7f9d9d 100644 --- a/api/envoy/config/route/v4alpha/BUILD +++ b/api/envoy/config/route/v4alpha/BUILD @@ -13,5 +13,6 @@ api_proto_package( "//envoy/type/tracing/v3:pkg", "//envoy/type/v3:pkg", "@com_github_cncf_udpa//udpa/annotations:pkg", + "@com_github_cncf_udpa//xds/type/matcher/v3:pkg", ], ) diff --git a/api/envoy/config/route/v4alpha/route_components.proto b/api/envoy/config/route/v4alpha/route_components.proto index 614a059f2761..10b00e83284a 100644 --- a/api/envoy/config/route/v4alpha/route_components.proto +++ b/api/envoy/config/route/v4alpha/route_components.proto @@ -16,6 +16,8 @@ import "google/protobuf/any.proto"; import "google/protobuf/duration.proto"; import "google/protobuf/wrappers.proto"; +import "xds/type/matcher/v3/matcher.proto"; + import "udpa/annotations/status.proto"; import "udpa/annotations/versioning.proto"; import "validate/validate.proto"; @@ -82,13 +84,14 @@ message VirtualHost { items {string {well_known_regex: HTTP_HEADER_VALUE strict: false}} }]; - // This is mega hacky but gets around the circular dependency between this file and the matcher file. - google.protobuf.Any matcher = 21; - // The list of routes that will be matched, in order, for incoming requests. // The first route that matches will be used. repeated Route routes = 3; + // The match tree to use when resolving route actions for incoming requests. Onle one of this and `routes` + // can be specified. + xds.type.matcher.v3.Matcher matcher = 21; + // Specifies the type of TLS enforcement the virtual host expects. If this option is not // specified, there is no TLS requirement for the virtual host. TlsRequirementType require_tls = 4 [(validate.rules).enum = {defined_only: true}]; diff --git a/docs/root/intro/arch_overview/http/http_routing.rst b/docs/root/intro/arch_overview/http/http_routing.rst index a76eb3d7b356..022f84d67cc7 100644 --- a/docs/root/intro/arch_overview/http/http_routing.rst +++ b/docs/root/intro/arch_overview/http/http_routing.rst @@ -201,3 +201,47 @@ specify the route table. This is a more expressive matching engine than the orig for sublinear matching on arbitrary headers (unlike the original matching engine which could only do this for :authority in some cases). +To use the generic matching tree, specify a ref:`matcher ` on a virtual host with a RouteAction action: + +``` + matcher: + "@type": type.googleapis.com/envoy.config.common.matcher.v3.Matcher + matcher_tree: + input: + name: request-headers + typed_config: + "@type": type.googleapis.com/envoy.type.matcher.v3.HttpRequestHeaderMatchInput + header_name: :path + exact_match_map: + map: + "/new_endpoint/foo": + action: + name: route + typed_config: + "@type": type.googleapis.com/envoy.config.route.v3.Route + route: + cluster: cluster_foo + request_headers_to_add: + - header: + key: x-route-header + value: new-value + "/new_endpoint/bar": + action: + name: route + typed_config: + "@type": type.googleapis.com/envoy.config.route.v3.Route + route: + cluster: cluster_bar + request_headers_to_add: + - header: + key: x-route-header + value: new-value +``` + +This allows resolving the same Route proto message used for the `routes`-based routing using the additional +matching flexibility provided by the generic matching framework. + +Known limiations: +- The matching tree doesn't work with path rewrites. This is because this relies on rewriting the matched path + against the rewrite rule, but the matching engine allows matching on :path in many different ways, making it + ambiguous which path match should be used when rewriting. diff --git a/generated_api_shadow/envoy/config/route/v3/BUILD b/generated_api_shadow/envoy/config/route/v3/BUILD index 81cdfdf8a93a..730789f9801d 100644 --- a/generated_api_shadow/envoy/config/route/v3/BUILD +++ b/generated_api_shadow/envoy/config/route/v3/BUILD @@ -15,5 +15,6 @@ api_proto_package( "//envoy/type/tracing/v3:pkg", "//envoy/type/v3:pkg", "@com_github_cncf_udpa//udpa/annotations:pkg", + "@com_github_cncf_udpa//xds/type/matcher/v3:pkg", ], ) diff --git a/generated_api_shadow/envoy/config/route/v3/route_components.proto b/generated_api_shadow/envoy/config/route/v3/route_components.proto index ab11909efdad..2771a4a8a5a4 100644 --- a/generated_api_shadow/envoy/config/route/v3/route_components.proto +++ b/generated_api_shadow/envoy/config/route/v3/route_components.proto @@ -17,6 +17,8 @@ import "google/protobuf/duration.proto"; import "google/protobuf/struct.proto"; import "google/protobuf/wrappers.proto"; +import "xds/type/matcher/v3/matcher.proto"; + import "envoy/annotations/deprecation.proto"; import "udpa/annotations/migrate.proto"; import "udpa/annotations/status.proto"; @@ -83,13 +85,14 @@ message VirtualHost { items {string {well_known_regex: HTTP_HEADER_VALUE strict: false}} }]; - // This is mega hacky but gets around the circular dependency between this file and the matcher file. - google.protobuf.Any matcher = 21; - // The list of routes that will be matched, in order, for incoming requests. // The first route that matches will be used. repeated Route routes = 3; + // The match tree to use when resolving route actions for incoming requests. Onle one of this and `routes` + // can be specified. + xds.type.matcher.v3.Matcher matcher = 21; + // Specifies the type of TLS enforcement the virtual host expects. If this option is not // specified, there is no TLS requirement for the virtual host. TlsRequirementType require_tls = 4 [(validate.rules).enum = {defined_only: true}]; diff --git a/generated_api_shadow/envoy/config/route/v4alpha/BUILD b/generated_api_shadow/envoy/config/route/v4alpha/BUILD index 569a1a438e07..83a691f0704b 100644 --- a/generated_api_shadow/envoy/config/route/v4alpha/BUILD +++ b/generated_api_shadow/envoy/config/route/v4alpha/BUILD @@ -14,5 +14,6 @@ api_proto_package( "//envoy/type/tracing/v3:pkg", "//envoy/type/v3:pkg", "@com_github_cncf_udpa//udpa/annotations:pkg", + "@com_github_cncf_udpa//xds/type/matcher/v3:pkg", ], ) diff --git a/generated_api_shadow/envoy/config/route/v4alpha/route_components.proto b/generated_api_shadow/envoy/config/route/v4alpha/route_components.proto index d526cddd2ea2..d2c1a00fbbd1 100644 --- a/generated_api_shadow/envoy/config/route/v4alpha/route_components.proto +++ b/generated_api_shadow/envoy/config/route/v4alpha/route_components.proto @@ -16,6 +16,8 @@ import "google/protobuf/any.proto"; import "google/protobuf/duration.proto"; import "google/protobuf/wrappers.proto"; +import "xds/type/matcher/v3/matcher.proto"; + import "envoy/annotations/deprecation.proto"; import "udpa/annotations/status.proto"; import "udpa/annotations/versioning.proto"; @@ -83,13 +85,14 @@ message VirtualHost { items {string {well_known_regex: HTTP_HEADER_VALUE strict: false}} }]; - // This is mega hacky but gets around the circular dependency between this file and the matcher file. - google.protobuf.Any matcher = 21; - // The list of routes that will be matched, in order, for incoming requests. // The first route that matches will be used. repeated Route routes = 3; + // The match tree to use when resolving route actions for incoming requests. Onle one of this and `routes` + // can be specified. + xds.type.matcher.v3.Matcher matcher = 21; + // Specifies the type of TLS enforcement the virtual host expects. If this option is not // specified, there is no TLS requirement for the virtual host. TlsRequirementType require_tls = 4 [(validate.rules).enum = {defined_only: true}]; diff --git a/source/common/router/config_impl.cc b/source/common/router/config_impl.cc index 7a22a8f71ec6..601bcb0bf4f5 100644 --- a/source/common/router/config_impl.cc +++ b/source/common/router/config_impl.cc @@ -67,14 +67,20 @@ class MatchTreeRouteEntryImpl : public RouteEntryImplBase { public: using RouteEntryImplBase::RouteEntryImplBase; - virtual absl::optional - currentUrlPathAfterRewrite(const Http::RequestHeaderMap&) const override { - return absl::nullopt; - } RouteConstSharedPtr matches(const Http::RequestHeaderMap&, const StreamInfo::StreamInfo&, uint64_t) const override { + // This is used during match resolution for the old linear matcher, should never be called when + // we have a match tree defined. NOT_REACHED_GCOVR_EXCL_LINE; } + + // We can't support path rewrites since it requires us to have a single path that we match on, + // but the matcher tree affords too much flexibility here making that ambiguous. + // TODO(snowp): Can we use tree validation to prevent these fields from being set? + absl::optional + currentUrlPathAfterRewrite(const Http::RequestHeaderMap&) const override { + return absl::nullopt; + } PathMatchType matchType() const override { return PathMatchType::None; } const std::string& matcher() const override { NOT_REACHED_GCOVR_EXCL_LINE; } }; @@ -1331,16 +1337,17 @@ VirtualHostImpl::VirtualHostImpl( hedge_policy_ = virtual_host.hedge_policy(); } - if (virtual_host.has_matcher()) { - envoy::config::common::matcher::v3::Matcher matcher; - MessageUtil::anyConvertAndValidate(virtual_host.matcher(), matcher, validator); + if (virtual_host.has_matcher() && !virtual_host.routes().empty()) { + throw EnvoyException("cannot set both matcher and routes on virtual host"); + } + if (virtual_host.has_matcher()) { RouteActionContext context{*this, optional_http_filters, factory_context}; RouteActionValidationVisitor validation_visitor; Matcher::MatchTreeFactory factory( context, factory_context, validation_visitor); - matcher_ = factory.create(matcher)(); + matcher_ = factory.create(virtual_host.matcher())(); } else { for (const auto& route : virtual_host.routes()) { if (!route.has_match()) { @@ -1478,9 +1485,13 @@ RouteConstSharedPtr VirtualHostImpl::getRouteFromEntries(const RouteCallback& cb auto match = Matcher::evaluateMatch(*matcher_, data); if (match.result_) { - return dynamic_cast(*match.result_).route(); + ASSERT(dynamic_cast(match.result_.get())); + return static_cast(*match.result_).route(); } + // TODO(snowp): Add logger + // ENVOY_LOG(debug, "failed to match incoming request: {}", match.result_); + return nullptr; } else { // Check for a route that matches the request. diff --git a/test/common/router/config_impl_test.cc b/test/common/router/config_impl_test.cc index 6b98e1ceedef..78f1fee841b6 100644 --- a/test/common/router/config_impl_test.cc +++ b/test/common/router/config_impl_test.cc @@ -1225,7 +1225,7 @@ TEST_F(RouteMatcherTest, TestRoutesWithInvalidVirtualCluster) { "virtual clusters must define 'headers'"); } -// Validates behavior of request_headers_to_add at router, vhost, and route levels. +// Validates basic usage of the match tree to resolve route actions. TEST_F(RouteMatcherTest, TestMatchTree) { const std::string yaml = R"EOF( virtual_hosts: From 2de2fa8ec02fdb6bb104aedb13e43015653c6053 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Mon, 9 Aug 2021 14:25:43 +0000 Subject: [PATCH 26/44] comments Signed-off-by: Snow Pettersen --- source/common/router/config_impl.cc | 1 + source/common/router/config_impl.h | 3 +++ 2 files changed, 4 insertions(+) diff --git a/source/common/router/config_impl.cc b/source/common/router/config_impl.cc index 601bcb0bf4f5..f1e97d0ca828 100644 --- a/source/common/router/config_impl.cc +++ b/source/common/router/config_impl.cc @@ -63,6 +63,7 @@ void mergeTransforms(Http::HeaderTransforms& dest, const Http::HeaderTransforms& src.headers_to_remove.end()); } +// A RouteEntry produced via a generic matching tree. class MatchTreeRouteEntryImpl : public RouteEntryImplBase { public: using RouteEntryImplBase::RouteEntryImplBase; diff --git a/source/common/router/config_impl.h b/source/common/router/config_impl.h index 6cd090643779..72a9c22b8ce3 100644 --- a/source/common/router/config_impl.h +++ b/source/common/router/config_impl.h @@ -1047,12 +1047,14 @@ class ConnectRouteEntryImpl : public RouteEntryImplBase { bool supportsPathlessHeaders() const override { return true; } }; +// Contextual information used to construct the route actions for a match tree. struct RouteActionContext { const VirtualHostImpl& vhost; const OptionalHttpFilters& optional_http_filters; Server::Configuration::ServerFactoryContext& factory_context; }; +// Action used with the matching tree to specify route to use for an incoming stream. class RouteMatchAction : public Matcher::ActionBase { public: explicit RouteMatchAction(RouteConstSharedPtr route) : route_(std::move(route)) {} @@ -1063,6 +1065,7 @@ class RouteMatchAction : public Matcher::ActionBase { public: Matcher::ActionFactoryCb From fe81ce110fda2c00dbe8f0b4eb8f025720471558 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Mon, 9 Aug 2021 14:28:59 +0000 Subject: [PATCH 27/44] update comments Signed-off-by: Snow Pettersen --- api/envoy/config/route/v3/route_components.proto | 3 ++- api/envoy/config/route/v4alpha/route_components.proto | 3 ++- .../envoy/config/route/v3/route_components.proto | 3 ++- .../envoy/config/route/v4alpha/route_components.proto | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/api/envoy/config/route/v3/route_components.proto b/api/envoy/config/route/v3/route_components.proto index 4957bebc7ba5..0c75ddfa1256 100644 --- a/api/envoy/config/route/v3/route_components.proto +++ b/api/envoy/config/route/v3/route_components.proto @@ -88,9 +88,10 @@ message VirtualHost { // The list of routes that will be matched, in order, for incoming requests. // The first route that matches will be used. + // Only one of this and `matcher` can be specified. repeated Route routes = 3; - // The match tree to use when resolving route actions for incoming requests. Onle one of this and `routes` + // The match tree to use when resolving route actions for incoming requests. Only one of this and `routes` // can be specified. xds.type.matcher.v3.Matcher matcher = 21; diff --git a/api/envoy/config/route/v4alpha/route_components.proto b/api/envoy/config/route/v4alpha/route_components.proto index 10b00e83284a..61481818a9ca 100644 --- a/api/envoy/config/route/v4alpha/route_components.proto +++ b/api/envoy/config/route/v4alpha/route_components.proto @@ -86,9 +86,10 @@ message VirtualHost { // The list of routes that will be matched, in order, for incoming requests. // The first route that matches will be used. + // Only one of this and `matcher` can be specified. repeated Route routes = 3; - // The match tree to use when resolving route actions for incoming requests. Onle one of this and `routes` + // The match tree to use when resolving route actions for incoming requests. Only one of this and `routes` // can be specified. xds.type.matcher.v3.Matcher matcher = 21; diff --git a/generated_api_shadow/envoy/config/route/v3/route_components.proto b/generated_api_shadow/envoy/config/route/v3/route_components.proto index 2771a4a8a5a4..7942c460ab13 100644 --- a/generated_api_shadow/envoy/config/route/v3/route_components.proto +++ b/generated_api_shadow/envoy/config/route/v3/route_components.proto @@ -87,9 +87,10 @@ message VirtualHost { // The list of routes that will be matched, in order, for incoming requests. // The first route that matches will be used. + // Only one of this and `matcher` can be specified. repeated Route routes = 3; - // The match tree to use when resolving route actions for incoming requests. Onle one of this and `routes` + // The match tree to use when resolving route actions for incoming requests. Only one of this and `routes` // can be specified. xds.type.matcher.v3.Matcher matcher = 21; diff --git a/generated_api_shadow/envoy/config/route/v4alpha/route_components.proto b/generated_api_shadow/envoy/config/route/v4alpha/route_components.proto index d2c1a00fbbd1..49ddac5fdac6 100644 --- a/generated_api_shadow/envoy/config/route/v4alpha/route_components.proto +++ b/generated_api_shadow/envoy/config/route/v4alpha/route_components.proto @@ -87,9 +87,10 @@ message VirtualHost { // The list of routes that will be matched, in order, for incoming requests. // The first route that matches will be used. + // Only one of this and `matcher` can be specified. repeated Route routes = 3; - // The match tree to use when resolving route actions for incoming requests. Onle one of this and `routes` + // The match tree to use when resolving route actions for incoming requests. Only one of this and `routes` // can be specified. xds.type.matcher.v3.Matcher matcher = 21; From 90d687fd07537914a39428dbbcab5190e7a8eb77 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Mon, 9 Aug 2021 14:44:54 +0000 Subject: [PATCH 28/44] doc updates Signed-off-by: Snow Pettersen --- .../advanced/matching/matching_api.rst | 18 ++++++++++++++---- .../intro/arch_overview/http/http_routing.rst | 11 +++++++---- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/docs/root/intro/arch_overview/advanced/matching/matching_api.rst b/docs/root/intro/arch_overview/advanced/matching/matching_api.rst index 1b56eb354d28..9ae4b1c68585 100644 --- a/docs/root/intro/arch_overview/advanced/matching/matching_api.rst +++ b/docs/root/intro/arch_overview/advanced/matching/matching_api.rst @@ -16,6 +16,9 @@ better performance than the linear list matching as seen in Envoy's HTTP routing use of extension points to make it easy to extend to different inputs based on protocol or environment data as well as custom sublinear matchers and direct matchers. +Filter Integration +################## + Within supported environments (currently only HTTP filters), a wrapper proto can be used to instantiate a matching filter associated with the wrapped structure: @@ -28,7 +31,7 @@ The above example wraps a HTTP filter (the allowing us to define a match tree to be evaluated in conjunction with evaluation of the wrapped filter. Prior to data being made available to the filter, it will be provided to the match tree, which will then attempt to evaluate the matching rules with the provided data, triggering an -action if match evaluation completes in an action. +action if match evaluation results in an action. In the above example, we are specifying that we want to match on the incoming request header ``some-header`` by setting the ``input`` to @@ -54,7 +57,7 @@ the filter if ``some-header: skip_filter`` is present and ``second-header`` is s .. _arch_overview_matching_api_iteration_impact: HTTP Filter Iteration Impact -============================ +**************************** The above example only demonstrates matching on request headers, which ends up being the simplest case due to it happening before the associated filter receives any data. Matching on other HTTP @@ -80,8 +83,15 @@ client will receive an invalid response back from Envoy. If the skip action was trailers, the same gRPC-Web filter would consume all the data but never write it back out (as this happens when it sees the trailers), resulting in a gRPC-Web response with an empty body. +HTTP Routing Integration +######################## + +The matching API can be used with HTTP routing, by specifying a match tree as part of the virtual host +and specifying a Route as the resulting action. See examples in the above sections for how the match +tree can be configured. + Match Tree Validation -===================== +##################### As the match tree structure is very flexible, some filters might need to impose additional restrictions on what kind of match trees can be used. This system is somewhat inflexible at the moment, only supporting @@ -91,7 +101,7 @@ will fail during configuration load, reporting back which data input was invalid This is done for example to limit the issues talked about in :ref:`the above section ` or to help users understand in what -context a match tree can be used for a specific filter. Due to the limitations of the validations framework +context a match tree can be used for a specific filter. Due to the limitations of the validation framework at the current time, it is not used for all filters. For HTTP filters, the restrictions are specified by the filter implementation, so consult the individual diff --git a/docs/root/intro/arch_overview/http/http_routing.rst b/docs/root/intro/arch_overview/http/http_routing.rst index 022f84d67cc7..2e4f79690456 100644 --- a/docs/root/intro/arch_overview/http/http_routing.rst +++ b/docs/root/intro/arch_overview/http/http_routing.rst @@ -214,8 +214,8 @@ To use the generic matching tree, specify a ref:`matcher ` on a virtual hos header_name: :path exact_match_map: map: - "/new_endpoint/foo": - action: + "/new_endpoint/foo": + action: name: route typed_config: "@type": type.googleapis.com/envoy.config.route.v3.Route @@ -225,8 +225,8 @@ To use the generic matching tree, specify a ref:`matcher ` on a virtual hos - header: key: x-route-header value: new-value - "/new_endpoint/bar": - action: + "/new_endpoint/bar": + action: name: route typed_config: "@type": type.googleapis.com/envoy.config.route.v3.Route @@ -241,6 +241,9 @@ To use the generic matching tree, specify a ref:`matcher ` on a virtual hos This allows resolving the same Route proto message used for the `routes`-based routing using the additional matching flexibility provided by the generic matching framework. +The only inputs supported are request headers (via `envoy.type.matcher.v3.HttpRequestHeaderMatchInput`). See +the docs for the :ref:`matching API ` for more information about the API as a whole. + Known limiations: - The matching tree doesn't work with path rewrites. This is because this relies on rewriting the matched path against the rewrite rule, but the matching engine allows matching on :path in many different ways, making it From 90e233291f73de2d656710db53344d22cf67b647 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Mon, 9 Aug 2021 14:49:02 +0000 Subject: [PATCH 29/44] revert stuff from bad merge Signed-off-by: Snow Pettersen --- .../matching/input_matchers/consistent_hashing/config.cc | 2 +- .../matching/input_matchers/consistent_hashing/config.h | 6 +++--- .../input_matchers/consistent_hashing/config_test.cc | 8 +++----- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/source/extensions/matching/input_matchers/consistent_hashing/config.cc b/source/extensions/matching/input_matchers/consistent_hashing/config.cc index d7bdd01bb257..1f7f4eb61ebe 100644 --- a/source/extensions/matching/input_matchers/consistent_hashing/config.cc +++ b/source/extensions/matching/input_matchers/consistent_hashing/config.cc @@ -11,7 +11,7 @@ Envoy::Matcher::InputMatcherFactoryCb ConsistentHashingConfig::createInputMatche const auto& consistent_hashing_config = MessageUtil::downcastAndValidate( - config, validation_visitor); + config, factory_context.messageValidationVisitor()); if (consistent_hashing_config.threshold() > consistent_hashing_config.modulo()) { throw EnvoyException(fmt::format("threshold cannot be greater than modulo: {} > {}", diff --git a/source/extensions/matching/input_matchers/consistent_hashing/config.h b/source/extensions/matching/input_matchers/consistent_hashing/config.h index fa73fb2f683e..eda2f6fdf4fa 100644 --- a/source/extensions/matching/input_matchers/consistent_hashing/config.h +++ b/source/extensions/matching/input_matchers/consistent_hashing/config.h @@ -16,9 +16,9 @@ namespace ConsistentHashing { class ConsistentHashingConfig : public Envoy::Matcher::InputMatcherFactory { public: - Envoy::Matcher::InputMatcherFactoryCb - createInputMatcherFactoryCb(const Protobuf::Message& config, - ProtobufMessage::ValidationVisitor& validation_visitor) override; + Envoy::Matcher::InputMatcherFactoryCb createInputMatcherFactoryCb( + const Protobuf::Message& config, + Server::Configuration::ServerFactoryContext& factory_context) override; std::string name() const override { return "envoy.matching.matchers.consistent_hashing"; } diff --git a/test/extensions/matching/input_matchers/consistent_hashing/config_test.cc b/test/extensions/matching/input_matchers/consistent_hashing/config_test.cc index 845ac1e49225..821b9b8998c0 100644 --- a/test/extensions/matching/input_matchers/consistent_hashing/config_test.cc +++ b/test/extensions/matching/input_matchers/consistent_hashing/config_test.cc @@ -26,8 +26,7 @@ TEST(ConfigTest, TestConfig) { ConsistentHashingConfig factory; auto message = Config::Utility::translateAnyToFactoryConfig( config.typed_config(), ProtobufMessage::getStrictValidationVisitor(), factory); - auto matcher = - factory.createInputMatcherFactoryCb(*message, ProtobufMessage::getStrictValidationVisitor()); + auto matcher = factory.createInputMatcherFactoryCb(*message, factory_context); ASSERT_NE(nullptr, matcher); matcher(); } @@ -49,9 +48,8 @@ TEST(ConfigTest, InvalidConfig) { ConsistentHashingConfig factory; auto message = Config::Utility::translateAnyToFactoryConfig( config.typed_config(), ProtobufMessage::getStrictValidationVisitor(), factory); - EXPECT_THROW_WITH_MESSAGE( - factory.createInputMatcherFactoryCb(*message, ProtobufMessage::getStrictValidationVisitor()), - EnvoyException, "threshold cannot be greater than modulo: 200 > 100"); + EXPECT_THROW_WITH_MESSAGE(factory.createInputMatcherFactoryCb(*message, factory_context), + EnvoyException, "threshold cannot be greater than modulo: 200 > 100"); } } // namespace ConsistentHashing } // namespace InputMatchers From 921dcddd424f014b7c34cb32da2afdad3a959d58 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Mon, 23 Aug 2021 23:51:32 +0000 Subject: [PATCH 30/44] wip Signed-off-by: Snow Pettersen --- docs/root/intro/arch_overview/http/http_routing.rst | 7 ++++--- source/common/router/config_impl.cc | 9 ++++++++- source/common/router/config_impl.h | 6 +++--- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/docs/root/intro/arch_overview/http/http_routing.rst b/docs/root/intro/arch_overview/http/http_routing.rst index 2e4f79690456..c6761b964cbf 100644 --- a/docs/root/intro/arch_overview/http/http_routing.rst +++ b/docs/root/intro/arch_overview/http/http_routing.rst @@ -203,7 +203,8 @@ do this for :authority in some cases). To use the generic matching tree, specify a ref:`matcher ` on a virtual host with a RouteAction action: -``` +.. code-block:: yaml + matcher: "@type": type.googleapis.com/envoy.config.common.matcher.v3.Matcher matcher_tree: @@ -236,7 +237,6 @@ To use the generic matching tree, specify a ref:`matcher ` on a virtual hos - header: key: x-route-header value: new-value -``` This allows resolving the same Route proto message used for the `routes`-based routing using the additional matching flexibility provided by the generic matching framework. @@ -245,6 +245,7 @@ The only inputs supported are request headers (via `envoy.type.matcher.v3.HttpRe the docs for the :ref:`matching API ` for more information about the API as a whole. Known limiations: -- The matching tree doesn't work with path rewrites. This is because this relies on rewriting the matched path + +* The matching tree doesn't work with path rewrites. This is because this relies on rewriting the matched path against the rewrite rule, but the matching engine allows matching on :path in many different ways, making it ambiguous which path match should be used when rewriting. diff --git a/source/common/router/config_impl.cc b/source/common/router/config_impl.cc index f1e97d0ca828..a46b2a7b291d 100644 --- a/source/common/router/config_impl.cc +++ b/source/common/router/config_impl.cc @@ -1487,7 +1487,14 @@ RouteConstSharedPtr VirtualHostImpl::getRouteFromEntries(const RouteCallback& cb if (match.result_) { ASSERT(dynamic_cast(match.result_.get())); - return static_cast(*match.result_).route(); + + const RouteMatchAction& route_action = static_cast(*match.result_); + + if (route_action.route()->matches(headers, stream_info, random_value)) { + return route_action.route(); + } + + return nullptr; } // TODO(snowp): Add logger diff --git a/source/common/router/config_impl.h b/source/common/router/config_impl.h index 72a9c22b8ce3..ee8c42abf47e 100644 --- a/source/common/router/config_impl.h +++ b/source/common/router/config_impl.h @@ -1057,12 +1057,12 @@ struct RouteActionContext { // Action used with the matching tree to specify route to use for an incoming stream. class RouteMatchAction : public Matcher::ActionBase { public: - explicit RouteMatchAction(RouteConstSharedPtr route) : route_(std::move(route)) {} + explicit RouteMatchAction(RouteEntryImplBaseConstSharedPtr route) : route_(std::move(route)) {} - RouteConstSharedPtr route() const { return route_; } + RouteEntryImplBaseConstSharedPtr route() const { return route_; } private: - const RouteConstSharedPtr route_; + const RouteEntryImplBaseConstSharedPtr route_; }; // Registered factory for RouteMatchAction. From 686344261cb9e25f6353695a28f7bffe9d9047b3 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Sun, 29 Aug 2021 13:42:39 +0000 Subject: [PATCH 31/44] evaluate matched route in order to support path rewriting Signed-off-by: Snow Pettersen --- .../config/route/v3/route_components.proto | 3 +- .../route/v4alpha/route_components.proto | 3 +- .../intro/arch_overview/http/http_routing.rst | 15 ++++++---- .../config/route/v3/route_components.proto | 3 +- .../route/v4alpha/route_components.proto | 3 +- source/common/router/config_impl.cc | 28 ++----------------- test/common/router/config_impl_test.cc | 5 +++- 7 files changed, 23 insertions(+), 37 deletions(-) diff --git a/api/envoy/config/route/v3/route_components.proto b/api/envoy/config/route/v3/route_components.proto index 0c75ddfa1256..1ae40c59235d 100644 --- a/api/envoy/config/route/v3/route_components.proto +++ b/api/envoy/config/route/v3/route_components.proto @@ -91,6 +91,7 @@ message VirtualHost { // Only one of this and `matcher` can be specified. repeated Route routes = 3; + // [#next-major-version: This should be included in a oneof with routes wrapped in a message.] // The match tree to use when resolving route actions for incoming requests. Only one of this and `routes` // can be specified. xds.type.matcher.v3.Matcher matcher = 21; @@ -221,7 +222,7 @@ message Route { string name = 14; // Route matching parameters. - RouteMatch match = 1; + RouteMatch match = 1 [(validate.rules).message = {required: true}]; oneof action { option (validate.required) = true; diff --git a/api/envoy/config/route/v4alpha/route_components.proto b/api/envoy/config/route/v4alpha/route_components.proto index 61481818a9ca..f249a70090cd 100644 --- a/api/envoy/config/route/v4alpha/route_components.proto +++ b/api/envoy/config/route/v4alpha/route_components.proto @@ -89,6 +89,7 @@ message VirtualHost { // Only one of this and `matcher` can be specified. repeated Route routes = 3; + // [#next-major-version: This should be included in a oneof with routes wrapped in a message.] // The match tree to use when resolving route actions for incoming requests. Only one of this and `routes` // can be specified. xds.type.matcher.v3.Matcher matcher = 21; @@ -219,7 +220,7 @@ message Route { string name = 14; // Route matching parameters. - RouteMatch match = 1; + RouteMatch match = 1 [(validate.rules).message = {required: true}]; oneof action { option (validate.required) = true; diff --git a/docs/root/intro/arch_overview/http/http_routing.rst b/docs/root/intro/arch_overview/http/http_routing.rst index c6761b964cbf..70dd13f64c35 100644 --- a/docs/root/intro/arch_overview/http/http_routing.rst +++ b/docs/root/intro/arch_overview/http/http_routing.rst @@ -220,6 +220,8 @@ To use the generic matching tree, specify a ref:`matcher ` on a virtual hos name: route typed_config: "@type": type.googleapis.com/envoy.config.route.v3.Route + match: + prefix: / route: cluster: cluster_foo request_headers_to_add: @@ -231,6 +233,8 @@ To use the generic matching tree, specify a ref:`matcher ` on a virtual hos name: route typed_config: "@type": type.googleapis.com/envoy.config.route.v3.Route + match: + prefix: / route: cluster: cluster_bar request_headers_to_add: @@ -241,11 +245,10 @@ To use the generic matching tree, specify a ref:`matcher ` on a virtual hos This allows resolving the same Route proto message used for the `routes`-based routing using the additional matching flexibility provided by the generic matching framework. +Note that the resulting Route also specifies a match criteria. This must be satisfied in addition to resolving +the route in order to achieve a route match. When path rewrites are used, the matched path will only depend on +the match criteria of the resolved Route. Path matching done during the match tree traversal does not contribute +to path rewrites. + The only inputs supported are request headers (via `envoy.type.matcher.v3.HttpRequestHeaderMatchInput`). See the docs for the :ref:`matching API ` for more information about the API as a whole. - -Known limiations: - -* The matching tree doesn't work with path rewrites. This is because this relies on rewriting the matched path - against the rewrite rule, but the matching engine allows matching on :path in many different ways, making it - ambiguous which path match should be used when rewriting. diff --git a/generated_api_shadow/envoy/config/route/v3/route_components.proto b/generated_api_shadow/envoy/config/route/v3/route_components.proto index 7942c460ab13..49d1aa06388e 100644 --- a/generated_api_shadow/envoy/config/route/v3/route_components.proto +++ b/generated_api_shadow/envoy/config/route/v3/route_components.proto @@ -90,6 +90,7 @@ message VirtualHost { // Only one of this and `matcher` can be specified. repeated Route routes = 3; + // [#next-major-version: This should be included in a oneof with routes wrapped in a message.] // The match tree to use when resolving route actions for incoming requests. Only one of this and `routes` // can be specified. xds.type.matcher.v3.Matcher matcher = 21; @@ -221,7 +222,7 @@ message Route { string name = 14; // Route matching parameters. - RouteMatch match = 1; + RouteMatch match = 1 [(validate.rules).message = {required: true}]; oneof action { option (validate.required) = true; diff --git a/generated_api_shadow/envoy/config/route/v4alpha/route_components.proto b/generated_api_shadow/envoy/config/route/v4alpha/route_components.proto index 49ddac5fdac6..a669b128892d 100644 --- a/generated_api_shadow/envoy/config/route/v4alpha/route_components.proto +++ b/generated_api_shadow/envoy/config/route/v4alpha/route_components.proto @@ -90,6 +90,7 @@ message VirtualHost { // Only one of this and `matcher` can be specified. repeated Route routes = 3; + // [#next-major-version: This should be included in a oneof with routes wrapped in a message.] // The match tree to use when resolving route actions for incoming requests. Only one of this and `routes` // can be specified. xds.type.matcher.v3.Matcher matcher = 21; @@ -220,7 +221,7 @@ message Route { string name = 14; // Route matching parameters. - RouteMatch match = 1; + RouteMatch match = 1 [(validate.rules).message = {required: true}]; oneof action { option (validate.required) = true; diff --git a/source/common/router/config_impl.cc b/source/common/router/config_impl.cc index a46b2a7b291d..0e12be1d4863 100644 --- a/source/common/router/config_impl.cc +++ b/source/common/router/config_impl.cc @@ -63,29 +63,6 @@ void mergeTransforms(Http::HeaderTransforms& dest, const Http::HeaderTransforms& src.headers_to_remove.end()); } -// A RouteEntry produced via a generic matching tree. -class MatchTreeRouteEntryImpl : public RouteEntryImplBase { -public: - using RouteEntryImplBase::RouteEntryImplBase; - - RouteConstSharedPtr matches(const Http::RequestHeaderMap&, const StreamInfo::StreamInfo&, - uint64_t) const override { - // This is used during match resolution for the old linear matcher, should never be called when - // we have a match tree defined. - NOT_REACHED_GCOVR_EXCL_LINE; - } - - // We can't support path rewrites since it requires us to have a single path that we match on, - // but the matcher tree affords too much flexibility here making that ambiguous. - // TODO(snowp): Can we use tree validation to prevent these fields from being set? - absl::optional - currentUrlPathAfterRewrite(const Http::RequestHeaderMap&) const override { - return absl::nullopt; - } - PathMatchType matchType() const override { return PathMatchType::None; } - const std::string& matcher() const override { NOT_REACHED_GCOVR_EXCL_LINE; } -}; - RouteEntryImplBaseConstSharedPtr createAndValidateRoute( const envoy::config::route::v3::Route& route_config, const VirtualHostImpl& vhost, const OptionalHttpFilters& optional_http_filters, @@ -1723,9 +1700,8 @@ Matcher::ActionFactoryCb RouteMatchActionFactory::createActionFactoryCb( const auto& route_config = MessageUtil::downcastAndValidate(config, validation_visitor); - auto route = std::make_shared( - context.vhost, route_config, context.optional_http_filters, context.factory_context, - validation_visitor); + auto route = createAndValidateRoute(route_config, context.vhost, context.optional_http_filters, + context.factory_context, validation_visitor, absl::nullopt); return [route]() { return std::make_unique(route); }; } diff --git a/test/common/router/config_impl_test.cc b/test/common/router/config_impl_test.cc index 78f1fee841b6..15873969972d 100644 --- a/test/common/router/config_impl_test.cc +++ b/test/common/router/config_impl_test.cc @@ -1233,7 +1233,6 @@ TEST_F(RouteMatcherTest, TestMatchTree) { domains: - lyft.com matcher: - "@type": type.googleapis.com/envoy.config.common.matcher.v3.Matcher matcher_tree: input: name: request-headers @@ -1247,6 +1246,8 @@ TEST_F(RouteMatcherTest, TestMatchTree) { name: route typed_config: "@type": type.googleapis.com/envoy.config.route.v3.Route + match: + prefix: / route: cluster: root_ww2 request_headers_to_add: @@ -1258,6 +1259,8 @@ TEST_F(RouteMatcherTest, TestMatchTree) { name: route typed_config: "@type": type.googleapis.com/envoy.config.route.v3.Route + match: + prefix: / route: cluster: root_ww2 request_headers_to_add: From f75e5394304fb86635a43b2673fc7808963328df Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Tue, 31 Aug 2021 15:31:00 +0000 Subject: [PATCH 32/44] fix docs Signed-off-by: Snow Pettersen --- docs/root/intro/arch_overview/http/http_routing.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/root/intro/arch_overview/http/http_routing.rst b/docs/root/intro/arch_overview/http/http_routing.rst index 70dd13f64c35..2c20dd9428f9 100644 --- a/docs/root/intro/arch_overview/http/http_routing.rst +++ b/docs/root/intro/arch_overview/http/http_routing.rst @@ -196,17 +196,17 @@ Envoy will include the specified headers in the direct HTTP response. Routing Via Generic Matching ---------------------------- -Envoy recently added support for utilzing a :ref:`generic match tree ` to +Envoy recently added support for utilzing a :ref:`generic match tree ` to specify the route table. This is a more expressive matching engine than the original one, allowing for sublinear matching on arbitrary headers (unlike the original matching engine which could only do this for :authority in some cases). -To use the generic matching tree, specify a ref:`matcher ` on a virtual host with a RouteAction action: +To use the generic matching tree, specify a matcher on a virtual host with a RouteAction action: .. code-block:: yaml matcher: - "@type": type.googleapis.com/envoy.config.common.matcher.v3.Matcher + "@type": type.googleapis.com/xds.type.matcher.v3.Matcher matcher_tree: input: name: request-headers From 9eedbd53c3ac1eebd772bc1533ce6dbb515e703b Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Tue, 31 Aug 2021 17:37:41 +0000 Subject: [PATCH 33/44] remove trailing whitespace Signed-off-by: Snow Pettersen --- test/common/router/config_impl_test.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/common/router/config_impl_test.cc b/test/common/router/config_impl_test.cc index a92a2d819c14..43babdcc0993 100644 --- a/test/common/router/config_impl_test.cc +++ b/test/common/router/config_impl_test.cc @@ -1231,8 +1231,8 @@ TEST_F(RouteMatcherTest, TestMatchTree) { header_name: :path exact_match_map: map: - "/new_endpoint/foo": - action: + "/new_endpoint/foo": + action: name: route typed_config: "@type": type.googleapis.com/envoy.config.route.v3.Route @@ -1244,8 +1244,8 @@ TEST_F(RouteMatcherTest, TestMatchTree) { - header: key: x-route-header value: match_tree - "/new_endpoint/bar": - action: + "/new_endpoint/bar": + action: name: route typed_config: "@type": type.googleapis.com/envoy.config.route.v3.Route From b31ef7a8daf32b4fe12bbca824ddfdd53ed718ff Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Wed, 1 Sep 2021 13:28:06 +0000 Subject: [PATCH 34/44] remove merge marker Signed-off-by: Snow Pettersen --- source/common/router/config_impl.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/source/common/router/config_impl.cc b/source/common/router/config_impl.cc index 2f1a9f4a654a..d12df3ee6d0f 100644 --- a/source/common/router/config_impl.cc +++ b/source/common/router/config_impl.cc @@ -63,7 +63,6 @@ void mergeTransforms(Http::HeaderTransforms& dest, const Http::HeaderTransforms& src.headers_to_remove.end()); } -<<<<<<< HEAD RouteEntryImplBaseConstSharedPtr createAndValidateRoute( const envoy::config::route::v3::Route& route_config, const VirtualHostImpl& vhost, const OptionalHttpFilters& optional_http_filters, From 2c2be125b834d94dfece3912a1a53f436a74afd5 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Thu, 2 Sep 2021 16:01:18 +0000 Subject: [PATCH 35/44] integration test, runtime flag Signed-off-by: Snow Pettersen --- .../config/route/v3/route_components.proto | 4 ++ .../config/route/v3/route_components.proto | 4 ++ source/common/router/config_impl.cc | 5 ++ test/common/router/config_impl_test.cc | 56 +++++++++++++++++++ test/integration/integration_test.cc | 49 ++++++++++++++++ 5 files changed, 118 insertions(+) diff --git a/api/envoy/config/route/v3/route_components.proto b/api/envoy/config/route/v3/route_components.proto index ef6c57ac8778..951f1548dd1e 100644 --- a/api/envoy/config/route/v3/route_components.proto +++ b/api/envoy/config/route/v3/route_components.proto @@ -95,6 +95,10 @@ message VirtualHost { // [#next-major-version: This should be included in a oneof with routes wrapped in a message.] // The match tree to use when resolving route actions for incoming requests. Only one of this and `routes` // can be specified. + // + // Note that this API is experimental and must be explicitly enabled by setting the runtime + // "envoy.reloadable_features.experimental_matching_api" to "true". + // [#alpha:] xds.type.matcher.v3.Matcher matcher = 21; // Specifies the type of TLS enforcement the virtual host expects. If this option is not diff --git a/generated_api_shadow/envoy/config/route/v3/route_components.proto b/generated_api_shadow/envoy/config/route/v3/route_components.proto index 4cdac6a227a6..ffd700b785be 100644 --- a/generated_api_shadow/envoy/config/route/v3/route_components.proto +++ b/generated_api_shadow/envoy/config/route/v3/route_components.proto @@ -94,6 +94,10 @@ message VirtualHost { // [#next-major-version: This should be included in a oneof with routes wrapped in a message.] // The match tree to use when resolving route actions for incoming requests. Only one of this and `routes` // can be specified. + // + // Note that this API is experimental and must be explicitly enabled by setting the runtime + // "envoy.reloadable_features.experimental_matching_api" to "true". + // [#alpha:] xds.type.matcher.v3.Matcher matcher = 21; // Specifies the type of TLS enforcement the virtual host expects. If this option is not diff --git a/source/common/router/config_impl.cc b/source/common/router/config_impl.cc index d12df3ee6d0f..a0984b4ecdd9 100644 --- a/source/common/router/config_impl.cc +++ b/source/common/router/config_impl.cc @@ -1318,6 +1318,11 @@ VirtualHostImpl::VirtualHostImpl( hedge_policy_ = virtual_host.hedge_policy(); } + if (virtual_host.has_matcher() && + !Runtime::runtimeFeatureEnabled("envoy.reloadable_features.experimental_matching_api")) { + throw EnvoyException("Experimental matching API is not enabled"); + } + if (virtual_host.has_matcher() && !virtual_host.routes().empty()) { throw EnvoyException("cannot set both matcher and routes on virtual host"); } diff --git a/test/common/router/config_impl_test.cc b/test/common/router/config_impl_test.cc index 43babdcc0993..850a5c5a46a0 100644 --- a/test/common/router/config_impl_test.cc +++ b/test/common/router/config_impl_test.cc @@ -1217,6 +1217,10 @@ TEST_F(RouteMatcherTest, TestRoutesWithInvalidVirtualCluster) { // Validates basic usage of the match tree to resolve route actions. TEST_F(RouteMatcherTest, TestMatchTree) { + TestScopedRuntime scoped_runtime; + Runtime::LoaderSingleton::getExisting()->mergeValues( + {{"envoy.reloadable_features.experimental_matching_api", "true"}}); + const std::string yaml = R"EOF( virtual_hosts: - name: www2 @@ -1279,6 +1283,58 @@ TEST_F(RouteMatcherTest, TestMatchTree) { } } +// Validates that we fail creating a route config with the match tree unless the runtime flag is +// set. +TEST_F(RouteMatcherTest, TestMatchTreeDisabledByDefault) { + const std::string yaml = R"EOF( +virtual_hosts: +- name: www2 + domains: + - lyft.com + matcher: + matcher_tree: + input: + name: request-headers + typed_config: + "@type": type.googleapis.com/envoy.type.matcher.v3.HttpRequestHeaderMatchInput + header_name: :path + exact_match_map: + map: + "/new_endpoint/foo": + action: + name: route + typed_config: + "@type": type.googleapis.com/envoy.config.route.v3.Route + match: + prefix: / + route: + cluster: root_ww2 + request_headers_to_add: + - header: + key: x-route-header + value: match_tree + "/new_endpoint/bar": + action: + name: route + typed_config: + "@type": type.googleapis.com/envoy.config.route.v3.Route + match: + prefix: / + route: + cluster: root_ww2 + request_headers_to_add: + - header: + key: x-route-header + value: match_tree_2 + )EOF"; + + NiceMock stream_info; + factory_context_.cluster_manager_.initializeClusters( + {"www2", "root_www2", "www2_staging", "instant-server"}, {}); + EXPECT_THROW(TestConfigImpl(parseRouteConfigurationFromYaml(yaml), factory_context_, true), + EnvoyException); +} + // Validates behavior of request_headers_to_add at router, vhost, and route levels. TEST_F(RouteMatcherTest, TestAddRemoveRequestHeaders) { const std::string yaml = R"EOF( diff --git a/test/integration/integration_test.cc b/test/integration/integration_test.cc index 450e787dd71e..da96133e9c36 100644 --- a/test/integration/integration_test.cc +++ b/test/integration/integration_test.cc @@ -561,6 +561,55 @@ name: matcher second_codec->close(); } +// Verifies routing via the match tree API. +TEST_P(IntegrationTest, MatchTreeRouting) { + config_helper_.addRuntimeOverride("envoy.reloadable_features.experimental_matching_api", "true"); + + const std::string vhost_yaml = R"EOF( + name: vhost + domains: ["matcher.com"] + matcher: + matcher_tree: + input: + name: request-headers + typed_config: + "@type": type.googleapis.com/envoy.type.matcher.v3.HttpRequestHeaderMatchInput + header_name: match-header + exact_match_map: + map: + "route": + action: + name: route + typed_config: + "@type": type.googleapis.com/envoy.config.route.v3.Route + match: + prefix: / + route: + cluster: cluster_0 + )EOF"; + + envoy::config::route::v3::VirtualHost virtual_host; + TestUtility::loadFromYaml(vhost_yaml, virtual_host); + + config_helper_.addVirtualHost(virtual_host); + autonomous_upstream_ = true; + + initialize(); + + codec_client_ = makeHttpConnection(lookupPort("http")); + + Http::TestRequestHeaderMapImpl headers{{":method", "GET"}, + {":path", "/whatever"}, + {":scheme", "http"}, + {"match-header", "route"}, + {":authority", "matcher.com"}}; + auto response = codec_client_->makeHeaderOnlyRequest(headers); + ASSERT_TRUE(response->waitForEndStream()); + EXPECT_THAT(response->headers(), HttpStatusIs("200")); + + codec_client_->close(); +} + // This is a regression for https://github.com/envoyproxy/envoy/issues/2715 and validates that a // pending request is not sent on a connection that has been half-closed. TEST_P(IntegrationTest, UpstreamDisconnectWithTwoRequests) { From 082376d5835c2e862fa8bf5e976c10a1e98b7c2d Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Thu, 2 Sep 2021 16:36:45 +0000 Subject: [PATCH 36/44] remove trailing whitespace Signed-off-by: Snow Pettersen --- test/integration/integration_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/integration_test.cc b/test/integration/integration_test.cc index da96133e9c36..5aeb0e3ff8ca 100644 --- a/test/integration/integration_test.cc +++ b/test/integration/integration_test.cc @@ -568,7 +568,7 @@ TEST_P(IntegrationTest, MatchTreeRouting) { const std::string vhost_yaml = R"EOF( name: vhost domains: ["matcher.com"] - matcher: + matcher: matcher_tree: input: name: request-headers From c3149c4fee67d8900f7cd3c958aa52307a7c0113 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Wed, 22 Sep 2021 18:52:13 +0000 Subject: [PATCH 37/44] wip Signed-off-by: Snow Pettersen --- source/common/matcher/matcher.h | 9 +++-- source/common/router/config_impl.cc | 30 +++++++++----- source/common/router/config_impl.h | 3 +- test/common/router/config_impl_test.cc | 55 ++++++++++++++++++++++++++ 4 files changed, 82 insertions(+), 15 deletions(-) diff --git a/source/common/matcher/matcher.h b/source/common/matcher/matcher.h index 2055e460aad0..c81a75a18c5a 100644 --- a/source/common/matcher/matcher.h +++ b/source/common/matcher/matcher.h @@ -25,12 +25,13 @@ namespace Matcher { template class ActionBase : public Action { public: - ActionBase() : type_name_(ProtoType().GetTypeName()) {} + absl::string_view typeUrl() const override { return staticTypeUrl(); } - absl::string_view typeUrl() const override { return type_name_; } + static absl::string_view staticTypeUrl() { + const static std::string typeUrl = ProtoType().GetTypeName(); -private: - const std::string type_name_; + return typeUrl; + } }; struct MaybeMatchResult { diff --git a/source/common/router/config_impl.cc b/source/common/router/config_impl.cc index a0984b4ecdd9..f6d363095ced 100644 --- a/source/common/router/config_impl.cc +++ b/source/common/router/config_impl.cc @@ -13,6 +13,8 @@ #include "envoy/config/core/v3/base.pb.h" #include "envoy/config/route/v3/route.pb.h" #include "envoy/config/route/v3/route_components.pb.h" +#include "envoy/type/matcher/v3/http_inputs.pb.h" +#include "envoy/type/matcher/v3/http_inputs.pb.validate.h" #include "envoy/http/header_map.h" #include "envoy/runtime/runtime.h" #include "envoy/type/matcher/v3/string.pb.h" @@ -115,8 +117,14 @@ class RouteActionValidationVisitor : public Matcher::MatchTreeValidationVisitor { public: absl::Status performDataInputValidation(const Matcher::DataInputFactory&, - absl::string_view) override { - return absl::OkStatus(); + absl::string_view type_url) override { + static std::string request_header_input_name = TypeUtil::descriptorFullNameToTypeUrl( + envoy::type::matcher::v3::HttpRequestHeaderMatchInput::descriptor()->full_name()); + if (type_url == request_header_input_name) { + return absl::OkStatus(); + } + + return absl::InvalidArgumentError("Route table can only match on request headers"); } }; @@ -1318,9 +1326,10 @@ VirtualHostImpl::VirtualHostImpl( hedge_policy_ = virtual_host.hedge_policy(); } + constexpr absl::string_view feature_flag = "envoy.reloadable_features.experimental_matching_api"; if (virtual_host.has_matcher() && - !Runtime::runtimeFeatureEnabled("envoy.reloadable_features.experimental_matching_api")) { - throw EnvoyException("Experimental matching API is not enabled"); + !Runtime::runtimeFeatureEnabled(feature_flag)) { + throw EnvoyException(fmt::format("Experimental matching API is not enabled: set `{}` to true to enable", feature_flag)); } if (virtual_host.has_matcher() && !virtual_host.routes().empty()) { @@ -1336,9 +1345,6 @@ VirtualHostImpl::VirtualHostImpl( matcher_ = factory.create(virtual_host.matcher())(); } else { for (const auto& route : virtual_host.routes()) { - if (!route.has_match()) { - throw EnvoyException("RouteValidationError.Match"); - } routes_.emplace_back(createAndValidateRoute(route, *this, optional_http_filters, factory_context, validator, validation_clusters)); } @@ -1471,19 +1477,23 @@ RouteConstSharedPtr VirtualHostImpl::getRouteFromEntries(const RouteCallback& cb auto match = Matcher::evaluateMatch(*matcher_, data); if (match.result_) { - ASSERT(dynamic_cast(match.result_.get())); + if (match.result_->typeUrl() != RouteMatchAction::staticTypeUrl()) { + ENVOY_LOG(error, "resolved unexpected match action {}", match.result_->typeUrl()); + return nullptr; + } + ASSERT(dynamic_cast(match.result_.get())); const RouteMatchAction& route_action = static_cast(*match.result_); if (route_action.route()->matches(headers, stream_info, random_value)) { return route_action.route(); } + ENVOY_LOG(debug, "route was resolved but final route did not match incoming request"); return nullptr; } - // TODO(snowp): Add logger - // ENVOY_LOG(debug, "failed to match incoming request: {}", match.result_); + ENVOY_LOG(debug, "failed to match incoming request: {}", match.match_state_); return nullptr; } else { diff --git a/source/common/router/config_impl.h b/source/common/router/config_impl.h index bf4e0a8f04ee..395ab22d85a5 100644 --- a/source/common/router/config_impl.h +++ b/source/common/router/config_impl.h @@ -191,7 +191,8 @@ class ConfigImpl; /** * Holds all routing configuration for an entire virtual host. */ -class VirtualHostImpl : public VirtualHost { +class VirtualHostImpl : public VirtualHost, + Logger::Loggable { public: VirtualHostImpl( const envoy::config::route::v3::VirtualHost& virtual_host, diff --git a/test/common/router/config_impl_test.cc b/test/common/router/config_impl_test.cc index 850a5c5a46a0..398529b2b4d9 100644 --- a/test/common/router/config_impl_test.cc +++ b/test/common/router/config_impl_test.cc @@ -1335,6 +1335,61 @@ TEST_F(RouteMatcherTest, TestMatchTreeDisabledByDefault) { EnvoyException); } +// Validates that we fail creating a route config if an invalid data input is used. +TEST_F(RouteMatcherTest, TestMatchInvalidInput) { + TestScopedRuntime scoped_runtime; + Runtime::LoaderSingleton::getExisting()->mergeValues( + {{"envoy.reloadable_features.experimental_matching_api", "true"}}); + + const std::string yaml = R"EOF( +virtual_hosts: +- name: www2 + domains: + - lyft.com + matcher: + matcher_tree: + input: + name: request-headers + typed_config: + "@type": type.googleapis.com/envoy.type.matcher.v3.HttpResponseHeaderMatchInput + header_name: :path + exact_match_map: + map: + "/new_endpoint/foo": + action: + name: route + typed_config: + "@type": type.googleapis.com/envoy.config.route.v3.Route + match: + prefix: / + route: + cluster: root_ww2 + request_headers_to_add: + - header: + key: x-route-header + value: match_tree + "/new_endpoint/bar": + action: + name: route + typed_config: + "@type": type.googleapis.com/envoy.config.route.v3.Route + match: + prefix: / + route: + cluster: root_ww2 + request_headers_to_add: + - header: + key: x-route-header + value: match_tree_2 + )EOF"; + + NiceMock stream_info; + factory_context_.cluster_manager_.initializeClusters( + {"www2", "root_www2", "www2_staging", "instant-server"}, {}); + EXPECT_THROW_WITH_MESSAGE(TestConfigImpl(parseRouteConfigurationFromYaml(yaml), factory_context_, true), + EnvoyException, "hello"); +} + // Validates behavior of request_headers_to_add at router, vhost, and route levels. TEST_F(RouteMatcherTest, TestAddRemoveRequestHeaders) { const std::string yaml = R"EOF( From 82a5fdd14119fe2f32b81569d856000d4d451284 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Wed, 29 Sep 2021 15:34:44 +0000 Subject: [PATCH 38/44] validate data input Signed-off-by: Snow Pettersen --- source/common/router/config_impl.cc | 15 +++++++++++---- test/common/router/config_impl_test.cc | 7 +++++-- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/source/common/router/config_impl.cc b/source/common/router/config_impl.cc index f6d363095ced..0bd5fcfa2e31 100644 --- a/source/common/router/config_impl.cc +++ b/source/common/router/config_impl.cc @@ -124,7 +124,8 @@ class RouteActionValidationVisitor return absl::OkStatus(); } - return absl::InvalidArgumentError("Route table can only match on request headers"); + return absl::InvalidArgumentError( + fmt::format("Route table can only match on request headers, saw {}", type_url)); } }; @@ -1327,9 +1328,9 @@ VirtualHostImpl::VirtualHostImpl( } constexpr absl::string_view feature_flag = "envoy.reloadable_features.experimental_matching_api"; - if (virtual_host.has_matcher() && - !Runtime::runtimeFeatureEnabled(feature_flag)) { - throw EnvoyException(fmt::format("Experimental matching API is not enabled: set `{}` to true to enable", feature_flag)); + if (virtual_host.has_matcher() && !Runtime::runtimeFeatureEnabled(feature_flag)) { + throw EnvoyException(fmt::format( + "Experimental matching API is not enabled: set `{}` to true to enable", feature_flag)); } if (virtual_host.has_matcher() && !virtual_host.routes().empty()) { @@ -1343,6 +1344,12 @@ VirtualHostImpl::VirtualHostImpl( context, factory_context, validation_visitor); matcher_ = factory.create(virtual_host.matcher())(); + + if (!validation_visitor.errors().empty()) { + // TODO(snowp): Output all violations. + throw EnvoyException(fmt::format("requirement violation while creating route match tree: {}", + validation_visitor.errors()[0])); + } } else { for (const auto& route : virtual_host.routes()) { routes_.emplace_back(createAndValidateRoute(route, *this, optional_http_filters, diff --git a/test/common/router/config_impl_test.cc b/test/common/router/config_impl_test.cc index 398529b2b4d9..5cb2cbb24cb8 100644 --- a/test/common/router/config_impl_test.cc +++ b/test/common/router/config_impl_test.cc @@ -1386,8 +1386,11 @@ TEST_F(RouteMatcherTest, TestMatchInvalidInput) { NiceMock stream_info; factory_context_.cluster_manager_.initializeClusters( {"www2", "root_www2", "www2_staging", "instant-server"}, {}); - EXPECT_THROW_WITH_MESSAGE(TestConfigImpl(parseRouteConfigurationFromYaml(yaml), factory_context_, true), - EnvoyException, "hello"); + EXPECT_THROW_WITH_MESSAGE( + TestConfigImpl(parseRouteConfigurationFromYaml(yaml), factory_context_, true), EnvoyException, + "requirement violation while creating route match tree: INVALID_ARGUMENT: Route table can " + "only match on request headers, saw " + "type.googleapis.com/envoy.type.matcher.v3.HttpResponseHeaderMatchInput"); } // Validates behavior of request_headers_to_add at router, vhost, and route levels. From 269954cd87cdcf40820b2232a52317f28fd57902 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Wed, 29 Sep 2021 15:35:34 +0000 Subject: [PATCH 39/44] format Signed-off-by: Snow Pettersen --- source/common/router/config_impl.cc | 4 ++-- source/common/router/config_impl.h | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/source/common/router/config_impl.cc b/source/common/router/config_impl.cc index 0bd5fcfa2e31..78cac2b3549b 100644 --- a/source/common/router/config_impl.cc +++ b/source/common/router/config_impl.cc @@ -13,10 +13,10 @@ #include "envoy/config/core/v3/base.pb.h" #include "envoy/config/route/v3/route.pb.h" #include "envoy/config/route/v3/route_components.pb.h" -#include "envoy/type/matcher/v3/http_inputs.pb.h" -#include "envoy/type/matcher/v3/http_inputs.pb.validate.h" #include "envoy/http/header_map.h" #include "envoy/runtime/runtime.h" +#include "envoy/type/matcher/v3/http_inputs.pb.h" +#include "envoy/type/matcher/v3/http_inputs.pb.validate.h" #include "envoy/type/matcher/v3/string.pb.h" #include "envoy/type/v3/percent.pb.h" #include "envoy/upstream/cluster_manager.h" diff --git a/source/common/router/config_impl.h b/source/common/router/config_impl.h index 395ab22d85a5..027441ed3b4a 100644 --- a/source/common/router/config_impl.h +++ b/source/common/router/config_impl.h @@ -191,8 +191,7 @@ class ConfigImpl; /** * Holds all routing configuration for an entire virtual host. */ -class VirtualHostImpl : public VirtualHost, - Logger::Loggable { +class VirtualHostImpl : public VirtualHost, Logger::Loggable { public: VirtualHostImpl( const envoy::config::route::v3::VirtualHost& virtual_host, From 418a270945ff78c6c7caa3fda2cb431bf95f86f7 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Wed, 29 Sep 2021 18:06:52 +0000 Subject: [PATCH 40/44] use wip instead of alpha Signed-off-by: Snow Pettersen --- api/envoy/config/route/v3/BUILD | 1 + api/envoy/config/route/v3/route_components.proto | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/api/envoy/config/route/v3/BUILD b/api/envoy/config/route/v3/BUILD index 730789f9801d..b82843eee7dd 100644 --- a/api/envoy/config/route/v3/BUILD +++ b/api/envoy/config/route/v3/BUILD @@ -15,6 +15,7 @@ api_proto_package( "//envoy/type/tracing/v3:pkg", "//envoy/type/v3:pkg", "@com_github_cncf_udpa//udpa/annotations:pkg", + "@com_github_cncf_udpa//xds/annotations/v3:pkg", "@com_github_cncf_udpa//xds/type/matcher/v3:pkg", ], ) diff --git a/api/envoy/config/route/v3/route_components.proto b/api/envoy/config/route/v3/route_components.proto index 2182fdd1618c..f79449ac7cac 100644 --- a/api/envoy/config/route/v3/route_components.proto +++ b/api/envoy/config/route/v3/route_components.proto @@ -17,6 +17,7 @@ import "google/protobuf/any.proto"; import "google/protobuf/duration.proto"; import "google/protobuf/wrappers.proto"; +import "xds/annotations/v3/status.proto"; import "xds/type/matcher/v3/matcher.proto"; import "envoy/annotations/deprecation.proto"; @@ -96,10 +97,10 @@ message VirtualHost { // The match tree to use when resolving route actions for incoming requests. Only one of this and `routes` // can be specified. // - // Note that this API is experimental and must be explicitly enabled by setting the runtime + // Note that this API is a work in progress and must be explicitly enabled by setting the runtime // "envoy.reloadable_features.experimental_matching_api" to "true". - // [#alpha:] - xds.type.matcher.v3.Matcher matcher = 21; + xds.type.matcher.v3.Matcher matcher = 21 + [(xds.annotations.v3.field_status).work_in_progress = true]; // Specifies the type of TLS enforcement the virtual host expects. If this option is not // specified, there is no TLS requirement for the virtual host. From 50080bde97aa83e8d84eb3c0a7e983af8054faa7 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Sat, 9 Oct 2021 03:35:54 +0000 Subject: [PATCH 41/44] improve coverage Signed-off-by: Snow Pettersen --- source/common/router/config_impl.cc | 8 +++----- test/common/router/config_impl_test.cc | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/source/common/router/config_impl.cc b/source/common/router/config_impl.cc index fbd265628b1f..e44b956917cb 100644 --- a/source/common/router/config_impl.cc +++ b/source/common/router/config_impl.cc @@ -1545,11 +1545,9 @@ RouteConstSharedPtr VirtualHostImpl::getRouteFromEntries(const RouteCallback& cb auto match = Matcher::evaluateMatch(*matcher_, data); if (match.result_) { - if (match.result_->typeUrl() != RouteMatchAction::staticTypeUrl()) { - ENVOY_LOG(error, "resolved unexpected match action {}", match.result_->typeUrl()); - return nullptr; - } - + // The only possible action that can be used within the route matching context + // is the RouteMatchAction, so this must be true. + ASSERT(match.result_->typeUrl() == RouteMatchAction::staticTypeUrl()); ASSERT(dynamic_cast(match.result_.get())); const RouteMatchAction& route_action = static_cast(*match.result_); diff --git a/test/common/router/config_impl_test.cc b/test/common/router/config_impl_test.cc index 904211891ee3..562989f00d0b 100644 --- a/test/common/router/config_impl_test.cc +++ b/test/common/router/config_impl_test.cc @@ -1261,6 +1261,19 @@ TEST_F(RouteMatcherTest, TestMatchTree) { - header: key: x-route-header value: match_tree_2 + "/new_endpoint/baz": + action: + name: route + typed_config: + "@type": type.googleapis.com/envoy.config.route.v3.Route + match: + prefix: /something/else + route: + cluster: root_ww2 + request_headers_to_add: + - header: + key: x-route-header + value: match_tree_2 )EOF"; NiceMock stream_info; @@ -1281,6 +1294,8 @@ TEST_F(RouteMatcherTest, TestMatchTree) { route->finalizeRequestHeaders(headers, stream_info, true); EXPECT_EQ("match_tree_2", headers.get_("x-route-header")); } + Http::TestRequestHeaderMapImpl headers = genHeaders("lyft.com", "/new_endpoint/baz", "GET"); + EXPECT_EQ(nullptr, config.route(headers, 0)); } // Validates that we fail creating a route config with the match tree unless the runtime flag is From a95c67c246e042764a8b7c4417746a1baa61d67c Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Sat, 9 Oct 2021 03:36:58 +0000 Subject: [PATCH 42/44] format Signed-off-by: Snow Pettersen --- source/common/router/config_impl.cc | 2 +- test/common/router/config_impl_test.cc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/source/common/router/config_impl.cc b/source/common/router/config_impl.cc index e44b956917cb..04fb3b623812 100644 --- a/source/common/router/config_impl.cc +++ b/source/common/router/config_impl.cc @@ -1545,7 +1545,7 @@ RouteConstSharedPtr VirtualHostImpl::getRouteFromEntries(const RouteCallback& cb auto match = Matcher::evaluateMatch(*matcher_, data); if (match.result_) { - // The only possible action that can be used within the route matching context + // The only possible action that can be used within the route matching context // is the RouteMatchAction, so this must be true. ASSERT(match.result_->typeUrl() == RouteMatchAction::staticTypeUrl()); ASSERT(dynamic_cast(match.result_.get())); diff --git a/test/common/router/config_impl_test.cc b/test/common/router/config_impl_test.cc index 562989f00d0b..659e98416bad 100644 --- a/test/common/router/config_impl_test.cc +++ b/test/common/router/config_impl_test.cc @@ -1294,8 +1294,8 @@ TEST_F(RouteMatcherTest, TestMatchTree) { route->finalizeRequestHeaders(headers, stream_info, true); EXPECT_EQ("match_tree_2", headers.get_("x-route-header")); } - Http::TestRequestHeaderMapImpl headers = genHeaders("lyft.com", "/new_endpoint/baz", "GET"); - EXPECT_EQ(nullptr, config.route(headers, 0)); + Http::TestRequestHeaderMapImpl headers = genHeaders("lyft.com", "/new_endpoint/baz", "GET"); + EXPECT_EQ(nullptr, config.route(headers, 0)); } // Validates that we fail creating a route config with the match tree unless the runtime flag is From 1d16ebac2673245fca2b603e7398c957dae1aea9 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Mon, 11 Oct 2021 16:55:23 +0000 Subject: [PATCH 43/44] improve coverage Signed-off-by: Snow Pettersen --- test/common/router/config_impl_test.cc | 56 +++++++++++++++++--------- test/per_file_coverage.sh | 2 +- 2 files changed, 39 insertions(+), 19 deletions(-) diff --git a/test/common/router/config_impl_test.cc b/test/common/router/config_impl_test.cc index 659e98416bad..fdf125c9d035 100644 --- a/test/common/router/config_impl_test.cc +++ b/test/common/router/config_impl_test.cc @@ -1315,19 +1315,6 @@ TEST_F(RouteMatcherTest, TestMatchTreeDisabledByDefault) { header_name: :path exact_match_map: map: - "/new_endpoint/foo": - action: - name: route - typed_config: - "@type": type.googleapis.com/envoy.config.route.v3.Route - match: - prefix: / - route: - cluster: root_ww2 - request_headers_to_add: - - header: - key: x-route-header - value: match_tree "/new_endpoint/bar": action: name: route @@ -1383,7 +1370,42 @@ TEST_F(RouteMatcherTest, TestMatchInvalidInput) { - header: key: x-route-header value: match_tree - "/new_endpoint/bar": + )EOF"; + + NiceMock stream_info; + factory_context_.cluster_manager_.initializeClusters( + {"www2", "root_www2", "www2_staging", "instant-server"}, {}); + EXPECT_THROW_WITH_MESSAGE( + TestConfigImpl(parseRouteConfigurationFromYaml(yaml), factory_context_, true), EnvoyException, + "requirement violation while creating route match tree: INVALID_ARGUMENT: Route table can " + "only match on request headers, saw " + "type.googleapis.com/envoy.type.matcher.v3.HttpResponseHeaderMatchInput"); +} + +// Validates that we fail creating a route config if an invalid data input is used. +TEST_F(RouteMatcherTest, TestMatchInvalidInputTwoMatchers) { + TestScopedRuntime scoped_runtime; + Runtime::LoaderSingleton::getExisting()->mergeValues( + {{"envoy.reloadable_features.experimental_matching_api", "true"}}); + + const std::string yaml = R"EOF( +virtual_hosts: +- name: www2 + domains: + - lyft.com + routes: + - match: { prefix: "/" } + route: { cluster: "regex" } + matcher: + matcher_tree: + input: + name: request-headers + typed_config: + "@type": type.googleapis.com/envoy.type.matcher.v3.HttpRequestHeaderMatchInput + header_name: :path + exact_match_map: + map: + "/new_endpoint/foo": action: name: route typed_config: @@ -1395,7 +1417,7 @@ TEST_F(RouteMatcherTest, TestMatchInvalidInput) { request_headers_to_add: - header: key: x-route-header - value: match_tree_2 + value: match_tree )EOF"; NiceMock stream_info; @@ -1403,9 +1425,7 @@ TEST_F(RouteMatcherTest, TestMatchInvalidInput) { {"www2", "root_www2", "www2_staging", "instant-server"}, {}); EXPECT_THROW_WITH_MESSAGE( TestConfigImpl(parseRouteConfigurationFromYaml(yaml), factory_context_, true), EnvoyException, - "requirement violation while creating route match tree: INVALID_ARGUMENT: Route table can " - "only match on request headers, saw " - "type.googleapis.com/envoy.type.matcher.v3.HttpResponseHeaderMatchInput"); + "cannot set both matcher and routes on virtual host"); } // Validates behavior of request_headers_to_add at router, vhost, and route levels. diff --git a/test/per_file_coverage.sh b/test/per_file_coverage.sh index e4813c691723..1c3c49d93caa 100755 --- a/test/per_file_coverage.sh +++ b/test/per_file_coverage.sh @@ -15,7 +15,7 @@ declare -a KNOWN_LOW_COVERAGE=( "source/common/http:96.3" "source/common/http/http2:96.4" "source/common/json:90.1" -"source/common/matcher:94.2" +"source/common/matcher:94.0" "source/common/network:94.4" # Flaky, `activateFileEvents`, `startSecureTransport` and `ioctl`, listener_socket do not always report LCOV "source/common/protobuf:95.3" "source/common/quic:91.8" From 71c4c5a463ddbddeb83098194b55e8f3f04f2155 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Tue, 12 Oct 2021 17:38:23 +0000 Subject: [PATCH 44/44] remove runtime flag Signed-off-by: Snow Pettersen --- .../config/route/v3/route_components.proto | 3 -- source/common/router/config_impl.cc | 6 --- test/common/router/config_impl_test.cc | 51 ------------------- 3 files changed, 60 deletions(-) diff --git a/api/envoy/config/route/v3/route_components.proto b/api/envoy/config/route/v3/route_components.proto index 9f625e83ecd3..5a915eee87ca 100644 --- a/api/envoy/config/route/v3/route_components.proto +++ b/api/envoy/config/route/v3/route_components.proto @@ -96,9 +96,6 @@ message VirtualHost { // [#next-major-version: This should be included in a oneof with routes wrapped in a message.] // The match tree to use when resolving route actions for incoming requests. Only one of this and `routes` // can be specified. - // - // Note that this API is a work in progress and must be explicitly enabled by setting the runtime - // "envoy.reloadable_features.experimental_matching_api" to "true". xds.type.matcher.v3.Matcher matcher = 21 [(xds.annotations.v3.field_status).work_in_progress = true]; diff --git a/source/common/router/config_impl.cc b/source/common/router/config_impl.cc index 04fb3b623812..4dbfd1555072 100644 --- a/source/common/router/config_impl.cc +++ b/source/common/router/config_impl.cc @@ -1388,12 +1388,6 @@ VirtualHostImpl::VirtualHostImpl( hedge_policy_ = virtual_host.hedge_policy(); } - constexpr absl::string_view feature_flag = "envoy.reloadable_features.experimental_matching_api"; - if (virtual_host.has_matcher() && !Runtime::runtimeFeatureEnabled(feature_flag)) { - throw EnvoyException(fmt::format( - "Experimental matching API is not enabled: set `{}` to true to enable", feature_flag)); - } - if (virtual_host.has_matcher() && !virtual_host.routes().empty()) { throw EnvoyException("cannot set both matcher and routes on virtual host"); } diff --git a/test/common/router/config_impl_test.cc b/test/common/router/config_impl_test.cc index fdf125c9d035..a5060fcc534b 100644 --- a/test/common/router/config_impl_test.cc +++ b/test/common/router/config_impl_test.cc @@ -1217,10 +1217,6 @@ TEST_F(RouteMatcherTest, TestRoutesWithInvalidVirtualCluster) { // Validates basic usage of the match tree to resolve route actions. TEST_F(RouteMatcherTest, TestMatchTree) { - TestScopedRuntime scoped_runtime; - Runtime::LoaderSingleton::getExisting()->mergeValues( - {{"envoy.reloadable_features.experimental_matching_api", "true"}}); - const std::string yaml = R"EOF( virtual_hosts: - name: www2 @@ -1298,51 +1294,8 @@ TEST_F(RouteMatcherTest, TestMatchTree) { EXPECT_EQ(nullptr, config.route(headers, 0)); } -// Validates that we fail creating a route config with the match tree unless the runtime flag is -// set. -TEST_F(RouteMatcherTest, TestMatchTreeDisabledByDefault) { - const std::string yaml = R"EOF( -virtual_hosts: -- name: www2 - domains: - - lyft.com - matcher: - matcher_tree: - input: - name: request-headers - typed_config: - "@type": type.googleapis.com/envoy.type.matcher.v3.HttpRequestHeaderMatchInput - header_name: :path - exact_match_map: - map: - "/new_endpoint/bar": - action: - name: route - typed_config: - "@type": type.googleapis.com/envoy.config.route.v3.Route - match: - prefix: / - route: - cluster: root_ww2 - request_headers_to_add: - - header: - key: x-route-header - value: match_tree_2 - )EOF"; - - NiceMock stream_info; - factory_context_.cluster_manager_.initializeClusters( - {"www2", "root_www2", "www2_staging", "instant-server"}, {}); - EXPECT_THROW(TestConfigImpl(parseRouteConfigurationFromYaml(yaml), factory_context_, true), - EnvoyException); -} - // Validates that we fail creating a route config if an invalid data input is used. TEST_F(RouteMatcherTest, TestMatchInvalidInput) { - TestScopedRuntime scoped_runtime; - Runtime::LoaderSingleton::getExisting()->mergeValues( - {{"envoy.reloadable_features.experimental_matching_api", "true"}}); - const std::string yaml = R"EOF( virtual_hosts: - name: www2 @@ -1384,10 +1337,6 @@ TEST_F(RouteMatcherTest, TestMatchInvalidInput) { // Validates that we fail creating a route config if an invalid data input is used. TEST_F(RouteMatcherTest, TestMatchInvalidInputTwoMatchers) { - TestScopedRuntime scoped_runtime; - Runtime::LoaderSingleton::getExisting()->mergeValues( - {{"envoy.reloadable_features.experimental_matching_api", "true"}}); - const std::string yaml = R"EOF( virtual_hosts: - name: www2