Skip to content

Commit

Permalink
Merge pull request envoyproxy#146 from istio/ignore-case
Browse files Browse the repository at this point in the history
[release-1.5] add ignore_case to StringMatcher that allows case insensitive exact/prefix/suffix string matching
  • Loading branch information
kyessenov authored Feb 12, 2020
2 parents 0ff001d + 40a99f1 commit 138043f
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 7 deletions.
7 changes: 6 additions & 1 deletion api/envoy/type/matcher/string.proto
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ option java_multiple_files = true;
// [#protodoc-title: StringMatcher]

// Specifies the way to match a string.
// [#next-free-field: 6]
// [#next-free-field: 7]
message StringMatcher {
oneof match_pattern {
option (validate.required) = true;
Expand Down Expand Up @@ -64,6 +64,11 @@ message StringMatcher {
// The input string must match the regular expression specified here.
RegexMatcher safe_regex = 5 [(validate.rules).message = {required: true}];
}

// If true, indicates the exact/prefix/suffix 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;
}

// Specifies a list of ways to match a string.
Expand Down
7 changes: 6 additions & 1 deletion api/envoy/type/matcher/v3/string.proto
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ option java_multiple_files = true;
// [#protodoc-title: StringMatcher]

// Specifies the way to match a string.
// [#next-free-field: 6]
// [#next-free-field: 7]
message StringMatcher {
option (udpa.annotations.versioning).previous_message_type = "envoy.type.matcher.StringMatcher";

Expand Down Expand Up @@ -53,6 +53,11 @@ message StringMatcher {
// The input string must match the regular expression specified here.
RegexMatcher safe_regex = 5 [(validate.rules).message = {required: true}];
}

// If true, indicates the exact/prefix/suffix 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;
}

// Specifies a list of ways to match a string.
Expand Down
7 changes: 6 additions & 1 deletion generated_api_shadow/envoy/type/matcher/string.proto

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion generated_api_shadow/envoy/type/matcher/v3/string.proto

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 12 additions & 3 deletions source/common/common/matchers.cc
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,16 @@ StringMatcherImpl::StringMatcherImpl(const envoy::type::matcher::v3::StringMatch
: matcher_(matcher) {
if (matcher.match_pattern_case() ==
envoy::type::matcher::v3::StringMatcher::MatchPatternCase::kHiddenEnvoyDeprecatedRegex) {
if (matcher.ignore_case()) {
throw EnvoyException("ignore_case has no effect for regex.");
}
regex_ =
Regex::Utility::parseStdRegexAsCompiledMatcher(matcher_.hidden_envoy_deprecated_regex());
} else if (matcher.match_pattern_case() ==
envoy::type::matcher::v3::StringMatcher::MatchPatternCase::kSafeRegex) {
if (matcher.ignore_case()) {
throw EnvoyException("ignore_case has no effect for safe_regex.");
}
regex_ = Regex::Utility::parseRegex(matcher_.safe_regex());
}
}
Expand All @@ -84,11 +90,14 @@ bool StringMatcherImpl::match(const ProtobufWkt::Value& value) const {
bool StringMatcherImpl::match(const absl::string_view value) const {
switch (matcher_.match_pattern_case()) {
case envoy::type::matcher::v3::StringMatcher::MatchPatternCase::kExact:
return matcher_.exact() == value;
return matcher_.ignore_case() ? absl::EqualsIgnoreCase(value, matcher_.exact())
: value == matcher_.exact();
case envoy::type::matcher::v3::StringMatcher::MatchPatternCase::kPrefix:
return absl::StartsWith(value, matcher_.prefix());
return matcher_.ignore_case() ? absl::StartsWithIgnoreCase(value, matcher_.prefix())
: absl::StartsWith(value, matcher_.prefix());
case envoy::type::matcher::v3::StringMatcher::MatchPatternCase::kSuffix:
return absl::EndsWith(value, matcher_.suffix());
return matcher_.ignore_case() ? absl::EndsWithIgnoreCase(value, matcher_.suffix())
: absl::EndsWith(value, matcher_.suffix());
case envoy::type::matcher::v3::StringMatcher::MatchPatternCase::kHiddenEnvoyDeprecatedRegex:
case envoy::type::matcher::v3::StringMatcher::MatchPatternCase::kSafeRegex:
return regex_->match(value);
Expand Down
1 change: 1 addition & 0 deletions test/common/common/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ envoy_cc_test(
deps = [
"//source/common/common:matchers_lib",
"//source/common/config:metadata_lib",
"//test/test_common:utility_lib",
"//source/common/protobuf:utility_lib",
"@envoy_api//envoy/config/core/v3:pkg_cc_proto",
"@envoy_api//envoy/type/matcher/v3:pkg_cc_proto",
Expand Down
65 changes: 65 additions & 0 deletions test/common/common/matchers_test.cc
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include "envoy/common/exception.h"
#include "envoy/config/core/v3/base.pb.h"
#include "envoy/type/matcher/v3/metadata.pb.h"
#include "envoy/type/matcher/v3/string.pb.h"
Expand All @@ -7,6 +8,8 @@
#include "common/config/metadata.h"
#include "common/protobuf/protobuf.h"

#include "test/test_common/utility.h"

#include "gtest/gtest.h"

namespace Envoy {
Expand Down Expand Up @@ -258,6 +261,51 @@ TEST(MetadataTest, MatchDoubleListValue) {
metadataValue.Clear();
}

TEST(StringMatcher, ExactMatchIgnoreCase) {
envoy::type::matcher::v3::StringMatcher matcher;
matcher.set_exact("exact");
EXPECT_TRUE(Matchers::StringMatcherImpl(matcher).match("exact"));
EXPECT_FALSE(Matchers::StringMatcherImpl(matcher).match("EXACT"));
EXPECT_FALSE(Matchers::StringMatcherImpl(matcher).match("exacz"));
EXPECT_FALSE(Matchers::StringMatcherImpl(matcher).match("other"));

matcher.set_ignore_case(true);
EXPECT_TRUE(Matchers::StringMatcherImpl(matcher).match("exact"));
EXPECT_TRUE(Matchers::StringMatcherImpl(matcher).match("EXACT"));
EXPECT_FALSE(Matchers::StringMatcherImpl(matcher).match("exacz"));
EXPECT_FALSE(Matchers::StringMatcherImpl(matcher).match("other"));
}

TEST(StringMatcher, PrefixMatchIgnoreCase) {
envoy::type::matcher::v3::StringMatcher matcher;
matcher.set_prefix("prefix");
EXPECT_TRUE(Matchers::StringMatcherImpl(matcher).match("prefix-abc"));
EXPECT_FALSE(Matchers::StringMatcherImpl(matcher).match("PREFIX-ABC"));
EXPECT_FALSE(Matchers::StringMatcherImpl(matcher).match("prefiz-abc"));
EXPECT_FALSE(Matchers::StringMatcherImpl(matcher).match("other"));

matcher.set_ignore_case(true);
EXPECT_TRUE(Matchers::StringMatcherImpl(matcher).match("prefix-abc"));
EXPECT_TRUE(Matchers::StringMatcherImpl(matcher).match("PREFIX-ABC"));
EXPECT_FALSE(Matchers::StringMatcherImpl(matcher).match("prefiz-abc"));
EXPECT_FALSE(Matchers::StringMatcherImpl(matcher).match("other"));
}

TEST(StringMatcher, SuffixMatchIgnoreCase) {
envoy::type::matcher::v3::StringMatcher matcher;
matcher.set_suffix("suffix");
EXPECT_TRUE(Matchers::StringMatcherImpl(matcher).match("abc-suffix"));
EXPECT_FALSE(Matchers::StringMatcherImpl(matcher).match("ABC-SUFFIX"));
EXPECT_FALSE(Matchers::StringMatcherImpl(matcher).match("abc-suffiz"));
EXPECT_FALSE(Matchers::StringMatcherImpl(matcher).match("other"));

matcher.set_ignore_case(true);
EXPECT_TRUE(Matchers::StringMatcherImpl(matcher).match("abc-suffix"));
EXPECT_TRUE(Matchers::StringMatcherImpl(matcher).match("ABC-SUFFIX"));
EXPECT_FALSE(Matchers::StringMatcherImpl(matcher).match("abc-suffiz"));
EXPECT_FALSE(Matchers::StringMatcherImpl(matcher).match("other"));
}

TEST(StringMatcher, SafeRegexValue) {
envoy::type::matcher::v3::StringMatcher matcher;
matcher.mutable_safe_regex()->mutable_google_re2();
Expand All @@ -267,6 +315,23 @@ TEST(StringMatcher, SafeRegexValue) {
EXPECT_FALSE(Matchers::StringMatcherImpl(matcher).match("bar"));
}

TEST(StringMatcher, RegexValueIgnoreCase) {
envoy::type::matcher::v3::StringMatcher matcher;
matcher.set_ignore_case(true);
matcher.set_hidden_envoy_deprecated_regex("foo");
EXPECT_THROW_WITH_MESSAGE(Matchers::StringMatcherImpl(matcher).match("foo"), EnvoyException,
"ignore_case has no effect for regex.");
}

TEST(StringMatcher, SafeRegexValueIgnoreCase) {
envoy::type::matcher::v3::StringMatcher matcher;
matcher.set_ignore_case(true);
matcher.mutable_safe_regex()->mutable_google_re2();
matcher.mutable_safe_regex()->set_regex("foo");
EXPECT_THROW_WITH_MESSAGE(Matchers::StringMatcherImpl(matcher).match("foo"), EnvoyException,
"ignore_case has no effect for safe_regex.");
}

TEST(LowerCaseStringMatcher, MatchExactValue) {
envoy::type::matcher::v3::StringMatcher matcher;
matcher.set_exact("Foo");
Expand Down

0 comments on commit 138043f

Please sign in to comment.