diff --git a/docs/root/version_history/current.rst b/docs/root/version_history/current.rst index b339fc8038734..0e39800ce6487 100644 --- a/docs/root/version_history/current.rst +++ b/docs/root/version_history/current.rst @@ -33,6 +33,7 @@ Removed Config or Runtime New Features ------------ * http3: downstream HTTP/3 support is now GA! Upstream HTTP/3 also GA for specific deployments. See :ref:`here ` for details. +* matching: the matching API can now express a match tree that will always match by omitting a matcher at the top level. Deprecated diff --git a/source/common/matcher/matcher.h b/source/common/matcher/matcher.h index 793c24f77f516..3402b1d50989e 100644 --- a/source/common/matcher/matcher.h +++ b/source/common/matcher/matcher.h @@ -61,6 +61,22 @@ static inline MaybeMatchResult evaluateMatch(MatchTree& match_tree, template using FieldMatcherFactoryCb = std::function()>; +/** + * A matcher that will always resolve to associated on_no_match. This is used when + * the matcher is configured without a matcher, allowing for a tree that always resolves + * to a specific OnMatch. + */ +template class AnyMatcher : public MatchTree { +public: + explicit AnyMatcher(absl::optional> on_no_match) + : on_no_match_(std::move(on_no_match)) {} + + typename MatchTree::MatchResult match(const DataType&) override { + return {MatchState::MatchComplete, on_no_match_}; + } + const absl::optional> on_no_match_; +}; + /** * Recursively constructs a MatchTree from a protobuf configuration. * @param DataType the type used as a source for DataInputs @@ -83,8 +99,7 @@ class MatchTreeFactory : public OnMatchFactory { case MatcherType::kMatcherList: return createListMatcher(config); case MatcherType::MATCHER_TYPE_NOT_SET: - IS_ENVOY_BUG("match fail"); - return nullptr; + return createAnyMatcher(config); } return nullptr; } @@ -100,6 +115,15 @@ class MatchTreeFactory : public OnMatchFactory { } private: + template + MatchTreeFactoryCb createAnyMatcher(const MatcherType& config) { + auto on_no_match = createOnMatch(config.on_no_match()); + + return [on_no_match]() { + return std::make_unique>( + on_no_match ? absl::make_optional((*on_no_match)()) : absl::nullopt); + }; + } template MatchTreeFactoryCb createListMatcher(const MatcherType& config) { std::vector, OnMatchFactoryCb>> diff --git a/test/common/matcher/matcher_test.cc b/test/common/matcher/matcher_test.cc index 8d1bdc895485b..7c0d751af3703 100644 --- a/test/common/matcher/matcher_test.cc +++ b/test/common/matcher/matcher_test.cc @@ -17,6 +17,7 @@ #include "test/test_common/utility.h" #include "gtest/gtest.h" +#include "xds/type/matcher/v3/matcher.pb.validate.h" namespace Envoy { namespace Matcher { @@ -83,6 +84,29 @@ TEST_F(MatcherTest, TestMatcher) { EXPECT_NE(result.on_match_->action_cb_, nullptr); } +TEST_F(MatcherTest, TestAnyMatcher) { + const std::string yaml = R"EOF( +on_no_match: + action: + name: test_action + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: match!! + )EOF"; + + xds::type::matcher::v3::Matcher matcher; + MessageUtil::loadFromYaml(yaml, matcher, ProtobufMessage::getStrictValidationVisitor()); + + TestUtility::validate(matcher); + + auto match_tree = factory_.create(matcher); + + const auto result = match_tree()->match(TestData()); + EXPECT_EQ(result.match_state_, MatchState::MatchComplete); + EXPECT_TRUE(result.on_match_.has_value()); + EXPECT_NE(result.on_match_->action_cb_, nullptr); +} + TEST_F(MatcherTest, CustomGenericInput) { const std::string yaml = R"EOF( matcher_list: