1
#pragma once
2

            
3
#include <functional>
4
#include <memory>
5
#include <variant>
6

            
7
#include "envoy/config/common/matcher/v3/matcher.pb.h"
8
#include "envoy/config/core/v3/extension.pb.h"
9
#include "envoy/config/typed_config.h"
10
#include "envoy/matcher/matcher.h"
11

            
12
#include "source/common/common/assert.h"
13
#include "source/common/config/utility.h"
14
#include "source/common/matcher/exact_map_matcher.h"
15
#include "source/common/matcher/field_matcher.h"
16
#include "source/common/matcher/list_matcher.h"
17
#include "source/common/matcher/prefix_map_matcher.h"
18
#include "source/common/matcher/validation_visitor.h"
19
#include "source/common/matcher/value_input_matcher.h"
20

            
21
#include "absl/strings/string_view.h"
22
#include "absl/types/optional.h"
23

            
24
namespace Envoy {
25
namespace Matcher {
26

            
27
template <class ProtoType, class Base = Action> class ActionBase : public Base {
28
public:
29
14844
  template <typename... Args> ActionBase(Args... args) : Base(args...) {}
30

            
31
525
  absl::string_view typeUrl() const override { return staticTypeUrl(); }
32

            
33
679
  static absl::string_view staticTypeUrl() {
34
679
    const static std::string typeUrl(ProtoType().GetTypeName());
35
679
    return typeUrl;
36
679
  }
37
};
38

            
39
// TODO(snowp): Make this a class that tracks the progress to speed up subsequent traversals.
40
template <class DataType>
41
static inline ActionMatchResult evaluateMatch(MatchTree<DataType>& match_tree, const DataType& data,
42
3658
                                              SkippedMatchCb skipped_match_cb = nullptr) {
43
3658
  return match_tree.match(data, skipped_match_cb);
44
3658
}
45

            
46
template <class DataType> using FieldMatcherFactoryCb = std::function<FieldMatcherPtr<DataType>()>;
47

            
48
/**
49
 * A matcher that will always resolve to associated on_no_match. This is used when
50
 * the matcher is configured without a matcher, allowing for a tree that always resolves
51
 * to a specific OnMatch.
52
 */
53
template <class DataType> class AnyMatcher : public MatchTree<DataType> {
54
public:
55
  explicit AnyMatcher(absl::optional<OnMatch<DataType>> on_no_match)
56
225
      : on_no_match_(std::move(on_no_match)) {}
57

            
58
  ActionMatchResult match(const DataType& data,
59
2071
                          SkippedMatchCb skipped_match_cb = nullptr) override {
60
2071
    return MatchTree<DataType>::handleRecursionAndSkips(on_no_match_, data, skipped_match_cb);
61
2071
  }
62
  const absl::optional<OnMatch<DataType>> on_no_match_;
63
};
64

            
65
/**
66
 * Constructs a data input function for a data type.
67
 **/
68
template <class DataType> class MatchInputFactory {
69
public:
70
  MatchInputFactory(ProtobufMessage::ValidationVisitor& validator,
71
                    MatchTreeValidationVisitor<DataType>& validation_visitor)
72
1486
      : validator_(validator), validation_visitor_(validation_visitor) {}
73

            
74
1754
  DataInputFactoryCb<DataType> createDataInput(const xds::core::v3::TypedExtensionConfig& config) {
75
1754
    return createDataInputBase(config);
76
1754
  }
77

            
78
  DataInputFactoryCb<DataType>
79
735
  createDataInput(const envoy::config::core::v3::TypedExtensionConfig& config) {
80
735
    return createDataInputBase(config);
81
735
  }
82

            
83
private:
84
  // Wrapper around a CommonProtocolInput that allows it to be used as a DataInput<DataType>.
85
  class CommonProtocolInputWrapper : public DataInput<DataType> {
86
  public:
87
    explicit CommonProtocolInputWrapper(CommonProtocolInputPtr&& common_protocol_input)
88
1
        : common_protocol_input_(std::move(common_protocol_input)) {}
89

            
90
1
    DataInputGetResult get(const DataType&) const override { return common_protocol_input_->get(); }
91

            
92
  private:
93
    const CommonProtocolInputPtr common_protocol_input_;
94
  };
95

            
96
  template <class TypedExtensionConfigType>
97
2489
  DataInputFactoryCb<DataType> createDataInputBase(const TypedExtensionConfigType& config) {
98
2489
    auto* factory = Config::Utility::getFactory<DataInputFactory<DataType>>(config);
99
2489
    if (factory != nullptr) {
100
2485
      validation_visitor_.validateDataInput(*factory, config.typed_config().type_url());
101

            
102
2485
      ProtobufTypes::MessagePtr message =
103
2485
          Config::Utility::translateAnyToFactoryConfig(config.typed_config(), validator_, *factory);
104
2485
      auto data_input = factory->createDataInputFactoryCb(*message, validator_);
105
2485
      return data_input;
106
2485
    }
107

            
108
    // If the provided config doesn't match a typed input, assume that this is one of the common
109
    // inputs.
110
4
    auto& common_input_factory =
111
4
        Config::Utility::getAndCheckFactory<CommonProtocolInputFactory>(config);
112
4
    ProtobufTypes::MessagePtr message = Config::Utility::translateAnyToFactoryConfig(
113
4
        config.typed_config(), validator_, common_input_factory);
114
4
    auto common_input =
115
4
        common_input_factory.createCommonProtocolInputFactoryCb(*message, validator_);
116
4
    return
117
4
        [common_input]() { return std::make_unique<CommonProtocolInputWrapper>(common_input()); };
118
2489
  }
119

            
120
  ProtobufMessage::ValidationVisitor& validator_;
121
  MatchTreeValidationVisitor<DataType>& validation_visitor_;
122
};
123

            
124
/**
125
 * Recursively constructs a MatchTree from a protobuf configuration.
126
 * @param DataType the type used as a source for DataInputs
127
 * @param ActionFactoryContext the context provided to Action factories
128
 */
129
template <class DataType, class ActionFactoryContext>
130
class MatchTreeFactory : public OnMatchFactory<DataType> {
131
public:
132
  MatchTreeFactory(ActionFactoryContext& context,
133
                   Server::Configuration::ServerFactoryContext& factory_context,
134
                   MatchTreeValidationVisitor<DataType>& validation_visitor)
135
1135
      : action_factory_context_(context), server_factory_context_(factory_context),
136
1135
        on_match_validation_visitor_(validation_visitor),
137
1135
        match_input_factory_(factory_context.messageValidationVisitor(), validation_visitor) {}
138

            
139
  // TODO(snowp): Remove this type parameter once we only have one Matcher proto.
140
1239
  template <class MatcherType> MatchTreeFactoryCb<DataType> create(const MatcherType& config) {
141
1239
    switch (config.matcher_type_case()) {
142
437
    case MatcherType::kMatcherTree:
143
437
      return createTreeMatcher(config);
144
580
    case MatcherType::kMatcherList:
145
580
      return createListMatcher(config);
146
222
    case MatcherType::MATCHER_TYPE_NOT_SET:
147
222
      return createAnyMatcher(config);
148
1239
    }
149
    PANIC_DUE_TO_CORRUPT_ENUM;
150
  }
151

            
152
  absl::optional<OnMatchFactoryCb<DataType>>
153
2699
  createOnMatch(const xds::type::matcher::v3::Matcher::OnMatch& on_match) override {
154
2699
    return createOnMatchBase(on_match);
155
2699
  }
156

            
157
  absl::optional<OnMatchFactoryCb<DataType>>
158
81
  createOnMatch(const envoy::config::common::matcher::v3::Matcher::OnMatch& on_match) override {
159
81
    return createOnMatchBase(on_match);
160
81
  }
161

            
162
private:
163
  template <class MatcherType>
164
222
  MatchTreeFactoryCb<DataType> createAnyMatcher(const MatcherType& config) {
165
222
    auto on_no_match = createOnMatch(config.on_no_match());
166

            
167
222
    return [on_no_match]() {
168
218
      return std::make_unique<AnyMatcher<DataType>>(
169
218
          on_no_match ? absl::make_optional((*on_no_match)()) : absl::nullopt);
170
218
    };
171
222
  }
172
  template <class MatcherType>
173
580
  MatchTreeFactoryCb<DataType> createListMatcher(const MatcherType& config) {
174
580
    std::vector<std::pair<FieldMatcherFactoryCb<DataType>, OnMatchFactoryCb<DataType>>>
175
580
        matcher_factories;
176
580
    matcher_factories.reserve(config.matcher_list().matchers().size());
177
1007
    for (const auto& matcher : config.matcher_list().matchers()) {
178
1007
      matcher_factories.push_back(std::make_pair(
179
1007
          createFieldMatcher<typename MatcherType::MatcherList::Predicate>(matcher.predicate()),
180
1007
          *createOnMatch(matcher.on_match())));
181
1007
    }
182

            
183
580
    auto on_no_match = createOnMatch(config.on_no_match());
184
580
    return [matcher_factories, on_no_match]() {
185
573
      auto list_matcher = std::make_unique<ListMatcher<DataType>>(
186
573
          on_no_match ? absl::make_optional((*on_no_match)()) : absl::nullopt);
187

            
188
999
      for (const auto& matcher : matcher_factories) {
189
999
        list_matcher->addMatcher(matcher.first(), matcher.second());
190
999
      }
191

            
192
573
      return list_matcher;
193
573
    };
194
580
  }
195

            
196
  template <class MatcherT, class PredicateType, class FieldPredicateType>
197
  FieldMatcherFactoryCb<DataType> createAggregateFieldMatcherFactoryCb(
198
201
      const Protobuf::RepeatedPtrField<FieldPredicateType>& predicates) {
199
201
    std::vector<FieldMatcherFactoryCb<DataType>> sub_matchers;
200
554
    for (const auto& predicate : predicates) {
201
554
      sub_matchers.emplace_back(createFieldMatcher<PredicateType>(predicate));
202
554
    }
203

            
204
201
    return [sub_matchers]() {
205
200
      std::vector<FieldMatcherPtr<DataType>> matchers;
206
200
      matchers.reserve(sub_matchers.size());
207
550
      for (const auto& factory_cb : sub_matchers) {
208
550
        matchers.emplace_back(factory_cb());
209
550
      }
210

            
211
200
      return std::make_unique<MatcherT>(std::move(matchers));
212
200
    };
213
201
  }
214

            
215
  template <class PredicateType, class FieldMatcherType>
216
1562
  FieldMatcherFactoryCb<DataType> createFieldMatcher(const FieldMatcherType& field_predicate) {
217
1562
    switch (field_predicate.match_type_case()) {
218
1360
    case (PredicateType::kSinglePredicate): {
219
1360
      auto data_input =
220
1360
          match_input_factory_.createDataInput(field_predicate.single_predicate().input());
221
1360
      auto input_matcher = createInputMatcher(field_predicate.single_predicate());
222

            
223
1360
      return [data_input, input_matcher]() {
224
1349
        return THROW_OR_RETURN_VALUE(
225
1349
            SingleFieldMatcher<DataType>::create(data_input(), input_matcher()),
226
1349
            std::unique_ptr<SingleFieldMatcher<DataType>>);
227
1349
      };
228
    }
229
174
    case (PredicateType::kOrMatcher):
230
174
      return createAggregateFieldMatcherFactoryCb<AnyFieldMatcher<DataType>, PredicateType>(
231
174
          field_predicate.or_matcher().predicate());
232
27
    case (PredicateType::kAndMatcher):
233
27
      return createAggregateFieldMatcherFactoryCb<AllFieldMatcher<DataType>, PredicateType>(
234
27
          field_predicate.and_matcher().predicate());
235
1
    case (PredicateType::kNotMatcher): {
236
1
      auto matcher_factory = createFieldMatcher<PredicateType>(field_predicate.not_matcher());
237

            
238
1
      return [matcher_factory]() {
239
1
        return std::make_unique<NotFieldMatcher<DataType>>(matcher_factory());
240
1
      };
241
    }
242
    case PredicateType::MATCH_TYPE_NOT_SET:
243
      PANIC_DUE_TO_PROTO_UNSET;
244
1562
    }
245
    PANIC_DUE_TO_CORRUPT_ENUM;
246
  }
247

            
248
  template <class MatcherType>
249
437
  MatchTreeFactoryCb<DataType> createTreeMatcher(const MatcherType& matcher) {
250
437
    auto data_input = match_input_factory_.createDataInput(matcher.matcher_tree().input());
251
437
    auto on_no_match = createOnMatch(matcher.on_no_match());
252

            
253
437
    switch (matcher.matcher_tree().tree_type_case()) {
254
332
    case MatcherType::MatcherTree::kExactMatchMap: {
255
332
      return createMapMatcher<ExactMapMatcher>(matcher.matcher_tree().exact_match_map(), data_input,
256
332
                                               on_no_match, &ExactMapMatcher<DataType>::create);
257
    }
258
10
    case MatcherType::MatcherTree::kPrefixMatchMap: {
259
10
      return createMapMatcher<PrefixMapMatcher>(matcher.matcher_tree().prefix_match_map(),
260
10
                                                data_input, on_no_match,
261
10
                                                &PrefixMapMatcher<DataType>::create);
262
    }
263
    case MatcherType::MatcherTree::TREE_TYPE_NOT_SET:
264
      PANIC("unexpected matcher type");
265
94
    case MatcherType::MatcherTree::kCustomMatch: {
266
94
      auto& factory = Config::Utility::getAndCheckFactory<CustomMatcherFactory<DataType>>(
267
94
          matcher.matcher_tree().custom_match());
268
94
      ProtobufTypes::MessagePtr message = Config::Utility::translateAnyToFactoryConfig(
269
94
          matcher.matcher_tree().custom_match().typed_config(),
270
94
          server_factory_context_.messageValidationVisitor(), factory);
271
94
      return factory.createCustomMatcherFactoryCb(*message, server_factory_context_, data_input,
272
94
                                                  on_no_match, *this);
273
    }
274
437
    }
275
    PANIC_DUE_TO_CORRUPT_ENUM;
276
  }
277

            
278
  using MapCreationFunction = std::function<absl::StatusOr<std::unique_ptr<MapMatcher<DataType>>>(
279
      DataInputPtr<DataType>&& data_input, absl::optional<OnMatch<DataType>> on_no_match)>;
280

            
281
  template <template <class> class MapMatcherType, class MapType>
282
  MatchTreeFactoryCb<DataType>
283
  createMapMatcher(const MapType& map, DataInputFactoryCb<DataType> data_input,
284
                   absl::optional<OnMatchFactoryCb<DataType>>& on_no_match,
285
342
                   MapCreationFunction creation_function) {
286
342
    std::vector<std::pair<std::string, OnMatchFactoryCb<DataType>>> match_children;
287
342
    match_children.reserve(map.map().size());
288

            
289
390
    for (const auto& children : map.map()) {
290
390
      match_children.push_back(
291
390
          std::make_pair(children.first, *MatchTreeFactory::createOnMatch(children.second)));
292
390
    }
293

            
294
344
    return [match_children, data_input, on_no_match, creation_function]() {
295
340
      auto matcher_or_error = creation_function(
296
340
          data_input(), on_no_match ? absl::make_optional((*on_no_match)()) : absl::nullopt);
297
340
      THROW_IF_NOT_OK(matcher_or_error.status());
298
338
      auto multimap_matcher = std::move(*matcher_or_error);
299
384
      for (const auto& children : match_children) {
300
384
        multimap_matcher->addChild(children.first, children.second());
301
384
      }
302
338
      return multimap_matcher;
303
340
    };
304
342
  }
305

            
306
  template <class OnMatchType>
307
2780
  absl::optional<OnMatchFactoryCb<DataType>> createOnMatchBase(const OnMatchType& on_match) {
308
2780
    on_match_validation_visitor_.validateOnMatch(on_match);
309
2780
    if (const std::vector<absl::Status>& errors = on_match_validation_visitor_.errors();
310
2780
        !errors.empty()) {
311
24
      return []() -> OnMatch<DataType> { return OnMatch<DataType>{}; };
312
24
    }
313
2756
    if (on_match.has_matcher()) {
314
81
      return [matcher_factory = std::move(create(on_match.matcher())),
315
81
              keep_matching = on_match.keep_matching()]() {
316
77
        return OnMatch<DataType>{{}, matcher_factory(), keep_matching};
317
77
      };
318
2675
    } else if (on_match.has_action()) {
319
1858
      auto& factory = Config::Utility::getAndCheckFactory<ActionFactory<ActionFactoryContext>>(
320
1858
          on_match.action());
321
1858
      ProtobufTypes::MessagePtr message = Config::Utility::translateAnyToFactoryConfig(
322
1858
          on_match.action().typed_config(), server_factory_context_.messageValidationVisitor(),
323
1858
          factory);
324

            
325
      // TODO(taoxuy): try to pass message by moving and let the created action take ownership
326
      // of the message if needed, which avoid copy.
327
1858
      auto action = factory.createAction(*message, action_factory_context_,
328
1858
                                         server_factory_context_.messageValidationVisitor());
329
1860
      return [action, keep_matching = on_match.keep_matching()] {
330
1848
        return OnMatch<DataType>{action, {}, keep_matching};
331
1848
      };
332
1858
    }
333

            
334
817
    return absl::nullopt;
335
2756
  }
336

            
337
  template <class SinglePredicateType>
338
1359
  InputMatcherFactoryCb createInputMatcher(const SinglePredicateType& predicate) {
339
1359
    switch (predicate.matcher_case()) {
340
1228
    case SinglePredicateType::kValueMatch:
341
1228
      return [&context = server_factory_context_, value_match = predicate.value_match()]() {
342
1219
        return std::make_unique<StringInputMatcher>(value_match, context);
343
1219
      };
344
131
    case SinglePredicateType::kCustomMatch: {
345
131
      auto& factory =
346
131
          Config::Utility::getAndCheckFactory<InputMatcherFactory>(predicate.custom_match());
347
131
      ProtobufTypes::MessagePtr message = Config::Utility::translateAnyToFactoryConfig(
348
131
          predicate.custom_match().typed_config(),
349
131
          server_factory_context_.messageValidationVisitor(), factory);
350
131
      return factory.createInputMatcherFactoryCb(*message, server_factory_context_);
351
    }
352
    case SinglePredicateType::MATCHER_NOT_SET:
353
      PANIC_DUE_TO_PROTO_UNSET;
354
1359
    }
355
    PANIC_DUE_TO_CORRUPT_ENUM;
356
  }
357

            
358
  const std::string stats_prefix_;
359
  ActionFactoryContext& action_factory_context_;
360
  Server::Configuration::ServerFactoryContext& server_factory_context_;
361
  MatchTreeValidationVisitor<DataType>& on_match_validation_visitor_;
362
  MatchInputFactory<DataType> match_input_factory_;
363
};
364
} // namespace Matcher
365
} // namespace Envoy