1
#include "source/extensions/router/cluster_specifiers/matcher/matcher_cluster_specifier.h"
2

            
3
#include "envoy/extensions/router/cluster_specifiers/matcher/v3/matcher.pb.validate.h"
4

            
5
#include "source/common/http/matching/data_impl.h"
6
#include "source/common/router/delegating_route_impl.h"
7

            
8
namespace Envoy {
9
namespace Extensions {
10
namespace Router {
11
namespace Matcher {
12

            
13
Envoy::Matcher::ActionConstSharedPtr
14
ClusterActionFactory::createAction(const Protobuf::Message& config, ClusterActionContext&,
15
12
                                   ProtobufMessage::ValidationVisitor& validation_visitor) {
16
12
  const auto& proto_config =
17
12
      MessageUtil::downcastAndValidate<const ClusterActionProto&>(config, validation_visitor);
18
12
  return std::make_shared<ClusterAction>(proto_config.cluster());
19
12
}
20

            
21
REGISTER_FACTORY(ClusterActionFactory, Envoy::Matcher::ActionFactory<ClusterActionContext>);
22

            
23
class MatcherRouteEntry : public Envoy::Router::DelegatingRouteEntry {
24
public:
25
  MatcherRouteEntry(Envoy::Router::RouteEntryAndRouteConstSharedPtr parent,
26
                    Envoy::Matcher::MatchTreeSharedPtr<Http::HttpMatchingData> match_tree)
27
9
      : DelegatingRouteEntry(std::move(parent)), match_tree_(std::move(match_tree)) {}
28

            
29
15
  const std::string& clusterName() const override {
30
15
    return cluster_name_.has_value() ? *cluster_name_ : EMPTY_STRING;
31
15
  }
32

            
33
  void refreshRouteCluster(const Http::RequestHeaderMap& headers,
34
10
                           const StreamInfo::StreamInfo& stream_info) const override {
35
10
    Http::Matching::HttpMatchingDataImpl data(stream_info);
36
10
    data.onRequestHeaders(headers);
37

            
38
10
    Envoy::Matcher::ActionMatchResult match_result =
39
10
        Envoy::Matcher::evaluateMatch<Http::HttpMatchingData>(*match_tree_, data);
40

            
41
10
    if (!match_result.isMatch()) {
42
1
      return;
43
1
    }
44
9
    cluster_name_.emplace(match_result.action()->getTyped<ClusterAction>().cluster());
45
9
  }
46

            
47
private:
48
  Envoy::Matcher::MatchTreeSharedPtr<Http::HttpMatchingData> match_tree_;
49
  mutable OptRef<const std::string> cluster_name_;
50
};
51

            
52
Envoy::Router::RouteConstSharedPtr
53
MatcherClusterSpecifierPlugin::route(Envoy::Router::RouteEntryAndRouteConstSharedPtr parent,
54
                                     const Http::RequestHeaderMap& headers,
55
9
                                     const StreamInfo::StreamInfo& stream_info, uint64_t) const {
56
9
  auto matcher_route = std::make_shared<MatcherRouteEntry>(parent, match_tree_);
57
9
  matcher_route->refreshRouteCluster(headers, stream_info);
58
9
  return matcher_route;
59
9
}
60

            
61
} // namespace Matcher
62
} // namespace Router
63
} // namespace Extensions
64
} // namespace Envoy