1
#pragma once
2

            
3
#include "envoy/matcher/matcher.h"
4

            
5
#include "absl/strings/str_join.h"
6

            
7
namespace Envoy {
8
namespace Matcher {
9

            
10
/**
11
 * Base class for matching against a single input.
12
 */
13
template <class DataType> class FieldMatcher {
14
public:
15
1611
  virtual ~FieldMatcher() = default;
16

            
17
  /**
18
   * Attempts to match against the provided data.
19
   */
20
  virtual MatchResult match(const DataType& data) PURE;
21
};
22
template <class DataType> using FieldMatcherPtr = std::unique_ptr<FieldMatcher<DataType>>;
23

            
24
/**
25
 * A FieldMatcher that attempts to match multiple FieldMatchers, evaluating to true iff all the
26
 * FieldMatchers evaluate to true.
27
 *
28
 * If any of the underlying FieldMatchers are unable to produce a result, absl::nullopt is returned.
29
 */
30
template <class DataType> class AllFieldMatcher : public FieldMatcher<DataType> {
31
public:
32
  explicit AllFieldMatcher(std::vector<FieldMatcherPtr<DataType>>&& matchers)
33
32
      : matchers_(std::move(matchers)) {}
34

            
35
40
  MatchResult match(const DataType& data) override {
36
83
    for (const auto& matcher : matchers_) {
37
83
      const MatchResult result = matcher->match(data);
38

            
39
      // If we are unable to decide on a match at this point, propagate this up to defer
40
      // the match result until we have the requisite data.
41
83
      if (result == MatchResult::InsufficientData) {
42
8
        return result;
43
8
      }
44

            
45
75
      if (result == MatchResult::NoMatch) {
46
15
        return result;
47
15
      }
48
75
    }
49

            
50
17
    return MatchResult::Matched;
51
40
  }
52

            
53
private:
54
  const std::vector<FieldMatcherPtr<DataType>> matchers_;
55
};
56

            
57
/**
58
 * A FieldMatcher that attempts to match multiple FieldMatchers, evaluating to true iff any of the
59
 * FieldMatchers evaluate to true.
60
 *
61
 * If any of the underlying FieldMatchers are unable to produce a result before we see a successful
62
 * match, absl::nullopt is returned.
63
 */
64
template <class DataType> class AnyFieldMatcher : public FieldMatcher<DataType> {
65
public:
66
  explicit AnyFieldMatcher(std::vector<FieldMatcherPtr<DataType>>&& matchers)
67
178
      : matchers_(std::move(matchers)) {}
68

            
69
138
  MatchResult match(const DataType& data) override {
70
138
    bool unable_to_match_some_matchers = false;
71
272
    for (const auto& matcher : matchers_) {
72
272
      const MatchResult result = matcher->match(data);
73

            
74
272
      if (result == MatchResult::InsufficientData) {
75
2
        unable_to_match_some_matchers = true;
76
2
        continue;
77
2
      }
78

            
79
270
      if (result == MatchResult::Matched) {
80
79
        return result;
81
79
      }
82
270
    }
83

            
84
    // If we didn't find a successful match but not all matchers could be evaluated,
85
    // return InsufficientData to defer the match result.
86
59
    if (unable_to_match_some_matchers) {
87
1
      return MatchResult::InsufficientData;
88
1
    }
89

            
90
58
    return MatchResult::NoMatch;
91
59
  }
92

            
93
private:
94
  const std::vector<FieldMatcherPtr<DataType>> matchers_;
95
};
96

            
97
/**
98
 * A FieldMatcher that returns the invert of a FieldMatcher.
99
 */
100
template <class DataType> class NotFieldMatcher : public FieldMatcher<DataType> {
101
public:
102
3
  explicit NotFieldMatcher(FieldMatcherPtr<DataType> matcher) : matcher_(std::move(matcher)) {}
103

            
104
3
  MatchResult match(const DataType& data) override {
105
3
    const MatchResult result = matcher_->match(data);
106
3
    if (result == MatchResult::InsufficientData) {
107
1
      return result;
108
1
    }
109
2
    return (result == MatchResult::Matched) ? MatchResult::NoMatch : MatchResult::Matched;
110
3
  }
111

            
112
private:
113
  const FieldMatcherPtr<DataType> matcher_;
114
};
115

            
116
/**
117
 * Implementation of a FieldMatcher that extracts an input value from the provided data and attempts
118
 * to match using an InputMatcher. InsufficientData is returned whenever the data is not available
119
 * or if we failed to match and there may be more data available later. A consequence of this is
120
 * that if a match result is desired, care should be taken so that matching is done with all the
121
 * data available at some point.
122
 */
123
template <class DataType>
124
class SingleFieldMatcher : public FieldMatcher<DataType>, Logger::Loggable<Logger::Id::matcher> {
125
public:
126
  static absl::StatusOr<std::unique_ptr<SingleFieldMatcher<DataType>>>
127
1400
  create(DataInputPtr<DataType>&& data_input, InputMatcherPtr&& input_matcher) {
128
1400
    const bool supported = input_matcher->supportsDataInputType(data_input->dataInputType());
129
1400
    if (!supported) {
130
2
      return absl::InvalidArgumentError(
131
2
          absl::StrCat("Unsupported data input type: ", data_input->dataInputType()));
132
2
    }
133

            
134
1398
    return std::unique_ptr<SingleFieldMatcher<DataType>>{
135
1398
        new SingleFieldMatcher<DataType>(std::move(data_input), std::move(input_matcher))};
136
1400
  }
137

            
138
2633
  MatchResult match(const DataType& data) override {
139
2633
    const auto input = data_input_->get(data);
140

            
141
2633
    if (input.availability() == DataAvailability::NotAvailable) {
142
12
      return MatchResult::InsufficientData;
143
12
    }
144

            
145
2621
    MatchResult current_match = input_matcher_->match(input);
146
2621
    if (current_match != MatchResult::Matched &&
147
2621
        input.availability() == DataAvailability::MoreDataMightBeAvailable) {
148
5
      return MatchResult::InsufficientData;
149
5
    }
150

            
151
2616
    return current_match;
152
2621
  }
153

            
154
private:
155
  SingleFieldMatcher(DataInputPtr<DataType>&& data_input, InputMatcherPtr&& input_matcher)
156
1398
      : data_input_(std::move(data_input)), input_matcher_(std::move(input_matcher)) {}
157

            
158
  const DataInputPtr<DataType> data_input_;
159
  const InputMatcherPtr input_matcher_;
160
};
161

            
162
template <class DataType>
163
using SingleFieldMatcherPtr = std::unique_ptr<SingleFieldMatcher<DataType>>;
164
} // namespace Matcher
165
} // namespace Envoy