• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "src/core/util/matchers.h"
16 
17 #include <grpc/support/port_platform.h>
18 
19 #include <utility>
20 
21 #include "absl/status/status.h"
22 #include "absl/strings/ascii.h"
23 #include "absl/strings/match.h"
24 #include "absl/strings/numbers.h"
25 #include "absl/strings/str_cat.h"
26 #include "absl/strings/str_format.h"
27 
28 namespace grpc_core {
29 
30 //
31 // StringMatcher
32 //
33 
Create(Type type,absl::string_view matcher,bool case_sensitive)34 absl::StatusOr<StringMatcher> StringMatcher::Create(Type type,
35                                                     absl::string_view matcher,
36                                                     bool case_sensitive) {
37   if (type == Type::kSafeRegex) {
38     auto regex_matcher = std::make_unique<RE2>(std::string(matcher));
39     if (!regex_matcher->ok()) {
40       return absl::InvalidArgumentError(
41           absl::StrCat("Invalid regex string specified in matcher: ",
42                        regex_matcher->error()));
43     }
44     return StringMatcher(std::move(regex_matcher));
45   } else {
46     return StringMatcher(type, matcher, case_sensitive);
47   }
48 }
49 
StringMatcher(Type type,absl::string_view matcher,bool case_sensitive)50 StringMatcher::StringMatcher(Type type, absl::string_view matcher,
51                              bool case_sensitive)
52     : type_(type), string_matcher_(matcher), case_sensitive_(case_sensitive) {}
53 
StringMatcher(std::unique_ptr<RE2> regex_matcher)54 StringMatcher::StringMatcher(std::unique_ptr<RE2> regex_matcher)
55     : type_(Type::kSafeRegex), regex_matcher_(std::move(regex_matcher)) {}
56 
StringMatcher(const StringMatcher & other)57 StringMatcher::StringMatcher(const StringMatcher& other)
58     : type_(other.type_), case_sensitive_(other.case_sensitive_) {
59   if (type_ == Type::kSafeRegex) {
60     regex_matcher_ = std::make_unique<RE2>(other.regex_matcher_->pattern());
61   } else {
62     string_matcher_ = other.string_matcher_;
63   }
64 }
65 
operator =(const StringMatcher & other)66 StringMatcher& StringMatcher::operator=(const StringMatcher& other) {
67   type_ = other.type_;
68   if (type_ == Type::kSafeRegex) {
69     regex_matcher_ = std::make_unique<RE2>(other.regex_matcher_->pattern());
70   } else {
71     string_matcher_ = other.string_matcher_;
72   }
73   case_sensitive_ = other.case_sensitive_;
74   return *this;
75 }
76 
StringMatcher(StringMatcher && other)77 StringMatcher::StringMatcher(StringMatcher&& other) noexcept
78     : type_(other.type_), case_sensitive_(other.case_sensitive_) {
79   if (type_ == Type::kSafeRegex) {
80     regex_matcher_ = std::move(other.regex_matcher_);
81   } else {
82     string_matcher_ = std::move(other.string_matcher_);
83   }
84 }
85 
operator =(StringMatcher && other)86 StringMatcher& StringMatcher::operator=(StringMatcher&& other) noexcept {
87   type_ = other.type_;
88   if (type_ == Type::kSafeRegex) {
89     regex_matcher_ = std::move(other.regex_matcher_);
90   } else {
91     string_matcher_ = std::move(other.string_matcher_);
92   }
93   case_sensitive_ = other.case_sensitive_;
94   return *this;
95 }
96 
operator ==(const StringMatcher & other) const97 bool StringMatcher::operator==(const StringMatcher& other) const {
98   if (type_ != other.type_ || case_sensitive_ != other.case_sensitive_) {
99     return false;
100   }
101   if (type_ == Type::kSafeRegex) {
102     return regex_matcher_->pattern() == other.regex_matcher_->pattern();
103   } else {
104     return string_matcher_ == other.string_matcher_;
105   }
106 }
107 
Match(absl::string_view value) const108 bool StringMatcher::Match(absl::string_view value) const {
109   switch (type_) {
110     case Type::kExact:
111       return case_sensitive_ ? value == string_matcher_
112                              : absl::EqualsIgnoreCase(value, string_matcher_);
113     case StringMatcher::Type::kPrefix:
114       return case_sensitive_
115                  ? absl::StartsWith(value, string_matcher_)
116                  : absl::StartsWithIgnoreCase(value, string_matcher_);
117     case StringMatcher::Type::kSuffix:
118       return case_sensitive_ ? absl::EndsWith(value, string_matcher_)
119                              : absl::EndsWithIgnoreCase(value, string_matcher_);
120     case StringMatcher::Type::kContains:
121       return case_sensitive_
122                  ? absl::StrContains(value, string_matcher_)
123                  : absl::StrContains(absl::AsciiStrToLower(value),
124                                      absl::AsciiStrToLower(string_matcher_));
125     case StringMatcher::Type::kSafeRegex:
126       return RE2::FullMatch(std::string(value), *regex_matcher_);
127     default:
128       return false;
129   }
130 }
131 
ToString() const132 std::string StringMatcher::ToString() const {
133   switch (type_) {
134     case Type::kExact:
135       return absl::StrFormat("StringMatcher{exact=%s%s}", string_matcher_,
136                              case_sensitive_ ? "" : ", case_sensitive=false");
137     case Type::kPrefix:
138       return absl::StrFormat("StringMatcher{prefix=%s%s}", string_matcher_,
139                              case_sensitive_ ? "" : ", case_sensitive=false");
140     case Type::kSuffix:
141       return absl::StrFormat("StringMatcher{suffix=%s%s}", string_matcher_,
142                              case_sensitive_ ? "" : ", case_sensitive=false");
143     case Type::kContains:
144       return absl::StrFormat("StringMatcher{contains=%s%s}", string_matcher_,
145                              case_sensitive_ ? "" : ", case_sensitive=false");
146     case Type::kSafeRegex:
147       return absl::StrFormat("StringMatcher{safe_regex=%s}",
148                              regex_matcher_->pattern());
149     default:
150       return "";
151   }
152 }
153 
154 //
155 // HeaderMatcher
156 //
157 
Create(absl::string_view name,Type type,absl::string_view matcher,int64_t range_start,int64_t range_end,bool present_match,bool invert_match,bool case_sensitive)158 absl::StatusOr<HeaderMatcher> HeaderMatcher::Create(
159     absl::string_view name, Type type, absl::string_view matcher,
160     int64_t range_start, int64_t range_end, bool present_match,
161     bool invert_match, bool case_sensitive) {
162   if (static_cast<int>(type) < 5) {
163     // Only for EXACT, PREFIX, SUFFIX, SAFE_REGEX and CONTAINS.
164     absl::StatusOr<StringMatcher> string_matcher = StringMatcher::Create(
165         static_cast<StringMatcher::Type>(type), matcher, case_sensitive);
166     if (!string_matcher.ok()) {
167       return string_matcher.status();
168     }
169     return HeaderMatcher(name, type, std::move(string_matcher.value()),
170                          invert_match);
171   } else if (type == Type::kRange) {
172     if (range_start > range_end) {
173       return absl::InvalidArgumentError(
174           "Invalid range specifier specified: end cannot be smaller than "
175           "start.");
176     }
177     return HeaderMatcher(name, range_start, range_end, invert_match);
178   } else {
179     return HeaderMatcher(name, present_match, invert_match);
180   }
181 }
182 
CreateFromStringMatcher(absl::string_view name,StringMatcher matcher,bool invert_match)183 HeaderMatcher HeaderMatcher::CreateFromStringMatcher(absl::string_view name,
184                                                      StringMatcher matcher,
185                                                      bool invert_match) {
186   HeaderMatcher::Type type = static_cast<HeaderMatcher::Type>(matcher.type());
187   return HeaderMatcher(name, type, std::move(matcher), invert_match);
188 }
189 
HeaderMatcher(absl::string_view name,Type type,StringMatcher string_matcher,bool invert_match)190 HeaderMatcher::HeaderMatcher(absl::string_view name, Type type,
191                              StringMatcher string_matcher, bool invert_match)
192     : name_(name),
193       type_(type),
194       matcher_(std::move(string_matcher)),
195       invert_match_(invert_match) {}
196 
HeaderMatcher(absl::string_view name,int64_t range_start,int64_t range_end,bool invert_match)197 HeaderMatcher::HeaderMatcher(absl::string_view name, int64_t range_start,
198                              int64_t range_end, bool invert_match)
199     : name_(name),
200       type_(Type::kRange),
201       range_start_(range_start),
202       range_end_(range_end),
203       invert_match_(invert_match) {}
204 
HeaderMatcher(absl::string_view name,bool present_match,bool invert_match)205 HeaderMatcher::HeaderMatcher(absl::string_view name, bool present_match,
206                              bool invert_match)
207     : name_(name),
208       type_(Type::kPresent),
209       present_match_(present_match),
210       invert_match_(invert_match) {}
211 
HeaderMatcher(const HeaderMatcher & other)212 HeaderMatcher::HeaderMatcher(const HeaderMatcher& other)
213     : name_(other.name_),
214       type_(other.type_),
215       invert_match_(other.invert_match_) {
216   switch (type_) {
217     case Type::kRange:
218       range_start_ = other.range_start_;
219       range_end_ = other.range_end_;
220       break;
221     case Type::kPresent:
222       present_match_ = other.present_match_;
223       break;
224     default:
225       matcher_ = other.matcher_;
226   }
227 }
228 
operator =(const HeaderMatcher & other)229 HeaderMatcher& HeaderMatcher::operator=(const HeaderMatcher& other) {
230   name_ = other.name_;
231   type_ = other.type_;
232   invert_match_ = other.invert_match_;
233   switch (type_) {
234     case Type::kRange:
235       range_start_ = other.range_start_;
236       range_end_ = other.range_end_;
237       break;
238     case Type::kPresent:
239       present_match_ = other.present_match_;
240       break;
241     default:
242       matcher_ = other.matcher_;
243   }
244   return *this;
245 }
246 
HeaderMatcher(HeaderMatcher && other)247 HeaderMatcher::HeaderMatcher(HeaderMatcher&& other) noexcept
248     : name_(std::move(other.name_)),
249       type_(other.type_),
250       invert_match_(other.invert_match_) {
251   switch (type_) {
252     case Type::kRange:
253       range_start_ = other.range_start_;
254       range_end_ = other.range_end_;
255       break;
256     case Type::kPresent:
257       present_match_ = other.present_match_;
258       break;
259     default:
260       matcher_ = std::move(other.matcher_);
261   }
262 }
263 
operator =(HeaderMatcher && other)264 HeaderMatcher& HeaderMatcher::operator=(HeaderMatcher&& other) noexcept {
265   name_ = std::move(other.name_);
266   type_ = other.type_;
267   invert_match_ = other.invert_match_;
268   switch (type_) {
269     case Type::kRange:
270       range_start_ = other.range_start_;
271       range_end_ = other.range_end_;
272       break;
273     case Type::kPresent:
274       present_match_ = other.present_match_;
275       break;
276     default:
277       matcher_ = std::move(other.matcher_);
278   }
279   return *this;
280 }
281 
operator ==(const HeaderMatcher & other) const282 bool HeaderMatcher::operator==(const HeaderMatcher& other) const {
283   if (name_ != other.name_) return false;
284   if (type_ != other.type_) return false;
285   if (invert_match_ != other.invert_match_) return false;
286   switch (type_) {
287     case Type::kRange:
288       return range_start_ == other.range_start_ &&
289              range_end_ == other.range_end_;
290     case Type::kPresent:
291       return present_match_ == other.present_match_;
292     default:
293       return matcher_ == other.matcher_;
294   }
295 }
296 
Match(const absl::optional<absl::string_view> & value) const297 bool HeaderMatcher::Match(
298     const absl::optional<absl::string_view>& value) const {
299   bool match;
300   if (type_ == Type::kPresent) {
301     match = value.has_value() == present_match_;
302   } else if (!value.has_value()) {
303     // All other types fail to match if field is not present.
304     return false;
305   } else if (type_ == Type::kRange) {
306     int64_t int_value;
307     match = absl::SimpleAtoi(value.value(), &int_value) &&
308             int_value >= range_start_ && int_value < range_end_;
309   } else {
310     match = matcher_.Match(value.value());
311   }
312   return match != invert_match_;
313 }
314 
ToString() const315 std::string HeaderMatcher::ToString() const {
316   switch (type_) {
317     case Type::kRange:
318       return absl::StrFormat("HeaderMatcher{%s %srange=[%d, %d]}", name_,
319                              invert_match_ ? "not " : "", range_start_,
320                              range_end_);
321     case Type::kPresent:
322       return absl::StrFormat("HeaderMatcher{%s %spresent=%s}", name_,
323                              invert_match_ ? "not " : "",
324                              present_match_ ? "true" : "false");
325     case Type::kExact:
326     case Type::kPrefix:
327     case Type::kSuffix:
328     case Type::kSafeRegex:
329     case Type::kContains:
330       return absl::StrFormat("HeaderMatcher{%s %s%s}", name_,
331                              invert_match_ ? "not " : "", matcher_.ToString());
332     default:
333       return "";
334   }
335 }
336 
337 }  // namespace grpc_core
338