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