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