1
#include "source/extensions/rate_limit_descriptors/expr/config.h"
2

            
3
#include "envoy/extensions/rate_limit_descriptors/expr/v3/expr.pb.h"
4
#include "envoy/extensions/rate_limit_descriptors/expr/v3/expr.pb.validate.h"
5

            
6
#include "source/common/protobuf/utility.h"
7

            
8
#if defined(USE_CEL_PARSER)
9
#include "parser/parser.h"
10
#endif
11

            
12
namespace Envoy {
13
namespace Extensions {
14
namespace RateLimitDescriptors {
15
namespace Expr {
16

            
17
namespace {
18

            
19
/**
20
 * Descriptor producer for a symbolic expression descriptor.
21
 */
22
class ExpressionDescriptor : public RateLimit::DescriptorProducer {
23
public:
24
  ExpressionDescriptor(
25
      const envoy::extensions::rate_limit_descriptors::expr::v3::Descriptor& config,
26
      Extensions::Filters::Common::Expr::CompiledExpression&& compiled_expr)
27
11
      : descriptor_key_(config.descriptor_key()), skip_if_error_(config.skip_if_error()),
28
11
        compiled_expr_(std::move(compiled_expr)) {}
29

            
30
  // Ratelimit::DescriptorProducer
31
  bool populateDescriptor(RateLimit::DescriptorEntry& descriptor_entry, const std::string&,
32
                          const Http::RequestHeaderMap& headers,
33
12
                          const StreamInfo::StreamInfo& info) const override {
34
12
    Protobuf::Arena arena;
35
12
    const auto result = compiled_expr_.evaluate(arena, nullptr, info, &headers, nullptr, nullptr);
36
12
    if (!result.has_value() || result.value().IsError()) {
37
      // If result is an error and if skip_if_error is true skip this descriptor,
38
      // while calling rate limiting service. If skip_if_error is false, do not call rate limiting
39
      // service.
40
2
      return skip_if_error_;
41
2
    }
42
10
    descriptor_entry = {descriptor_key_, Filters::Common::Expr::print(result.value())};
43
10
    return true;
44
12
  }
45

            
46
private:
47
  const std::string descriptor_key_;
48
  const bool skip_if_error_;
49
  const Extensions::Filters::Common::Expr::CompiledExpression compiled_expr_;
50
};
51

            
52
} // namespace
53

            
54
5
std::string ExprDescriptorFactory::name() const { return "envoy.rate_limit_descriptors.expr"; }
55

            
56
18
ProtobufTypes::MessagePtr ExprDescriptorFactory::createEmptyConfigProto() {
57
18
  return std::make_unique<envoy::extensions::rate_limit_descriptors::expr::v3::Descriptor>();
58
18
}
59

            
60
absl::StatusOr<RateLimit::DescriptorProducerPtr>
61
ExprDescriptorFactory::createDescriptorProducerFromProto(
62
16
    const Protobuf::Message& message, Server::Configuration::CommonFactoryContext& context) {
63
16
  const auto& config = MessageUtil::downcastAndValidate<
64
16
      const envoy::extensions::rate_limit_descriptors::expr::v3::Descriptor&>(
65
16
      message, context.messageValidationVisitor());
66
16
  auto builder = Extensions::Filters::Common::Expr::getBuilder(context);
67
16
  switch (config.expr_specifier_case()) {
68
#if defined(USE_CEL_PARSER)
69
12
  case envoy::extensions::rate_limit_descriptors::expr::v3::Descriptor::kText: {
70
12
    auto parse_status = google::api::expr::parser::Parse(config.text());
71
12
    if (!parse_status.ok()) {
72
1
      return absl::InvalidArgumentError(absl::StrCat("Unable to parse descriptor expression: ",
73
1
                                                     parse_status.status().ToString()));
74
1
    }
75
11
    auto compiled_expr = Extensions::Filters::Common::Expr::CompiledExpression::Create(
76
11
        builder, parse_status.value().expr());
77
11
    if (!compiled_expr.ok()) {
78
1
      return absl::InvalidArgumentError(
79
1
          absl::StrCat("failed to create an expression: ", compiled_expr.status().message()));
80
1
    }
81
10
    return std::make_unique<ExpressionDescriptor>(config, std::move(compiled_expr.value()));
82
11
  }
83
#endif
84
2
  case envoy::extensions::rate_limit_descriptors::expr::v3::Descriptor::kParsed: {
85
2
    auto compiled_expr =
86
2
        Extensions::Filters::Common::Expr::CompiledExpression::Create(builder, config.parsed());
87
2
    if (!compiled_expr.ok()) {
88
1
      return absl::InvalidArgumentError(
89
1
          absl::StrCat("failed to create an expression: ", compiled_expr.status().message()));
90
1
    }
91
1
    return std::make_unique<ExpressionDescriptor>(config, std::move(compiled_expr.value()));
92
2
  }
93
2
  default:
94
2
    return absl::InvalidArgumentError(
95
2
        "Rate limit descriptor extension failed: expression specifier is not set");
96
16
  }
97
16
}
98

            
99
REGISTER_FACTORY(ExprDescriptorFactory, RateLimit::DescriptorProducerFactory);
100

            
101
} // namespace Expr
102
} // namespace RateLimitDescriptors
103
} // namespace Extensions
104
} // namespace Envoy