• 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 <grpc/support/port_platform.h>
16 
17 #include "src/core/lib/matchers/matchers.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 
HeaderMatcher(absl::string_view name,Type type,StringMatcher string_matcher,bool invert_match)183 HeaderMatcher::HeaderMatcher(absl::string_view name, Type type,
184                              StringMatcher string_matcher, bool invert_match)
185     : name_(name),
186       type_(type),
187       matcher_(std::move(string_matcher)),
188       invert_match_(invert_match) {}
189 
HeaderMatcher(absl::string_view name,int64_t range_start,int64_t range_end,bool invert_match)190 HeaderMatcher::HeaderMatcher(absl::string_view name, int64_t range_start,
191                              int64_t range_end, bool invert_match)
192     : name_(name),
193       type_(Type::kRange),
194       range_start_(range_start),
195       range_end_(range_end),
196       invert_match_(invert_match) {}
197 
HeaderMatcher(absl::string_view name,bool present_match,bool invert_match)198 HeaderMatcher::HeaderMatcher(absl::string_view name, bool present_match,
199                              bool invert_match)
200     : name_(name),
201       type_(Type::kPresent),
202       present_match_(present_match),
203       invert_match_(invert_match) {}
204 
HeaderMatcher(const HeaderMatcher & other)205 HeaderMatcher::HeaderMatcher(const HeaderMatcher& other)
206     : name_(other.name_),
207       type_(other.type_),
208       invert_match_(other.invert_match_) {
209   switch (type_) {
210     case Type::kRange:
211       range_start_ = other.range_start_;
212       range_end_ = other.range_end_;
213       break;
214     case Type::kPresent:
215       present_match_ = other.present_match_;
216       break;
217     default:
218       matcher_ = other.matcher_;
219   }
220 }
221 
operator =(const HeaderMatcher & other)222 HeaderMatcher& HeaderMatcher::operator=(const HeaderMatcher& other) {
223   name_ = other.name_;
224   type_ = other.type_;
225   invert_match_ = other.invert_match_;
226   switch (type_) {
227     case Type::kRange:
228       range_start_ = other.range_start_;
229       range_end_ = other.range_end_;
230       break;
231     case Type::kPresent:
232       present_match_ = other.present_match_;
233       break;
234     default:
235       matcher_ = other.matcher_;
236   }
237   return *this;
238 }
239 
HeaderMatcher(HeaderMatcher && other)240 HeaderMatcher::HeaderMatcher(HeaderMatcher&& other) noexcept
241     : name_(std::move(other.name_)),
242       type_(other.type_),
243       invert_match_(other.invert_match_) {
244   switch (type_) {
245     case Type::kRange:
246       range_start_ = other.range_start_;
247       range_end_ = other.range_end_;
248       break;
249     case Type::kPresent:
250       present_match_ = other.present_match_;
251       break;
252     default:
253       matcher_ = std::move(other.matcher_);
254   }
255 }
256 
operator =(HeaderMatcher && other)257 HeaderMatcher& HeaderMatcher::operator=(HeaderMatcher&& other) noexcept {
258   name_ = std::move(other.name_);
259   type_ = other.type_;
260   invert_match_ = other.invert_match_;
261   switch (type_) {
262     case Type::kRange:
263       range_start_ = other.range_start_;
264       range_end_ = other.range_end_;
265       break;
266     case Type::kPresent:
267       present_match_ = other.present_match_;
268       break;
269     default:
270       matcher_ = std::move(other.matcher_);
271   }
272   return *this;
273 }
274 
operator ==(const HeaderMatcher & other) const275 bool HeaderMatcher::operator==(const HeaderMatcher& other) const {
276   if (name_ != other.name_) return false;
277   if (type_ != other.type_) return false;
278   if (invert_match_ != other.invert_match_) return false;
279   switch (type_) {
280     case Type::kRange:
281       return range_start_ == other.range_start_ &&
282              range_end_ == other.range_end_;
283     case Type::kPresent:
284       return present_match_ == other.present_match_;
285     default:
286       return matcher_ == other.matcher_;
287   }
288 }
289 
Match(const absl::optional<absl::string_view> & value) const290 bool HeaderMatcher::Match(
291     const absl::optional<absl::string_view>& value) const {
292   bool match;
293   if (type_ == Type::kPresent) {
294     match = value.has_value() == present_match_;
295   } else if (!value.has_value()) {
296     // All other types fail to match if field is not present.
297     return false;
298   } else if (type_ == Type::kRange) {
299     int64_t int_value;
300     match = absl::SimpleAtoi(value.value(), &int_value) &&
301             int_value >= range_start_ && int_value < range_end_;
302   } else {
303     match = matcher_.Match(value.value());
304   }
305   return match != invert_match_;
306 }
307 
ToString() const308 std::string HeaderMatcher::ToString() const {
309   switch (type_) {
310     case Type::kRange:
311       return absl::StrFormat("HeaderMatcher{%s %srange=[%d, %d]}", name_,
312                              invert_match_ ? "not " : "", range_start_,
313                              range_end_);
314     case Type::kPresent:
315       return absl::StrFormat("HeaderMatcher{%s %spresent=%s}", name_,
316                              invert_match_ ? "not " : "",
317                              present_match_ ? "true" : "false");
318     case Type::kExact:
319     case Type::kPrefix:
320     case Type::kSuffix:
321     case Type::kSafeRegex:
322     case Type::kContains:
323       return absl::StrFormat("HeaderMatcher{%s %s%s}", name_,
324                              invert_match_ ? "not " : "", matcher_.ToString());
325     default:
326       return "";
327   }
328 }
329 
330 }  // namespace grpc_core
331