parent
4860738db7
commit
4ca878799b
30 changed files with 964 additions and 519 deletions
@ -0,0 +1,339 @@ |
||||
// Copyright 2021 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/lib/security/authorization/matchers.h" |
||||
|
||||
#include "absl/memory/memory.h" |
||||
#include "absl/strings/str_cat.h" |
||||
#include "absl/strings/str_format.h" |
||||
#include "absl/strings/str_join.h" |
||||
#include "absl/strings/str_split.h" |
||||
|
||||
namespace grpc_core { |
||||
|
||||
//
|
||||
// StringMatcher
|
||||
//
|
||||
|
||||
absl::StatusOr<StringMatcher> StringMatcher::Create(Type type, |
||||
const std::string& matcher, |
||||
bool case_sensitive) { |
||||
if (type == Type::SAFE_REGEX) { |
||||
RE2::Options options; |
||||
options.set_case_sensitive(case_sensitive); |
||||
auto regex_matcher = absl::make_unique<RE2>(matcher, options); |
||||
if (!regex_matcher->ok()) { |
||||
return absl::InvalidArgumentError( |
||||
"Invalid regex string specified in matcher."); |
||||
} |
||||
return StringMatcher(std::move(regex_matcher), case_sensitive); |
||||
} else { |
||||
return StringMatcher(type, matcher, case_sensitive); |
||||
} |
||||
} |
||||
|
||||
StringMatcher::StringMatcher(Type type, const std::string& matcher, |
||||
bool case_sensitive) |
||||
: type_(type), string_matcher_(matcher), case_sensitive_(case_sensitive) {} |
||||
|
||||
StringMatcher::StringMatcher(std::unique_ptr<RE2> regex_matcher, |
||||
bool case_sensitive) |
||||
: type_(Type::SAFE_REGEX), |
||||
regex_matcher_(std::move(regex_matcher)), |
||||
case_sensitive_(case_sensitive) {} |
||||
|
||||
StringMatcher::StringMatcher(const StringMatcher& other) |
||||
: type_(other.type_), case_sensitive_(other.case_sensitive_) { |
||||
if (type_ == Type::SAFE_REGEX) { |
||||
RE2::Options options; |
||||
options.set_case_sensitive(other.case_sensitive_); |
||||
regex_matcher_ = |
||||
absl::make_unique<RE2>(other.regex_matcher_->pattern(), options); |
||||
} else { |
||||
string_matcher_ = other.string_matcher_; |
||||
} |
||||
} |
||||
|
||||
StringMatcher& StringMatcher::operator=(const StringMatcher& other) { |
||||
type_ = other.type_; |
||||
if (type_ == Type::SAFE_REGEX) { |
||||
RE2::Options options; |
||||
options.set_case_sensitive(other.case_sensitive_); |
||||
regex_matcher_ = |
||||
absl::make_unique<RE2>(other.regex_matcher_->pattern(), options); |
||||
} else { |
||||
string_matcher_ = other.string_matcher_; |
||||
} |
||||
case_sensitive_ = other.case_sensitive_; |
||||
return *this; |
||||
} |
||||
|
||||
StringMatcher::StringMatcher(StringMatcher&& other) noexcept |
||||
: type_(other.type_), case_sensitive_(other.case_sensitive_) { |
||||
if (type_ == Type::SAFE_REGEX) { |
||||
regex_matcher_ = std::move(other.regex_matcher_); |
||||
} else { |
||||
string_matcher_ = std::move(other.string_matcher_); |
||||
} |
||||
} |
||||
|
||||
StringMatcher& StringMatcher::operator=(StringMatcher&& other) noexcept { |
||||
type_ = other.type_; |
||||
if (type_ == Type::SAFE_REGEX) { |
||||
regex_matcher_ = std::move(other.regex_matcher_); |
||||
} else { |
||||
string_matcher_ = std::move(other.string_matcher_); |
||||
} |
||||
case_sensitive_ = other.case_sensitive_; |
||||
return *this; |
||||
} |
||||
|
||||
bool StringMatcher::operator==(const StringMatcher& other) const { |
||||
if (type_ != other.type_ || case_sensitive_ != other.case_sensitive_) { |
||||
return false; |
||||
} |
||||
if (type_ == Type::SAFE_REGEX) { |
||||
return regex_matcher_->pattern() == other.regex_matcher_->pattern(); |
||||
} else { |
||||
return string_matcher_ == other.string_matcher_; |
||||
} |
||||
} |
||||
|
||||
bool StringMatcher::Match(absl::string_view value) const { |
||||
switch (type_) { |
||||
case Type::EXACT: |
||||
return case_sensitive_ ? value == string_matcher_ |
||||
: absl::EqualsIgnoreCase(value, string_matcher_); |
||||
case StringMatcher::Type::PREFIX: |
||||
return case_sensitive_ |
||||
? absl::StartsWith(value, string_matcher_) |
||||
: absl::StartsWithIgnoreCase(value, string_matcher_); |
||||
case StringMatcher::Type::SUFFIX: |
||||
return case_sensitive_ ? absl::EndsWith(value, string_matcher_) |
||||
: absl::EndsWithIgnoreCase(value, string_matcher_); |
||||
case StringMatcher::Type::CONTAINS: |
||||
return case_sensitive_ |
||||
? absl::StrContains(value, string_matcher_) |
||||
: absl::StrContains(absl::AsciiStrToLower(value), |
||||
absl::AsciiStrToLower(string_matcher_)); |
||||
case StringMatcher::Type::SAFE_REGEX: |
||||
return RE2::FullMatch(std::string(value), *regex_matcher_); |
||||
default: |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
std::string StringMatcher::ToString() const { |
||||
switch (type_) { |
||||
case Type::EXACT: |
||||
return absl::StrFormat("StringMatcher{exact=%s%s}", string_matcher_, |
||||
case_sensitive_ ? "" : ", case_sensitive=false"); |
||||
case Type::PREFIX: |
||||
return absl::StrFormat("StringMatcher{prefix=%s%s}", string_matcher_, |
||||
case_sensitive_ ? "" : ", case_sensitive=false"); |
||||
case Type::SUFFIX: |
||||
return absl::StrFormat("StringMatcher{suffix=%s%s}", string_matcher_, |
||||
case_sensitive_ ? "" : ", case_sensitive=false"); |
||||
case Type::CONTAINS: |
||||
return absl::StrFormat("StringMatcher{contains=%s%s}", string_matcher_, |
||||
case_sensitive_ ? "" : ", case_sensitive=false"); |
||||
case Type::SAFE_REGEX: |
||||
return absl::StrFormat("StringMatcher{safe_regex=%s%s}", |
||||
regex_matcher_->pattern(), |
||||
case_sensitive_ ? "" : ", case_sensitive=false"); |
||||
default: |
||||
return ""; |
||||
} |
||||
} |
||||
|
||||
//
|
||||
// HeaderMatcher
|
||||
//
|
||||
|
||||
absl::StatusOr<HeaderMatcher> HeaderMatcher::Create( |
||||
const std::string& name, Type type, const std::string& matcher, |
||||
int64_t range_start, int64_t range_end, bool present_match, |
||||
bool invert_match) { |
||||
if (static_cast<int>(type) < 5) { |
||||
// Only for EXACT, PREFIX, SUFFIX, SAFE_REGEX and CONTAINS.
|
||||
absl::StatusOr<StringMatcher> string_matcher = |
||||
StringMatcher::Create(static_cast<StringMatcher::Type>(type), matcher, |
||||
/*case_sensitive=*/true); |
||||
if (!string_matcher.ok()) { |
||||
return string_matcher.status(); |
||||
} |
||||
return HeaderMatcher(name, type, std::move(string_matcher.value()), |
||||
invert_match); |
||||
} else if (type == Type::RANGE) { |
||||
if (range_start > range_end) { |
||||
return absl::InvalidArgumentError( |
||||
"Invalid range specifier specified: end cannot be smaller than " |
||||
"start."); |
||||
} |
||||
return HeaderMatcher(name, range_start, range_end, invert_match); |
||||
} else { |
||||
return HeaderMatcher(name, present_match, invert_match); |
||||
} |
||||
} |
||||
|
||||
HeaderMatcher::HeaderMatcher(const std::string& name, Type type, |
||||
StringMatcher string_matcher, bool invert_match) |
||||
: name_(name), |
||||
type_(type), |
||||
matcher_(std::move(string_matcher)), |
||||
invert_match_(invert_match) {} |
||||
|
||||
HeaderMatcher::HeaderMatcher(const std::string& name, int64_t range_start, |
||||
int64_t range_end, bool invert_match) |
||||
: name_(name), |
||||
type_(Type::RANGE), |
||||
range_start_(range_start), |
||||
range_end_(range_end), |
||||
invert_match_(invert_match) {} |
||||
|
||||
HeaderMatcher::HeaderMatcher(const std::string& name, bool present_match, |
||||
bool invert_match) |
||||
: name_(name), |
||||
type_(Type::PRESENT), |
||||
present_match_(present_match), |
||||
invert_match_(invert_match) {} |
||||
|
||||
HeaderMatcher::HeaderMatcher(const HeaderMatcher& other) |
||||
: name_(other.name_), |
||||
type_(other.type_), |
||||
invert_match_(other.invert_match_) { |
||||
switch (type_) { |
||||
case Type::RANGE: |
||||
range_start_ = other.range_start_; |
||||
range_end_ = other.range_end_; |
||||
break; |
||||
case Type::PRESENT: |
||||
present_match_ = other.present_match_; |
||||
break; |
||||
default: |
||||
matcher_ = other.matcher_; |
||||
} |
||||
} |
||||
|
||||
HeaderMatcher& HeaderMatcher::operator=(const HeaderMatcher& other) { |
||||
name_ = other.name_; |
||||
type_ = other.type_; |
||||
invert_match_ = other.invert_match_; |
||||
switch (type_) { |
||||
case Type::RANGE: |
||||
range_start_ = other.range_start_; |
||||
range_end_ = other.range_end_; |
||||
break; |
||||
case Type::PRESENT: |
||||
present_match_ = other.present_match_; |
||||
break; |
||||
default: |
||||
matcher_ = other.matcher_; |
||||
} |
||||
return *this; |
||||
} |
||||
|
||||
HeaderMatcher::HeaderMatcher(HeaderMatcher&& other) noexcept |
||||
: name_(std::move(other.name_)), |
||||
type_(other.type_), |
||||
invert_match_(other.invert_match_) { |
||||
switch (type_) { |
||||
case Type::RANGE: |
||||
range_start_ = other.range_start_; |
||||
range_end_ = other.range_end_; |
||||
break; |
||||
case Type::PRESENT: |
||||
present_match_ = other.present_match_; |
||||
break; |
||||
default: |
||||
matcher_ = std::move(other.matcher_); |
||||
} |
||||
} |
||||
|
||||
HeaderMatcher& HeaderMatcher::operator=(HeaderMatcher&& other) noexcept { |
||||
name_ = std::move(other.name_); |
||||
type_ = other.type_; |
||||
invert_match_ = other.invert_match_; |
||||
switch (type_) { |
||||
case Type::RANGE: |
||||
range_start_ = other.range_start_; |
||||
range_end_ = other.range_end_; |
||||
break; |
||||
case Type::PRESENT: |
||||
present_match_ = other.present_match_; |
||||
break; |
||||
default: |
||||
matcher_ = std::move(other.matcher_); |
||||
} |
||||
return *this; |
||||
} |
||||
|
||||
bool HeaderMatcher::operator==(const HeaderMatcher& other) const { |
||||
if (name_ != other.name_) return false; |
||||
if (type_ != other.type_) return false; |
||||
if (invert_match_ != other.invert_match_) return false; |
||||
switch (type_) { |
||||
case Type::RANGE: |
||||
return range_start_ == other.range_start_ && |
||||
range_end_ == other.range_end_; |
||||
case Type::PRESENT: |
||||
return present_match_ == other.present_match_; |
||||
default: |
||||
return matcher_ == other.matcher_; |
||||
} |
||||
} |
||||
|
||||
bool HeaderMatcher::Match( |
||||
const absl::optional<absl::string_view>& value) const { |
||||
bool match; |
||||
if (type_ == Type::PRESENT) { |
||||
match = value.has_value() == present_match_; |
||||
} else if (!value.has_value()) { |
||||
// All other types fail to match if field is not present.
|
||||
match = false; |
||||
} else if (type_ == Type::RANGE) { |
||||
int64_t int_value; |
||||
match = absl::SimpleAtoi(value.value(), &int_value) && |
||||
int_value >= range_start_ && int_value < range_end_; |
||||
} else { |
||||
match = matcher_.Match(value.value()); |
||||
} |
||||
return match != invert_match_; |
||||
} |
||||
|
||||
std::string HeaderMatcher::ToString() const { |
||||
switch (type_) { |
||||
case Type::RANGE: |
||||
return absl::StrFormat("HeaderMatcher{%s %srange=[%d, %d]}", name_, |
||||
invert_match_ ? "not " : "", range_start_, |
||||
range_end_); |
||||
case Type::PRESENT: |
||||
return absl::StrFormat("HeaderMatcher{%s %spresent=%s}", name_, |
||||
invert_match_ ? "not " : "", |
||||
present_match_ ? "true" : "false"); |
||||
case Type::EXACT: |
||||
case Type::PREFIX: |
||||
case Type::SUFFIX: |
||||
case Type::SAFE_REGEX: |
||||
case Type::CONTAINS: |
||||
return absl::StrFormat("HeaderMatcher{%s %s%s}", name_, |
||||
invert_match_ ? "not " : "", matcher_.ToString()); |
||||
default: |
||||
return ""; |
||||
} |
||||
} |
||||
|
||||
} // namespace grpc_core
|
@ -0,0 +1,158 @@ |
||||
// Copyright 2021 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef GRPC_CORE_LIB_SECURITY_AUTHORIZATION_MATCHERS_H |
||||
#define GRPC_CORE_LIB_SECURITY_AUTHORIZATION_MATCHERS_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <memory> |
||||
#include <string> |
||||
|
||||
#include "absl/status/statusor.h" |
||||
#include "absl/strings/string_view.h" |
||||
#include "absl/types/optional.h" |
||||
|
||||
#include "re2/re2.h" |
||||
|
||||
namespace grpc_core { |
||||
|
||||
class StringMatcher { |
||||
public: |
||||
enum class Type { |
||||
EXACT, // value stored in string_matcher_ field
|
||||
PREFIX, // value stored in string_matcher_ field
|
||||
SUFFIX, // value stored in string_matcher_ field
|
||||
SAFE_REGEX, // pattern stored in regex_matcher_ field
|
||||
CONTAINS, // value stored in string_matcher_ field
|
||||
}; |
||||
|
||||
// Creates StringMatcher instance. Returns error status on failure.
|
||||
static absl::StatusOr<StringMatcher> Create(Type type, |
||||
const std::string& matcher, |
||||
bool case_sensitive = true); |
||||
|
||||
StringMatcher() = default; |
||||
StringMatcher(const StringMatcher& other); |
||||
StringMatcher& operator=(const StringMatcher& other); |
||||
StringMatcher(StringMatcher&& other) noexcept; |
||||
StringMatcher& operator=(StringMatcher&& other) noexcept; |
||||
bool operator==(const StringMatcher& other) const; |
||||
|
||||
bool Match(absl::string_view value) const; |
||||
|
||||
std::string ToString() const; |
||||
|
||||
Type type() const { return type_; } |
||||
|
||||
// Valid for EXACT, PREFIX, SUFFIX and CONTAINS
|
||||
const std::string& string_matcher() const { return string_matcher_; } |
||||
|
||||
// Valid for SAFE_REGEX
|
||||
RE2* regex_matcher() const { return regex_matcher_.get(); } |
||||
|
||||
bool case_sensitive() const { return case_sensitive_; } |
||||
|
||||
private: |
||||
StringMatcher(Type type, const std::string& matcher, bool case_sensitive); |
||||
StringMatcher(std::unique_ptr<RE2> regex_matcher, bool case_sensitive); |
||||
|
||||
Type type_ = Type::EXACT; |
||||
std::string string_matcher_; |
||||
std::unique_ptr<RE2> regex_matcher_; |
||||
bool case_sensitive_ = true; |
||||
}; |
||||
|
||||
class HeaderMatcher { |
||||
public: |
||||
enum class Type { |
||||
EXACT, // value stored in StringMatcher field
|
||||
PREFIX, // value stored in StringMatcher field
|
||||
SUFFIX, // value stored in StringMatcher field
|
||||
SAFE_REGEX, // value stored in StringMatcher field
|
||||
CONTAINS, // value stored in StringMatcher field
|
||||
RANGE, // uses range_start and range_end fields
|
||||
PRESENT, // uses present_match field
|
||||
}; |
||||
|
||||
// Make sure that the first five HeaderMatcher::Type enum values match up to
|
||||
// the corresponding StringMatcher::Type enum values, so that it's safe to
|
||||
// convert by casting when delegating to StringMatcher.
|
||||
static_assert(static_cast<StringMatcher::Type>(Type::EXACT) == |
||||
StringMatcher::Type::EXACT, |
||||
""); |
||||
static_assert(static_cast<StringMatcher::Type>(Type::PREFIX) == |
||||
StringMatcher::Type::PREFIX, |
||||
""); |
||||
static_assert(static_cast<StringMatcher::Type>(Type::SUFFIX) == |
||||
StringMatcher::Type::SUFFIX, |
||||
""); |
||||
static_assert(static_cast<StringMatcher::Type>(Type::SAFE_REGEX) == |
||||
StringMatcher::Type::SAFE_REGEX, |
||||
""); |
||||
static_assert(static_cast<StringMatcher::Type>(Type::CONTAINS) == |
||||
StringMatcher::Type::CONTAINS, |
||||
""); |
||||
|
||||
// Creates HeaderMatcher instance. Returns error status on failure.
|
||||
static absl::StatusOr<HeaderMatcher> Create( |
||||
const std::string& name, Type type, const std::string& matcher, |
||||
int64_t range_start = 0, int64_t range_end = 0, |
||||
bool present_match = false, bool invert_match = false); |
||||
|
||||
HeaderMatcher() = default; |
||||
HeaderMatcher(const HeaderMatcher& other); |
||||
HeaderMatcher& operator=(const HeaderMatcher& other); |
||||
HeaderMatcher(HeaderMatcher&& other) noexcept; |
||||
HeaderMatcher& operator=(HeaderMatcher&& other) noexcept; |
||||
bool operator==(const HeaderMatcher& other) const; |
||||
|
||||
const std::string& name() const { return name_; } |
||||
|
||||
Type type() const { return type_; } |
||||
|
||||
// Valid for EXACT, PREFIX, SUFFIX and CONTAINS
|
||||
const std::string& string_matcher() const { |
||||
return matcher_.string_matcher(); |
||||
} |
||||
|
||||
// Valid for SAFE_REGEX
|
||||
RE2* regex_matcher() const { return matcher_.regex_matcher(); } |
||||
|
||||
bool Match(const absl::optional<absl::string_view>& value) const; |
||||
|
||||
std::string ToString() const; |
||||
|
||||
private: |
||||
// For StringMatcher.
|
||||
HeaderMatcher(const std::string& name, Type type, StringMatcher matcher, |
||||
bool invert_match); |
||||
// For RangeMatcher.
|
||||
HeaderMatcher(const std::string& name, int64_t range_start, int64_t range_end, |
||||
bool invert_match); |
||||
// For PresentMatcher.
|
||||
HeaderMatcher(const std::string& name, bool present_match, bool invert_match); |
||||
|
||||
std::string name_; |
||||
Type type_ = Type::EXACT; |
||||
StringMatcher matcher_; |
||||
int64_t range_start_; |
||||
int64_t range_end_; |
||||
bool present_match_; |
||||
bool invert_match_ = false; |
||||
}; |
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
#endif /* GRPC_CORE_LIB_SECURITY_AUTHORIZATION_MATCHERS_H */ |
@ -0,0 +1,218 @@ |
||||
// Copyright 2021 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "src/core/lib/security/authorization/matchers.h" |
||||
|
||||
#include <gtest/gtest.h> |
||||
|
||||
namespace grpc_core { |
||||
|
||||
TEST(StringMatcherTest, ExactMatchCaseSensitive) { |
||||
auto string_matcher = |
||||
StringMatcher::Create(StringMatcher::Type::EXACT, |
||||
/*matcher=*/"exact", /*case_sensitive=*/true); |
||||
ASSERT_TRUE(string_matcher.ok()); |
||||
EXPECT_TRUE(string_matcher->Match("exact")); |
||||
EXPECT_FALSE(string_matcher->Match("Exact")); |
||||
EXPECT_FALSE(string_matcher->Match("exacz")); |
||||
} |
||||
|
||||
TEST(StringMatcherTest, ExactMatchCaseInsensitive) { |
||||
auto string_matcher = |
||||
StringMatcher::Create(StringMatcher::Type::EXACT, |
||||
/*matcher=*/"exact", /*case_sensitive=*/false); |
||||
ASSERT_TRUE(string_matcher.ok()); |
||||
EXPECT_TRUE(string_matcher->Match("Exact")); |
||||
EXPECT_FALSE(string_matcher->Match("Exacz")); |
||||
} |
||||
|
||||
TEST(StringMatcherTest, PrefixMatchCaseSensitive) { |
||||
auto string_matcher = StringMatcher::Create(StringMatcher::Type::PREFIX, |
||||
/*matcher=*/"prefix", |
||||
/*case_sensitive=*/true); |
||||
ASSERT_TRUE(string_matcher.ok()); |
||||
EXPECT_TRUE(string_matcher->Match("prefix-test")); |
||||
EXPECT_FALSE(string_matcher->Match("xx-prefix-test")); |
||||
EXPECT_FALSE(string_matcher->Match("Prefix-test")); |
||||
EXPECT_FALSE(string_matcher->Match("pre-test")); |
||||
} |
||||
|
||||
TEST(StringMatcherTest, PrefixMatchCaseInsensitive) { |
||||
auto string_matcher = StringMatcher::Create(StringMatcher::Type::PREFIX, |
||||
/*matcher=*/"prefix", |
||||
/*case_sensitive=*/false); |
||||
ASSERT_TRUE(string_matcher.ok()); |
||||
EXPECT_TRUE(string_matcher->Match("PREfix-test")); |
||||
EXPECT_FALSE(string_matcher->Match("xx-PREfix-test")); |
||||
EXPECT_FALSE(string_matcher->Match("PRE-test")); |
||||
} |
||||
|
||||
TEST(StringMatcherTest, SuffixMatchCaseSensitive) { |
||||
auto string_matcher = StringMatcher::Create(StringMatcher::Type::SUFFIX, |
||||
/*matcher=*/"suffix", |
||||
/*case_sensitive=*/true); |
||||
ASSERT_TRUE(string_matcher.ok()); |
||||
EXPECT_TRUE(string_matcher->Match("test-suffix")); |
||||
EXPECT_FALSE(string_matcher->Match("test-Suffix")); |
||||
EXPECT_FALSE(string_matcher->Match("test-suffix-xx")); |
||||
EXPECT_FALSE(string_matcher->Match("test-suffiz")); |
||||
} |
||||
|
||||
TEST(StringMatcherTest, SuffixMatchCaseInSensitive) { |
||||
auto string_matcher = StringMatcher::Create(StringMatcher::Type::SUFFIX, |
||||
/*matcher=*/"suffix", |
||||
/*case_sensitive=*/false); |
||||
ASSERT_TRUE(string_matcher.ok()); |
||||
EXPECT_TRUE(string_matcher->Match("Test-SUFFIX")); |
||||
EXPECT_FALSE(string_matcher->Match("Test-SUFFIX-xx")); |
||||
EXPECT_FALSE(string_matcher->Match("Test-SUFFIZ")); |
||||
} |
||||
|
||||
TEST(StringMatcherTest, InvalidRegex) { |
||||
auto string_matcher = StringMatcher::Create(StringMatcher::Type::SAFE_REGEX, |
||||
/*matcher=*/"a[b-a]", |
||||
/*case_sensitive=*/true); |
||||
EXPECT_FALSE(string_matcher.ok()); |
||||
EXPECT_EQ(string_matcher.status().code(), absl::StatusCode::kInvalidArgument); |
||||
EXPECT_EQ(string_matcher.status().message(), |
||||
"Invalid regex string specified in matcher."); |
||||
} |
||||
|
||||
TEST(StringMatcherTest, SafeRegexMatchCaseSensitive) { |
||||
auto string_matcher = StringMatcher::Create(StringMatcher::Type::SAFE_REGEX, |
||||
/*matcher=*/"regex.*", |
||||
/*case_sensitive=*/true); |
||||
ASSERT_TRUE(string_matcher.ok()); |
||||
EXPECT_TRUE(string_matcher->Match("regex-test")); |
||||
EXPECT_FALSE(string_matcher->Match("xx-regex-test")); |
||||
EXPECT_FALSE(string_matcher->Match("Regex-test")); |
||||
EXPECT_FALSE(string_matcher->Match("test-regex")); |
||||
} |
||||
|
||||
TEST(StringMatcherTest, SafeRegexMatchCaseInSensitive) { |
||||
auto string_matcher = StringMatcher::Create(StringMatcher::Type::SAFE_REGEX, |
||||
/*matcher=*/"regex.*", |
||||
/*case_sensitive=*/false); |
||||
ASSERT_TRUE(string_matcher.ok()); |
||||
EXPECT_TRUE(string_matcher->Match("regex-test")); |
||||
EXPECT_TRUE(string_matcher->Match("Regex-test")); |
||||
EXPECT_FALSE(string_matcher->Match("xx-Regex-test")); |
||||
EXPECT_FALSE(string_matcher->Match("test-regex")); |
||||
} |
||||
|
||||
TEST(StringMatcherTest, ContainsMatchCaseSensitive) { |
||||
auto string_matcher = StringMatcher::Create(StringMatcher::Type::CONTAINS, |
||||
/*matcher=*/"contains", |
||||
/*case_sensitive=*/true); |
||||
ASSERT_TRUE(string_matcher.ok()); |
||||
EXPECT_TRUE(string_matcher->Match("test-contains")); |
||||
EXPECT_TRUE(string_matcher->Match("test-contains-test")); |
||||
EXPECT_FALSE(string_matcher->Match("test-Contains")); |
||||
EXPECT_FALSE(string_matcher->Match("test-containz")); |
||||
} |
||||
|
||||
TEST(StringMatcherTest, ContainsMatchCaseInSensitive) { |
||||
auto string_matcher = StringMatcher::Create(StringMatcher::Type::CONTAINS, |
||||
/*matcher=*/"contains", |
||||
/*case_sensitive=*/false); |
||||
ASSERT_TRUE(string_matcher.ok()); |
||||
EXPECT_TRUE(string_matcher->Match("Test-Contains")); |
||||
EXPECT_TRUE(string_matcher->Match("Test-Contains-Test")); |
||||
EXPECT_FALSE(string_matcher->Match("Test-Containz")); |
||||
} |
||||
|
||||
TEST(HeaderMatcherTest, StringMatcher) { |
||||
auto header_matcher = |
||||
HeaderMatcher::Create(/*name=*/"key", HeaderMatcher::Type::EXACT, |
||||
/*matcher=*/"exact"); |
||||
ASSERT_TRUE(header_matcher.ok()); |
||||
EXPECT_TRUE(header_matcher->Match("exact")); |
||||
EXPECT_FALSE(header_matcher->Match("Exact")); |
||||
EXPECT_FALSE(header_matcher->Match("exacz")); |
||||
} |
||||
|
||||
TEST(HeaderMatcherTest, StringMatcherWithInvertMatch) { |
||||
auto header_matcher = |
||||
HeaderMatcher::Create(/*name=*/"key", HeaderMatcher::Type::EXACT, |
||||
/*matcher=*/"exact", |
||||
/*range_start=*/0, /*range_end=*/0, |
||||
/*present_match=*/false, /*invert_match=*/true); |
||||
ASSERT_TRUE(header_matcher.ok()); |
||||
EXPECT_FALSE(header_matcher->Match("exact")); |
||||
EXPECT_TRUE(header_matcher->Match("Exact")); |
||||
EXPECT_TRUE(header_matcher->Match("exacz")); |
||||
} |
||||
|
||||
TEST(HeaderMatcherTest, InvalidRegex) { |
||||
auto header_matcher = |
||||
HeaderMatcher::Create(/*name=*/"key", HeaderMatcher::Type::SAFE_REGEX, |
||||
/*matcher=*/"a[b-a]", |
||||
/*range_start=*/0, /*range_end=*/0, |
||||
/*present_match=*/false, /*invert_match=*/true); |
||||
EXPECT_FALSE(header_matcher.ok()); |
||||
EXPECT_EQ(header_matcher.status().code(), absl::StatusCode::kInvalidArgument); |
||||
EXPECT_EQ(header_matcher.status().message(), |
||||
"Invalid regex string specified in matcher."); |
||||
} |
||||
|
||||
TEST(HeaderMatcherTest, RangeMatcherValidRange) { |
||||
auto header_matcher = |
||||
HeaderMatcher::Create(/*name=*/"key", HeaderMatcher::Type::RANGE, |
||||
/*matcher=*/"", /*range_start=*/10, |
||||
/*range_end*/ 20); |
||||
ASSERT_TRUE(header_matcher.ok()); |
||||
EXPECT_TRUE(header_matcher->Match("16")); |
||||
EXPECT_TRUE(header_matcher->Match("10")); |
||||
EXPECT_FALSE(header_matcher->Match("3")); |
||||
EXPECT_FALSE(header_matcher->Match("20")); |
||||
} |
||||
|
||||
TEST(HeaderMatcherTest, RangeMatcherInvalidRange) { |
||||
auto header_matcher = |
||||
HeaderMatcher::Create(/*name=*/"key", HeaderMatcher::Type::RANGE, |
||||
/*matcher=*/"", /*range_start=*/20, |
||||
/*range_end*/ 10); |
||||
EXPECT_FALSE(header_matcher.ok()); |
||||
EXPECT_EQ(header_matcher.status().code(), absl::StatusCode::kInvalidArgument); |
||||
EXPECT_EQ( |
||||
header_matcher.status().message(), |
||||
"Invalid range specifier specified: end cannot be smaller than start."); |
||||
} |
||||
|
||||
TEST(HeaderMatcherTest, PresentMatcherTrue) { |
||||
auto header_matcher = |
||||
HeaderMatcher::Create(/*name=*/"key", HeaderMatcher::Type::PRESENT, |
||||
/*matcher=*/"", /*range_start=*/0, |
||||
/*range_end=*/0, /*present_match=*/true); |
||||
ASSERT_TRUE(header_matcher.ok()); |
||||
EXPECT_TRUE(header_matcher->Match("any_value")); |
||||
EXPECT_FALSE(header_matcher->Match(absl::nullopt)); |
||||
} |
||||
|
||||
TEST(HeaderMatcherTest, PresentMatcherFalse) { |
||||
auto header_matcher = |
||||
HeaderMatcher::Create(/*name=*/"key", HeaderMatcher::Type::PRESENT, |
||||
/*matcher=*/"", /*range_start=*/0, |
||||
/*range_end=*/0, /*present_match=*/false); |
||||
ASSERT_TRUE(header_matcher.ok()); |
||||
EXPECT_FALSE(header_matcher->Match("any_value")); |
||||
EXPECT_TRUE(header_matcher->Match(absl::nullopt)); |
||||
} |
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
int main(int argc, char** argv) { |
||||
::testing::InitGoogleTest(&argc, argv); |
||||
return RUN_ALL_TESTS(); |
||||
} |
Loading…
Reference in new issue