From 2d1ed7feb7587b42aa0f3ea1e0ef19f691159a25 Mon Sep 17 00:00:00 2001 From: Yangmin Zhu Date: Wed, 23 Jun 2021 18:01:18 -0700 Subject: [PATCH 01/12] http: support ignore_case for exact/prefix/suffic/contain match in HeaderMatcher Signed-off-by: Yangmin Zhu --- .../config/route/v3/route_components.proto | 6 +- .../route/v4alpha/route_components.proto | 6 +- docs/root/version_history/current.rst | 1 + .../config/route/v3/route_components.proto | 6 +- .../route/v4alpha/route_components.proto | 6 +- source/common/http/header_utility.cc | 26 +++-- source/common/http/header_utility.h | 3 + test/common/http/header_utility_test.cc | 102 ++++++++++++++++-- 8 files changed, 136 insertions(+), 20 deletions(-) diff --git a/api/envoy/config/route/v3/route_components.proto b/api/envoy/config/route/v3/route_components.proto index ee82e8f73226..836130bb62d7 100644 --- a/api/envoy/config/route/v3/route_components.proto +++ b/api/envoy/config/route/v3/route_components.proto @@ -1850,7 +1850,7 @@ message RateLimit { // value. // // [#next-major-version: HeaderMatcher should be refactored to use StringMatcher.] -// [#next-free-field: 13] +// [#next-free-field: 14] message HeaderMatcher { option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.route.HeaderMatcher"; @@ -1922,6 +1922,10 @@ message HeaderMatcher { // * The regex ``\d{3}`` does not match the value *1234*, so it will match when inverted. // * The range [-10,0) will match the value -1, so it will not match when inverted. bool invert_match = 8; + + // If true, indicates the exact_match/prefix_match/suffix_match/contains_match should be case + // insensitive. This has no effect for the safe_regex_match. + bool ignore_case = 13; } // Query parameter matching treats the query string of a request's :path header diff --git a/api/envoy/config/route/v4alpha/route_components.proto b/api/envoy/config/route/v4alpha/route_components.proto index 256a3c742ff3..d61e70a7ab36 100644 --- a/api/envoy/config/route/v4alpha/route_components.proto +++ b/api/envoy/config/route/v4alpha/route_components.proto @@ -1801,7 +1801,7 @@ message RateLimit { // value. // // [#next-major-version: HeaderMatcher should be refactored to use StringMatcher.] -// [#next-free-field: 13] +// [#next-free-field: 14] message HeaderMatcher { option (udpa.annotations.versioning).previous_message_type = "envoy.config.route.v3.HeaderMatcher"; @@ -1874,6 +1874,10 @@ message HeaderMatcher { // * The regex ``\d{3}`` does not match the value *1234*, so it will match when inverted. // * The range [-10,0) will match the value -1, so it will not match when inverted. bool invert_match = 8; + + // If true, indicates the exact_match/prefix_match/suffix_match/contains_match should be case + // insensitive. This has no effect for the safe_regex_match. + bool ignore_case = 13; } // Query parameter matching treats the query string of a request's :path header diff --git a/docs/root/version_history/current.rst b/docs/root/version_history/current.rst index c452100d31ee..a749bcab2287 100644 --- a/docs/root/version_history/current.rst +++ b/docs/root/version_history/current.rst @@ -103,6 +103,7 @@ New Features * http: added a new option to upstream HTTP/2 :ref:`keepalive ` to send a PING ahead of a new stream if the connection has been idle for a sufficient duration. * http: added the ability to :ref:`unescape slash sequences ` in the path. Requests with unescaped slashes can be proxied, rejected or redirected to the new unescaped path. By default this feature is disabled. The default behavior can be overridden through :ref:`http_connection_manager.path_with_escaped_slashes_action` runtime variable. This action can be selectively enabled for a portion of requests by setting the :ref:`http_connection_manager.path_with_escaped_slashes_action_sampling` runtime variable. * http: added upstream and downstream alpha HTTP/3 support! See :ref:`quic_options ` for downstream and the new http3_protocol_options in :ref:`http_protocol_options ` for upstream HTTP/3. +* http: added :ref:`ignore_case ` for the exact, prefix, suffix and contains match in the header matcher. * jwt_authn: added support to fetch remote jwks asynchronously specified by :ref:`async_fetch `. * listener: added ability to change an existing listener's address. * local_rate_limit_filter: added suppoort for locally rate limiting http requests on a per connection basis. This can be enabled by setting the :ref:`local_rate_limit_per_downstream_connection ` field to 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..0febadf41fec 100644 --- a/generated_api_shadow/envoy/config/route/v3/route_components.proto +++ b/generated_api_shadow/envoy/config/route/v3/route_components.proto @@ -1883,7 +1883,7 @@ message RateLimit { // value. // // [#next-major-version: HeaderMatcher should be refactored to use StringMatcher.] -// [#next-free-field: 13] +// [#next-free-field: 14] message HeaderMatcher { option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.route.HeaderMatcher"; @@ -1960,6 +1960,10 @@ message HeaderMatcher { // * The regex ``\d{3}`` does not match the value *1234*, so it will match when inverted. // * The range [-10,0) will match the value -1, so it will not match when inverted. bool invert_match = 8; + + // If true, indicates the exact_match/prefix_match/suffix_match/contains_match should be case + // insensitive. This has no effect for the safe_regex_match. + bool ignore_case = 13; } // Query parameter matching treats the query string of a request's :path header 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..3f03d558460e 100644 --- a/generated_api_shadow/envoy/config/route/v4alpha/route_components.proto +++ b/generated_api_shadow/envoy/config/route/v4alpha/route_components.proto @@ -1879,7 +1879,7 @@ message RateLimit { // value. // // [#next-major-version: HeaderMatcher should be refactored to use StringMatcher.] -// [#next-free-field: 13] +// [#next-free-field: 14] message HeaderMatcher { option (udpa.annotations.versioning).previous_message_type = "envoy.config.route.v3.HeaderMatcher"; @@ -1952,6 +1952,10 @@ message HeaderMatcher { // * The regex ``\d{3}`` does not match the value *1234*, so it will match when inverted. // * The range [-10,0) will match the value -1, so it will not match when inverted. bool invert_match = 8; + + // If true, indicates the exact_match/prefix_match/suffix_match/contains_match should be case + // insensitive. This has no effect for the safe_regex_match. + bool ignore_case = 13; } // Query parameter matching treats the query string of a request's :path header diff --git a/source/common/http/header_utility.cc b/source/common/http/header_utility.cc index a25d62cc83a3..dccd03cbf315 100644 --- a/source/common/http/header_utility.cc +++ b/source/common/http/header_utility.cc @@ -35,7 +35,8 @@ using SharedResponseCodeDetails = ConstSingletonmatch(header_value.result().value()); + match = header_data.regex_->match(value); break; case HeaderMatchType::Range: { int64_t header_int_value = 0; - match = absl::SimpleAtoi(header_value.result().value(), &header_int_value) && + match = absl::SimpleAtoi(value, &header_int_value) && header_int_value >= header_data.range_.start() && header_int_value < header_data.range_.end(); break; @@ -157,13 +164,18 @@ bool HeaderUtility::matchHeaders(const HeaderMap& request_headers, const HeaderD match = header_data.present_; break; case HeaderMatchType::Prefix: - match = absl::StartsWith(header_value.result().value(), header_data.value_); + match = header_data.ignore_case_ ? absl::StartsWithIgnoreCase(value, header_data.value_) + : absl::StartsWith(value, header_data.value_); break; case HeaderMatchType::Suffix: - match = absl::EndsWith(header_value.result().value(), header_data.value_); + match = header_data.ignore_case_ ? absl::EndsWithIgnoreCase(value, header_data.value_) + : absl::EndsWith(value, header_data.value_); break; case HeaderMatchType::Contains: - match = absl::StrContains(header_value.result().value(), header_data.value_); + match = header_data.ignore_case_ + ? absl::StrContains(absl::AsciiStrToLower(value), + header_data.contains_match_lowercase_.get()) + : absl::StrContains(value, header_data.value_); break; default: NOT_REACHED_GCOVR_EXCL_LINE; diff --git a/source/common/http/header_utility.h b/source/common/http/header_utility.h index c3b8a2088ea9..0edad936d59f 100644 --- a/source/common/http/header_utility.h +++ b/source/common/http/header_utility.h @@ -63,10 +63,13 @@ class HeaderUtility { const LowerCaseString name_; HeaderMatchType header_match_type_; std::string value_; + // The contains_match_lowercase_ is populated only for contains match when ignore_case is true. + LowerCaseString contains_match_lowercase_; Regex::CompiledMatcherPtr regex_; envoy::type::v3::Int64Range range_; const bool invert_match_; bool present_; + bool ignore_case_; // HeaderMatcher bool matchesHeaders(const HeaderMap& headers) const override { diff --git a/test/common/http/header_utility_test.cc b/test/common/http/header_utility_test.cc index 59a52bd5c3ae..1f2f914f7602 100644 --- a/test/common/http/header_utility_test.cc +++ b/test/common/http/header_utility_test.cc @@ -382,8 +382,9 @@ name: match-header TEST(MatchHeadersTest, HeaderExactMatch) { TestRequestHeaderMapImpl matching_headers{{"match-header", "match-value"}}; - TestRequestHeaderMapImpl unmatching_headers{{"match-header", "other-value"}, - {"other-header", "match-value"}}; + TestRequestHeaderMapImpl unmatching_headers_1{{"match-header", "other-value"}, + {"other-header", "match-value"}}; + TestRequestHeaderMapImpl unmatching_headers_2{{"match-header", "MATCH-VALUE"}}; const std::string yaml = R"EOF( name: match-header exact_match: match-value @@ -393,7 +394,8 @@ exact_match: match-value header_data.push_back( std::make_unique(parseHeaderMatcherFromYaml(yaml))); EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers, header_data)); - EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); + EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers_1, header_data)); + EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers_2, header_data)); } TEST(MatchHeadersTest, HeaderExactMatchInverse) { @@ -414,6 +416,25 @@ invert_match: true EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); } +TEST(MatchHeadersTest, HeaderExactMatchIgnoreCase) { + TestRequestHeaderMapImpl matching_headers_1{{"match-header", "match-value"}}; + TestRequestHeaderMapImpl matching_headers_2{{"match-header", "MATCH-VALUE"}}; + TestRequestHeaderMapImpl unmatching_headers{{"match-header", "other-value"}, + {"other-header", "match-value"}}; + const std::string yaml = R"EOF( +name: match-header +exact_match: match-value +ignore_case: true + )EOF"; + + std::vector header_data; + header_data.push_back( + std::make_unique(parseHeaderMatcherFromYaml(yaml))); + EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_1, header_data)); + EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_2, header_data)); + EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); +} + TEST(MatchHeadersTest, HeaderSafeRegexMatch) { TestRequestHeaderMapImpl matching_headers{{"match-header", "123"}}; TestRequestHeaderMapImpl unmatching_headers{{"match-header", "1234"}, @@ -574,7 +595,8 @@ invert_match: true TEST(MatchHeadersTest, HeaderPrefixMatch) { TestRequestHeaderMapImpl matching_headers{{"match-header", "value123"}}; - TestRequestHeaderMapImpl unmatching_headers{{"match-header", "123value"}}; + TestRequestHeaderMapImpl unmatching_headers_1{{"match-header", "123value"}}; + TestRequestHeaderMapImpl unmatching_headers_2{{"match-header", "VALUE123"}}; const std::string yaml = R"EOF( name: match-header @@ -585,7 +607,8 @@ prefix_match: value header_data.push_back( std::make_unique(parseHeaderMatcherFromYaml(yaml))); EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers, header_data)); - EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); + EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers_1, header_data)); + EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers_2, header_data)); } TEST(MatchHeadersTest, HeaderPrefixInverseMatch) { @@ -605,9 +628,29 @@ invert_match: true EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); } +TEST(MatchHeadersTest, HeaderPrefixMatchIgnoreCase) { + TestRequestHeaderMapImpl matching_headers_1{{"match-header", "value123"}}; + TestRequestHeaderMapImpl matching_headers_2{{"match-header", "VALUE123"}}; + TestRequestHeaderMapImpl unmatching_headers{{"match-header", "123value"}}; + + const std::string yaml = R"EOF( +name: match-header +prefix_match: value +ignore_case: true + )EOF"; + + std::vector header_data; + header_data.push_back( + std::make_unique(parseHeaderMatcherFromYaml(yaml))); + EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_1, header_data)); + EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_2, header_data)); + EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); +} + TEST(MatchHeadersTest, HeaderSuffixMatch) { TestRequestHeaderMapImpl matching_headers{{"match-header", "123value"}}; - TestRequestHeaderMapImpl unmatching_headers{{"match-header", "value123"}}; + TestRequestHeaderMapImpl unmatching_headers_1{{"match-header", "value123"}}; + TestRequestHeaderMapImpl unmatching_headers_2{{"match-header", "123VALUE"}}; const std::string yaml = R"EOF( name: match-header @@ -618,7 +661,8 @@ suffix_match: value header_data.push_back( std::make_unique(parseHeaderMatcherFromYaml(yaml))); EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers, header_data)); - EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); + EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers_1, header_data)); + EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers_2, header_data)); } TEST(MatchHeadersTest, HeaderSuffixInverseMatch) { @@ -638,9 +682,29 @@ invert_match: true EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); } +TEST(MatchHeadersTest, HeaderSuffixMatchIgnoreCase) { + TestRequestHeaderMapImpl matching_headers_1{{"match-header", "123value"}}; + TestRequestHeaderMapImpl matching_headers_2{{"match-header", "123VALUE"}}; + TestRequestHeaderMapImpl unmatching_headers{{"match-header", "value123"}}; + + const std::string yaml = R"EOF( +name: match-header +suffix_match: value +ignore_case: true + )EOF"; + + std::vector header_data; + header_data.push_back( + std::make_unique(parseHeaderMatcherFromYaml(yaml))); + EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_1, header_data)); + EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_2, header_data)); + EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); +} + TEST(MatchHeadersTest, HeaderContainsMatch) { TestRequestHeaderMapImpl matching_headers{{"match-header", "123onevalue456"}}; - TestRequestHeaderMapImpl unmatching_headers{{"match-header", "123anothervalue456"}}; + TestRequestHeaderMapImpl unmatching_headers_1{{"match-header", "123anothervalue456"}}; + TestRequestHeaderMapImpl unmatching_headers_2{{"match-header", "123ONEVALUE456"}}; const std::string yaml = R"EOF( name: match-header @@ -651,7 +715,8 @@ contains_match: onevalue header_data.push_back( std::make_unique(parseHeaderMatcherFromYaml(yaml))); EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers, header_data)); - EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); + EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers_1, header_data)); + EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers_2, header_data)); } TEST(MatchHeadersTest, HeaderContainsInverseMatch) { @@ -671,6 +736,25 @@ invert_match: true EXPECT_FALSE(HeaderUtility::matchHeaders(matching_headers, header_data)); } +TEST(MatchHeadersTest, HeaderContainsMatchIgnoreCase) { + TestRequestHeaderMapImpl matching_headers_1{{"match-header", "123onevalue456"}}; + TestRequestHeaderMapImpl matching_headers_2{{"match-header", "123ONEVALUE456"}}; + TestRequestHeaderMapImpl unmatching_headers{{"match-header", "123anothervalue456"}}; + + const std::string yaml = R"EOF( +name: match-header +contains_match: onevalue +ignore_case: true + )EOF"; + + std::vector header_data; + header_data.push_back( + std::make_unique(parseHeaderMatcherFromYaml(yaml))); + EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_1, header_data)); + EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_2, header_data)); + EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); +} + TEST(HeaderIsValidTest, InvalidHeaderValuesAreRejected) { // ASCII values 1-31 are control characters (with the exception of ASCII // values 9, 10, and 13 which are a horizontal tab, line feed, and carriage From e9ba4340a4921f0582e67440b397cca41b92f518 Mon Sep 17 00:00:00 2001 From: Yangmin Zhu Date: Fri, 25 Jun 2021 14:27:54 -0700 Subject: [PATCH 02/12] update test Signed-off-by: Yangmin Zhu --- test/common/http/header_utility_test.cc | 130 ++++++++++++++---------- 1 file changed, 75 insertions(+), 55 deletions(-) diff --git a/test/common/http/header_utility_test.cc b/test/common/http/header_utility_test.cc index 1f2f914f7602..21f43bbbf560 100644 --- a/test/common/http/header_utility_test.cc +++ b/test/common/http/header_utility_test.cc @@ -417,22 +417,27 @@ invert_match: true } TEST(MatchHeadersTest, HeaderExactMatchIgnoreCase) { - TestRequestHeaderMapImpl matching_headers_1{{"match-header", "match-value"}}; - TestRequestHeaderMapImpl matching_headers_2{{"match-header", "MATCH-VALUE"}}; - TestRequestHeaderMapImpl unmatching_headers{{"match-header", "other-value"}, - {"other-header", "match-value"}}; - const std::string yaml = R"EOF( + for (const auto& match_value : {"match-value", "Match-Value"}) { + const std::string yaml = fmt::format(R"EOF( name: match-header -exact_match: match-value +exact_match: {} ignore_case: true - )EOF"; + )EOF", + match_value); - std::vector header_data; - header_data.push_back( - std::make_unique(parseHeaderMatcherFromYaml(yaml))); - EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_1, header_data)); - EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_2, header_data)); - EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); + TestRequestHeaderMapImpl matching_headers_1{{"match-header", "match-value"}}; + TestRequestHeaderMapImpl matching_headers_2{{"match-header", "MATCH-VALUE"}}; + TestRequestHeaderMapImpl matching_headers_3{{"match-header", "Match-Value"}}; + TestRequestHeaderMapImpl unmatching_headers{{"match-header", "other-value"}, + {"other-header", "match-value"}}; + std::vector header_data; + header_data.push_back( + std::make_unique(parseHeaderMatcherFromYaml(yaml))); + EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_1, header_data)); + EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_2, header_data)); + EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_3, header_data)); + EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); + } } TEST(MatchHeadersTest, HeaderSafeRegexMatch) { @@ -629,22 +634,27 @@ invert_match: true } TEST(MatchHeadersTest, HeaderPrefixMatchIgnoreCase) { - TestRequestHeaderMapImpl matching_headers_1{{"match-header", "value123"}}; - TestRequestHeaderMapImpl matching_headers_2{{"match-header", "VALUE123"}}; - TestRequestHeaderMapImpl unmatching_headers{{"match-header", "123value"}}; - - const std::string yaml = R"EOF( + for (const auto& match_value : {"value", "Value"}) { + const std::string yaml = fmt::format(R"EOF( name: match-header -prefix_match: value +prefix_match: {} ignore_case: true - )EOF"; - - std::vector header_data; - header_data.push_back( - std::make_unique(parseHeaderMatcherFromYaml(yaml))); - EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_1, header_data)); - EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_2, header_data)); - EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); + )EOF", + match_value); + + TestRequestHeaderMapImpl matching_headers_1{{"match-header", "value123"}}; + TestRequestHeaderMapImpl matching_headers_2{{"match-header", "VALUE123"}}; + TestRequestHeaderMapImpl matching_headers_3{{"match-header", "Value123"}}; + TestRequestHeaderMapImpl unmatching_headers{{"match-header", "123value"}}; + + std::vector header_data; + header_data.push_back( + std::make_unique(parseHeaderMatcherFromYaml(yaml))); + EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_1, header_data)); + EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_2, header_data)); + EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_3, header_data)); + EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); + } } TEST(MatchHeadersTest, HeaderSuffixMatch) { @@ -683,22 +693,27 @@ invert_match: true } TEST(MatchHeadersTest, HeaderSuffixMatchIgnoreCase) { - TestRequestHeaderMapImpl matching_headers_1{{"match-header", "123value"}}; - TestRequestHeaderMapImpl matching_headers_2{{"match-header", "123VALUE"}}; - TestRequestHeaderMapImpl unmatching_headers{{"match-header", "value123"}}; - - const std::string yaml = R"EOF( + for (const auto& match_value : {"value", "Value"}) { + const std::string yaml = fmt::format(R"EOF( name: match-header -suffix_match: value +suffix_match: {} ignore_case: true - )EOF"; - - std::vector header_data; - header_data.push_back( - std::make_unique(parseHeaderMatcherFromYaml(yaml))); - EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_1, header_data)); - EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_2, header_data)); - EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); + )EOF", + match_value); + + TestRequestHeaderMapImpl matching_headers_1{{"match-header", "123value"}}; + TestRequestHeaderMapImpl matching_headers_2{{"match-header", "123VALUE"}}; + TestRequestHeaderMapImpl matching_headers_3{{"match-header", "123Value"}}; + TestRequestHeaderMapImpl unmatching_headers{{"match-header", "value123"}}; + + std::vector header_data; + header_data.push_back( + std::make_unique(parseHeaderMatcherFromYaml(yaml))); + EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_1, header_data)); + EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_2, header_data)); + EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_3, header_data)); + EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); + } } TEST(MatchHeadersTest, HeaderContainsMatch) { @@ -737,22 +752,27 @@ invert_match: true } TEST(MatchHeadersTest, HeaderContainsMatchIgnoreCase) { - TestRequestHeaderMapImpl matching_headers_1{{"match-header", "123onevalue456"}}; - TestRequestHeaderMapImpl matching_headers_2{{"match-header", "123ONEVALUE456"}}; - TestRequestHeaderMapImpl unmatching_headers{{"match-header", "123anothervalue456"}}; - - const std::string yaml = R"EOF( + for (const auto& match_value : {"onevalue", "OneValue"}) { + const std::string yaml = fmt::format(R"EOF( name: match-header -contains_match: onevalue +contains_match: {} ignore_case: true - )EOF"; - - std::vector header_data; - header_data.push_back( - std::make_unique(parseHeaderMatcherFromYaml(yaml))); - EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_1, header_data)); - EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_2, header_data)); - EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); + )EOF", + match_value); + + TestRequestHeaderMapImpl matching_headers_1{{"match-header", "123onevalue456"}}; + TestRequestHeaderMapImpl matching_headers_2{{"match-header", "123ONEVALUE456"}}; + TestRequestHeaderMapImpl matching_headers_3{{"match-header", "123OneValue456"}}; + TestRequestHeaderMapImpl unmatching_headers{{"match-header", "123anothervalue456"}}; + + std::vector header_data; + header_data.push_back( + std::make_unique(parseHeaderMatcherFromYaml(yaml))); + EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_1, header_data)); + EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_2, header_data)); + EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_3, header_data)); + EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); + } } TEST(HeaderIsValidTest, InvalidHeaderValuesAreRejected) { From ed274b0aeb865a0f991c326032061deec097dd5f Mon Sep 17 00:00:00 2001 From: Yangmin Zhu Date: Mon, 28 Jun 2021 17:45:06 -0700 Subject: [PATCH 03/12] use StringMatcher Signed-off-by: Yangmin Zhu --- .../config/route/v3/route_components.proto | 36 +++- .../route/v4alpha/route_components.proto | 43 +--- api/envoy/type/matcher/v3/string.proto | 4 +- api/envoy/type/matcher/v4alpha/string.proto | 4 +- docs/root/version_history/current.rst | 5 +- .../config/route/v3/route_components.proto | 36 +++- .../route/v4alpha/route_components.proto | 36 +++- .../envoy/type/matcher/v3/string.proto | 4 +- .../envoy/type/matcher/v4alpha/string.proto | 4 +- source/common/http/BUILD | 2 + source/common/http/header_utility.cc | 29 ++- source/common/http/header_utility.h | 16 +- test/common/http/header_utility_test.cc | 187 ++++++++---------- 13 files changed, 202 insertions(+), 204 deletions(-) diff --git a/api/envoy/config/route/v3/route_components.proto b/api/envoy/config/route/v3/route_components.proto index fa71658c6a81..e1ba698aba0b 100644 --- a/api/envoy/config/route/v3/route_components.proto +++ b/api/envoy/config/route/v3/route_components.proto @@ -1872,12 +1872,16 @@ message HeaderMatcher { // Specifies how the header match will be performed to route the request. oneof header_match_specifier { // If specified, header match will be performed based on the value of the header. - string exact_match = 4; + // This field is deprecated. Please use :ref:`string_match `. + string exact_match = 4 + [deprecated = true, (envoy.annotations.deprecated_at_minor_version) = "3.0"]; // If specified, this regex string is a regular expression rule which implies the entire request // header value must match the regex. The rule will not match if only a subsequence of the // request header value matches the regex. - type.matcher.v3.RegexMatcher safe_regex_match = 11; + // This field is deprecated. Please use :ref:`string_match `. + type.matcher.v3.RegexMatcher safe_regex_match = 11 + [deprecated = true, (envoy.annotations.deprecated_at_minor_version) = "3.0"]; // If specified, header match will be performed based on range. // The rule will match if the request header value is within this range. @@ -1898,28 +1902,46 @@ message HeaderMatcher { // If specified, header match will be performed based on the prefix of the header value. // Note: empty prefix is not allowed, please use present_match instead. + // This field is deprecated. Please use :ref:`string_match `. // // Examples: // // * The prefix *abcd* matches the value *abcdxyz*, but not for *abcxyz*. - string prefix_match = 9 [(validate.rules).string = {min_len: 1}]; + string prefix_match = 9 [ + deprecated = true, + (validate.rules).string = {min_len: 1}, + (envoy.annotations.deprecated_at_minor_version) = "3.0" + ]; // If specified, header match will be performed based on the suffix of the header value. // Note: empty suffix is not allowed, please use present_match instead. + // This field is deprecated. Please use :ref:`string_match `. // // Examples: // // * The suffix *abcd* matches the value *xyzabcd*, but not for *xyzbcd*. - string suffix_match = 10 [(validate.rules).string = {min_len: 1}]; + string suffix_match = 10 [ + deprecated = true, + (validate.rules).string = {min_len: 1}, + (envoy.annotations.deprecated_at_minor_version) = "3.0" + ]; // If specified, header match will be performed based on whether the header value contains // the given value or not. // Note: empty contains match is not allowed, please use present_match instead. + // This field is deprecated. Please use :ref:`string_match `. // // Examples: // // * The value *abcd* matches the value *xyzabcdpqr*, but not for *xyzbcdpqr*. - string contains_match = 12 [(validate.rules).string = {min_len: 1}]; + string contains_match = 12 [ + deprecated = true, + (validate.rules).string = {min_len: 1}, + (envoy.annotations.deprecated_at_minor_version) = "3.0" + ]; + + // If specified, header match will be performed based on the string match of the header value. + type.matcher.v3.StringMatcher string_match = 13; } // If specified, the match result will be inverted before checking. Defaults to false. @@ -1929,10 +1951,6 @@ message HeaderMatcher { // * The regex ``\d{3}`` does not match the value *1234*, so it will match when inverted. // * The range [-10,0) will match the value -1, so it will not match when inverted. bool invert_match = 8; - - // If true, indicates the exact_match/prefix_match/suffix_match/contains_match should be case - // insensitive. This has no effect for the safe_regex_match. - bool ignore_case = 13; } // Query parameter matching treats the query string of a request's :path header diff --git a/api/envoy/config/route/v4alpha/route_components.proto b/api/envoy/config/route/v4alpha/route_components.proto index 00daf63e60ac..4d0e0797345f 100644 --- a/api/envoy/config/route/v4alpha/route_components.proto +++ b/api/envoy/config/route/v4alpha/route_components.proto @@ -1813,9 +1813,10 @@ message HeaderMatcher { option (udpa.annotations.versioning).previous_message_type = "envoy.config.route.v3.HeaderMatcher"; - reserved 2, 3, 5; + reserved 2, 3, 5, 4, 11, 9, 10, 12; - reserved "regex_match"; + reserved "regex_match", "exact_match", "safe_regex_match", "prefix_match", "suffix_match", + "contains_match"; // Specifies the name of the header in the request. string name = 1 @@ -1823,14 +1824,6 @@ message HeaderMatcher { // Specifies how the header match will be performed to route the request. oneof header_match_specifier { - // If specified, header match will be performed based on the value of the header. - string exact_match = 4; - - // If specified, this regex string is a regular expression rule which implies the entire request - // header value must match the regex. The rule will not match if only a subsequence of the - // request header value matches the regex. - type.matcher.v4alpha.RegexMatcher safe_regex_match = 11; - // If specified, header match will be performed based on range. // The rule will match if the request header value is within this range. // The entire request header value must represent an integer in base 10 notation: consisting of @@ -1848,30 +1841,8 @@ message HeaderMatcher { // request. If specified as false, header match will be performed based on whether the header is absent. bool present_match = 7; - // If specified, header match will be performed based on the prefix of the header value. - // Note: empty prefix is not allowed, please use present_match instead. - // - // Examples: - // - // * The prefix *abcd* matches the value *abcdxyz*, but not for *abcxyz*. - string prefix_match = 9 [(validate.rules).string = {min_len: 1}]; - - // If specified, header match will be performed based on the suffix of the header value. - // Note: empty suffix is not allowed, please use present_match instead. - // - // Examples: - // - // * The suffix *abcd* matches the value *xyzabcd*, but not for *xyzbcd*. - string suffix_match = 10 [(validate.rules).string = {min_len: 1}]; - - // If specified, header match will be performed based on whether the header value contains - // the given value or not. - // Note: empty contains match is not allowed, please use present_match instead. - // - // Examples: - // - // * The value *abcd* matches the value *xyzabcdpqr*, but not for *xyzbcdpqr*. - string contains_match = 12 [(validate.rules).string = {min_len: 1}]; + // If specified, header match will be performed based on the string match of the header value. + type.matcher.v4alpha.StringMatcher string_match = 13; } // If specified, the match result will be inverted before checking. Defaults to false. @@ -1881,10 +1852,6 @@ message HeaderMatcher { // * The regex ``\d{3}`` does not match the value *1234*, so it will match when inverted. // * The range [-10,0) will match the value -1, so it will not match when inverted. bool invert_match = 8; - - // If true, indicates the exact_match/prefix_match/suffix_match/contains_match should be case - // insensitive. This has no effect for the safe_regex_match. - bool ignore_case = 13; } // Query parameter matching treats the query string of a request's :path header diff --git a/api/envoy/type/matcher/v3/string.proto b/api/envoy/type/matcher/v3/string.proto index 78e1572bf8cf..c64edde142ff 100644 --- a/api/envoy/type/matcher/v3/string.proto +++ b/api/envoy/type/matcher/v3/string.proto @@ -62,8 +62,8 @@ message StringMatcher { string contains = 7 [(validate.rules).string = {min_len: 1}]; } - // If true, indicates the exact/prefix/suffix matching should be case insensitive. This has no - // effect for the safe_regex match. + // If true, indicates the exact/prefix/suffix/contains matching should be case insensitive. This + // has no effect for the safe_regex match. // For example, the matcher *data* will match both input string *Data* and *data* if set to true. bool ignore_case = 6; } diff --git a/api/envoy/type/matcher/v4alpha/string.proto b/api/envoy/type/matcher/v4alpha/string.proto index 14098fac4d41..ab9662319bdb 100644 --- a/api/envoy/type/matcher/v4alpha/string.proto +++ b/api/envoy/type/matcher/v4alpha/string.proto @@ -63,8 +63,8 @@ message StringMatcher { string contains = 7 [(validate.rules).string = {min_len: 1}]; } - // If true, indicates the exact/prefix/suffix matching should be case insensitive. This has no - // effect for the safe_regex match. + // If true, indicates the exact/prefix/suffix/contains matching should be case insensitive. This + // has no effect for the safe_regex match.. // For example, the matcher *data* will match both input string *Data* and *data* if set to true. bool ignore_case = 6; } diff --git a/docs/root/version_history/current.rst b/docs/root/version_history/current.rst index ae29b3e15cce..1b783aeda879 100644 --- a/docs/root/version_history/current.rst +++ b/docs/root/version_history/current.rst @@ -104,7 +104,7 @@ New Features * http: added a new option to upstream HTTP/2 :ref:`keepalive ` to send a PING ahead of a new stream if the connection has been idle for a sufficient duration. * http: added the ability to :ref:`unescape slash sequences ` in the path. Requests with unescaped slashes can be proxied, rejected or redirected to the new unescaped path. By default this feature is disabled. The default behavior can be overridden through :ref:`http_connection_manager.path_with_escaped_slashes_action` runtime variable. This action can be selectively enabled for a portion of requests by setting the :ref:`http_connection_manager.path_with_escaped_slashes_action_sampling` runtime variable. * http: added upstream and downstream alpha HTTP/3 support! See :ref:`quic_options ` for downstream and the new http3_protocol_options in :ref:`http_protocol_options ` for upstream HTTP/3. -* http: added :ref:`ignore_case ` for the exact, prefix, suffix and contains match in the header matcher. +* http: added :ref:`string_match ` in the header matcher. * input matcher: a new input matcher that :ref:`matches an IP address against a list of CIDR ranges `. * jwt_authn: added support to fetch remote jwks asynchronously specified by :ref:`async_fetch `. * listener: added ability to change an existing listener's address. @@ -130,3 +130,6 @@ Deprecated * 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`. +* http: The HeaderMatcher fields :ref:`exact_match `, :ref:`safe_regex_match `, + :ref:`prefix_match `, :ref:`suffix_match ` and + :ref:`contains_match ` are deprecated by :ref:`string_match `. \ No newline at end of file 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 190081288794..9a1ef9b8db9d 100644 --- a/generated_api_shadow/envoy/config/route/v3/route_components.proto +++ b/generated_api_shadow/envoy/config/route/v3/route_components.proto @@ -1903,12 +1903,16 @@ message HeaderMatcher { // Specifies how the header match will be performed to route the request. oneof header_match_specifier { // If specified, header match will be performed based on the value of the header. - string exact_match = 4; + // This field is deprecated. Please use :ref:`string_match `. + string exact_match = 4 + [deprecated = true, (envoy.annotations.deprecated_at_minor_version) = "3.0"]; // If specified, this regex string is a regular expression rule which implies the entire request // header value must match the regex. The rule will not match if only a subsequence of the // request header value matches the regex. - type.matcher.v3.RegexMatcher safe_regex_match = 11; + // This field is deprecated. Please use :ref:`string_match `. + type.matcher.v3.RegexMatcher safe_regex_match = 11 + [deprecated = true, (envoy.annotations.deprecated_at_minor_version) = "3.0"]; // If specified, header match will be performed based on range. // The rule will match if the request header value is within this range. @@ -1929,28 +1933,46 @@ message HeaderMatcher { // If specified, header match will be performed based on the prefix of the header value. // Note: empty prefix is not allowed, please use present_match instead. + // This field is deprecated. Please use :ref:`string_match `. // // Examples: // // * The prefix *abcd* matches the value *abcdxyz*, but not for *abcxyz*. - string prefix_match = 9 [(validate.rules).string = {min_len: 1}]; + string prefix_match = 9 [ + deprecated = true, + (validate.rules).string = {min_len: 1}, + (envoy.annotations.deprecated_at_minor_version) = "3.0" + ]; // If specified, header match will be performed based on the suffix of the header value. // Note: empty suffix is not allowed, please use present_match instead. + // This field is deprecated. Please use :ref:`string_match `. // // Examples: // // * The suffix *abcd* matches the value *xyzabcd*, but not for *xyzbcd*. - string suffix_match = 10 [(validate.rules).string = {min_len: 1}]; + string suffix_match = 10 [ + deprecated = true, + (validate.rules).string = {min_len: 1}, + (envoy.annotations.deprecated_at_minor_version) = "3.0" + ]; // If specified, header match will be performed based on whether the header value contains // the given value or not. // Note: empty contains match is not allowed, please use present_match instead. + // This field is deprecated. Please use :ref:`string_match `. // // Examples: // // * The value *abcd* matches the value *xyzabcdpqr*, but not for *xyzbcdpqr*. - string contains_match = 12 [(validate.rules).string = {min_len: 1}]; + string contains_match = 12 [ + deprecated = true, + (validate.rules).string = {min_len: 1}, + (envoy.annotations.deprecated_at_minor_version) = "3.0" + ]; + + // If specified, header match will be performed based on the string match of the header value. + type.matcher.v3.StringMatcher string_match = 13; string hidden_envoy_deprecated_regex_match = 5 [ deprecated = true, @@ -1967,10 +1989,6 @@ message HeaderMatcher { // * The regex ``\d{3}`` does not match the value *1234*, so it will match when inverted. // * The range [-10,0) will match the value -1, so it will not match when inverted. bool invert_match = 8; - - // If true, indicates the exact_match/prefix_match/suffix_match/contains_match should be case - // insensitive. This has no effect for the safe_regex_match. - bool ignore_case = 13; } // Query parameter matching treats the query string of a request's :path header 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 bd4544eb353f..430b0583769e 100644 --- a/generated_api_shadow/envoy/config/route/v4alpha/route_components.proto +++ b/generated_api_shadow/envoy/config/route/v4alpha/route_components.proto @@ -1902,12 +1902,16 @@ message HeaderMatcher { // Specifies how the header match will be performed to route the request. oneof header_match_specifier { // If specified, header match will be performed based on the value of the header. - string exact_match = 4; + // This field is deprecated. Please use :ref:`string_match `. + string hidden_envoy_deprecated_exact_match = 4 + [deprecated = true, (envoy.annotations.deprecated_at_minor_version) = "3.0"]; // If specified, this regex string is a regular expression rule which implies the entire request // header value must match the regex. The rule will not match if only a subsequence of the // request header value matches the regex. - type.matcher.v4alpha.RegexMatcher safe_regex_match = 11; + // This field is deprecated. Please use :ref:`string_match `. + type.matcher.v4alpha.RegexMatcher hidden_envoy_deprecated_safe_regex_match = 11 + [deprecated = true, (envoy.annotations.deprecated_at_minor_version) = "3.0"]; // If specified, header match will be performed based on range. // The rule will match if the request header value is within this range. @@ -1928,28 +1932,46 @@ message HeaderMatcher { // If specified, header match will be performed based on the prefix of the header value. // Note: empty prefix is not allowed, please use present_match instead. + // This field is deprecated. Please use :ref:`string_match `. // // Examples: // // * The prefix *abcd* matches the value *abcdxyz*, but not for *abcxyz*. - string prefix_match = 9 [(validate.rules).string = {min_len: 1}]; + string hidden_envoy_deprecated_prefix_match = 9 [ + deprecated = true, + (validate.rules).string = {min_len: 1}, + (envoy.annotations.deprecated_at_minor_version) = "3.0" + ]; // If specified, header match will be performed based on the suffix of the header value. // Note: empty suffix is not allowed, please use present_match instead. + // This field is deprecated. Please use :ref:`string_match `. // // Examples: // // * The suffix *abcd* matches the value *xyzabcd*, but not for *xyzbcd*. - string suffix_match = 10 [(validate.rules).string = {min_len: 1}]; + string hidden_envoy_deprecated_suffix_match = 10 [ + deprecated = true, + (validate.rules).string = {min_len: 1}, + (envoy.annotations.deprecated_at_minor_version) = "3.0" + ]; // If specified, header match will be performed based on whether the header value contains // the given value or not. // Note: empty contains match is not allowed, please use present_match instead. + // This field is deprecated. Please use :ref:`string_match `. // // Examples: // // * The value *abcd* matches the value *xyzabcdpqr*, but not for *xyzbcdpqr*. - string contains_match = 12 [(validate.rules).string = {min_len: 1}]; + string hidden_envoy_deprecated_contains_match = 12 [ + deprecated = true, + (validate.rules).string = {min_len: 1}, + (envoy.annotations.deprecated_at_minor_version) = "3.0" + ]; + + // If specified, header match will be performed based on the string match of the header value. + type.matcher.v4alpha.StringMatcher string_match = 13; } // If specified, the match result will be inverted before checking. Defaults to false. @@ -1959,10 +1981,6 @@ message HeaderMatcher { // * The regex ``\d{3}`` does not match the value *1234*, so it will match when inverted. // * The range [-10,0) will match the value -1, so it will not match when inverted. bool invert_match = 8; - - // If true, indicates the exact_match/prefix_match/suffix_match/contains_match should be case - // insensitive. This has no effect for the safe_regex_match. - bool ignore_case = 13; } // Query parameter matching treats the query string of a request's :path header diff --git a/generated_api_shadow/envoy/type/matcher/v3/string.proto b/generated_api_shadow/envoy/type/matcher/v3/string.proto index 934b19d71cc1..4dc7cacffae6 100644 --- a/generated_api_shadow/envoy/type/matcher/v3/string.proto +++ b/generated_api_shadow/envoy/type/matcher/v3/string.proto @@ -66,8 +66,8 @@ message StringMatcher { ]; } - // If true, indicates the exact/prefix/suffix matching should be case insensitive. This has no - // effect for the safe_regex match. + // If true, indicates the exact/prefix/suffix/contains matching should be case insensitive. This + // has no effect for the safe_regex match. // For example, the matcher *data* will match both input string *Data* and *data* if set to true. bool ignore_case = 6; } diff --git a/generated_api_shadow/envoy/type/matcher/v4alpha/string.proto b/generated_api_shadow/envoy/type/matcher/v4alpha/string.proto index 14098fac4d41..f9fa48cd3195 100644 --- a/generated_api_shadow/envoy/type/matcher/v4alpha/string.proto +++ b/generated_api_shadow/envoy/type/matcher/v4alpha/string.proto @@ -63,8 +63,8 @@ message StringMatcher { string contains = 7 [(validate.rules).string = {min_len: 1}]; } - // If true, indicates the exact/prefix/suffix matching should be case insensitive. This has no - // effect for the safe_regex match. + // If true, indicates the exact/prefix/suffix/contains matching should be case insensitive. This + // has no effect for the safe_regex match. // For example, the matcher *data* will match both input string *Data* and *data* if set to true. bool ignore_case = 6; } diff --git a/source/common/http/BUILD b/source/common/http/BUILD index 55c15b06a3f3..db231bbd66b0 100644 --- a/source/common/http/BUILD +++ b/source/common/http/BUILD @@ -467,8 +467,10 @@ envoy_cc_library( ":header_map_lib", ":status_lib", ":utility_lib", + "//envoy/common:matchers_interface", "//envoy/common:regex_interface", "//envoy/http:header_map_interface", + "//source/common/common:matchers_lib", "//source/common/common:regex_lib", "//source/common/common:utility_lib", "//source/common/protobuf:utility_lib", diff --git a/source/common/http/header_utility.cc b/source/common/http/header_utility.cc index dccd03cbf315..b0fc8d02fe5e 100644 --- a/source/common/http/header_utility.cc +++ b/source/common/http/header_utility.cc @@ -2,6 +2,7 @@ #include "envoy/config/route/v3/route_components.pb.h" +#include "source/common/common/matchers.h" #include "source/common/common/regex.h" #include "source/common/common/utility.h" #include "source/common/http/header_map_impl.h" @@ -35,8 +36,7 @@ using SharedResponseCodeDetails = ConstSingleton(config.string_match()); break; case envoy::config::route::v3::HeaderMatcher::HeaderMatchSpecifierCase:: HEADER_MATCH_SPECIFIER_NOT_SET: @@ -146,9 +147,7 @@ bool HeaderUtility::matchHeaders(const HeaderMap& request_headers, const HeaderD bool match; switch (header_data.header_match_type_) { case HeaderMatchType::Value: - match = header_data.value_.empty() || - (header_data.ignore_case_ ? absl::EqualsIgnoreCase(value, header_data.value_) - : value == header_data.value_); + match = header_data.value_.empty() || value == header_data.value_; break; case HeaderMatchType::Regex: match = header_data.regex_->match(value); @@ -164,18 +163,16 @@ bool HeaderUtility::matchHeaders(const HeaderMap& request_headers, const HeaderD match = header_data.present_; break; case HeaderMatchType::Prefix: - match = header_data.ignore_case_ ? absl::StartsWithIgnoreCase(value, header_data.value_) - : absl::StartsWith(value, header_data.value_); + match = absl::StartsWith(value, header_data.value_); break; case HeaderMatchType::Suffix: - match = header_data.ignore_case_ ? absl::EndsWithIgnoreCase(value, header_data.value_) - : absl::EndsWith(value, header_data.value_); + match = absl::EndsWith(value, header_data.value_); break; case HeaderMatchType::Contains: - match = header_data.ignore_case_ - ? absl::StrContains(absl::AsciiStrToLower(value), - header_data.contains_match_lowercase_.get()) - : absl::StrContains(value, header_data.value_); + match = absl::StrContains(value, header_data.value_); + break; + case HeaderMatchType::StringMatch: + match = header_data.string_match_->match(value); break; default: NOT_REACHED_GCOVR_EXCL_LINE; diff --git a/source/common/http/header_utility.h b/source/common/http/header_utility.h index 0edad936d59f..50b1d571f60e 100644 --- a/source/common/http/header_utility.h +++ b/source/common/http/header_utility.h @@ -2,6 +2,7 @@ #include +#include "envoy/common/matchers.h" #include "envoy/common/regex.h" #include "envoy/config/core/v3/protocol.pb.h" #include "envoy/config/route/v3/route_components.pb.h" @@ -20,7 +21,16 @@ namespace Http { */ class HeaderUtility { public: - enum class HeaderMatchType { Value, Regex, Range, Present, Prefix, Suffix, Contains }; + enum class HeaderMatchType { + Value, + Regex, + Range, + Present, + Prefix, + Suffix, + Contains, + StringMatch + }; /** * Get all header values as a single string. Multiple headers are concatenated with ','. @@ -63,13 +73,11 @@ class HeaderUtility { const LowerCaseString name_; HeaderMatchType header_match_type_; std::string value_; - // The contains_match_lowercase_ is populated only for contains match when ignore_case is true. - LowerCaseString contains_match_lowercase_; Regex::CompiledMatcherPtr regex_; envoy::type::v3::Int64Range range_; + Matchers::StringMatcherPtr string_match_; const bool invert_match_; bool present_; - bool ignore_case_; // HeaderMatcher bool matchesHeaders(const HeaderMap& headers) const override { diff --git a/test/common/http/header_utility_test.cc b/test/common/http/header_utility_test.cc index 21f43bbbf560..e7635972addd 100644 --- a/test/common/http/header_utility_test.cc +++ b/test/common/http/header_utility_test.cc @@ -289,6 +289,21 @@ contains_match: somevalueinside EXPECT_EQ("somevalueinside", header_data.value_); } +TEST(HeaderDataConstructorTest, StringMatchSpecifier) { + const std::string yaml = R"EOF( +name: test-header +string_match: + exact: value + )EOF"; + + HeaderUtility::HeaderData header_data = + HeaderUtility::HeaderData(parseHeaderMatcherFromYaml(yaml)); + + EXPECT_EQ("test-header", header_data.name_.get()); + EXPECT_EQ(HeaderUtility::HeaderMatchType::StringMatch, header_data.header_match_type_); + EXPECT_TRUE(header_data.string_match_->match("value")); +} + TEST(HeaderDataConstructorTest, InvertMatchSpecifier) { const std::string yaml = R"EOF( name: test-header @@ -382,9 +397,8 @@ name: match-header TEST(MatchHeadersTest, HeaderExactMatch) { TestRequestHeaderMapImpl matching_headers{{"match-header", "match-value"}}; - TestRequestHeaderMapImpl unmatching_headers_1{{"match-header", "other-value"}, - {"other-header", "match-value"}}; - TestRequestHeaderMapImpl unmatching_headers_2{{"match-header", "MATCH-VALUE"}}; + TestRequestHeaderMapImpl unmatching_headers{{"match-header", "other-value"}, + {"other-header", "match-value"}}; const std::string yaml = R"EOF( name: match-header exact_match: match-value @@ -394,8 +408,7 @@ exact_match: match-value header_data.push_back( std::make_unique(parseHeaderMatcherFromYaml(yaml))); EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers, header_data)); - EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers_1, header_data)); - EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers_2, header_data)); + EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); } TEST(MatchHeadersTest, HeaderExactMatchInverse) { @@ -416,30 +429,6 @@ invert_match: true EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); } -TEST(MatchHeadersTest, HeaderExactMatchIgnoreCase) { - for (const auto& match_value : {"match-value", "Match-Value"}) { - const std::string yaml = fmt::format(R"EOF( -name: match-header -exact_match: {} -ignore_case: true - )EOF", - match_value); - - TestRequestHeaderMapImpl matching_headers_1{{"match-header", "match-value"}}; - TestRequestHeaderMapImpl matching_headers_2{{"match-header", "MATCH-VALUE"}}; - TestRequestHeaderMapImpl matching_headers_3{{"match-header", "Match-Value"}}; - TestRequestHeaderMapImpl unmatching_headers{{"match-header", "other-value"}, - {"other-header", "match-value"}}; - std::vector header_data; - header_data.push_back( - std::make_unique(parseHeaderMatcherFromYaml(yaml))); - EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_1, header_data)); - EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_2, header_data)); - EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_3, header_data)); - EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); - } -} - TEST(MatchHeadersTest, HeaderSafeRegexMatch) { TestRequestHeaderMapImpl matching_headers{{"match-header", "123"}}; TestRequestHeaderMapImpl unmatching_headers{{"match-header", "1234"}, @@ -600,8 +589,7 @@ invert_match: true TEST(MatchHeadersTest, HeaderPrefixMatch) { TestRequestHeaderMapImpl matching_headers{{"match-header", "value123"}}; - TestRequestHeaderMapImpl unmatching_headers_1{{"match-header", "123value"}}; - TestRequestHeaderMapImpl unmatching_headers_2{{"match-header", "VALUE123"}}; + TestRequestHeaderMapImpl unmatching_headers{{"match-header", "123value"}}; const std::string yaml = R"EOF( name: match-header @@ -612,8 +600,7 @@ prefix_match: value header_data.push_back( std::make_unique(parseHeaderMatcherFromYaml(yaml))); EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers, header_data)); - EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers_1, header_data)); - EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers_2, header_data)); + EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); } TEST(MatchHeadersTest, HeaderPrefixInverseMatch) { @@ -633,34 +620,9 @@ invert_match: true EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); } -TEST(MatchHeadersTest, HeaderPrefixMatchIgnoreCase) { - for (const auto& match_value : {"value", "Value"}) { - const std::string yaml = fmt::format(R"EOF( -name: match-header -prefix_match: {} -ignore_case: true - )EOF", - match_value); - - TestRequestHeaderMapImpl matching_headers_1{{"match-header", "value123"}}; - TestRequestHeaderMapImpl matching_headers_2{{"match-header", "VALUE123"}}; - TestRequestHeaderMapImpl matching_headers_3{{"match-header", "Value123"}}; - TestRequestHeaderMapImpl unmatching_headers{{"match-header", "123value"}}; - - std::vector header_data; - header_data.push_back( - std::make_unique(parseHeaderMatcherFromYaml(yaml))); - EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_1, header_data)); - EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_2, header_data)); - EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_3, header_data)); - EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); - } -} - TEST(MatchHeadersTest, HeaderSuffixMatch) { TestRequestHeaderMapImpl matching_headers{{"match-header", "123value"}}; - TestRequestHeaderMapImpl unmatching_headers_1{{"match-header", "value123"}}; - TestRequestHeaderMapImpl unmatching_headers_2{{"match-header", "123VALUE"}}; + TestRequestHeaderMapImpl unmatching_headers{{"match-header", "value123"}}; const std::string yaml = R"EOF( name: match-header @@ -671,8 +633,7 @@ suffix_match: value header_data.push_back( std::make_unique(parseHeaderMatcherFromYaml(yaml))); EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers, header_data)); - EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers_1, header_data)); - EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers_2, header_data)); + EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); } TEST(MatchHeadersTest, HeaderSuffixInverseMatch) { @@ -692,34 +653,9 @@ invert_match: true EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); } -TEST(MatchHeadersTest, HeaderSuffixMatchIgnoreCase) { - for (const auto& match_value : {"value", "Value"}) { - const std::string yaml = fmt::format(R"EOF( -name: match-header -suffix_match: {} -ignore_case: true - )EOF", - match_value); - - TestRequestHeaderMapImpl matching_headers_1{{"match-header", "123value"}}; - TestRequestHeaderMapImpl matching_headers_2{{"match-header", "123VALUE"}}; - TestRequestHeaderMapImpl matching_headers_3{{"match-header", "123Value"}}; - TestRequestHeaderMapImpl unmatching_headers{{"match-header", "value123"}}; - - std::vector header_data; - header_data.push_back( - std::make_unique(parseHeaderMatcherFromYaml(yaml))); - EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_1, header_data)); - EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_2, header_data)); - EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_3, header_data)); - EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); - } -} - TEST(MatchHeadersTest, HeaderContainsMatch) { TestRequestHeaderMapImpl matching_headers{{"match-header", "123onevalue456"}}; - TestRequestHeaderMapImpl unmatching_headers_1{{"match-header", "123anothervalue456"}}; - TestRequestHeaderMapImpl unmatching_headers_2{{"match-header", "123ONEVALUE456"}}; + TestRequestHeaderMapImpl unmatching_headers{{"match-header", "123anothervalue456"}}; const std::string yaml = R"EOF( name: match-header @@ -730,8 +666,7 @@ contains_match: onevalue header_data.push_back( std::make_unique(parseHeaderMatcherFromYaml(yaml))); EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers, header_data)); - EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers_1, header_data)); - EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers_2, header_data)); + EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); } TEST(MatchHeadersTest, HeaderContainsInverseMatch) { @@ -751,28 +686,60 @@ invert_match: true EXPECT_FALSE(HeaderUtility::matchHeaders(matching_headers, header_data)); } -TEST(MatchHeadersTest, HeaderContainsMatchIgnoreCase) { - for (const auto& match_value : {"onevalue", "OneValue"}) { - const std::string yaml = fmt::format(R"EOF( +TEST(MatchHeadersTest, HeaderStringMatch) { + TestRequestHeaderMapImpl matching_headers{{"match-header", "match-value"}}; + TestRequestHeaderMapImpl unmatching_headers{{"match-header", "other-value"}, + {"other-header", "match-value"}}; + const std::string yaml = R"EOF( name: match-header -contains_match: {} -ignore_case: true - )EOF", - match_value); - - TestRequestHeaderMapImpl matching_headers_1{{"match-header", "123onevalue456"}}; - TestRequestHeaderMapImpl matching_headers_2{{"match-header", "123ONEVALUE456"}}; - TestRequestHeaderMapImpl matching_headers_3{{"match-header", "123OneValue456"}}; - TestRequestHeaderMapImpl unmatching_headers{{"match-header", "123anothervalue456"}}; - - std::vector header_data; - header_data.push_back( - std::make_unique(parseHeaderMatcherFromYaml(yaml))); - EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_1, header_data)); - EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_2, header_data)); - EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_3, header_data)); - EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); - } +string_match: + exact: match-value + )EOF"; + + std::vector header_data; + header_data.push_back( + std::make_unique(parseHeaderMatcherFromYaml(yaml))); + EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers, header_data)); + EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); +} + +TEST(MatchHeadersTest, HeaderStringMatchIgnoreCase) { + TestRequestHeaderMapImpl matching_headers_1{{"match-header", "123onevalue456"}}; + TestRequestHeaderMapImpl matching_headers_2{{"match-header", "123OneValue456"}}; + TestRequestHeaderMapImpl unmatching_headers{{"match-header", "123anothervalue456"}}; + + const std::string yaml = R"EOF( +name: match-header +string_match: + contains: onevalue + ignore_case: true + )EOF"; + + std::vector header_data; + header_data.push_back( + std::make_unique(parseHeaderMatcherFromYaml(yaml))); + EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_1, header_data)); + EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_2, header_data)); + EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); +} + +TEST(MatchHeadersTest, HeaderStringMatchInverse) { + TestRequestHeaderMapImpl matching_headers{{"match-header", "other-value"}, + {"other-header", "match-value"}}; + TestRequestHeaderMapImpl unmatching_headers{{"match-header", "match-value"}}; + + const std::string yaml = R"EOF( +name: match-header +string_match: + exact: match-value +invert_match: true + )EOF"; + + std::vector header_data; + header_data.push_back( + std::make_unique(parseHeaderMatcherFromYaml(yaml))); + EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers, header_data)); + EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); } TEST(HeaderIsValidTest, InvalidHeaderValuesAreRejected) { From affb6b3b084473b8aa928630d8becec8ae8f742b Mon Sep 17 00:00:00 2001 From: Yangmin Zhu Date: Mon, 28 Jun 2021 18:17:26 -0700 Subject: [PATCH 04/12] fix format Signed-off-by: Yangmin Zhu --- docs/root/version_history/current.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/root/version_history/current.rst b/docs/root/version_history/current.rst index 1b783aeda879..87b2f04c98b8 100644 --- a/docs/root/version_history/current.rst +++ b/docs/root/version_history/current.rst @@ -132,4 +132,4 @@ Deprecated * http: :ref:`xff_num_trusted_hops ` is deprecated in favor of :ref:`original IP detection extensions`. * http: The HeaderMatcher fields :ref:`exact_match `, :ref:`safe_regex_match `, :ref:`prefix_match `, :ref:`suffix_match ` and - :ref:`contains_match ` are deprecated by :ref:`string_match `. \ No newline at end of file + :ref:`contains_match ` are deprecated by :ref:`string_match `. From 91baeaacdca2429d5dcad1383a7f133007439177 Mon Sep 17 00:00:00 2001 From: Yangmin Zhu Date: Tue, 29 Jun 2021 10:06:39 -0700 Subject: [PATCH 05/12] fix format Signed-off-by: Yangmin Zhu --- api/envoy/type/matcher/v4alpha/string.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/envoy/type/matcher/v4alpha/string.proto b/api/envoy/type/matcher/v4alpha/string.proto index ab9662319bdb..f9fa48cd3195 100644 --- a/api/envoy/type/matcher/v4alpha/string.proto +++ b/api/envoy/type/matcher/v4alpha/string.proto @@ -64,7 +64,7 @@ message StringMatcher { } // If true, indicates the exact/prefix/suffix/contains matching should be case insensitive. This - // has no effect for the safe_regex match.. + // has no effect for the safe_regex match. // For example, the matcher *data* will match both input string *Data* and *data* if set to true. bool ignore_case = 6; } From 2eb89668af3086eabdca8083e59626c9f9f1e98b Mon Sep 17 00:00:00 2001 From: Yangmin Zhu Date: Tue, 29 Jun 2021 17:31:09 -0700 Subject: [PATCH 06/12] fix test Signed-off-by: Yangmin Zhu --- test/tools/router_check/router.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/tools/router_check/router.cc b/test/tools/router_check/router.cc index 7da0acffffa7..aa983e92551a 100644 --- a/test/tools/router_check/router.cc +++ b/test/tools/router_check/router.cc @@ -48,6 +48,9 @@ toString(envoy::config::route::v3::HeaderMatcher::HeaderMatchSpecifierCase speci case envoy::config::route::v3::HeaderMatcher::HeaderMatchSpecifierCase::kContainsMatch: return "contains_match"; break; + case envoy::config::route::v3::HeaderMatcher::HeaderMatchSpecifierCase::kStringMatch: + return "string_match"; + break; } NOT_REACHED_GCOVR_EXCL_LINE; } From 1a1de1ebafba4647451f51aac5cf40425ac89ba3 Mon Sep 17 00:00:00 2001 From: Yangmin Zhu Date: Tue, 29 Jun 2021 20:11:05 -0700 Subject: [PATCH 07/12] fix test failure in example config Signed-off-by: Yangmin Zhu --- configs/envoy_double_proxy.template.yaml | 3 +- configs/envoy_front_proxy.template.yaml | 3 +- .../envoy_service_to_service.template.yaml | 6 +- configs/terminate_http2_post.yaml | 3 +- .../test/config/ComprehensiveRoutes.yaml | 10 ++- .../router_check/test/config/ContentType.yaml | 3 +- .../test/config/HeaderMatchedRouting.yaml | 22 ++++-- .../router_check/test/config/TestRoutes.yaml | 78 +++++++++++-------- .../router_check/test/config/Weighted.yaml | 10 ++- 9 files changed, 84 insertions(+), 54 deletions(-) diff --git a/configs/envoy_double_proxy.template.yaml b/configs/envoy_double_proxy.template.yaml index 7e922bfd7542..e620b9024f09 100644 --- a/configs/envoy_double_proxy.template.yaml +++ b/configs/envoy_double_proxy.template.yaml @@ -53,7 +53,8 @@ "@type": type.googleapis.com/envoy.extensions.filters.http.health_check.v3.HealthCheck pass_through_mode: false headers: - - exact_match: /healthcheck + - string_match: + exact: /healthcheck name: :path - name: envoy.filters.http.buffer typed_config: diff --git a/configs/envoy_front_proxy.template.yaml b/configs/envoy_front_proxy.template.yaml index 22f6fc2de3b3..047390d8ef67 100644 --- a/configs/envoy_front_proxy.template.yaml +++ b/configs/envoy_front_proxy.template.yaml @@ -54,7 +54,8 @@ pass_through_mode: false headers: - name: ":path" - exact_match: "/healthcheck" + string_match: + exact: "/healthcheck" - name: envoy.filters.http.buffer typed_config: "@type": type.googleapis.com/envoy.extensions.filters.http.buffer.v3.Buffer diff --git a/configs/envoy_service_to_service.template.yaml b/configs/envoy_service_to_service.template.yaml index f55fe4dd0b55..6ec2f0bde905 100644 --- a/configs/envoy_service_to_service.template.yaml +++ b/configs/envoy_service_to_service.template.yaml @@ -25,7 +25,8 @@ prefix: "/" headers: - name: content-type - exact_match: application/grpc + string_match: + exact: application/grpc route: cluster: local_service_grpc - match: @@ -39,7 +40,8 @@ pass_through_mode: true headers: - name: ":path" - exact_match: "/healthcheck" + string_match: + exact: "/healthcheck" cache_time: 2.5s - name: envoy.filters.http.buffer typed_config: diff --git a/configs/terminate_http2_post.yaml b/configs/terminate_http2_post.yaml index 4c76f72313e2..d2ede127da35 100644 --- a/configs/terminate_http2_post.yaml +++ b/configs/terminate_http2_post.yaml @@ -32,7 +32,8 @@ static_resources: prefix: "/" headers: - name: ":method" - exact_match: "POST" + string_match: + exact: "POST" route: cluster: service_google upgrade_configs: diff --git a/test/tools/router_check/test/config/ComprehensiveRoutes.yaml b/test/tools/router_check/test/config/ComprehensiveRoutes.yaml index a477fbe0a7a8..fef2ba6cf16a 100644 --- a/test/tools/router_check/test/config/ComprehensiveRoutes.yaml +++ b/test/tools/router_check/test/config/ComprehensiveRoutes.yaml @@ -19,9 +19,11 @@ virtual_hosts: virtual_clusters: - headers: - name: :path - safe_regex_match: - google_re2: {} - regex: ^/users/\d+$ + string_match: + safe_regex: + google_re2: {} + regex: ^/users/\d+$ - name: :method - exact_match: PUT + string_match: + exact: PUT name: update_user diff --git a/test/tools/router_check/test/config/ContentType.yaml b/test/tools/router_check/test/config/ContentType.yaml index 17f1d551755e..0d7ea6557241 100644 --- a/test/tools/router_check/test/config/ContentType.yaml +++ b/test/tools/router_check/test/config/ContentType.yaml @@ -7,7 +7,8 @@ virtual_hosts: prefix: "/" headers: - name: "content-type" - exact_match: "application/grpc" + string_match: + exact: "application/grpc" route: cluster: local_service_grpc - match: diff --git a/test/tools/router_check/test/config/HeaderMatchedRouting.yaml b/test/tools/router_check/test/config/HeaderMatchedRouting.yaml index 5f891bea08d5..0a58891d7ed2 100644 --- a/test/tools/router_check/test/config/HeaderMatchedRouting.yaml +++ b/test/tools/router_check/test/config/HeaderMatchedRouting.yaml @@ -7,16 +7,19 @@ virtual_hosts: prefix: / headers: - name: test_header - exact_match: test + string_match: + exact: test route: cluster: local_service_with_headers - match: prefix: / headers: - name: test_header_multiple1 - exact_match: test1 + string_match: + exact: test1 - name: test_header_multiple2 - exact_match: test2 + string_match: + exact: test2 route: cluster: local_service_with_multiple_headers @@ -30,16 +33,18 @@ virtual_hosts: prefix: / headers: - name: test_header_pattern - safe_regex_match: - google_re2: {} - regex: ^user=test-\d+$ + string_match: + safe_regex: + google_re2: {} + regex: ^user=test-\d+$ route: cluster: local_service_with_header_pattern_set_regex - match: prefix: / headers: - name: test_header_pattern - exact_match: ^customer=test-\d+$ + string_match: + exact: ^customer=test-\d+$ route: cluster: local_service_with_header_pattern_unset_regex - match: @@ -47,7 +52,8 @@ virtual_hosts: grpc: {} headers: - name: test_header - exact_match: some_value + string_match: + exact: some_value route: cluster: local_service_with_grpc_and_other_header - match: diff --git a/test/tools/router_check/test/config/TestRoutes.yaml b/test/tools/router_check/test/config/TestRoutes.yaml index a047ce0f89bc..929a415b9768 100644 --- a/test/tools/router_check/test/config/TestRoutes.yaml +++ b/test/tools/router_check/test/config/TestRoutes.yaml @@ -61,12 +61,12 @@ virtual_hosts: prefix: /host/rewrite/me route: cluster: ats - host_rewrite: new_host + host_rewrite_literal: new_host - match: prefix: /oldhost/rewrite/me route: cluster: ats - host_rewrite: new_oldhost + host_rewrite_literal: new_oldhost - match: path: /foo case_sensitive: true @@ -84,7 +84,7 @@ virtual_hosts: case_sensitive: false route: cluster: ats - host_rewrite: new_host + host_rewrite_literal: new_host - match: path: /FOOD case_sensitive: false @@ -101,7 +101,7 @@ virtual_hosts: prefix: /customheaders route: cluster: ats - host_rewrite: new_host + host_rewrite_literal: new_host request_headers_to_add: - header: key: X-Client-IP @@ -115,59 +115,73 @@ virtual_hosts: virtual_clusters: - headers: - name: :path - safe_regex_match: - google_re2: {} - regex: ^/rides$ + string_match: + safe_regex: + google_re2: {} + regex: ^/rides$ - name: :method - exact_match: POST + string_match: + exact: POST name: ride_request - headers: - name: :path - safe_regex_match: - google_re2: {} - regex: ^/rides/\d+$ + string_match: + safe_regex: + google_re2: {} + regex: ^/rides/\d+$ - name: :method - exact_match: PUT + string_match: + exact: PUT name: update_ride - headers: - name: :path - safe_regex_match: - google_re2: {} - regex: ^/users/\d+/chargeaccounts$ + string_match: + safe_regex: + google_re2: {} + regex: ^/users/\d+/chargeaccounts$ - name: :method - exact_match: POST + string_match: + exact: POST name: cc_add - headers: - name: :path - safe_regex_match: - google_re2: {} - regex: ^/users/\d+/chargeaccounts/[^validate]\w+$ + string_match: + safe_regex: + google_re2: {} + regex: ^/users/\d+/chargeaccounts/[^validate]\w+$ - name: :method - exact_match: PUT + string_match: + exact: PUT name: cc_add - headers: - name: :path - safe_regex_match: - google_re2: {} - regex: ^/users$ + string_match: + safe_regex: + google_re2: {} + regex: ^/users$ - name: :method - exact_match: POST + string_match: + exact: POST name: create_user_login - headers: - name: :path - safe_regex_match: - google_re2: {} - regex: ^/users/\d+$ + string_match: + safe_regex: + google_re2: {} + regex: ^/users/\d+$ - name: :method - exact_match: PUT + string_match: + exact: PUT name: update_user - headers: - name: :path - safe_regex_match: - google_re2: {} - regex: ^/users/\d+/location$ + string_match: + safe_regex: + google_re2: {} + regex: ^/users/\d+/location$ - name: :method - exact_match: POST + string_match: + exact: POST name: ulu internal_only_headers: - x-lyft-user-id diff --git a/test/tools/router_check/test/config/Weighted.yaml b/test/tools/router_check/test/config/Weighted.yaml index a7f6f3b6667a..655e72a944a8 100644 --- a/test/tools/router_check/test/config/Weighted.yaml +++ b/test/tools/router_check/test/config/Weighted.yaml @@ -17,11 +17,13 @@ virtual_hosts: virtual_clusters: - headers: - name: :path - safe_regex_match: - google_re2: {} - regex: ^/test/\d+$ + string_match: + safe_regex: + google_re2: {} + regex: ^/test/\d+$ - name: :method - exact_match: GET + string_match: + exact: GET name: test_virtual_cluster - name: www2 domains: From b2bcee5c9c155d0e83124ccfe44decea1c70871d Mon Sep 17 00:00:00 2001 From: Yangmin Zhu Date: Wed, 30 Jun 2021 15:37:44 -0700 Subject: [PATCH 08/12] fix other examples and usage Signed-off-by: Yangmin Zhu --- api/envoy/config/rbac/v3/rbac.proto | 5 +- api/envoy/config/rbac/v4alpha/rbac.proto | 5 +- .../http/http_filters/tap_filter.rst | 18 ++- .../operations/tools/router_check.rst | 6 +- .../envoy/config/rbac/v3/rbac.proto | 5 +- .../envoy/config/rbac/v4alpha/rbac.proto | 5 +- .../common/access_log/access_log_impl_test.cc | 10 +- .../config_impl_headermap_benchmark_test.cc | 2 +- test/common/router/config_impl_test.cc | 140 +++++++++++------- test/common/router/retry_state_impl_test.cc | 10 +- test/common/router/router_ratelimit_test.cc | 15 +- test/config/utility.cc | 2 +- .../aws_metadata_fetcher_integration_test.cc | 3 +- .../extensions/common/matcher/matcher_test.cc | 3 +- .../filters/common/rbac/matchers_test.cc | 2 +- .../filters/http/fault/fault_filter_test.cc | 3 +- .../filters/http/health_check/config_test.cc | 30 ++-- .../http/health_check/health_check_test.cc | 2 +- .../filters/http/oauth2/filter_test.cc | 4 +- .../http/rbac/rbac_filter_integration_test.cc | 20 ++- .../http/tap/tap_filter_integration_test.cc | 30 ++-- .../network/dubbo_proxy/route_matcher_test.cc | 6 +- .../rocketmq_proxy/route_matcher_test.cc | 3 +- .../network/thrift_proxy/integration_test.cc | 16 +- .../thrift_proxy/route_matcher_test.cc | 16 +- .../thrift_proxy/router_ratelimit_test.cc | 15 +- .../http_subset_lb_integration_test.cc | 2 +- .../local_reply_integration_test.cc | 33 +++-- ...transport_socket_match_integration_test.cc | 2 +- 29 files changed, 264 insertions(+), 149 deletions(-) diff --git a/api/envoy/config/rbac/v3/rbac.proto b/api/envoy/config/rbac/v3/rbac.proto index 3b7f79d605df..44b3cf7cee6e 100644 --- a/api/envoy/config/rbac/v3/rbac.proto +++ b/api/envoy/config/rbac/v3/rbac.proto @@ -60,7 +60,10 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // permissions: // - and_rules: // rules: -// - header: { name: ":method", exact_match: "GET" } +// - header: +// name: ":method" +// string_match: +// exact: "GET" // - url_path: // path: { prefix: "/products" } // - or_rules: diff --git a/api/envoy/config/rbac/v4alpha/rbac.proto b/api/envoy/config/rbac/v4alpha/rbac.proto index 59c4ba111d1d..bd56c0c3dc32 100644 --- a/api/envoy/config/rbac/v4alpha/rbac.proto +++ b/api/envoy/config/rbac/v4alpha/rbac.proto @@ -58,7 +58,10 @@ option (udpa.annotations.file_status).package_version_status = NEXT_MAJOR_VERSIO // permissions: // - and_rules: // rules: -// - header: { name: ":method", exact_match: "GET" } +// - header: +// name: ":method" +// string_match: +// exact: "GET" // - url_path: // path: { prefix: "/products" } // - or_rules: diff --git a/docs/root/configuration/http/http_filters/tap_filter.rst b/docs/root/configuration/http/http_filters/tap_filter.rst index 97fe68e984d6..049eeaca9f43 100644 --- a/docs/root/configuration/http/http_filters/tap_filter.rst +++ b/docs/root/configuration/http/http_filters/tap_filter.rst @@ -78,11 +78,13 @@ An example POST body: - http_request_headers_match: headers: - name: foo - exact_match: bar + string_match: + exact: bar - http_response_headers_match: headers: - name: bar - exact_match: baz + string_match: + exact: baz output_config: sinks: - streaming_admin: {} @@ -103,11 +105,13 @@ Another example POST body: - http_request_headers_match: headers: - name: foo - exact_match: bar + string_match: + exact: bar - http_response_headers_match: headers: - name: bar - exact_match: baz + string_match: + exact: baz output_config: sinks: - streaming_admin: {} @@ -143,7 +147,8 @@ Another example POST body: - http_request_headers_match: headers: - name: foo - exact_match: bar + string_match: + exact: bar - http_request_generic_body_match: patterns: - string_match: test @@ -242,7 +247,8 @@ An static filter configuration to enable streaming output looks like: http_response_headers_match: headers: - name: bar - exact_match: baz + string_match: + exact: baz output_config: streaming: true sinks: diff --git a/docs/root/configuration/operations/tools/router_check.rst b/docs/root/configuration/operations/tools/router_check.rst index e60ef9e737a5..9fff1cb28469 100644 --- a/docs/root/configuration/operations/tools/router_check.rst +++ b/docs/root/configuration/operations/tools/router_check.rst @@ -69,10 +69,12 @@ expects a cluster name match of "instant-server".:: path_redirect: ..., request_header_matches: - name: ..., - exact_match: ... + string_match: + exact: ... response_header_matches: - name: ..., - exact_match: ... + string_match: + exact: ... - name: ..., presence_match: ... diff --git a/generated_api_shadow/envoy/config/rbac/v3/rbac.proto b/generated_api_shadow/envoy/config/rbac/v3/rbac.proto index 3b7f79d605df..44b3cf7cee6e 100644 --- a/generated_api_shadow/envoy/config/rbac/v3/rbac.proto +++ b/generated_api_shadow/envoy/config/rbac/v3/rbac.proto @@ -60,7 +60,10 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // permissions: // - and_rules: // rules: -// - header: { name: ":method", exact_match: "GET" } +// - header: +// name: ":method" +// string_match: +// exact: "GET" // - url_path: // path: { prefix: "/products" } // - or_rules: diff --git a/generated_api_shadow/envoy/config/rbac/v4alpha/rbac.proto b/generated_api_shadow/envoy/config/rbac/v4alpha/rbac.proto index 7006099d4169..3b27e68bba1d 100644 --- a/generated_api_shadow/envoy/config/rbac/v4alpha/rbac.proto +++ b/generated_api_shadow/envoy/config/rbac/v4alpha/rbac.proto @@ -59,7 +59,10 @@ option (udpa.annotations.file_status).package_version_status = NEXT_MAJOR_VERSIO // permissions: // - and_rules: // rules: -// - header: { name: ":method", exact_match: "GET" } +// - header: +// name: ":method" +// string_match: +// exact: "GET" // - url_path: // path: { prefix: "/products" } // - or_rules: diff --git a/test/common/access_log/access_log_impl_test.cc b/test/common/access_log/access_log_impl_test.cc index 427392a2df98..b52e2d038057 100644 --- a/test/common/access_log/access_log_impl_test.cc +++ b/test/common/access_log/access_log_impl_test.cc @@ -783,7 +783,8 @@ name: accesslog header_filter: header: name: test-header - exact_match: exact-match-value + string_match: + exact: exact-match-value typed_config: "@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog @@ -812,9 +813,10 @@ name: accesslog header_filter: header: name: test-header - safe_regex_match: - google_re2: {} - regex: "\\d{3}" + string_match: + safe_regex: + google_re2: {} + regex: "\\d{3}" typed_config: "@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog path: /dev/null diff --git a/test/common/router/config_impl_headermap_benchmark_test.cc b/test/common/router/config_impl_headermap_benchmark_test.cc index 755f858c8837..b30332475c85 100644 --- a/test/common/router/config_impl_headermap_benchmark_test.cc +++ b/test/common/router/config_impl_headermap_benchmark_test.cc @@ -45,7 +45,7 @@ static void manyCountryRoutesLongHeaders(benchmark::State& state) { new_routes->mutable_route()->set_cluster(country_name); auto headers_matcher = new_routes->mutable_match()->mutable_headers()->Add(); headers_matcher->set_name(country_header_name.get()); - headers_matcher->set_exact_match(country_name); + headers_matcher->mutable_string_match()->set_exact(country_name); } // Add the default route. auto new_routes = main_virtual_host->mutable_routes()->Add(); diff --git a/test/common/router/config_impl_test.cc b/test/common/router/config_impl_test.cc index a403b857474a..edec06438223 100644 --- a/test/common/router/config_impl_test.cc +++ b/test/common/router/config_impl_test.cc @@ -373,7 +373,8 @@ TEST_F(RouteMatcherTest, TestConnectRoutes) { {} headers: - name: x-safe - exact_match: "safe" + string_match: + exact: "safe" route: cluster: connect_header_match - name: default @@ -388,11 +389,13 @@ TEST_F(RouteMatcherTest, TestConnectRoutes) { virtual_clusters: - headers: - name: ":path" - safe_regex_match: - google_re2: {} - regex: "^/users/\\d+/location$" + string_match: + safe_regex: + google_re2: {} + regex: "^/users/\\d+/location$" - name: ":method" - exact_match: POST + string_match: + exact: POST name: ulu )EOF"; NiceMock stream_info; @@ -677,51 +680,63 @@ TEST_F(RouteMatcherTest, TestRoutes) { virtual_clusters: - headers: - name: ":path" - safe_regex_match: - google_re2: {} - regex: "^/rides$" + string_match: + safe_regex: + google_re2: {} + regex: "^/rides$" - name: ":method" - exact_match: POST + string_match: + exact: POST name: ride_request - headers: - name: ":path" - safe_regex_match: - google_re2: {} - regex: "^/rides/\\d+$" + string_match: + safe_regex: + google_re2: {} + regex: "^/rides/\\d+$" - name: ":method" - exact_match: PUT + string_match: + exact: PUT name: update_ride - headers: - name: ":path" - safe_regex_match: - google_re2: {} - regex: "^/users/\\d+/chargeaccounts$" + string_match: + safe_regex: + google_re2: {} + regex: "^/users/\\d+/chargeaccounts$" - name: ":method" - exact_match: POST + string_match: + exact: POST name: cc_add - headers: - name: ":path" - safe_regex_match: - google_re2: {} - regex: "^/users$" + string_match: + safe_regex: + google_re2: {} + regex: "^/users$" - name: ":method" - exact_match: POST + string_match: + exact: POST name: create_user_login - headers: - name: ":path" - safe_regex_match: - google_re2: {} - regex: "^/users/\\d+$" + string_match: + safe_regex: + google_re2: {} + regex: "^/users/\\d+$" - name: ":method" - exact_match: PUT + string_match: + exact: PUT name: update_user - headers: - name: ":path" - safe_regex_match: - google_re2: {} - regex: "^/users/\\d+/location$" + string_match: + safe_regex: + google_re2: {} + regex: "^/users/\\d+/location$" - name: ":method" - exact_match: POST + string_match: + exact: POST name: ulu )EOF"; NiceMock stream_info; @@ -1173,9 +1188,10 @@ TEST_F(RouteMatcherTest, TestRoutesWithInvalidRegex) { name: "invalid" headers: name: "invalid" - safe_regex_match: - google_re2: {} - regex: "^/(+invalid)" + string_match: + safe_regex: + google_re2: {} + regex: "^/(+invalid)" )EOF"; NiceMock stream_info; @@ -1845,16 +1861,19 @@ TEST_F(RouteMatcherTest, HeaderMatchedRouting) { prefix: "/" headers: - name: test_header - exact_match: test + string_match: + exact: test route: cluster: local_service_with_headers - match: prefix: "/" headers: - name: test_header_multiple1 - exact_match: test1 + string_match: + exact: test1 - name: test_header_multiple2 - exact_match: test2 + string_match: + exact: test2 route: cluster: local_service_with_multiple_headers - match: @@ -1868,16 +1887,18 @@ TEST_F(RouteMatcherTest, HeaderMatchedRouting) { prefix: "/" headers: - name: test_header_pattern - safe_regex_match: - google_re2: {} - regex: "^user=test-\\d+$" + string_match: + safe_regex: + google_re2: {} + regex: "^user=test-\\d+$" route: cluster: local_service_with_header_pattern_set_regex - match: prefix: "/" headers: - name: test_header_pattern - exact_match: "^customer=test-\\d+$" + string_match: + exact: "^customer=test-\\d+$" route: cluster: local_service_with_header_pattern_unset_regex - match: @@ -1976,7 +1997,8 @@ TEST_F(RouteMatcherTest, InvalidHeaderMatchedRoutingConfig) { prefix: "/" headers: - name: test_header - exact_match: "(+not a regex)" + string_match: + exact: "(+not a regex)" route: { cluster: "local_service" } )EOF"; @@ -1989,9 +2011,10 @@ TEST_F(RouteMatcherTest, InvalidHeaderMatchedRoutingConfig) { prefix: "/" headers: - name: test_header - safe_regex_match: - google_re2: {} - regex: "(+invalid regex)" + string_match: + safe_regex: + google_re2: {} + regex: "(+invalid regex)" route: { cluster: "local_service" } )EOF"; @@ -2808,7 +2831,8 @@ TEST_F(RouteMatcherTest, ContentType) { prefix: "/" headers: - name: content-type - exact_match: application/grpc + string_match: + exact: application/grpc route: cluster: local_service_grpc - match: @@ -6692,16 +6716,19 @@ TEST_F(RouteMatcherTest, HeaderMatchedRoutingV2) { prefix: "/" headers: - name: test_header - exact_match: test + string_match: + exact: test route: cluster: local_service_with_headers - match: prefix: "/" headers: - name: test_header_multiple1 - exact_match: test1 + string_match: + exact: test1 - name: test_header_multiple2 - exact_match: test2 + string_match: + exact: test2 route: cluster: local_service_with_multiple_headers - match: @@ -6714,16 +6741,18 @@ TEST_F(RouteMatcherTest, HeaderMatchedRoutingV2) { prefix: "/" headers: - name: test_header_pattern - safe_regex_match: - google_re2: {} - regex: "^user=test-\\d+$" + string_match: + safe_regex: + google_re2: {} + regex: "^user=test-\\d+$" route: cluster: local_service_with_header_pattern_set_regex - match: prefix: "/" headers: - name: test_header_pattern - exact_match: "^customer=test-\\d+$" + string_match: + exact: "^customer=test-\\d+$" route: cluster: local_service_with_header_pattern_unset_regex - match: @@ -6743,7 +6772,8 @@ TEST_F(RouteMatcherTest, HeaderMatchedRoutingV2) { start: -10 end: 1 - name: test_header_multiple_exact - exact_match: test + string_match: + exact: test route: cluster: local_service_with_header_range_test2 - match: @@ -6768,7 +6798,8 @@ TEST_F(RouteMatcherTest, HeaderMatchedRoutingV2) { prefix: "/" headers: - name: test_header_range - exact_match: "9223372036854775807" + string_match: + exact: "9223372036854775807" route: cluster: local_service_with_header_range_test5 - match: @@ -7172,7 +7203,8 @@ TEST_F(RouteConfigurationV2, RetriableHeaders) { retry_policy: retriable_headers: - name: ":status" - exact_match: "500" + string_match: + exact: "500" - name: X-Upstream-Pushback )EOF"; diff --git a/test/common/router/retry_state_impl_test.cc b/test/common/router/retry_state_impl_test.cc index fd0ed209c656..1640683d81c9 100644 --- a/test/common/router/retry_state_impl_test.cc +++ b/test/common/router/retry_state_impl_test.cc @@ -477,11 +477,11 @@ TEST_F(RouterRetryStateImplTest, RetriableHeadersPolicyViaRetryPolicyConfigurati auto* matcher2 = matchers.Add(); matcher2->set_name("should-retry"); - matcher2->set_exact_match("yes"); + matcher2->mutable_string_match()->set_exact("yes"); auto* matcher3 = matchers.Add(); matcher3->set_name("X-Verdict"); - matcher3->set_prefix_match("retry"); + matcher3->mutable_string_match()->set_prefix("retry"); auto* matcher4 = matchers.Add(); matcher4->set_name(":status"); @@ -623,7 +623,7 @@ TEST_F(RouterRetryStateImplTest, RetriableHeadersMergedConfigAndRequestHeaders) // Config says: retry if response is not 200. auto* matcher = matchers.Add(); matcher->set_name(":status"); - matcher->set_exact_match("200"); + matcher->mutable_string_match()->set_exact("200"); matcher->set_invert_match(true); policy_.retriable_headers_ = Http::HeaderUtility::buildHeaderMatcherVector(matchers); @@ -674,11 +674,11 @@ TEST_F(RouterRetryStateImplTest, PolicyLimitedByRequestHeaders) { Protobuf::RepeatedPtrField matchers; auto* matcher = matchers.Add(); matcher->set_name(":method"); - matcher->set_exact_match("GET"); + matcher->mutable_string_match()->set_exact("GET"); auto* matcher2 = matchers.Add(); matcher2->set_name(":method"); - matcher2->set_exact_match("HEAD"); + matcher2->mutable_string_match()->set_exact("HEAD"); policy_.retriable_request_headers_ = Http::HeaderUtility::buildHeaderMatcherVector(matchers); diff --git a/test/common/router/router_ratelimit_test.cc b/test/common/router/router_ratelimit_test.cc index 01127c1a0797..358c9513f5cd 100644 --- a/test/common/router/router_ratelimit_test.cc +++ b/test/common/router/router_ratelimit_test.cc @@ -827,7 +827,8 @@ TEST_F(RateLimitPolicyEntryTest, HeaderValueMatch) { descriptor_value: fake_value headers: - name: x-header-name - exact_match: test_value + string_match: + exact: test_value )EOF"; setupTest(yaml); @@ -848,7 +849,8 @@ TEST_F(RateLimitPolicyEntryTest, HeaderValueMatchNoMatch) { descriptor_value: fake_value headers: - name: x-header-name - exact_match: test_value + string_match: + exact: test_value )EOF"; setupTest(yaml); @@ -868,7 +870,8 @@ TEST_F(RateLimitPolicyEntryTest, HeaderValueMatchHeadersNotPresent) { expect_match: false headers: - name: x-header-name - exact_match: test_value + string_match: + exact: test_value )EOF"; setupTest(yaml); @@ -890,7 +893,8 @@ TEST_F(RateLimitPolicyEntryTest, HeaderValueMatchHeadersPresent) { expect_match: false headers: - name: x-header-name - exact_match: test_value + string_match: + exact: test_value )EOF"; setupTest(yaml); @@ -932,7 +936,8 @@ TEST_F(RateLimitPolicyEntryTest, CompoundActionsNoDescriptor) { descriptor_value: fake_value headers: - name: x-header-name - exact_match: test_value + string_match: + exact: test_value )EOF"; setupTest(yaml); diff --git a/test/config/utility.cc b/test/config/utility.cc index 10ad584efcbc..e7e346d5cc36 100644 --- a/test/config/utility.cc +++ b/test/config/utility.cc @@ -668,7 +668,7 @@ void ConfigHelper::setConnectConfig( auto* header = match->add_headers(); header->set_name(":method"); - header->set_exact_match("POST"); + header->mutable_string_match()->set_exact("POST"); } else { match->mutable_connect_matcher(); } diff --git a/test/extensions/common/aws/aws_metadata_fetcher_integration_test.cc b/test/extensions/common/aws/aws_metadata_fetcher_integration_test.cc index ee2c03595080..be22190b31f4 100644 --- a/test/extensions/common/aws/aws_metadata_fetcher_integration_test.cc +++ b/test/extensions/common/aws/aws_metadata_fetcher_integration_test.cc @@ -55,7 +55,8 @@ class AwsMetadataIntegrationTestBase : public ::testing::Test, public BaseIntegr prefix: "/" headers: - name: Authorization - exact_match: AUTH_TOKEN + string_match: + exact: AUTH_TOKEN - name: no_auth_route direct_response: status: {} diff --git a/test/extensions/common/matcher/matcher_test.cc b/test/extensions/common/matcher/matcher_test.cc index 6531884fe830..cad6e76b8dc9 100644 --- a/test/extensions/common/matcher/matcher_test.cc +++ b/test/extensions/common/matcher/matcher_test.cc @@ -98,7 +98,8 @@ TEST_F(TapMatcherTest, AndMightChangeStatus) { - http_response_headers_match: headers: - name: bar - exact_match: baz + string_match: + exact: baz )EOF"; TestUtility::loadFromYaml(matcher_yaml, config_); diff --git a/test/extensions/filters/common/rbac/matchers_test.cc b/test/extensions/filters/common/rbac/matchers_test.cc index ed39ff132283..87d22517dd42 100644 --- a/test/extensions/filters/common/rbac/matchers_test.cc +++ b/test/extensions/filters/common/rbac/matchers_test.cc @@ -146,7 +146,7 @@ TEST(NotMatcher, Principal) { TEST(HeaderMatcher, HeaderMatcher) { envoy::config::route::v3::HeaderMatcher config; config.set_name("foo"); - config.set_exact_match("bar"); + config.mutable_string_match()->set_exact("bar"); Envoy::Http::TestRequestHeaderMapImpl headers; Envoy::Http::LowerCaseString key("foo"); diff --git a/test/extensions/filters/http/fault/fault_filter_test.cc b/test/extensions/filters/http/fault/fault_filter_test.cc index f09372a74c38..b4add362fb60 100644 --- a/test/extensions/filters/http/fault/fault_filter_test.cc +++ b/test/extensions/filters/http/fault/fault_filter_test.cc @@ -114,7 +114,8 @@ class FaultFilterTest : public testing::Test { http_status: 503 headers: - name: X-Foo1 - exact_match: Bar + string_match: + exact: Bar - name: X-Foo2 )EOF"; diff --git a/test/extensions/filters/http/health_check/config_test.cc b/test/extensions/filters/http/health_check/config_test.cc index d3e697276fb2..4faa78c630af 100644 --- a/test/extensions/filters/http/health_check/config_test.cc +++ b/test/extensions/filters/http/health_check/config_test.cc @@ -26,7 +26,8 @@ TEST(HealthCheckFilterConfig, HealthCheckFilter) { pass_through_mode: true headers: - name: ":path" - exact_match: "/hc" + string_match: + exact: "/hc" )EOF"; envoy::extensions::filters::http::health_check::v3::HealthCheck proto_config; @@ -44,7 +45,8 @@ TEST(HealthCheckFilterConfig, BadHealthCheckFilterConfig) { pass_through_mode: true headers: - name: ":path" - exact_match: "/hc" + string_match: + exact: "/hc" status: 500 )EOF"; @@ -59,7 +61,8 @@ TEST(HealthCheckFilterConfig, FailsWhenNotPassThroughButTimeoutSetYaml) { cache_time: 0.234s headers: - name: ":path" - exact_match: "/foo" + string_match: + exact: "/foo" )EOF"; envoy::extensions::filters::http::health_check::v3::HealthCheck proto_config; @@ -78,7 +81,8 @@ TEST(HealthCheckFilterConfig, NotFailingWhenNotPassThroughAndTimeoutNotSetYaml) cache_time: 0.234s headers: - name: ":path" - exact_match: "/foo" + string_match: + exact: "/foo" )EOF"; envoy::extensions::filters::http::health_check::v3::HealthCheck proto_config; @@ -100,7 +104,7 @@ TEST(HealthCheckFilterConfig, FailsWhenNotPassThroughButTimeoutSetProto) { config.mutable_cache_time()->set_seconds(10); envoy::config::route::v3::HeaderMatcher& header = *config.add_headers(); header.set_name(":path"); - header.set_exact_match("foo"); + header.mutable_string_match()->set_exact("foo"); EXPECT_THROW( healthCheckFilterConfig.createFilterFactoryFromProto(config, "dummy_stats_prefix", context), @@ -115,7 +119,7 @@ TEST(HealthCheckFilterConfig, NotFailingWhenNotPassThroughAndTimeoutNotSetProto) config.mutable_pass_through_mode()->set_value(false); envoy::config::route::v3::HeaderMatcher& header = *config.add_headers(); header.set_name(":path"); - header.set_exact_match("foo"); + header.mutable_string_match()->set_exact("foo"); healthCheckFilterConfig.createFilterFactoryFromProto(config, "dummy_stats_prefix", context); } @@ -129,7 +133,7 @@ TEST(HealthCheckFilterConfig, HealthCheckFilterWithEmptyProto) { config.mutable_pass_through_mode()->set_value(false); envoy::config::route::v3::HeaderMatcher& header = *config.add_headers(); header.set_name(":path"); - header.set_exact_match("foo"); + header.mutable_string_match()->set_exact("foo"); healthCheckFilterConfig.createFilterFactoryFromProto(config, "dummy_stats_prefix", context); } @@ -184,7 +188,7 @@ TEST(HealthCheckFilterConfig, HealthCheckFilterHeaderMatch) { envoy::config::route::v3::HeaderMatcher& yheader = *config.add_headers(); yheader.set_name("y-healthcheck"); - yheader.set_exact_match("foo"); + yheader.mutable_string_match()->set_exact("foo"); Http::TestRequestHeaderMapImpl headers{{"x-healthcheck", "arbitrary_value"}, {"y-healthcheck", "foo"}}; @@ -203,7 +207,7 @@ TEST(HealthCheckFilterConfig, HealthCheckFilterHeaderMatchWrongValue) { envoy::config::route::v3::HeaderMatcher& yheader = *config.add_headers(); yheader.set_name("y-healthcheck"); - yheader.set_exact_match("foo"); + yheader.mutable_string_match()->set_exact("foo"); Http::TestRequestHeaderMapImpl headers{{"x-healthcheck", "arbitrary_value"}, {"y-healthcheck", "bar"}}; @@ -222,7 +226,7 @@ TEST(HealthCheckFilterConfig, HealthCheckFilterHeaderMatchMissingHeader) { envoy::config::route::v3::HeaderMatcher& yheader = *config.add_headers(); yheader.set_name("y-healthcheck"); - yheader.set_exact_match("foo"); + yheader.mutable_string_match()->set_exact("foo"); Http::TestRequestHeaderMapImpl headers{{"y-healthcheck", "foo"}}; @@ -237,7 +241,7 @@ TEST(HealthCheckFilterConfig, HealthCheckFilterDuplicateMatch) { envoy::config::route::v3::HeaderMatcher& header = *config.add_headers(); header.set_name("x-healthcheck"); - header.set_exact_match("foo"); + header.mutable_string_match()->set_exact("foo"); envoy::config::route::v3::HeaderMatcher& dup_header = *config.add_headers(); dup_header.set_name("x-healthcheck"); @@ -255,11 +259,11 @@ TEST(HealthCheckFilterConfig, HealthCheckFilterDuplicateNoMatch) { envoy::config::route::v3::HeaderMatcher& header = *config.add_headers(); header.set_name("x-healthcheck"); - header.set_exact_match("foo"); + header.mutable_string_match()->set_exact("foo"); envoy::config::route::v3::HeaderMatcher& dup_header = *config.add_headers(); dup_header.set_name("x-healthcheck"); - dup_header.set_exact_match("bar"); + dup_header.mutable_string_match()->set_exact("bar"); Http::TestRequestHeaderMapImpl headers{{"x-healthcheck", "foo"}}; diff --git a/test/extensions/filters/http/health_check/health_check_test.cc b/test/extensions/filters/http/health_check/health_check_test.cc index b61685e8d677..d2715efa89c6 100644 --- a/test/extensions/filters/http/health_check/health_check_test.cc +++ b/test/extensions/filters/http/health_check/health_check_test.cc @@ -50,7 +50,7 @@ class HealthCheckFilterTest : public testing::Test { header_data_ = std::make_shared>(); envoy::config::route::v3::HeaderMatcher matcher; matcher.set_name(":path"); - matcher.set_exact_match("/healthcheck"); + matcher.mutable_string_match()->set_exact("/healthcheck"); header_data_->emplace_back(std::make_unique(matcher)); filter_ = std::make_unique(context_, pass_through, cache_manager_, header_data_, cluster_min_healthy_percentages); diff --git a/test/extensions/filters/http/oauth2/filter_test.cc b/test/extensions/filters/http/oauth2/filter_test.cc index 9179db9d6686..db54e404a7ed 100644 --- a/test/extensions/filters/http/oauth2/filter_test.cc +++ b/test/extensions/filters/http/oauth2/filter_test.cc @@ -114,7 +114,7 @@ class OAuth2Test : public testing::Test { p.add_resources("https://example.com"); auto* matcher = p.add_pass_through_matcher(); matcher->set_name(":method"); - matcher->set_exact_match("OPTIONS"); + matcher->mutable_string_match()->set_exact("OPTIONS"); auto credentials = p.mutable_credentials(); credentials->set_client_id(TEST_CLIENT_ID); credentials->mutable_token_secret()->set_name("secret"); @@ -257,7 +257,7 @@ TEST_F(OAuth2Test, DefaultAuthScope) { p.set_forward_bearer_token(true); auto* matcher = p.add_pass_through_matcher(); matcher->set_name(":method"); - matcher->set_exact_match("OPTIONS"); + matcher->mutable_string_match()->set_exact("OPTIONS"); auto credentials = p.mutable_credentials(); credentials->set_client_id(TEST_CLIENT_ID); diff --git a/test/extensions/filters/http/rbac/rbac_filter_integration_test.cc b/test/extensions/filters/http/rbac/rbac_filter_integration_test.cc index 4874d30d0778..265fc0e05f2f 100644 --- a/test/extensions/filters/http/rbac/rbac_filter_integration_test.cc +++ b/test/extensions/filters/http/rbac/rbac_filter_integration_test.cc @@ -16,7 +16,10 @@ name: rbac policies: foo: permissions: - - header: { name: ":method", exact_match: "GET" } + - header: + name: ":method" + string_match: + exact: "GET" principals: - any: true )EOF"; @@ -30,7 +33,10 @@ name: rbac policies: "deny policy": permissions: - - header: { name: ":method", exact_match: "GET" } + - header: + name: ":method" + string_match: + exact: "GET" principals: - any: true )EOF"; @@ -43,7 +49,10 @@ name: rbac policies: foo: permissions: - - header: { name: ":path", prefix_match: "/foo" } + - header: + name: ":path" + string_match: + prefix: "/foo" principals: - any: true )EOF"; @@ -85,7 +94,10 @@ name: rbac policies: foo: permissions: - - header: { name: ":method", exact_match: "GET" } + - header: + name: ":method" + string_match: + exact: "GET" principals: - any: true )EOF"; diff --git a/test/extensions/filters/http/tap/tap_filter_integration_test.cc b/test/extensions/filters/http/tap/tap_filter_integration_test.cc index 2806dd7bc4a7..403c5ca02384 100644 --- a/test/extensions/filters/http/tap/tap_filter_integration_test.cc +++ b/test/extensions/filters/http/tap/tap_filter_integration_test.cc @@ -239,11 +239,13 @@ config_id: test_config_id - http_request_headers_match: headers: - name: foo - exact_match: bar + string_match: + exact: bar - http_response_headers_match: headers: - name: bar - exact_match: baz + string_match: + exact: baz output_config: sinks: - streaming_admin: {} @@ -305,11 +307,13 @@ config_id: test_config_id - http_request_headers_match: headers: - name: foo - exact_match: bar + string_match: + exact: bar - http_response_headers_match: headers: - name: bar - exact_match: baz + string_match: + exact: baz output_config: sinks: - streaming_admin: {} @@ -349,11 +353,13 @@ config_id: test_config_id - http_request_trailers_match: headers: - name: foo_trailer - exact_match: bar + string_match: + exact: bar - http_response_trailers_match: headers: - name: bar_trailer - exact_match: baz + string_match: + exact: baz output_config: sinks: - streaming_admin: {} @@ -398,11 +404,13 @@ config_id: test_config_id - http_request_trailers_match: headers: - name: foo_trailer - exact_match: bar + string_match: + exact: bar - http_response_trailers_match: headers: - name: bar_trailer - exact_match: baz + string_match: + exact: baz output_config: sinks: - streaming_admin: {} @@ -535,7 +543,8 @@ name: tap http_request_headers_match: headers: - name: foo - exact_match: bar + string_match: + exact: bar output_config: streaming: true sinks: @@ -581,7 +590,8 @@ name: tap http_response_headers_match: headers: - name: bar - exact_match: baz + string_match: + exact: baz output_config: streaming: true sinks: diff --git a/test/extensions/filters/network/dubbo_proxy/route_matcher_test.cc b/test/extensions/filters/network/dubbo_proxy/route_matcher_test.cc index a523468d69a2..efd8ca25294d 100644 --- a/test/extensions/filters/network/dubbo_proxy/route_matcher_test.cc +++ b/test/extensions/filters/network/dubbo_proxy/route_matcher_test.cc @@ -679,9 +679,11 @@ interface: org.apache.dubbo.demo.DemoService exact: "add" headers: - name: custom - exact_match: "123" + string_match: + exact: "123" - name: custom1 - exact_match: "123" + string_match: + exact: "123" invert_match: true route: cluster: user_service_dubbo_server diff --git a/test/extensions/filters/network/rocketmq_proxy/route_matcher_test.cc b/test/extensions/filters/network/rocketmq_proxy/route_matcher_test.cc index 620fb5432124..5153bc13729d 100644 --- a/test/extensions/filters/network/rocketmq_proxy/route_matcher_test.cc +++ b/test/extensions/filters/network/rocketmq_proxy/route_matcher_test.cc @@ -36,7 +36,8 @@ name: default_route exact: test_topic headers: - name: code - exact_match: '310' + string_match: + exact: '310' route: cluster: fake_cluster metadata_match: diff --git a/test/extensions/filters/network/thrift_proxy/integration_test.cc b/test/extensions/filters/network/thrift_proxy/integration_test.cc index 5f7cb2c41b15..d13f9ddd2975 100644 --- a/test/extensions/filters/network/thrift_proxy/integration_test.cc +++ b/test/extensions/filters/network/thrift_proxy/integration_test.cc @@ -41,19 +41,23 @@ class ThriftConnManagerIntegrationTest method_name: "execute" headers: - name: "x-header-1" - exact_match: "x-value-1" + string_match: + exact: "x-value-1" - name: "x-header-2" - safe_regex_match: - google_re2: {} - regex: "0.[5-9]" + string_match: + safe_regex: + google_re2: {} + regex: "0.[5-9]" - name: "x-header-3" range_match: start: 100 end: 200 - name: "x-header-4" - prefix_match: "user_id:" + string_match: + prefix: "user_id:" - name: "x-header-5" - suffix_match: "asdf" + string_match: + suffix: "asdf" route: cluster: "cluster_1" - match: diff --git a/test/extensions/filters/network/thrift_proxy/route_matcher_test.cc b/test/extensions/filters/network/thrift_proxy/route_matcher_test.cc index d7623f2418d2..8e19060b27e7 100644 --- a/test/extensions/filters/network/thrift_proxy/route_matcher_test.cc +++ b/test/extensions/filters/network/thrift_proxy/route_matcher_test.cc @@ -309,7 +309,8 @@ name: config method_name: "method1" headers: - name: "x-header-1" - exact_match: "x-value-1" + string_match: + exact: "x-value-1" route: cluster: "cluster1" )EOF"; @@ -340,9 +341,10 @@ name: config method_name: "method1" headers: - name: "x-version" - safe_regex_match: - google_re2: {} - regex: "0.[5-9]" + string_match: + safe_regex: + google_re2: {} + regex: "0.[5-9]" route: cluster: "cluster1" )EOF"; @@ -453,7 +455,8 @@ name: config method_name: "method1" headers: - name: "x-header-1" - prefix_match: "user_id:" + string_match: + prefix: "user_id:" route: cluster: "cluster1" )EOF"; @@ -489,7 +492,8 @@ name: config method_name: "method1" headers: - name: "x-header-1" - suffix_match: "asdf" + string_match: + suffix: "asdf" route: cluster: "cluster1" )EOF"; diff --git a/test/extensions/filters/network/thrift_proxy/router_ratelimit_test.cc b/test/extensions/filters/network/thrift_proxy/router_ratelimit_test.cc index 9e5c6a1bcb01..15c19bd2be7b 100644 --- a/test/extensions/filters/network/thrift_proxy/router_ratelimit_test.cc +++ b/test/extensions/filters/network/thrift_proxy/router_ratelimit_test.cc @@ -468,7 +468,8 @@ TEST_F(ThriftRateLimitPolicyEntryTest, HeaderValueActionMatch) { descriptor_value: fake_value headers: - name: x-header-name - exact_match: test_value + string_match: + exact: test_value )EOF"; initialize(yaml); @@ -487,7 +488,8 @@ TEST_F(ThriftRateLimitPolicyEntryTest, HeaderValueActionValueMismatch) { descriptor_value: fake_value headers: - name: x-header-name - exact_match: test_value + string_match: + exact: test_value )EOF"; initialize(yaml); @@ -506,7 +508,8 @@ TEST_F(ThriftRateLimitPolicyEntryTest, HeaderValueActionNegateMatch) { expect_match: false headers: - name: x-header-name - exact_match: test_value + string_match: + exact: test_value )EOF"; initialize(yaml); @@ -525,7 +528,8 @@ TEST_F(ThriftRateLimitPolicyEntryTest, HeaderValueActionNegatedMatchProducesDesc expect_match: false headers: - name: x-header-name - exact_match: test_value + string_match: + exact: test_value )EOF"; initialize(yaml); @@ -562,7 +566,8 @@ TEST_F(ThriftRateLimitPolicyEntryTest, CompoundActionNoDescriptor) { descriptor_value: fake_value headers: - name: x-header-name - exact_match: test_value + string_match: + exact: test_value )EOF"; initialize(yaml); diff --git a/test/integration/http_subset_lb_integration_test.cc b/test/integration/http_subset_lb_integration_test.cc index e78db3278b62..6d9b1d96e363 100644 --- a/test/integration/http_subset_lb_integration_test.cc +++ b/test/integration/http_subset_lb_integration_test.cc @@ -120,7 +120,7 @@ class HttpSubsetLbIntegrationTest // Match the x-type header against the given host_type (a/b). auto* match_header = match->add_headers(); match_header->set_name(type_header_); - match_header->set_exact_match(host_type); + match_header->mutable_string_match()->set_exact(host_type); // Route to cluster_0, selecting metadata type=a or type=b. auto* action = route->mutable_route(); diff --git a/test/integration/local_reply_integration_test.cc b/test/integration/local_reply_integration_test.cc index fb9225a88bad..3e8f7af5338a 100644 --- a/test/integration/local_reply_integration_test.cc +++ b/test/integration/local_reply_integration_test.cc @@ -26,7 +26,8 @@ TEST_P(LocalReplyIntegrationTest, MapStatusCodeAndFormatToJson) { header_filter: header: name: test-header - exact_match: exact-match-value + string_match: + exact: exact-match-value status_code: 550 headers_to_add: - header: @@ -92,7 +93,8 @@ TEST_P(LocalReplyIntegrationTest, EmptyStructFormatter) { header_filter: header: name: test-header - exact_match: exact-match-value + string_match: + exact: exact-match-value status_code: 550 body_format: json_format: @@ -203,13 +205,15 @@ TEST_P(LocalReplyIntegrationTest, MapStatusCodeAndFormatToJsonForFirstMatchingFi header_filter: header: name: test-header - exact_match: exact-match-value-1 + string_match: + exact: exact-match-value-1 status_code: 550 - filter: header_filter: header: name: test-header - exact_match: exact-match-value + string_match: + exact: exact-match-value status_code: 551 headers_to_add: - header: @@ -225,7 +229,8 @@ TEST_P(LocalReplyIntegrationTest, MapStatusCodeAndFormatToJsonForFirstMatchingFi header_filter: header: name: test-header - exact_match: exact-match-value + string_match: + exact: exact-match-value status_code: 552 body_format: json_format: @@ -283,19 +288,22 @@ TEST_P(LocalReplyIntegrationTest, ShouldNotMatchAnyFilter) { header_filter: header: name: test-header - exact_match: exact-match-value-1 + string_match: + exact: exact-match-value-1 status_code: 550 - filter: header_filter: header: name: test-header - exact_match: exact-match-value-2 + string_match: + exact: exact-match-value-2 status_code: 551 - filter: header_filter: header: name: test-header - exact_match: exact-match-value-3 + string_match: + exact: exact-match-value-3 status_code: 552 body_format: json_format: @@ -355,19 +363,22 @@ TEST_P(LocalReplyIntegrationTest, ShouldMapResponseCodeAndMapToDefaultTextRespon header_filter: header: name: test-header - exact_match: exact-match-value-1 + string_match: + exact: exact-match-value-1 status_code: 550 - filter: header_filter: header: name: test-header - exact_match: exact-match-value-2 + string_match: + exact: exact-match-value-2 status_code: 551 - filter: header_filter: header: name: test-header - exact_match: exact-match-value-3 + string_match: + exact: exact-match-value-3 status_code: 552 )EOF"; setLocalReplyConfig(yaml); diff --git a/test/integration/transport_socket_match_integration_test.cc b/test/integration/transport_socket_match_integration_test.cc index fe5fe47026df..6b97546e038b 100644 --- a/test/integration/transport_socket_match_integration_test.cc +++ b/test/integration/transport_socket_match_integration_test.cc @@ -101,7 +101,7 @@ name: "tls_socket" // Match the x-type header against the given host_type (a/b). auto* match_header = match->add_headers(); match_header->set_name(type_header_); - match_header->set_exact_match(host_type); + match_header->mutable_string_match()->set_exact(host_type); // Route to cluster_0, selecting metadata type=a or type=b. auto* action = route->mutable_route(); From 36f2acccd167dc12ada0ada5ce19628c29dddbe6 Mon Sep 17 00:00:00 2001 From: Yangmin Zhu Date: Thu, 1 Jul 2021 14:49:56 -0700 Subject: [PATCH 09/12] fix router_tool_test Signed-off-by: Yangmin Zhu --- test/tools/router_check/router.cc | 39 +++++++++++++++---- .../config/DirectResponse.golden.proto.json | 20 +++++++--- .../test/config/TestRoutes.golden.proto.json | 24 +++++++++--- .../TestRoutesFailures.golden.proto.json | 8 +++- test/tools/router_check/test/route_tests.sh | 4 +- 5 files changed, 73 insertions(+), 22 deletions(-) diff --git a/test/tools/router_check/router.cc b/test/tools/router_check/router.cc index aa983e92551a..a19a75b3a089 100644 --- a/test/tools/router_check/router.cc +++ b/test/tools/router_check/router.cc @@ -18,9 +18,29 @@ #include "test/test_common/printers.h" namespace { -const std::string -toString(envoy::config::route::v3::HeaderMatcher::HeaderMatchSpecifierCase specifier) { - switch (specifier) { + +const std::string toString(envoy::type::matcher::v3::StringMatcher::MatchPatternCase pattern) { + switch (pattern) { + case envoy::type::matcher::v3::StringMatcher::MatchPatternCase::kExact: + return "exact"; + case envoy::type::matcher::v3::StringMatcher::MatchPatternCase::kPrefix: + return "prefix"; + case envoy::type::matcher::v3::StringMatcher::MatchPatternCase::kSuffix: + return "suffix"; + case envoy::type::matcher::v3::StringMatcher::MatchPatternCase::kSafeRegex: + return "safe_regex"; + case envoy::type::matcher::v3::StringMatcher::MatchPatternCase::kHiddenEnvoyDeprecatedRegex: + return "deprecated_regex"; + case envoy::type::matcher::v3::StringMatcher::MatchPatternCase::kContains: + return "contains"; + case envoy::type::matcher::v3::StringMatcher::MatchPatternCase::MATCH_PATTERN_NOT_SET: + return "match_pattern_not_set"; + } + NOT_REACHED_GCOVR_EXCL_LINE; +} + +const std::string toString(const envoy::config::route::v3::HeaderMatcher& header) { + switch (header.header_match_specifier_case()) { case envoy::config::route::v3::HeaderMatcher::HeaderMatchSpecifierCase::kExactMatch: return "exact_match"; break; @@ -49,7 +69,7 @@ toString(envoy::config::route::v3::HeaderMatcher::HeaderMatchSpecifierCase speci return "contains_match"; break; case envoy::config::route::v3::HeaderMatcher::HeaderMatchSpecifierCase::kStringMatch: - return "string_match"; + return "string_match." + ::toString(header.string_match().match_pattern_case()); break; } NOT_REACHED_GCOVR_EXCL_LINE; @@ -466,12 +486,16 @@ bool RouterCheckTool::matchHeaderField(const HeaderMap& header_map, // Test failed. Decide on what to log. std::string actual, expected; - std::string match_test_type{test_type + "." + ::toString(header.header_match_specifier_case())}; + std::string match_test_type{test_type + "." + ::toString(header)}; switch (header.header_match_specifier_case()) { - case envoy::config::route::v3::HeaderMatcher::HeaderMatchSpecifierCase::kExactMatch: + case envoy::config::route::v3::HeaderMatcher::HeaderMatchSpecifierCase::kStringMatch: + if (header.string_match().match_pattern_case() != + envoy::type::matcher::v3::StringMatcher::MatchPatternCase::kExact) { + goto default_case; + } actual = header.name() + ": " + ::toString(header_map.get(Http::LowerCaseString(header.name()))); - expected = header.name() + ": " + header.exact_match(); + expected = header.name() + ": " + header.string_match().exact(); reportFailure(actual, expected, match_test_type, !header.invert_match()); break; case envoy::config::route::v3::HeaderMatcher::HeaderMatchSpecifierCase::kPresentMatch: @@ -481,6 +505,7 @@ bool RouterCheckTool::matchHeaderField(const HeaderMap& header_map, expected = "has(" + header.name() + "):" + (header.invert_match() ? "false" : "true"); reportFailure(actual, expected, match_test_type); break; + default_case: default: actual = header.name() + ": " + ::toString(header_map.get(Http::LowerCaseString(header.name()))); diff --git a/test/tools/router_check/test/config/DirectResponse.golden.proto.json b/test/tools/router_check/test/config/DirectResponse.golden.proto.json index 729dd11788ce..f516ba133bfc 100644 --- a/test/tools/router_check/test/config/DirectResponse.golden.proto.json +++ b/test/tools/router_check/test/config/DirectResponse.golden.proto.json @@ -17,11 +17,15 @@ "response_header_matches": [ { "name": "content-type", - "exact_match": "text/plain" + "string_match": { + "exact": "text/plain" + } }, { "name": "content-length", - "exact_match": "8" + "string_match": { + "exact": "8" + } } ] } @@ -43,11 +47,15 @@ "response_header_matches": [ { "name": "content-type", - "exact_match": "application/json" + "string_match": { + "exact": "application/json" + } }, { "name": "content-length", - "exact_match": "25" + "string_match": { + "exact": "25" + } } ] } @@ -69,7 +77,9 @@ "response_header_matches": [ { "name": "content-type", - "exact_match": "text/plain,application/json" + "string_match": { + "exact": "text/plain,application/json" + } } ] } diff --git a/test/tools/router_check/test/config/TestRoutes.golden.proto.json b/test/tools/router_check/test/config/TestRoutes.golden.proto.json index 25c2ed007523..69b33e95c788 100644 --- a/test/tools/router_check/test/config/TestRoutes.golden.proto.json +++ b/test/tools/router_check/test/config/TestRoutes.golden.proto.json @@ -292,15 +292,21 @@ "request_header_matches": [ { "name": ":authority", - "exact_match": "new_host" + "string_match": { + "exact": "new_host" + } }, { "name": ":path", - "exact_match": "/host/rewrite/me" + "string_match": { + "exact": "/host/rewrite/me" + } }, { "name": ":method", - "exact_match": "GET" + "string_match": { + "exact": "GET" + } }, { "name": ":cookie", @@ -320,7 +326,9 @@ "request_header_matches": [ { "name": "X-Client-IP", - "exact_match": "127.0.0.1" + "string_match": { + "exact": "127.0.0.1" + } } ] } @@ -342,7 +350,9 @@ "response_header_matches": [ { "name": "content-type", - "exact_match": "text/plain" + "string_match": { + "exact": "text/plain" + } }, { "name": "content-length", @@ -354,7 +364,9 @@ }, { "name": "x-ping-response", - "exact_match": "yes" + "string_match": { + "exact": "yes" + } }, { "name": "x-ping-response", diff --git a/test/tools/router_check/test/config/TestRoutesFailures.golden.proto.json b/test/tools/router_check/test/config/TestRoutesFailures.golden.proto.json index 498f155a4d5c..80d1df05fd30 100644 --- a/test/tools/router_check/test/config/TestRoutesFailures.golden.proto.json +++ b/test/tools/router_check/test/config/TestRoutesFailures.golden.proto.json @@ -17,7 +17,9 @@ "response_header_matches": [ { "name": "content-type", - "exact_match": "text/plain", + "string_match": { + "exact": "text/plain" + }, "invert_match": true }, { @@ -30,7 +32,9 @@ }, { "name": "x-ping-response", - "exact_match": "pong" + "string_match": { + "exact": "pong" + } }, { "name": "x-ping-response", diff --git a/test/tools/router_check/test/route_tests.sh b/test/tools/router_check/test/route_tests.sh index 7d7e6bdb55f6..ea785de8b36a 100755 --- a/test/tools/router_check/test/route_tests.sh +++ b/test/tools/router_check/test/route_tests.sh @@ -88,13 +88,13 @@ fi echo "testing error strings" FAILURE_OUTPUT=$("${PATH_BIN}" "-c" "${PATH_CONFIG}/TestRoutes.yaml" "-t" "${PATH_CONFIG}/TestRoutesFailures.golden.proto.json" "--only-show-failures" 2>&1) || echo "${FAILURE_OUTPUT:-no-output}" -if ! echo "${FAILURE_OUTPUT}" | grep -Fxq "expected: [content-type: text/plain], actual: NOT [content-type: text/plain], test type: response_header_matches.exact_match"; then +if ! echo "${FAILURE_OUTPUT}" | grep -Fxq "expected: [content-type: text/plain], actual: NOT [content-type: text/plain], test type: response_header_matches.string_match.exact"; then exit 1 fi if ! echo "${FAILURE_OUTPUT}" | grep -Fxq "actual: [content-length: 25], test type: response_header_matches.range_match"; then exit 1 fi -if ! echo "${FAILURE_OUTPUT}" | grep -Fxq "expected: [x-ping-response: pong], actual: [x-ping-response: yes], test type: response_header_matches.exact_match"; then +if ! echo "${FAILURE_OUTPUT}" | grep -Fxq "expected: [x-ping-response: pong], actual: [x-ping-response: yes], test type: response_header_matches.string_match.exact"; then exit 1 fi if ! echo "${FAILURE_OUTPUT}" | grep -Fxq "expected: [has(x-ping-response):false], actual: [has(x-ping-response):true], test type: response_header_matches.present_match"; then From 7c05be912c1e02255dffff1bd05d097fb24dc455 Mon Sep 17 00:00:00 2001 From: Yangmin Zhu Date: Thu, 8 Jul 2021 15:38:44 -0700 Subject: [PATCH 10/12] address comments Signed-off-by: Yangmin Zhu --- test/common/http/header_utility_test.cc | 45 +++++++++++++------------ test/tools/router_check/router.cc | 22 ++++++------ 2 files changed, 35 insertions(+), 32 deletions(-) diff --git a/test/common/http/header_utility_test.cc b/test/common/http/header_utility_test.cc index e7635972addd..7e9ed68e23df 100644 --- a/test/common/http/header_utility_test.cc +++ b/test/common/http/header_utility_test.cc @@ -201,7 +201,7 @@ name: test-header EXPECT_EQ(HeaderUtility::HeaderMatchType::Present, header_data.header_match_type_); } -TEST(HeaderDataConstructorTest, ExactMatchSpecifier) { +TEST(HeaderDataConstructorTest, DEPRECATED_FEATURE_TEST(ExactMatchSpecifier)) { const std::string yaml = R"EOF( name: test-header exact_match: value @@ -247,7 +247,7 @@ present_match: true EXPECT_EQ("", header_data.value_); } -TEST(HeaderDataConstructorTest, PrefixMatchSpecifier) { +TEST(HeaderDataConstructorTest, DEPRECATED_FEATURE_TEST(PrefixMatchSpecifier)) { const std::string yaml = R"EOF( name: test-header prefix_match: value @@ -261,7 +261,7 @@ prefix_match: value EXPECT_EQ("value", header_data.value_); } -TEST(HeaderDataConstructorTest, SuffixMatchSpecifier) { +TEST(HeaderDataConstructorTest, DEPRECATED_FEATURE_TEST(SuffixMatchSpecifier)) { const std::string yaml = R"EOF( name: test-header suffix_match: value @@ -275,7 +275,7 @@ suffix_match: value EXPECT_EQ("value", header_data.value_); } -TEST(HeaderDataConstructorTest, ContainsMatchSpecifier) { +TEST(HeaderDataConstructorTest, DEPRECATED_FEATURE_TEST(ContainsMatchSpecifier)) { const std::string yaml = R"EOF( name: test-header contains_match: somevalueinside @@ -307,7 +307,8 @@ name: test-header TEST(HeaderDataConstructorTest, InvertMatchSpecifier) { const std::string yaml = R"EOF( name: test-header -exact_match: value +string_match: + exact: value invert_match: true )EOF"; @@ -315,8 +316,8 @@ invert_match: true HeaderUtility::HeaderData(parseHeaderMatcherFromYaml(yaml)); EXPECT_EQ("test-header", header_data.name_.get()); - EXPECT_EQ(HeaderUtility::HeaderMatchType::Value, header_data.header_match_type_); - EXPECT_EQ("value", header_data.value_); + EXPECT_EQ(HeaderUtility::HeaderMatchType::StringMatch, header_data.header_match_type_); + EXPECT_TRUE(header_data.string_match_->match("value")); EXPECT_EQ(true, header_data.invert_match_); } @@ -325,9 +326,10 @@ TEST(MatchHeadersTest, MayMatchOneOrMoreRequestHeader) { const std::string yaml = R"EOF( name: match-header -safe_regex_match: - google_re2: {} - regex: (a|b) +string_match: + safe_regex: + google_re2: {} + regex: (a|b) )EOF"; std::vector header_data; @@ -345,7 +347,8 @@ name: match-header header_data[0] = std::make_unique(parseHeaderMatcherFromYaml(R"EOF( name: match-header -exact_match: a,b +string_match: + exact: a,b )EOF")); // Make sure that an exact match on "a,b" does in fact work. EXPECT_TRUE(HeaderUtility::matchHeaders(headers, header_data)); @@ -395,7 +398,7 @@ name: match-header EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); } -TEST(MatchHeadersTest, HeaderExactMatch) { +TEST(MatchHeadersTest, DEPRECATED_FEATURE_TEST(HeaderExactMatch)) { TestRequestHeaderMapImpl matching_headers{{"match-header", "match-value"}}; TestRequestHeaderMapImpl unmatching_headers{{"match-header", "other-value"}, {"other-header", "match-value"}}; @@ -411,7 +414,7 @@ exact_match: match-value EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); } -TEST(MatchHeadersTest, HeaderExactMatchInverse) { +TEST(MatchHeadersTest, DEPRECATED_FEATURE_TEST(HeaderExactMatchInverse)) { TestRequestHeaderMapImpl matching_headers{{"match-header", "other-value"}, {"other-header", "match-value"}}; TestRequestHeaderMapImpl unmatching_headers{{"match-header", "match-value"}}; @@ -429,7 +432,7 @@ invert_match: true EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); } -TEST(MatchHeadersTest, HeaderSafeRegexMatch) { +TEST(MatchHeadersTest, DEPRECATED_FEATURE_TEST(HeaderSafeRegexMatch)) { TestRequestHeaderMapImpl matching_headers{{"match-header", "123"}}; TestRequestHeaderMapImpl unmatching_headers{{"match-header", "1234"}, {"match-header", "123.456"}}; @@ -447,7 +450,7 @@ name: match-header EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); } -TEST(MatchHeadersTest, HeaderSafeRegexInverseMatch) { +TEST(MatchHeadersTest, DEPRECATED_FEATURE_TEST(HeaderSafeRegexInverseMatch)) { TestDeprecatedV2Api _deprecated_v2_api; TestRequestHeaderMapImpl matching_headers{{"match-header", "1234"}, {"match-header", "123.456"}}; TestRequestHeaderMapImpl unmatching_headers{{"match-header", "123"}}; @@ -587,7 +590,7 @@ invert_match: true EXPECT_TRUE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); } -TEST(MatchHeadersTest, HeaderPrefixMatch) { +TEST(MatchHeadersTest, DEPRECATED_FEATURE_TEST(HeaderPrefixMatch)) { TestRequestHeaderMapImpl matching_headers{{"match-header", "value123"}}; TestRequestHeaderMapImpl unmatching_headers{{"match-header", "123value"}}; @@ -603,7 +606,7 @@ prefix_match: value EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); } -TEST(MatchHeadersTest, HeaderPrefixInverseMatch) { +TEST(MatchHeadersTest, DEPRECATED_FEATURE_TEST(HeaderPrefixInverseMatch)) { TestRequestHeaderMapImpl unmatching_headers{{"match-header", "value123"}}; TestRequestHeaderMapImpl matching_headers{{"match-header", "123value"}}; @@ -620,7 +623,7 @@ invert_match: true EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); } -TEST(MatchHeadersTest, HeaderSuffixMatch) { +TEST(MatchHeadersTest, DEPRECATED_FEATURE_TEST(HeaderSuffixMatch)) { TestRequestHeaderMapImpl matching_headers{{"match-header", "123value"}}; TestRequestHeaderMapImpl unmatching_headers{{"match-header", "value123"}}; @@ -636,7 +639,7 @@ suffix_match: value EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); } -TEST(MatchHeadersTest, HeaderSuffixInverseMatch) { +TEST(MatchHeadersTest, DEPRECATED_FEATURE_TEST(HeaderSuffixInverseMatch)) { TestRequestHeaderMapImpl unmatching_headers{{"match-header", "123value"}}; TestRequestHeaderMapImpl matching_headers{{"match-header", "value123"}}; @@ -653,7 +656,7 @@ invert_match: true EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); } -TEST(MatchHeadersTest, HeaderContainsMatch) { +TEST(MatchHeadersTest, DEPRECATED_FEATURE_TEST(HeaderContainsMatch)) { TestRequestHeaderMapImpl matching_headers{{"match-header", "123onevalue456"}}; TestRequestHeaderMapImpl unmatching_headers{{"match-header", "123anothervalue456"}}; @@ -669,7 +672,7 @@ contains_match: onevalue EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data)); } -TEST(MatchHeadersTest, HeaderContainsInverseMatch) { +TEST(MatchHeadersTest, DEPRECATED_FEATURE_TEST(HeaderContainsInverseMatch)) { TestRequestHeaderMapImpl matching_headers{{"match-header", "123onevalue456"}}; TestRequestHeaderMapImpl unmatching_headers{{"match-header", "123anothervalue456"}}; diff --git a/test/tools/router_check/router.cc b/test/tools/router_check/router.cc index a19a75b3a089..65ee00c42884 100644 --- a/test/tools/router_check/router.cc +++ b/test/tools/router_check/router.cc @@ -8,6 +8,7 @@ #include "envoy/config/route/v3/route.pb.h" #include "envoy/type/v3/percent.pb.h" +#include "source/common/common/macros.h" #include "source/common/common/random_generator.h" #include "source/common/network/socket_impl.h" #include "source/common/network/utility.h" @@ -488,16 +489,6 @@ bool RouterCheckTool::matchHeaderField(const HeaderMap& header_map, std::string actual, expected; std::string match_test_type{test_type + "." + ::toString(header)}; switch (header.header_match_specifier_case()) { - case envoy::config::route::v3::HeaderMatcher::HeaderMatchSpecifierCase::kStringMatch: - if (header.string_match().match_pattern_case() != - envoy::type::matcher::v3::StringMatcher::MatchPatternCase::kExact) { - goto default_case; - } - actual = - header.name() + ": " + ::toString(header_map.get(Http::LowerCaseString(header.name()))); - expected = header.name() + ": " + header.string_match().exact(); - reportFailure(actual, expected, match_test_type, !header.invert_match()); - break; case envoy::config::route::v3::HeaderMatcher::HeaderMatchSpecifierCase::kPresentMatch: case envoy::config::route::v3::HeaderMatcher::HeaderMatchSpecifierCase:: HEADER_MATCH_SPECIFIER_NOT_SET: @@ -505,7 +496,16 @@ bool RouterCheckTool::matchHeaderField(const HeaderMap& header_map, expected = "has(" + header.name() + "):" + (header.invert_match() ? "false" : "true"); reportFailure(actual, expected, match_test_type); break; - default_case: + case envoy::config::route::v3::HeaderMatcher::HeaderMatchSpecifierCase::kStringMatch: + if (header.string_match().match_pattern_case() == + envoy::type::matcher::v3::StringMatcher::MatchPatternCase::kExact) { + actual = + header.name() + ": " + ::toString(header_map.get(Http::LowerCaseString(header.name()))); + expected = header.name() + ": " + header.string_match().exact(); + reportFailure(actual, expected, match_test_type, !header.invert_match()); + break; + } + FALLTHRU; default: actual = header.name() + ": " + ::toString(header_map.get(Http::LowerCaseString(header.name()))); From 92284de40b2dc3306287c3d1fc9b26a507864d8d Mon Sep 17 00:00:00 2001 From: Yangmin Zhu Date: Tue, 13 Jul 2021 20:36:25 -0700 Subject: [PATCH 11/12] fix merge issue Signed-off-by: Yangmin Zhu --- docs/root/version_history/current.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/root/version_history/current.rst b/docs/root/version_history/current.rst index 236a53c6b573..7ba091268b26 100644 --- a/docs/root/version_history/current.rst +++ b/docs/root/version_history/current.rst @@ -112,7 +112,6 @@ New Features * http: added the ability to :ref:`unescape slash sequences ` in the path. Requests with unescaped slashes can be proxied, rejected or redirected to the new unescaped path. By default this feature is disabled. The default behavior can be overridden through :ref:`http_connection_manager.path_with_escaped_slashes_action` runtime variable. This action can be selectively enabled for a portion of requests by setting the :ref:`http_connection_manager.path_with_escaped_slashes_action_sampling` runtime variable. * http: added upstream and downstream alpha HTTP/3 support! See :ref:`quic_options ` for downstream and the new http3_protocol_options in :ref:`http_protocol_options ` for upstream HTTP/3. * http: added :ref:`string_match ` in the header matcher. -* input matcher: a new input matcher that :ref:`matches an IP address against a list of CIDR ranges `. * http: raise max configurable max_request_headers_kb limit to 8192 KiB (8MiB) from 96 KiB in http connection manager. * input matcher: added a new input matcher that :ref:`matches an IP address against a list of CIDR ranges `. * jwt_authn: added support to fetch remote jwks asynchronously specified by :ref:`async_fetch `. From 5a92d835d9ae345553e892a8323aa2b2e470eed3 Mon Sep 17 00:00:00 2001 From: Yangmin Zhu Date: Wed, 14 Jul 2021 13:15:54 -0700 Subject: [PATCH 12/12] resolve conflicts Signed-off-by: Yangmin Zhu --- docs/root/version_history/current.rst | 61 +-------------------------- 1 file changed, 1 insertion(+), 60 deletions(-) diff --git a/docs/root/version_history/current.rst b/docs/root/version_history/current.rst index 5ef0d124c98d..792dcbe2f1d4 100644 --- a/docs/root/version_history/current.rst +++ b/docs/root/version_history/current.rst @@ -27,69 +27,10 @@ Removed Config or Runtime New Features ------------ - -* access_log: added the new response flag for :ref:`overload manager termination `. The response flag will be set when the http stream is terminated by overload manager. -* admission control: added :ref:`rps_threshold ` option that when average RPS of the sampling window is below this threshold, the filter will not throttle requests. Added :ref:`max_rejection_probability ` option to set an upper limit on the probability of rejection. -* bandwidth_limit: added new :ref:`HTTP bandwidth limit filter `. -* bootstrap: added :ref:`dns_resolution_config ` to aggregate all of the DNS resolver configuration in a single message. By setting ``no_default_search_domain`` to true the DNS resolver will not use the default search domains. By setting the ``resolvers`` the external DNS servers to be used for external DNS queries can be specified. -* cluster: added :ref:`dns_resolution_config ` to aggregate all of the DNS resolver configuration in a single message. By setting ``no_default_search_domain`` to true the DNS resolver will not use the default search domains. -* cluster: added :ref:`host_rewrite_literal ` to WeightedCluster. -* cluster: added :ref:`wait_for_warm_on_init `, which allows cluster readiness to not block on cluster warm-up. It is true by default, which preserves existing behavior. Currently, only applicable for DNS-based clusters. -* composite filter: can now be used with filters that also add an access logger, such as the WASM filter. -* config: added stat :ref:`config_reload_time_ms `. -* connection_limit: added new :ref:`Network connection limit filter `. -* crash support: restore crash context when continuing to processing requests or responses as a result of an asynchronous callback that invokes a filter directly. This is unlike the call stacks that go through the various network layers, to eventually reach the filter. For a concrete example see: ``Envoy::Extensions::HttpFilters::Cache::CacheFilter::getHeaders`` which posts a callback on the dispatcher that will invoke the filter directly. -* dns cache: added :ref:`preresolve_hostnames ` option to the DNS cache config. This option allows hostnames to be preresolved into the cache upon cache creation. This might provide performance improvement, in the form of cache hits, for hostnames that are going to be resolved during steady state and are known at config load time. -* dns cache: added :ref:`dns_query_timeout ` option to the DNS cache config. This option allows explicitly controlling the timeout of underlying queries independently of the underlying DNS platform implementation. Coupled with success and failure retry policies the use of this timeout will lead to more deterministic DNS resolution times. -* dns resolver: added ``DnsResolverOptions`` protobuf message to reconcile all of the DNS lookup option flags. By setting the configuration option :ref:`use_tcp_for_dns_lookups ` as true we can make the underlying dns resolver library to make only TCP queries to the DNS servers and by setting the configuration option :ref:`no_default_search_domain ` as true the DNS resolver library will not use the default search domains. -* dns resolver: added ``DnsResolutionConfig`` to combine :ref:`dns_resolver_options ` and :ref:`resolvers ` in a single protobuf message. The field ``resolvers`` can be specified with a list of DNS resolver addresses. If specified, DNS client library will perform resolution via the underlying DNS resolvers. Otherwise, the default system resolvers (e.g., /etc/resolv.conf) will be used. -* dns_filter: added :ref:`dns_resolution_config ` to aggregate all of the DNS resolver configuration in a single message. By setting the configuration option ``use_tcp_for_dns_lookups`` to true we can make dns filter's external resolvers to answer queries using TCP only, by setting the configuration option ``no_default_search_domain`` as true the DNS resolver will not use the default search domains. And by setting the configuration ``resolvers`` we can specify the external DNS servers to be used for external DNS query which replaces the pre-existing alpha api field ``upstream_resolvers``. -* dynamic_forward_proxy: added :ref:`dns_resolution_config ` option to the DNS cache config in order to aggregate all of the DNS resolver configuration in a single message. By setting one such configuration option ``no_default_search_domain`` as true the DNS resolver will not use the default search domains. And by setting the configuration ``resolvers`` we can specify the external DNS servers to be used for external DNS query instead of the system default resolvers. -* ext_authz_filter: added :ref:`bootstrap_metadata_labels_key ` option to configure labels of destination service. -* http: added new field ``is_optional`` to ``extensions.filters.network.http_connection_manager.v3.HttpFilter``. When - set to ``true``, unsupported http filters will be ignored by envoy. This is also same with unsupported http filter - in the typed per filter config. For more information, please reference - :ref:`HttpFilter `. -* http: added :ref:`scheme options ` for adding or overwriting scheme. -* http: added :ref:`stripping trailing host dot from host header ` support. -* http: added support for :ref:`original IP detection extensions `. - Two initial extensions were added, the :ref:`custom header ` extension and the - :ref:`xff ` extension. -* http: added a new option to upstream HTTP/2 :ref:`keepalive ` to send a PING ahead of a new stream if the connection has been idle for a sufficient duration. -* http: added the ability to :ref:`unescape slash sequences ` in the path. Requests with unescaped slashes can be proxied, rejected or redirected to the new unescaped path. By default this feature is disabled. The default behavior can be overridden through :ref:`http_connection_manager.path_with_escaped_slashes_action` runtime variable. This action can be selectively enabled for a portion of requests by setting the :ref:`http_connection_manager.path_with_escaped_slashes_action_sampling` runtime variable. -* http: added upstream and downstream alpha HTTP/3 support! See :ref:`quic_options ` for downstream and the new http3_protocol_options in :ref:`http_protocol_options ` for upstream HTTP/3. * http: added :ref:`string_match ` in the header matcher. -* http: raise max configurable max_request_headers_kb limit to 8192 KiB (8MiB) from 96 KiB in http connection manager. -* input matcher: added a new input matcher that :ref:`matches an IP address against a list of CIDR ranges `. -* jwt_authn: added support to fetch remote jwks asynchronously specified by :ref:`async_fetch `. -* jwt_authn: added support to add padding in the forwarded JWT payload specified by :ref:`pad_forward_payload_header `. -* listener: added ability to change an existing listener's address. -* listener: added filter chain match support for :ref:`direct source address `. -* local_rate_limit_filter: added suppoort for locally rate limiting http requests on a per connection basis. This can be enabled by setting the :ref:`local_rate_limit_per_downstream_connection ` field to true. -* metric service: added support for sending metric tags as labels. This can be enabled by setting the :ref:`emit_tags_as_labels ` field to true. -* proxy protocol: added support for generating the header while using the :ref:`HTTP connection manager `. This is done using the :ref:`Proxy Protocol Transport Socket ` on upstream clusters. - This feature is currently affected by a memory leak `issue `_. -* req_without_query: added access log formatter extension implementing command operator :ref:`REQ_WITHOUT_QUERY ` to log the request path, while excluding the query string. -* router: added option ``suppress_grpc_request_failure_code_stats`` to :ref:`the router ` to allow users to exclude incrementing HTTP status code stats on gRPC requests. -* stats: added native :ref:`Graphite-formatted tag ` support. -* tcp: added support for :ref:`preconnecting `. Preconnecting is off by default, but recommended for clusters serving latency-sensitive traffic. -* thrift_proxy: added per upstream metrics within the :ref:`thrift router ` for request and response size histograms. -* thrift_proxy: added support for :ref:`outlier detection `. -* tls: allow dual ECDSA/RSA certs via SDS. Previously, SDS only supported a single certificate per context, and dual cert was only supported via non-SDS. -* tracing: add option :ref:`use_request_id_for_trace_sampling ` which allows configuring whether to perform sampling based on :ref:`x-request-id` or not. -* udp_proxy: added :ref:`key ` as another hash policy to support hash based routing on any given key. -* windows container image: added user, EnvoyUser which is part of the Network Configuration Operators group to the container image. Deprecated ---------- - -* 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`. -* http: The HeaderMatcher fields :ref:`exact_match `, :ref:`safe_regex_match `, +* http: the HeaderMatcher fields :ref:`exact_match `, :ref:`safe_regex_match `, :ref:`prefix_match `, :ref:`suffix_match ` and :ref:`contains_match ` are deprecated by :ref:`string_match `. -Deprecated -----------