Coverage Report

Created: 2024-09-19 09:45

/proc/self/cwd/source/common/common/matchers.h
Line
Count
Source (jump to first uncovered line)
1
#pragma once
2
3
#include <string>
4
5
#include "envoy/common/exception.h"
6
#include "envoy/common/matchers.h"
7
#include "envoy/common/regex.h"
8
#include "envoy/config/core/v3/base.pb.h"
9
#include "envoy/type/matcher/v3/filter_state.pb.h"
10
#include "envoy/type/matcher/v3/metadata.pb.h"
11
#include "envoy/type/matcher/v3/number.pb.h"
12
#include "envoy/type/matcher/v3/path.pb.h"
13
#include "envoy/type/matcher/v3/string.pb.h"
14
#include "envoy/type/matcher/v3/value.pb.h"
15
16
#include "source/common/common/regex.h"
17
#include "source/common/common/utility.h"
18
#include "source/common/protobuf/protobuf.h"
19
20
#include "absl/strings/match.h"
21
22
namespace Envoy {
23
namespace Matchers {
24
25
class ValueMatcher;
26
using ValueMatcherConstSharedPtr = std::shared_ptr<const ValueMatcher>;
27
28
class PathMatcher;
29
using PathMatcherConstSharedPtr = std::shared_ptr<const PathMatcher>;
30
31
class ValueMatcher {
32
public:
33
262k
  virtual ~ValueMatcher() = default;
34
35
  /**
36
   * Check whether the value is matched to the matcher.
37
   */
38
  virtual bool match(const ProtobufWkt::Value& value) const PURE;
39
40
  /**
41
   * Create the matcher object.
42
   */
43
  static ValueMatcherConstSharedPtr create(const envoy::type::matcher::v3::ValueMatcher& value,
44
                                           Server::Configuration::CommonFactoryContext& context);
45
};
46
47
class NullMatcher : public ValueMatcher {
48
public:
49
  /**
50
   * Check whether the value is NULL.
51
   */
52
  bool match(const ProtobufWkt::Value& value) const override;
53
};
54
55
class BoolMatcher : public ValueMatcher {
56
public:
57
14.3k
  BoolMatcher(bool matcher) : matcher_(matcher) {}
58
59
  bool match(const ProtobufWkt::Value& value) const override;
60
61
private:
62
  const bool matcher_;
63
};
64
65
class PresentMatcher : public ValueMatcher {
66
public:
67
19.5k
  PresentMatcher(bool matcher) : matcher_(matcher) {}
68
69
  bool match(const ProtobufWkt::Value& value) const override;
70
71
private:
72
  const bool matcher_;
73
};
74
75
class DoubleMatcher : public ValueMatcher {
76
public:
77
3.62k
  DoubleMatcher(const envoy::type::matcher::v3::DoubleMatcher& matcher) : matcher_(matcher) {}
78
79
  bool match(const ProtobufWkt::Value& value) const override;
80
81
private:
82
  const envoy::type::matcher::v3::DoubleMatcher matcher_;
83
};
84
85
class UniversalStringMatcher : public StringMatcher {
86
public:
87
66
  bool match(absl::string_view) const override { return true; }
88
};
89
90
StringMatcherPtr getExtensionStringMatcher(const ::xds::core::v3::TypedExtensionConfig& config,
91
                                           Server::Configuration::CommonFactoryContext& context);
92
93
template <class StringMatcherType = envoy::type::matcher::v3::StringMatcher>
94
class StringMatcherImpl : public ValueMatcher, public StringMatcher {
95
public:
96
  explicit StringMatcherImpl(const StringMatcherType& matcher,
97
                             Server::Configuration::CommonFactoryContext& context)
98
171k
      : matcher_(matcher) {
99
171k
    if (matcher.match_pattern_case() == StringMatcherType::MatchPatternCase::kSafeRegex) {
100
21.0k
      if (matcher.ignore_case()) {
101
89
        ExceptionUtil::throwEnvoyException("ignore_case has no effect for safe_regex.");
102
89
      }
103
21.0k
      regex_ = Regex::Utility::parseRegex(matcher_.safe_regex(), context.regexEngine());
104
150k
    } else if (matcher.match_pattern_case() == StringMatcherType::MatchPatternCase::kContains) {
105
17.6k
      if (matcher_.ignore_case()) {
106
        // Cache the lowercase conversion of the Contains matcher for future use
107
6.00k
        lowercase_contains_match_ = absl::AsciiStrToLower(matcher_.contains());
108
6.00k
      }
109
132k
    } else if (matcher.has_custom()) {
110
682
      custom_ = getExtensionStringMatcher(matcher.custom(), context);
111
682
    }
112
171k
  }
Envoy::Matchers::StringMatcherImpl<envoy::type::matcher::v3::StringMatcher>::StringMatcherImpl(envoy::type::matcher::v3::StringMatcher const&, Envoy::Server::Configuration::CommonFactoryContext&)
Line
Count
Source
98
159k
      : matcher_(matcher) {
99
159k
    if (matcher.match_pattern_case() == StringMatcherType::MatchPatternCase::kSafeRegex) {
100
20.8k
      if (matcher.ignore_case()) {
101
85
        ExceptionUtil::throwEnvoyException("ignore_case has no effect for safe_regex.");
102
85
      }
103
20.8k
      regex_ = Regex::Utility::parseRegex(matcher_.safe_regex(), context.regexEngine());
104
138k
    } else if (matcher.match_pattern_case() == StringMatcherType::MatchPatternCase::kContains) {
105
15.3k
      if (matcher_.ignore_case()) {
106
        // Cache the lowercase conversion of the Contains matcher for future use
107
5.29k
        lowercase_contains_match_ = absl::AsciiStrToLower(matcher_.contains());
108
5.29k
      }
109
123k
    } else if (matcher.has_custom()) {
110
650
      custom_ = getExtensionStringMatcher(matcher.custom(), context);
111
650
    }
112
159k
  }
Envoy::Matchers::StringMatcherImpl<xds::type::matcher::v3::StringMatcher>::StringMatcherImpl(xds::type::matcher::v3::StringMatcher const&, Envoy::Server::Configuration::CommonFactoryContext&)
Line
Count
Source
98
11.8k
      : matcher_(matcher) {
99
11.8k
    if (matcher.match_pattern_case() == StringMatcherType::MatchPatternCase::kSafeRegex) {
100
169
      if (matcher.ignore_case()) {
101
4
        ExceptionUtil::throwEnvoyException("ignore_case has no effect for safe_regex.");
102
4
      }
103
169
      regex_ = Regex::Utility::parseRegex(matcher_.safe_regex(), context.regexEngine());
104
11.6k
    } else if (matcher.match_pattern_case() == StringMatcherType::MatchPatternCase::kContains) {
105
2.35k
      if (matcher_.ignore_case()) {
106
        // Cache the lowercase conversion of the Contains matcher for future use
107
708
        lowercase_contains_match_ = absl::AsciiStrToLower(matcher_.contains());
108
708
      }
109
9.32k
    } else if (matcher.has_custom()) {
110
32
      custom_ = getExtensionStringMatcher(matcher.custom(), context);
111
32
    }
112
11.8k
  }
113
114
  // StringMatcher
115
128k
  bool match(const absl::string_view value) const override {
116
128k
    switch (matcher_.match_pattern_case()) {
117
60.8k
    case StringMatcherType::MatchPatternCase::kExact:
118
60.8k
      return matcher_.ignore_case() ? absl::EqualsIgnoreCase(value, matcher_.exact())
119
60.8k
                                    : value == matcher_.exact();
120
32.6k
    case StringMatcherType::MatchPatternCase::kPrefix:
121
32.6k
      return matcher_.ignore_case() ? absl::StartsWithIgnoreCase(value, matcher_.prefix())
122
32.6k
                                    : absl::StartsWith(value, matcher_.prefix());
123
8.64k
    case StringMatcherType::MatchPatternCase::kSuffix:
124
8.64k
      return matcher_.ignore_case() ? absl::EndsWithIgnoreCase(value, matcher_.suffix())
125
8.64k
                                    : absl::EndsWith(value, matcher_.suffix());
126
18.3k
    case StringMatcherType::MatchPatternCase::kContains:
127
18.3k
      return matcher_.ignore_case()
128
18.3k
                 ? absl::StrContains(absl::AsciiStrToLower(value), lowercase_contains_match_)
129
18.3k
                 : absl::StrContains(value, matcher_.contains());
130
7.97k
    case StringMatcherType::MatchPatternCase::kSafeRegex:
131
7.97k
      return regex_->match(value);
132
0
    case StringMatcherType::MatchPatternCase::kCustom:
133
0
      return custom_->match(value);
134
0
    default:
135
0
      PANIC("unexpected");
136
128k
    }
137
128k
  }
Envoy::Matchers::StringMatcherImpl<envoy::type::matcher::v3::StringMatcher>::match(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const
Line
Count
Source
115
123k
  bool match(const absl::string_view value) const override {
116
123k
    switch (matcher_.match_pattern_case()) {
117
58.5k
    case StringMatcherType::MatchPatternCase::kExact:
118
58.5k
      return matcher_.ignore_case() ? absl::EqualsIgnoreCase(value, matcher_.exact())
119
58.5k
                                    : value == matcher_.exact();
120
31.8k
    case StringMatcherType::MatchPatternCase::kPrefix:
121
31.8k
      return matcher_.ignore_case() ? absl::StartsWithIgnoreCase(value, matcher_.prefix())
122
31.8k
                                    : absl::StartsWith(value, matcher_.prefix());
123
7.87k
    case StringMatcherType::MatchPatternCase::kSuffix:
124
7.87k
      return matcher_.ignore_case() ? absl::EndsWithIgnoreCase(value, matcher_.suffix())
125
7.87k
                                    : absl::EndsWith(value, matcher_.suffix());
126
17.0k
    case StringMatcherType::MatchPatternCase::kContains:
127
17.0k
      return matcher_.ignore_case()
128
17.0k
                 ? absl::StrContains(absl::AsciiStrToLower(value), lowercase_contains_match_)
129
17.0k
                 : absl::StrContains(value, matcher_.contains());
130
7.94k
    case StringMatcherType::MatchPatternCase::kSafeRegex:
131
7.94k
      return regex_->match(value);
132
0
    case StringMatcherType::MatchPatternCase::kCustom:
133
0
      return custom_->match(value);
134
0
    default:
135
0
      PANIC("unexpected");
136
123k
    }
137
123k
  }
Envoy::Matchers::StringMatcherImpl<xds::type::matcher::v3::StringMatcher>::match(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const
Line
Count
Source
115
5.25k
  bool match(const absl::string_view value) const override {
116
5.25k
    switch (matcher_.match_pattern_case()) {
117
2.29k
    case StringMatcherType::MatchPatternCase::kExact:
118
2.29k
      return matcher_.ignore_case() ? absl::EqualsIgnoreCase(value, matcher_.exact())
119
2.29k
                                    : value == matcher_.exact();
120
891
    case StringMatcherType::MatchPatternCase::kPrefix:
121
891
      return matcher_.ignore_case() ? absl::StartsWithIgnoreCase(value, matcher_.prefix())
122
891
                                    : absl::StartsWith(value, matcher_.prefix());
123
766
    case StringMatcherType::MatchPatternCase::kSuffix:
124
766
      return matcher_.ignore_case() ? absl::EndsWithIgnoreCase(value, matcher_.suffix())
125
766
                                    : absl::EndsWith(value, matcher_.suffix());
126
1.27k
    case StringMatcherType::MatchPatternCase::kContains:
127
1.27k
      return matcher_.ignore_case()
128
1.27k
                 ? absl::StrContains(absl::AsciiStrToLower(value), lowercase_contains_match_)
129
1.27k
                 : absl::StrContains(value, matcher_.contains());
130
30
    case StringMatcherType::MatchPatternCase::kSafeRegex:
131
30
      return regex_->match(value);
132
0
    case StringMatcherType::MatchPatternCase::kCustom:
133
0
      return custom_->match(value);
134
0
    default:
135
0
      PANIC("unexpected");
136
5.25k
    }
137
5.25k
  }
138
139
7.38k
  bool match(const ProtobufWkt::Value& value) const override {
140
141
7.38k
    if (value.kind_case() != ProtobufWkt::Value::kStringValue) {
142
6.21k
      return false;
143
6.21k
    }
144
145
1.17k
    return match(value.string_value());
146
7.38k
  }
Envoy::Matchers::StringMatcherImpl<envoy::type::matcher::v3::StringMatcher>::match(google::protobuf::Value const&) const
Line
Count
Source
139
7.38k
  bool match(const ProtobufWkt::Value& value) const override {
140
141
7.38k
    if (value.kind_case() != ProtobufWkt::Value::kStringValue) {
142
6.21k
      return false;
143
6.21k
    }
144
145
1.17k
    return match(value.string_value());
146
7.38k
  }
Unexecuted instantiation: Envoy::Matchers::StringMatcherImpl<xds::type::matcher::v3::StringMatcher>::match(google::protobuf::Value const&) const
147
148
1.17k
  const StringMatcherType& matcher() const { return matcher_; }
149
150
  /**
151
   * Helps applications optimize the case where a matcher is a case-sensitive
152
   * prefix-match.
153
   *
154
   * @param prefix the returned prefix string
155
   * @return true if the matcher is a case-sensitive prefix-match.
156
   */
157
8.83k
  bool getCaseSensitivePrefixMatch(std::string& prefix) const {
158
8.83k
    if (matcher_.match_pattern_case() ==
159
8.83k
            envoy::type::matcher::v3::StringMatcher::MatchPatternCase::kPrefix &&
160
8.83k
        !matcher_.ignore_case()) {
161
4.65k
      prefix = matcher_.prefix();
162
4.65k
      return true;
163
4.65k
    }
164
4.18k
    return false;
165
8.83k
  }
166
167
private:
168
  const StringMatcherType matcher_;
169
  Regex::CompiledMatcherPtr regex_;
170
  std::string lowercase_contains_match_;
171
  StringMatcherPtr custom_;
172
};
173
174
class StringMatcherExtensionFactory : public Config::TypedFactory {
175
public:
176
  virtual StringMatcherPtr
177
  createStringMatcher(const Protobuf::Message& config,
178
                      Server::Configuration::CommonFactoryContext& context) PURE;
179
180
8
  std::string category() const override { return "envoy.string_matcher"; }
181
};
182
183
class ListMatcher : public ValueMatcher {
184
public:
185
  ListMatcher(const envoy::type::matcher::v3::ListMatcher& matcher,
186
              Server::Configuration::CommonFactoryContext& context);
187
188
  bool match(const ProtobufWkt::Value& value) const override;
189
190
private:
191
  const envoy::type::matcher::v3::ListMatcher matcher_;
192
193
  ValueMatcherConstSharedPtr oneof_value_matcher_;
194
};
195
196
class OrMatcher : public ValueMatcher {
197
public:
198
  OrMatcher(const envoy::type::matcher::v3::OrMatcher& matcher,
199
            Server::Configuration::CommonFactoryContext& context);
200
201
  bool match(const ProtobufWkt::Value& value) const override;
202
203
private:
204
  std::vector<ValueMatcherConstSharedPtr> or_matchers_;
205
};
206
207
class MetadataMatcher {
208
public:
209
  MetadataMatcher(const envoy::type::matcher::v3::MetadataMatcher& matcher,
210
                  Server::Configuration::CommonFactoryContext& context);
211
212
  /**
213
   * Check whether the metadata is matched to the matcher.
214
   * @param metadata the metadata to check.
215
   * @return true if it's matched otherwise false.
216
   */
217
  bool match(const envoy::config::core::v3::Metadata& metadata) const;
218
219
private:
220
  const envoy::type::matcher::v3::MetadataMatcher matcher_;
221
  std::vector<std::string> path_;
222
223
  ValueMatcherConstSharedPtr value_matcher_;
224
};
225
226
class FilterStateMatcher {
227
public:
228
  FilterStateMatcher(const envoy::type::matcher::v3::FilterStateMatcher& matcher,
229
                     Server::Configuration::CommonFactoryContext& context);
230
231
  /**
232
   * Check whether the filter state object is matched to the matcher.
233
   * @param filter state to check.
234
   * @return true if it's matched otherwise false.
235
   */
236
  bool match(const StreamInfo::FilterState& filter_state) const;
237
238
private:
239
  const std::string key_;
240
  const StringMatcherPtr value_matcher_;
241
};
242
243
class PathMatcher : public StringMatcher {
244
public:
245
  PathMatcher(const envoy::type::matcher::v3::PathMatcher& path,
246
              Server::Configuration::CommonFactoryContext& context)
247
7.00k
      : matcher_(path.path(), context) {}
248
  PathMatcher(const envoy::type::matcher::v3::StringMatcher& matcher,
249
              Server::Configuration::CommonFactoryContext& context)
250
53.7k
      : matcher_(matcher, context) {}
251
252
  static PathMatcherConstSharedPtr
253
  createExact(const std::string& exact, bool ignore_case,
254
              Server::Configuration::CommonFactoryContext& context);
255
  static PathMatcherConstSharedPtr
256
  createPrefix(const std::string& prefix, bool ignore_case,
257
               Server::Configuration::CommonFactoryContext& context);
258
  static PathMatcherConstSharedPtr
259
  createPattern(const std::string& pattern, bool ignore_case,
260
                Server::Configuration::CommonFactoryContext& context);
261
  static PathMatcherConstSharedPtr
262
  createSafeRegex(const envoy::type::matcher::v3::RegexMatcher& regex_matcher,
263
                  Server::Configuration::CommonFactoryContext& context);
264
265
  bool match(const absl::string_view path) const override;
266
1.17k
  const StringMatcherImpl<envoy::type::matcher::v3::StringMatcher>& matcher() const {
267
1.17k
    return matcher_;
268
1.17k
  }
269
270
private:
271
  const StringMatcherImpl<envoy::type::matcher::v3::StringMatcher> matcher_;
272
};
273
274
} // namespace Matchers
275
} // namespace Envoy