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 "absl/memory/memory.h"
20 #include "absl/strings/str_cat.h"
21 #include "absl/strings/str_format.h"
22 #include "absl/strings/str_join.h"
23 #include "absl/strings/str_split.h"
24 
25 namespace grpc_core {
26 
27 //
28 // StringMatcher
29 //
30 
Create(Type type,absl::string_view matcher,bool case_sensitive)31 absl::StatusOr<StringMatcher> StringMatcher::Create(Type type,
32                                                     absl::string_view matcher,
33                                                     bool case_sensitive) {
34   if (type == Type::kSafeRegex) {
35     auto regex_matcher = absl::make_unique<RE2>(std::string(matcher));
36     if (!regex_matcher->ok()) {
37       return absl::InvalidArgumentError(
38           "Invalid regex string specified in matcher.");
39     }
40     return StringMatcher(std::move(regex_matcher));
41   } else {
42     return StringMatcher(type, matcher, case_sensitive);
43   }
44 }
45 
StringMatcher(Type type,absl::string_view matcher,bool case_sensitive)46 StringMatcher::StringMatcher(Type type, absl::string_view matcher,
47                              bool case_sensitive)
48     : type_(type), string_matcher_(matcher), case_sensitive_(case_sensitive) {}
49 
StringMatcher(std::unique_ptr<RE2> regex_matcher)50 StringMatcher::StringMatcher(std::unique_ptr<RE2> regex_matcher)
51     : type_(Type::kSafeRegex), regex_matcher_(std::move(regex_matcher)) {}
52 
StringMatcher(const StringMatcher & other)53 StringMatcher::StringMatcher(const StringMatcher& other)
54     : type_(other.type_), case_sensitive_(other.case_sensitive_) {
55   if (type_ == Type::kSafeRegex) {
56     regex_matcher_ = absl::make_unique<RE2>(other.regex_matcher_->pattern());
57   } else {
58     string_matcher_ = other.string_matcher_;
59   }
60 }
61 
operator =(const StringMatcher & other)62 StringMatcher& StringMatcher::operator=(const StringMatcher& other) {
63   type_ = other.type_;
64   if (type_ == Type::kSafeRegex) {
65     regex_matcher_ = absl::make_unique<RE2>(other.regex_matcher_->pattern());
66   } else {
67     string_matcher_ = other.string_matcher_;
68   }
69   case_sensitive_ = other.case_sensitive_;
70   return *this;
71 }
72 
StringMatcher(StringMatcher && other)73 StringMatcher::StringMatcher(StringMatcher&& other) noexcept
74     : type_(other.type_), case_sensitive_(other.case_sensitive_) {
75   if (type_ == Type::kSafeRegex) {
76     regex_matcher_ = std::move(other.regex_matcher_);
77   } else {
78     string_matcher_ = std::move(other.string_matcher_);
79   }
80 }
81 
operator =(StringMatcher && other)82 StringMatcher& StringMatcher::operator=(StringMatcher&& other) noexcept {
83   type_ = other.type_;
84   if (type_ == Type::kSafeRegex) {
85     regex_matcher_ = std::move(other.regex_matcher_);
86   } else {
87     string_matcher_ = std::move(other.string_matcher_);
88   }
89   case_sensitive_ = other.case_sensitive_;
90   return *this;
91 }
92 
operator ==(const StringMatcher & other) const93 bool StringMatcher::operator==(const StringMatcher& other) const {
94   if (type_ != other.type_ || case_sensitive_ != other.case_sensitive_) {
95     return false;
96   }
97   if (type_ == Type::kSafeRegex) {
98     return regex_matcher_->pattern() == other.regex_matcher_->pattern();
99   } else {
100     return string_matcher_ == other.string_matcher_;
101   }
102 }
103 
Match(absl::string_view value) const104 bool StringMatcher::Match(absl::string_view value) const {
105   switch (type_) {
106     case Type::kExact:
107       return case_sensitive_ ? value == string_matcher_
108                              : absl::EqualsIgnoreCase(value, string_matcher_);
109     case StringMatcher::Type::kPrefix:
110       return case_sensitive_
111                  ? absl::StartsWith(value, string_matcher_)
112                  : absl::StartsWithIgnoreCase(value, string_matcher_);
113     case StringMatcher::Type::kSuffix:
114       return case_sensitive_ ? absl::EndsWith(value, string_matcher_)
115                              : absl::EndsWithIgnoreCase(value, string_matcher_);
116     case StringMatcher::Type::kContains:
117       return case_sensitive_
118                  ? absl::StrContains(value, string_matcher_)
119                  : absl::StrContains(absl::AsciiStrToLower(value),
120                                      absl::AsciiStrToLower(string_matcher_));
121     case StringMatcher::Type::kSafeRegex:
122       return RE2::FullMatch(std::string(value), *regex_matcher_);
123     default:
124       return false;
125   }
126 }
127 
ToString() const128 std::string StringMatcher::ToString() const {
129   switch (type_) {
130     case Type::kExact:
131       return absl::StrFormat("StringMatcher{exact=%s%s}", string_matcher_,
132                              case_sensitive_ ? "" : ", case_sensitive=false");
133     case Type::kPrefix:
134       return absl::StrFormat("StringMatcher{prefix=%s%s}", string_matcher_,
135                              case_sensitive_ ? "" : ", case_sensitive=false");
136     case Type::kSuffix:
137       return absl::StrFormat("StringMatcher{suffix=%s%s}", string_matcher_,
138                              case_sensitive_ ? "" : ", case_sensitive=false");
139     case Type::kContains:
140       return absl::StrFormat("StringMatcher{contains=%s%s}", string_matcher_,
141                              case_sensitive_ ? "" : ", case_sensitive=false");
142     case Type::kSafeRegex:
143       return absl::StrFormat("StringMatcher{safe_regex=%s}",
144                              regex_matcher_->pattern());
145     default:
146       return "";
147   }
148 }
149 
150 //
151 // HeaderMatcher
152 //
153 
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)154 absl::StatusOr<HeaderMatcher> HeaderMatcher::Create(
155     absl::string_view name, Type type, absl::string_view matcher,
156     int64_t range_start, int64_t range_end, bool present_match,
157     bool invert_match) {
158   if (static_cast<int>(type) < 5) {
159     // Only for EXACT, PREFIX, SUFFIX, SAFE_REGEX and CONTAINS.
160     absl::StatusOr<StringMatcher> string_matcher =
161         StringMatcher::Create(static_cast<StringMatcher::Type>(type), matcher,
162                               /*case_sensitive=*/true);
163     if (!string_matcher.ok()) {
164       return string_matcher.status();
165     }
166     return HeaderMatcher(name, type, std::move(string_matcher.value()),
167                          invert_match);
168   } else if (type == Type::kRange) {
169     if (range_start > range_end) {
170       return absl::InvalidArgumentError(
171           "Invalid range specifier specified: end cannot be smaller than "
172           "start.");
173     }
174     return HeaderMatcher(name, range_start, range_end, invert_match);
175   } else {
176     return HeaderMatcher(name, present_match, invert_match);
177   }
178 }
179 
HeaderMatcher(absl::string_view name,Type type,StringMatcher string_matcher,bool invert_match)180 HeaderMatcher::HeaderMatcher(absl::string_view name, Type type,
181                              StringMatcher string_matcher, bool invert_match)
182     : name_(name),
183       type_(type),
184       matcher_(std::move(string_matcher)),
185       invert_match_(invert_match) {}
186 
HeaderMatcher(absl::string_view name,int64_t range_start,int64_t range_end,bool invert_match)187 HeaderMatcher::HeaderMatcher(absl::string_view name, int64_t range_start,
188                              int64_t range_end, bool invert_match)
189     : name_(name),
190       type_(Type::kRange),
191       range_start_(range_start),
192       range_end_(range_end),
193       invert_match_(invert_match) {}
194 
HeaderMatcher(absl::string_view name,bool present_match,bool invert_match)195 HeaderMatcher::HeaderMatcher(absl::string_view name, bool present_match,
196                              bool invert_match)
197     : name_(name),
198       type_(Type::kPresent),
199       present_match_(present_match),
200       invert_match_(invert_match) {}
201 
HeaderMatcher(const HeaderMatcher & other)202 HeaderMatcher::HeaderMatcher(const HeaderMatcher& other)
203     : name_(other.name_),
204       type_(other.type_),
205       invert_match_(other.invert_match_) {
206   switch (type_) {
207     case Type::kRange:
208       range_start_ = other.range_start_;
209       range_end_ = other.range_end_;
210       break;
211     case Type::kPresent:
212       present_match_ = other.present_match_;
213       break;
214     default:
215       matcher_ = other.matcher_;
216   }
217 }
218 
operator =(const HeaderMatcher & other)219 HeaderMatcher& HeaderMatcher::operator=(const HeaderMatcher& other) {
220   name_ = other.name_;
221   type_ = other.type_;
222   invert_match_ = other.invert_match_;
223   switch (type_) {
224     case Type::kRange:
225       range_start_ = other.range_start_;
226       range_end_ = other.range_end_;
227       break;
228     case Type::kPresent:
229       present_match_ = other.present_match_;
230       break;
231     default:
232       matcher_ = other.matcher_;
233   }
234   return *this;
235 }
236 
HeaderMatcher(HeaderMatcher && other)237 HeaderMatcher::HeaderMatcher(HeaderMatcher&& other) noexcept
238     : name_(std::move(other.name_)),
239       type_(other.type_),
240       invert_match_(other.invert_match_) {
241   switch (type_) {
242     case Type::kRange:
243       range_start_ = other.range_start_;
244       range_end_ = other.range_end_;
245       break;
246     case Type::kPresent:
247       present_match_ = other.present_match_;
248       break;
249     default:
250       matcher_ = std::move(other.matcher_);
251   }
252 }
253 
operator =(HeaderMatcher && other)254 HeaderMatcher& HeaderMatcher::operator=(HeaderMatcher&& other) noexcept {
255   name_ = std::move(other.name_);
256   type_ = other.type_;
257   invert_match_ = other.invert_match_;
258   switch (type_) {
259     case Type::kRange:
260       range_start_ = other.range_start_;
261       range_end_ = other.range_end_;
262       break;
263     case Type::kPresent:
264       present_match_ = other.present_match_;
265       break;
266     default:
267       matcher_ = std::move(other.matcher_);
268   }
269   return *this;
270 }
271 
operator ==(const HeaderMatcher & other) const272 bool HeaderMatcher::operator==(const HeaderMatcher& other) const {
273   if (name_ != other.name_) return false;
274   if (type_ != other.type_) return false;
275   if (invert_match_ != other.invert_match_) return false;
276   switch (type_) {
277     case Type::kRange:
278       return range_start_ == other.range_start_ &&
279              range_end_ == other.range_end_;
280     case Type::kPresent:
281       return present_match_ == other.present_match_;
282     default:
283       return matcher_ == other.matcher_;
284   }
285 }
286 
Match(const absl::optional<absl::string_view> & value) const287 bool HeaderMatcher::Match(
288     const absl::optional<absl::string_view>& value) const {
289   bool match;
290   if (type_ == Type::kPresent) {
291     match = value.has_value() == present_match_;
292   } else if (!value.has_value()) {
293     // All other types fail to match if field is not present.
294     match = false;
295   } else if (type_ == Type::kRange) {
296     int64_t int_value;
297     match = absl::SimpleAtoi(value.value(), &int_value) &&
298             int_value >= range_start_ && int_value < range_end_;
299   } else {
300     match = matcher_.Match(value.value());
301   }
302   return match != invert_match_;
303 }
304 
ToString() const305 std::string HeaderMatcher::ToString() const {
306   switch (type_) {
307     case Type::kRange:
308       return absl::StrFormat("HeaderMatcher{%s %srange=[%d, %d]}", name_,
309                              invert_match_ ? "not " : "", range_start_,
310                              range_end_);
311     case Type::kPresent:
312       return absl::StrFormat("HeaderMatcher{%s %spresent=%s}", name_,
313                              invert_match_ ? "not " : "",
314                              present_match_ ? "true" : "false");
315     case Type::kExact:
316     case Type::kPrefix:
317     case Type::kSuffix:
318     case Type::kSafeRegex:
319     case Type::kContains:
320       return absl::StrFormat("HeaderMatcher{%s %s%s}", name_,
321                              invert_match_ ? "not " : "", matcher_.ToString());
322     default:
323       return "";
324   }
325 }
326 
327 }  // namespace grpc_core
328