Coverage Report

Created: 2023-11-12 09:30

/proc/self/cwd/source/extensions/filters/network/thrift_proxy/router/router_ratelimit_impl.cc
Line
Count
Source (jump to first uncovered line)
1
#include "source/extensions/filters/network/thrift_proxy/router/router_ratelimit_impl.h"
2
3
#include "envoy/common/exception.h"
4
#include "envoy/config/route/v3/route_components.pb.h"
5
#include "envoy/ratelimit/ratelimit.h"
6
7
#include "source/extensions/filters/network/thrift_proxy/router/router.h"
8
9
namespace Envoy {
10
namespace Extensions {
11
namespace NetworkFilters {
12
namespace ThriftProxy {
13
namespace Router {
14
15
bool SourceClusterAction::populateDescriptor(const RouteEntry&, RateLimit::Descriptor& descriptor,
16
                                             const std::string& local_service_cluster,
17
                                             const MessageMetadata&,
18
0
                                             const Network::Address::Instance&) const {
19
0
  descriptor.entries_.push_back({"source_cluster", local_service_cluster});
20
0
  return true;
21
0
}
22
23
bool DestinationClusterAction::populateDescriptor(const RouteEntry& route,
24
                                                  RateLimit::Descriptor& descriptor,
25
                                                  const std::string&, const MessageMetadata&,
26
0
                                                  const Network::Address::Instance&) const {
27
0
  descriptor.entries_.push_back({"destination_cluster", route.clusterName()});
28
0
  return true;
29
0
}
30
31
bool RequestHeadersAction::populateDescriptor(const RouteEntry&, RateLimit::Descriptor& descriptor,
32
                                              const std::string&, const MessageMetadata& metadata,
33
0
                                              const Network::Address::Instance&) const {
34
0
  if (use_method_name_) {
35
0
    if (!metadata.hasMethodName()) {
36
0
      return false;
37
0
    }
38
39
0
    descriptor.entries_.push_back({descriptor_key_, metadata.methodName()});
40
0
    return true;
41
0
  }
42
43
0
  const auto header_value = metadata.requestHeaders().get(header_name_);
44
0
  if (header_value.empty()) {
45
0
    return false;
46
0
  }
47
48
  // TODO(https://github.com/envoyproxy/envoy/issues/13454): Potentially populate all values.
49
0
  descriptor.entries_.push_back(
50
0
      {descriptor_key_, std::string(header_value[0]->value().getStringView())});
51
0
  return true;
52
0
}
53
54
bool RemoteAddressAction::populateDescriptor(
55
    const RouteEntry&, RateLimit::Descriptor& descriptor, const std::string&,
56
0
    const MessageMetadata&, const Network::Address::Instance& remote_address) const {
57
0
  if (remote_address.type() != Network::Address::Type::Ip) {
58
0
    return false;
59
0
  }
60
61
0
  descriptor.entries_.push_back({"remote_address", remote_address.ip()->addressAsString()});
62
0
  return true;
63
0
}
64
65
bool GenericKeyAction::populateDescriptor(const RouteEntry&, RateLimit::Descriptor& descriptor,
66
                                          const std::string&, const MessageMetadata&,
67
0
                                          const Network::Address::Instance&) const {
68
0
  descriptor.entries_.push_back({"generic_key", descriptor_value_});
69
0
  return true;
70
0
}
71
72
HeaderValueMatchAction::HeaderValueMatchAction(
73
    const envoy::config::route::v3::RateLimit::Action::HeaderValueMatch& action)
74
    : descriptor_value_(action.descriptor_value()),
75
      expect_match_(PROTOBUF_GET_WRAPPED_OR_DEFAULT(action, expect_match, true)),
76
0
      action_headers_(Http::HeaderUtility::buildHeaderDataVector(action.headers())) {}
77
78
bool HeaderValueMatchAction::populateDescriptor(const RouteEntry&,
79
                                                RateLimit::Descriptor& descriptor,
80
                                                const std::string&, const MessageMetadata& metadata,
81
0
                                                const Network::Address::Instance&) const {
82
0
  if (expect_match_ ==
83
0
      Http::HeaderUtility::matchHeaders(metadata.requestHeaders(), action_headers_)) {
84
0
    descriptor.entries_.push_back({"header_match", descriptor_value_});
85
0
    return true;
86
0
  } else {
87
0
    return false;
88
0
  }
89
0
}
90
91
RateLimitPolicyEntryImpl::RateLimitPolicyEntryImpl(
92
    const envoy::config::route::v3::RateLimit& config)
93
    : disable_key_(config.disable_key()),
94
0
      stage_(PROTOBUF_GET_WRAPPED_OR_DEFAULT(config, stage, 0)) {
95
0
  for (const auto& action : config.actions()) {
96
0
    switch (action.action_specifier_case()) {
97
0
    case envoy::config::route::v3::RateLimit::Action::ActionSpecifierCase::kSourceCluster:
98
0
      actions_.emplace_back(new SourceClusterAction());
99
0
      break;
100
0
    case envoy::config::route::v3::RateLimit::Action::ActionSpecifierCase::kDestinationCluster:
101
0
      actions_.emplace_back(new DestinationClusterAction());
102
0
      break;
103
0
    case envoy::config::route::v3::RateLimit::Action::ActionSpecifierCase::kRequestHeaders:
104
0
      actions_.emplace_back(new RequestHeadersAction(action.request_headers()));
105
0
      break;
106
0
    case envoy::config::route::v3::RateLimit::Action::ActionSpecifierCase::kRemoteAddress:
107
0
      actions_.emplace_back(new RemoteAddressAction());
108
0
      break;
109
0
    case envoy::config::route::v3::RateLimit::Action::ActionSpecifierCase::kGenericKey:
110
0
      actions_.emplace_back(new GenericKeyAction(action.generic_key()));
111
0
      break;
112
0
    case envoy::config::route::v3::RateLimit::Action::ActionSpecifierCase::kHeaderValueMatch:
113
0
      actions_.emplace_back(new HeaderValueMatchAction(action.header_value_match()));
114
0
      break;
115
0
    default:
116
0
      throw EnvoyException(
117
0
          absl::StrCat("unsupported RateLimit Action ", action.action_specifier_case()));
118
0
    }
119
0
  }
120
0
}
121
122
void RateLimitPolicyEntryImpl::populateDescriptors(
123
    const RouteEntry& route, std::vector<RateLimit::Descriptor>& descriptors,
124
    const std::string& local_service_cluster, const MessageMetadata& metadata,
125
0
    const Network::Address::Instance& remote_address) const {
126
0
  RateLimit::Descriptor descriptor;
127
0
  bool result = true;
128
0
  for (const RateLimitActionPtr& action : actions_) {
129
0
    result = result && action->populateDescriptor(route, descriptor, local_service_cluster,
130
0
                                                  metadata, remote_address);
131
0
    if (!result) {
132
0
      break;
133
0
    }
134
0
  }
135
136
0
  if (result) {
137
0
    descriptors.emplace_back(descriptor);
138
0
  }
139
0
}
140
141
RateLimitPolicyImpl::RateLimitPolicyImpl(
142
    const Protobuf::RepeatedPtrField<envoy::config::route::v3::RateLimit>& rate_limits)
143
0
    : rate_limit_entries_reference_(RateLimitPolicyImpl::MAX_STAGE_NUMBER + 1) {
144
0
  for (const auto& rate_limit : rate_limits) {
145
0
    std::unique_ptr<RateLimitPolicyEntry> rate_limit_policy_entry(
146
0
        new RateLimitPolicyEntryImpl(rate_limit));
147
0
    uint32_t stage = rate_limit_policy_entry->stage();
148
0
    ASSERT(stage < rate_limit_entries_reference_.size());
149
0
    rate_limit_entries_reference_[stage].emplace_back(*rate_limit_policy_entry);
150
0
    rate_limit_entries_.emplace_back(std::move(rate_limit_policy_entry));
151
0
  }
152
0
}
153
154
const std::vector<std::reference_wrapper<const Router::RateLimitPolicyEntry>>&
155
0
RateLimitPolicyImpl::getApplicableRateLimit(uint32_t stage) const {
156
0
  ASSERT(stage < rate_limit_entries_reference_.size());
157
0
  return rate_limit_entries_reference_[stage];
158
0
}
159
160
} // namespace Router
161
} // namespace ThriftProxy
162
} // namespace NetworkFilters
163
} // namespace Extensions
164
} // namespace Envoy