diff --git a/api/envoy/type/matcher/v3/metadata.proto b/api/envoy/type/matcher/v3/metadata.proto index 68710dc718546..de19a2f34dbd1 100644 --- a/api/envoy/type/matcher/v3/metadata.proto +++ b/api/envoy/type/matcher/v3/metadata.proto @@ -101,4 +101,7 @@ message MetadataMatcher { // The MetadataMatcher is matched if the value retrieved by path is matched to this value. ValueMatcher value = 3 [(validate.rules).message = {required: true}]; + + // If true, the match result will be inverted. + bool invert = 4; } diff --git a/docs/root/version_history/current.rst b/docs/root/version_history/current.rst index cf650995d098d..d704872238670 100644 --- a/docs/root/version_history/current.rst +++ b/docs/root/version_history/current.rst @@ -95,6 +95,7 @@ New Features * http: sanitizing the referer header as documented :ref:`here `. This feature can be temporarily turned off by setting runtime guard ``envoy.reloadable_features.sanitize_http_header_referer`` to false. * jwt_authn: added support for :ref:`Jwt Cache ` and its size can be specified by :ref:`jwt_cache_size `. * listener: new listener metric ``downstream_cx_transport_socket_connect_timeout`` to track transport socket timeouts. +* matcher: added :ref:`invert ` for inverting the match result in the metadata matcher. * overload: add a new overload action that resets streams using a lot of memory. To enable the tracking of allocated bytes in buffers that a stream is using we need to configure the minimum threshold for tracking via:ref:`buffer_factory_config `. We have an overload action ``Envoy::Server::OverloadActionNameValues::ResetStreams`` that takes advantage of the tracking to reset the most expensive stream first. * rbac: added :ref:`destination_port_range ` for matching range of destination ports. * route config: added :ref:`dynamic_metadata ` for routing based on dynamic metadata. diff --git a/generated_api_shadow/envoy/type/matcher/v3/metadata.proto b/generated_api_shadow/envoy/type/matcher/v3/metadata.proto index 68710dc718546..de19a2f34dbd1 100644 --- a/generated_api_shadow/envoy/type/matcher/v3/metadata.proto +++ b/generated_api_shadow/envoy/type/matcher/v3/metadata.proto @@ -101,4 +101,7 @@ message MetadataMatcher { // The MetadataMatcher is matched if the value retrieved by path is matched to this value. ValueMatcher value = 3 [(validate.rules).message = {required: true}]; + + // If true, the match result will be inverted. + bool invert = 4; } diff --git a/source/common/common/matchers.cc b/source/common/common/matchers.cc index cb57af2869f3f..f34a482ca7a35 100644 --- a/source/common/common/matchers.cc +++ b/source/common/common/matchers.cc @@ -118,7 +118,7 @@ PathMatcher::createSafeRegex(const envoy::type::matcher::v3::RegexMatcher& regex bool MetadataMatcher::match(const envoy::config::core::v3::Metadata& metadata) const { const auto& value = Envoy::Config::Metadata::metadataValue(&metadata, matcher_.filter(), path_); - return value_matcher_ && value_matcher_->match(value); + return value_matcher_->match(value) ^ matcher_.invert(); } bool PathMatcher::match(const absl::string_view path) const { diff --git a/test/common/common/matchers_test.cc b/test/common/common/matchers_test.cc index bcdf34441acc7..581967af8b3ea 100644 --- a/test/common/common/matchers_test.cc +++ b/test/common/common/matchers_test.cc @@ -280,6 +280,22 @@ TEST(MetadataTest, MatchDoubleListValue) { metadataValue.Clear(); } +TEST(MetadataTest, InvertMatch) { + envoy::config::core::v3::Metadata metadata; + Envoy::Config::Metadata::mutableMetadataValue(metadata, "envoy.filter.x", "label") + .set_string_value("prod"); + + envoy::type::matcher::v3::MetadataMatcher matcher; + matcher.set_filter("envoy.filter.x"); + matcher.add_path()->set_key("label"); + matcher.set_invert(true); + + matcher.mutable_value()->mutable_string_match()->set_exact("test"); + EXPECT_TRUE(Envoy::Matchers::MetadataMatcher(matcher).match(metadata)); + matcher.mutable_value()->mutable_string_match()->set_exact("prod"); + EXPECT_FALSE(Envoy::Matchers::MetadataMatcher(matcher).match(metadata)); +} + TEST(StringMatcher, ExactMatchIgnoreCase) { envoy::type::matcher::v3::StringMatcher matcher; matcher.set_exact("exact");