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