Line data Source code
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 : * The result of a field match. 12 : */ 13 : struct FieldMatchResult { 14 : // Encodes whether we were able to perform the match. 15 : MatchState match_state_; 16 : 17 : // The result, if matching was completed. 18 : absl::optional<bool> result_; 19 : 20 : // The unwrapped result. Should only be called if match_state_ == MatchComplete. 21 0 : bool result() const { 22 0 : ASSERT(match_state_ == MatchState::MatchComplete); 23 0 : ASSERT(result_.has_value()); 24 0 : return *result_; 25 0 : } 26 : }; 27 : 28 : /** 29 : * Base class for matching against a single input. 30 : */ 31 : template <class DataType> class FieldMatcher { 32 : public: 33 0 : virtual ~FieldMatcher() = default; 34 : 35 : /** 36 : * Attempts to match against the provided data. 37 : * @returns absl::optional<bool> if matching was possible, the result of the match. Otherwise 38 : * absl::nullopt if the data is not available. 39 : */ 40 : virtual FieldMatchResult match(const DataType& data) PURE; 41 : }; 42 : template <class DataType> using FieldMatcherPtr = std::unique_ptr<FieldMatcher<DataType>>; 43 : 44 : /** 45 : * A FieldMatcher that attempts to match multiple FieldMatchers, evaluating to true iff all the 46 : * FieldMatchers evaluate to true. 47 : * 48 : * If any of the underlying FieldMatchers are unable to produce a result, absl::nullopt is returned. 49 : */ 50 : template <class DataType> class AllFieldMatcher : public FieldMatcher<DataType> { 51 : public: 52 : explicit AllFieldMatcher(std::vector<FieldMatcherPtr<DataType>>&& matchers) 53 0 : : matchers_(std::move(matchers)) {} 54 : 55 0 : FieldMatchResult match(const DataType& data) override { 56 0 : for (const auto& matcher : matchers_) { 57 0 : const auto result = matcher->match(data); 58 : 59 : // If we are unable to decide on a match at this point, propagate this up to defer 60 : // the match result until we have the requisite data. 61 0 : if (result.match_state_ == MatchState::UnableToMatch) { 62 0 : return result; 63 0 : } 64 : 65 0 : if (!result.result()) { 66 0 : return result; 67 0 : } 68 0 : } 69 : 70 0 : return {MatchState::MatchComplete, true}; 71 0 : } 72 : 73 : private: 74 : const std::vector<FieldMatcherPtr<DataType>> matchers_; 75 : }; 76 : 77 : /** 78 : * A FieldMatcher that attempts to match multiple FieldMatchers, evaluating to true iff any of the 79 : * FieldMatchers evaluate to true. 80 : * 81 : * If any of the underlying FieldMatchers are unable to produce a result before we see a successful 82 : * match, absl::nullopt is returned. 83 : */ 84 : template <class DataType> class AnyFieldMatcher : public FieldMatcher<DataType> { 85 : public: 86 : explicit AnyFieldMatcher(std::vector<FieldMatcherPtr<DataType>>&& matchers) 87 0 : : matchers_(std::move(matchers)) {} 88 : 89 0 : FieldMatchResult match(const DataType& data) override { 90 0 : bool unable_to_match_some_matchers = false; 91 0 : for (const auto& matcher : matchers_) { 92 0 : const auto result = matcher->match(data); 93 : 94 0 : if (result.match_state_ == MatchState::UnableToMatch) { 95 0 : unable_to_match_some_matchers = true; 96 0 : continue; 97 0 : } 98 : 99 0 : if (result.result()) { 100 0 : return {MatchState::MatchComplete, true}; 101 0 : } 102 0 : } 103 : 104 : // If we didn't find a successful match but not all matchers could be evaluated, 105 : // return UnableToMatch to defer the match result. 106 0 : if (unable_to_match_some_matchers) { 107 0 : return {MatchState::UnableToMatch, absl::nullopt}; 108 0 : } 109 : 110 0 : return {MatchState::MatchComplete, false}; 111 0 : } 112 : 113 : private: 114 : const std::vector<FieldMatcherPtr<DataType>> matchers_; 115 : }; 116 : 117 : /** 118 : * A FieldMatcher that returns the invert of a FieldMatcher. 119 : */ 120 : template <class DataType> class NotFieldMatcher : public FieldMatcher<DataType> { 121 : public: 122 0 : explicit NotFieldMatcher(FieldMatcherPtr<DataType> matcher) : matcher_(std::move(matcher)) {} 123 : 124 0 : FieldMatchResult match(const DataType& data) override { 125 0 : const auto result = matcher_->match(data); 126 0 : if (result.match_state_ == MatchState::UnableToMatch) { 127 0 : return result; 128 0 : } 129 : 130 0 : return {MatchState::MatchComplete, !result.result()}; 131 0 : } 132 : 133 : private: 134 : const FieldMatcherPtr<DataType> matcher_; 135 : }; 136 : 137 : /** 138 : * Implementation of a FieldMatcher that extracts an input value from the provided data and attempts 139 : * to match using an InputMatcher. absl::nullopt is returned whenever the data is not available or 140 : * if we failed to match and there is more data available. 141 : * A consequence of this is that if a match result is desired, care should be taken so that matching 142 : * is done with all the data available at some point. 143 : */ 144 : template <class DataType> 145 : class SingleFieldMatcher : public FieldMatcher<DataType>, Logger::Loggable<Logger::Id::matcher> { 146 : public: 147 : SingleFieldMatcher(DataInputPtr<DataType>&& data_input, InputMatcherPtr&& input_matcher) 148 0 : : data_input_(std::move(data_input)), input_matcher_(std::move(input_matcher)) { 149 0 : auto supported_input_types = input_matcher_->supportedDataInputTypes(); 150 0 : if (supported_input_types.find(data_input_->dataInputType()) == supported_input_types.end()) { 151 0 : std::string supported_types = 152 0 : absl::StrJoin(supported_input_types.begin(), supported_input_types.end(), ", "); 153 0 : throwEnvoyExceptionOrPanic( 154 0 : absl::StrCat("Unsupported data input type: ", data_input_->dataInputType(), 155 0 : ". The matcher supports input type: ", supported_types)); 156 0 : } 157 0 : } 158 : 159 0 : FieldMatchResult match(const DataType& data) override { 160 0 : const auto input = data_input_->get(data); 161 : 162 0 : ENVOY_LOG(trace, "Attempting to match {}", input); 163 0 : if (input.data_availability_ == DataInputGetResult::DataAvailability::NotAvailable) { 164 0 : return {MatchState::UnableToMatch, absl::nullopt}; 165 0 : } 166 : 167 0 : bool current_match = input_matcher_->match(input.data_); 168 0 : if (!current_match && input.data_availability_ == 169 0 : DataInputGetResult::DataAvailability::MoreDataMightBeAvailable) { 170 0 : ENVOY_LOG(trace, "No match yet; delaying result as more data might be available."); 171 0 : return {MatchState::UnableToMatch, absl::nullopt}; 172 0 : } 173 : 174 0 : ENVOY_LOG(trace, "Match result: {}", current_match); 175 : 176 0 : return {MatchState::MatchComplete, current_match}; 177 0 : } 178 : 179 : private: 180 : const DataInputPtr<DataType> data_input_; 181 : const InputMatcherPtr input_matcher_; 182 : }; 183 : 184 : template <class DataType> 185 : using SingleFieldMatcherPtr = std::unique_ptr<SingleFieldMatcher<DataType>>; 186 : } // namespace Matcher 187 : } // namespace Envoy