Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
1940c6c
ratelimit: add support for x-ratelimit-* headers in local rate limiting
zhxie Sep 16, 2021
5482d0d
ratelimit: escape unabled requests from appending headers
zhxie Sep 17, 2021
e5230d9
ratelimit: fix crash on description-based rate limit
zhxie Sep 17, 2021
a71c1ca
test: add test for local rate limiter
zhxie Sep 17, 2021
b356032
ratelimit: escape from crash in test of network filter
zhxie Sep 18, 2021
36c31d6
test: fix build failure
zhxie Sep 18, 2021
98101be
test: fix format
zhxie Sep 18, 2021
0fe03e8
test: add test for x-ratelimit-* headers
zhxie Sep 22, 2021
612e6f1
ratelimit: remove generated_api_shadow
zhxie Sep 23, 2021
47c9f6d
ratelimit: merge x-ratelimit-* headers enum
zhxie Sep 24, 2021
92d18f2
ratelimit: deprecate original x-ratelimit-* headers enum
zhxie Sep 29, 2021
5f26554
Merge remote-tracking branch 'envoyproxy/main' into header-lrl
zhxie Sep 29, 2021
20907cc
ratelimit: fix docs
zhxie Sep 29, 2021
1eafb85
ratelimit: revert to avoid API change in ratelimit
zhxie Oct 8, 2021
ba6f194
Merge remote-tracking branch 'envoyproxy/main' into header-lrl
zhxie Oct 8, 2021
266e72a
Merge remote-tracking branch 'envoyproxy/main' into header-lrl
zhxie Oct 12, 2021
10ba430
docs: add release note
zhxie Oct 12, 2021
39e98c2
docs: fix release note
zhxie Oct 12, 2021
bee36ef
Merge remote-tracking branch 'envoyproxy/main' into header-lrl
zhxie Oct 13, 2021
5a9b778
docs: fix release notes
zhxie Oct 13, 2021
e44d0ed
ratelimit: fix missing x- in ratelimit headers
zhxie Oct 14, 2021
0e2daa5
Merge remote-tracking branch 'envoyproxy/main' into header-lrl
zhxie Oct 15, 2021
a458994
Merge remote-tracking branch 'envoyproxy/main' into header-lrl
zhxie Oct 18, 2021
56787c8
docs: fix release notes
zhxie Oct 18, 2021
e3bd3be
Merge remote-tracking branch 'envoyproxy/main' into header-lrl
zhxie Oct 20, 2021
8f6d427
ratelimit: consolidate header values
zhxie Oct 21, 2021
a4e76c0
ratelimit: move headers to place without sponsorship required
zhxie Oct 21, 2021
c2216e7
Merge remote-tracking branch 'envoyproxy/main' into header-lrl
zhxie Oct 25, 2021
ff59453
ratelimit: fix release notes
zhxie Oct 25, 2021
e897ad6
Merge remote-tracking branch 'envoyproxy/main' into header-lrl
zhxie Nov 5, 2021
d324244
docs: fix release notes
zhxie Nov 5, 2021
f52ea50
Merge remote-tracking branch 'envoyproxy/main' into header-lrl
zhxie Nov 29, 2021
5e3977d
docs: fix release notes
zhxie Nov 29, 2021
1928a6f
Merge remote-tracking branch 'envoyproxy/main' into header-lrl
zhxie Jan 19, 2022
c41acab
docs: fix release notes
zhxie Jan 19, 2022
0be82da
nit: move comments and change name
zhxie Jan 19, 2022
f4e540b
ratelimit: return remaining fill interval in int64_t
zhxie Jan 19, 2022
bda1a88
ratelimit: fill time in a single place
zhxie Jan 19, 2022
afe2035
ratelimit: guard headers encoding by checking enabled
zhxie Jan 19, 2022
d485bf0
ratelimit: remove unwanted flag
zhxie Jan 19, 2022
3993927
ratelimit: add a helper method for selecting descriptor
zhxie Jan 20, 2022
978ed0a
ratelimit: store descriptors in filter itself
zhxie Jan 20, 2022
2bd01c1
tests: add a unit test for multiple descriptors
zhxie Jan 20, 2022
a52570b
nit: fix typo and format and remove redundant variables
zhxie Jan 21, 2022
85c5c3e
ratelimit: avoid header copy
zhxie Jan 21, 2022
d23c9a3
ratelimit: update descriptor helper to avoid adding a default descriptor
zhxie Jan 21, 2022
a78997b
tests: switch time system
zhxie Jan 21, 2022
67ea8ae
test: fix time system issue in filter test
zhxie Jan 27, 2022
9afce6f
nit: fix typo
zhxie Jan 30, 2022
8b043ef
ratelimit: replace StatusOr with OptRef and add comment
zhxie Jan 30, 2022
c601b82
nit: remove redundant
zhxie Jan 30, 2022
6a57280
Merge remote-tracking branch 'envoyproxy/main' into header-lrl
zhxie Feb 14, 2022
31c7daa
docs: update release notes
zhxie Feb 14, 2022
cdb1471
nit: remove extra comment slash
zhxie Feb 14, 2022
124f0ef
docs: fix release notes
zhxie Feb 14, 2022
4b74159
api: do not deprecate XRateLimitHeadersRFCVersion
zhxie Feb 21, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions api/envoy/extensions/common/ratelimit/v3/ratelimit.proto
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,23 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE;

// [#protodoc-title: Common rate limit components]

// Defines the version of the standard to use for X-RateLimit headers.
enum XRateLimitHeadersRFCVersion {
// X-RateLimit headers disabled.
OFF = 0;

// Use `draft RFC Version 03 <https://tools.ietf.org/id/draft-polli-ratelimit-headers-03.html>`_ where 3 headers will be added:
//
// * ``X-RateLimit-Limit`` - indicates the request-quota associated to the
// client in the current time-window followed by the description of the
// quota policy. The value is returned by the maximum tokens of the token bucket.
// * ``X-RateLimit-Remaining`` - indicates the remaining requests in the
// current time-window. The value is returned by the remaining tokens in the token bucket.
// * ``X-RateLimit-Reset`` - indicates the number of seconds until reset of
// the current time-window. The value is returned by the remaining fill interval of the token bucket.
DRAFT_VERSION_03 = 1;
}

// A RateLimitDescriptor is a list of hierarchical entries that are used by the service to
// determine the final rate limit key and overall allowed limit. Here are some examples of how
// they might be used for the domain "envoy".
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE;
// Local Rate limit :ref:`configuration overview <config_http_filters_local_rate_limit>`.
// [#extension: envoy.filters.http.local_ratelimit]

// [#next-free-field: 12]
// [#next-free-field: 13]
message LocalRateLimit {
// The human readable prefix to use when emitting stats.
string stat_prefix = 1 [(validate.rules).string = {min_len: 1}];
Expand Down Expand Up @@ -107,4 +107,10 @@ message LocalRateLimit {
// one to rate limit requests on a per connection basis.
// If unspecified, the default value is false.
bool local_rate_limit_per_downstream_connection = 11;

// Defines the standard version to use for X-RateLimit headers emitted by the filter.
//
// Disabled by default.
common.ratelimit.v3.XRateLimitHeadersRFCVersion enable_x_ratelimit_headers = 12
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: maybe just ratelimit_headers_version or x_ratelimit_headers_version?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I will changed to x_ratelimit_headers_version.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some thoughts, I think it is worth considering since I want to align with ratelimit's enable_x_ratelimit_headers. Maybe we can keep the name unchanged?

[(validate.rules).enum = {defined_only: true}];
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ message RateLimit {
"envoy.config.filter.http.rate_limit.v2.RateLimit";

// Defines the version of the standard to use for X-RateLimit headers.
//
// [#next-major-version: unify with local ratelimit, should use common.ratelimit.v3.XRateLimitHeadersRFCVersion instead.]
enum XRateLimitHeadersRFCVersion {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be deprecated.

// X-RateLimit headers disabled.
OFF = 0;
Expand Down Expand Up @@ -100,6 +102,8 @@ message RateLimit {
// the `draft RFC <https://tools.ietf.org/id/draft-polli-ratelimit-headers-03.html>`_.
//
// Disabled by default.
//
// [#next-major-version: unify with local ratelimit, should use common.ratelimit.v3.XRateLimitHeadersRFCVersion instead.]
XRateLimitHeadersRFCVersion enable_x_ratelimit_headers = 8
Copy link
Copy Markdown
Contributor

@esmet esmet Oct 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that the comment shows X-RateLimit-Limit (draft 02?) but the RFC link is to 03. The remote ratelimit filter code also uses X-RateLimit-Limit. Is the RFC link (and the name of the enum) wrong?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which line do you mean? I think the code does mean draft 03.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like draft 03 uses "RateLimit-Limit" while draft 00-02 uses "X-RateLimit-Limit". The enum claims draft 03 but the code is prefixed with X-. What's the desired state?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The prefix "X-" is attached since Envoy is a proxy but not a client. A proxy will generally add headers with a prefix "X-".

[(validate.rules).enum = {defined_only: true}];

Expand Down
1 change: 1 addition & 0 deletions docs/root/version_history/current.rst
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ New Features
* http: make consistent custom header format fields ``%(DOWN|DIRECT_DOWN|UP)STREAM_(LOCAL|REMOTE)_*%`` to provide all combinations of local & remote addresses for upstream & downstream connections.
* http3: downstream HTTP/3 support is now GA! Upstream HTTP/3 also GA for specific deployments. See :ref:`here <arch_overview_http3>` for details.
* http3: supports upstream HTTP/3 retries. Automatically retry `0-RTT safe requests <https://www.rfc-editor.org/rfc/rfc7231#section-4.2.1>`_ if they are rejected because they are sent `too early <https://datatracker.ietf.org/doc/html/rfc8470#section-5.2>`_. And automatically retry 0-RTT safe requests if connect attempt fails later on and the cluster is configured with TCP fallback. And add retry on ``http3-post-connect-failure`` policy which allows retry of failed HTTP/3 requests with TCP fallback even after handshake if the cluster is configured with TCP fallback. This feature is guarded by ``envoy.reloadable_features.conn_pool_new_stream_with_early_data_and_http3``.
* local_ratelimit: added support for X-RateLimit-* headers as defined in `draft RFC <https://tools.ietf.org/id/draft-polli-ratelimit-headers-03.html>`_.
* matching: the matching API can now express a match tree that will always match by omitting a matcher at the top level.

Deprecated
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "source/extensions/filters/common/local_ratelimit/local_ratelimit_impl.h"

#include <chrono>

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

namespace Envoy {
Expand All @@ -25,6 +27,7 @@ LocalRateLimiterImpl::LocalRateLimiterImpl(
token_bucket_.tokens_per_fill_ = tokens_per_fill;
token_bucket_.fill_interval_ = absl::FromChrono(fill_interval);
tokens_.tokens_ = max_tokens;
tokens_.fill_time_ = time_source_.monotonicTime();

if (fill_timer_) {
fill_timer_->enableTimer(fill_interval);
Expand Down Expand Up @@ -72,7 +75,7 @@ void LocalRateLimiterImpl::onFillTimer() {
fill_timer_->enableTimer(absl::ToChronoMilliseconds(token_bucket_.fill_interval_));
}

void LocalRateLimiterImpl::onFillTimerHelper(const TokenState& tokens,
void LocalRateLimiterImpl::onFillTimerHelper(TokenState& tokens,
const RateLimit::TokenBucket& bucket) {
// Relaxed consistency is used for all operations because we don't care about ordering, just the
// final atomic correctness.
Expand All @@ -88,6 +91,9 @@ void LocalRateLimiterImpl::onFillTimerHelper(const TokenState& tokens,
// Loop while the weak CAS fails trying to update the tokens value.
} while (!tokens.tokens_.compare_exchange_weak(expected_tokens, new_tokens_value,
std::memory_order_relaxed));

// Update fill time at last.
tokens.fill_time_ = time_source_.monotonicTime();
}

void LocalRateLimiterImpl::onFillTimerDescriptorHelper() {
Expand All @@ -97,7 +103,6 @@ void LocalRateLimiterImpl::onFillTimerDescriptorHelper() {
current_time - descriptor.token_state_->fill_time_) >=
absl::ToChronoMilliseconds(descriptor.token_bucket_.fill_interval_)) {
onFillTimerHelper(*descriptor.token_state_, descriptor.token_bucket_);
descriptor.token_state_->fill_time_ = current_time;
}
}
}
Expand All @@ -123,17 +128,63 @@ bool LocalRateLimiterImpl::requestAllowedHelper(const TokenState& tokens) const
return true;
}

bool LocalRateLimiterImpl::requestAllowed(
OptRef<const LocalRateLimiterImpl::LocalDescriptorImpl> LocalRateLimiterImpl::descriptorHelper(
absl::Span<const RateLimit::LocalDescriptor> request_descriptors) const {
if (!descriptors_.empty() && !request_descriptors.empty()) {
// The override rate limit descriptor is selected by the first full match from the request
// descriptors.
for (const auto& request_descriptor : request_descriptors) {
auto it = descriptors_.find(request_descriptor);
if (it != descriptors_.end()) {
return requestAllowedHelper(*it->token_state_);
return *it;
}
}
}
return requestAllowedHelper(tokens_);
return {};
}

bool LocalRateLimiterImpl::requestAllowed(
absl::Span<const RateLimit::LocalDescriptor> request_descriptors) const {
auto descriptor = descriptorHelper(request_descriptors);

return descriptor.has_value() ? requestAllowedHelper(*descriptor.value().get().token_state_)
: requestAllowedHelper(tokens_);
}

uint32_t LocalRateLimiterImpl::maxTokens(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per the previous discussion on this maybe we should have these functions be called maxTokensForApplicableDescriptor or something that more clearly conveys what this does?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure if we need this change because it would make the method names very long.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We tend to favor longer names if it helps readability, but it's probably ok as is

absl::Span<const RateLimit::LocalDescriptor> request_descriptors) const {
auto descriptor = descriptorHelper(request_descriptors);

return descriptor.has_value() ? descriptor.value().get().token_bucket_.max_tokens_
: token_bucket_.max_tokens_;
}

uint32_t LocalRateLimiterImpl::remainingTokens(
absl::Span<const RateLimit::LocalDescriptor> request_descriptors) const {
auto descriptor = descriptorHelper(request_descriptors);

return descriptor.has_value()
? descriptor.value().get().token_state_->tokens_.load(std::memory_order_relaxed)
: tokens_.tokens_.load(std::memory_order_relaxed);
}

int64_t LocalRateLimiterImpl::remainingFillInterval(
absl::Span<const RateLimit::LocalDescriptor> request_descriptors) const {
using namespace std::literals;

auto current_time = time_source_.monotonicTime();
auto descriptor = descriptorHelper(request_descriptors);
// Remaining time to next fill = fill interval - (current time - last fill time).
if (descriptor.has_value()) {
ASSERT(std::chrono::duration_cast<std::chrono::milliseconds>(
current_time - descriptor.value().get().token_state_->fill_time_) <=
absl::ToChronoMilliseconds(descriptor.value().get().token_bucket_.fill_interval_));
return absl::ToInt64Seconds(
descriptor.value().get().token_bucket_.fill_interval_ -
absl::Seconds((current_time - descriptor.value().get().token_state_->fill_time_) / 1s));
}
return absl::ToInt64Seconds(token_bucket_.fill_interval_ -
absl::Seconds((current_time - tokens_.fill_time_) / 1s));
}

} // namespace LocalRateLimit
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ class LocalRateLimiterImpl {
~LocalRateLimiterImpl();

bool requestAllowed(absl::Span<const RateLimit::LocalDescriptor> request_descriptors) const;
uint32_t maxTokens(absl::Span<const RateLimit::LocalDescriptor> request_descriptors) const;
uint32_t remainingTokens(absl::Span<const RateLimit::LocalDescriptor> request_descriptors) const;
int64_t
remainingFillInterval(absl::Span<const RateLimit::LocalDescriptor> request_descriptors) const;

private:
struct TokenState {
Expand Down Expand Up @@ -59,8 +63,10 @@ class LocalRateLimiterImpl {
};

void onFillTimer();
void onFillTimerHelper(const TokenState& state, const RateLimit::TokenBucket& bucket);
void onFillTimerHelper(TokenState& state, const RateLimit::TokenBucket& bucket);
void onFillTimerDescriptorHelper();
OptRef<const LocalDescriptorImpl>
descriptorHelper(absl::Span<const RateLimit::LocalDescriptor> request_descriptors) const;
bool requestAllowedHelper(const TokenState& tokens) const;

RateLimit::TokenBucket token_bucket_;
Expand Down
8 changes: 8 additions & 0 deletions source/extensions/filters/http/common/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,11 @@ envoy_cc_library(
"//source/common/common:token_bucket_impl_lib",
],
)

envoy_cc_library(
name = "ratelimit_headers_lib",
hdrs = ["ratelimit_headers.h"],
deps = [
"//source/common/http:header_map_lib",
],
)
30 changes: 30 additions & 0 deletions source/extensions/filters/http/common/ratelimit_headers.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#pragma once

#include "envoy/http/header_map.h"

#include "source/common/singleton/const_singleton.h"

namespace Envoy {
namespace Extensions {
namespace HttpFilters {
namespace Common {
namespace RateLimit {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: newline after namespace (would have thought clang-tidy would complain here).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. I will run clang-tidy and fix related issues.


class XRateLimitHeaderValues {
public:
const Http::LowerCaseString XRateLimitLimit{"x-ratelimit-limit"};
const Http::LowerCaseString XRateLimitRemaining{"x-ratelimit-remaining"};
const Http::LowerCaseString XRateLimitReset{"x-ratelimit-reset"};

struct {
const std::string Window{"w"};
const std::string Name{"name"};
} QuotaPolicyKeys;
};

using XRateLimitHeaders = ConstSingleton<XRateLimitHeaderValues>;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

} // namespace RateLimit
} // namespace Common
} // namespace HttpFilters
} // namespace Extensions
} // namespace Envoy
2 changes: 2 additions & 0 deletions source/extensions/filters/http/local_ratelimit/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ envoy_cc_library(
"//source/extensions/filters/common/local_ratelimit:local_ratelimit_lib",
"//source/extensions/filters/common/ratelimit:ratelimit_lib",
"//source/extensions/filters/http/common:pass_through_filter_lib",
"//source/extensions/filters/http/common:ratelimit_headers_lib",
"@envoy_api//envoy/extensions/common/ratelimit/v3:pkg_cc_proto",
"@envoy_api//envoy/extensions/filters/http/local_ratelimit/v3:pkg_cc_proto",
],
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@
#include <string>
#include <vector>

#include "envoy/extensions/common/ratelimit/v3/ratelimit.pb.h"
#include "envoy/extensions/filters/http/local_ratelimit/v3/local_rate_limit.pb.h"
#include "envoy/http/codes.h"

#include "source/common/http/utility.h"
#include "source/common/router/config_impl.h"
#include "source/extensions/filters/http/common/ratelimit_headers.h"

namespace Envoy {
namespace Extensions {
Expand Down Expand Up @@ -48,7 +51,9 @@ FilterConfig::FilterConfig(
request_headers_parser_(Envoy::Router::HeaderParser::configure(
config.request_headers_to_add_when_not_enforced())),
stage_(static_cast<uint64_t>(config.stage())),
has_descriptors_(!config.descriptors().empty()) {
has_descriptors_(!config.descriptors().empty()),
enable_x_rate_limit_headers_(config.enable_x_ratelimit_headers() ==
envoy::extensions::common::ratelimit::v3::DRAFT_VERSION_03) {
// Note: no token bucket is fine for the global config, which would be the case for enabling
// the filter globally but disabled and then applying limits at the virtual host or
// route level. At the virtual or route level, it makes no sense to have an no token
Expand All @@ -64,6 +69,21 @@ bool FilterConfig::requestAllowed(
return rate_limiter_.requestAllowed(request_descriptors);
}

uint32_t
FilterConfig::maxTokens(absl::Span<const RateLimit::LocalDescriptor> request_descriptors) const {
return rate_limiter_.maxTokens(request_descriptors);
}

uint32_t FilterConfig::remainingTokens(
absl::Span<const RateLimit::LocalDescriptor> request_descriptors) const {
return rate_limiter_.remainingTokens(request_descriptors);
}

int64_t FilterConfig::remainingFillInterval(
absl::Span<const RateLimit::LocalDescriptor> request_descriptors) const {
return rate_limiter_.remainingFillInterval(request_descriptors);
}

LocalRateLimitStats FilterConfig::generateStats(const std::string& prefix, Stats::Scope& scope) {
const std::string final_prefix = prefix + ".http_local_rate_limit";
return {ALL_LOCAL_RATE_LIMIT_STATS(POOL_COUNTER_PREFIX(scope, final_prefix))};
Expand Down Expand Up @@ -91,6 +111,9 @@ Http::FilterHeadersStatus Filter::decodeHeaders(Http::RequestHeaderMap& headers,
populateDescriptors(descriptors, headers);
}

// Store descriptors which is used to generate x-ratelimit-* headers in encoding response headers.
stored_descriptors_ = descriptors;

if (requestAllowed(descriptors)) {
config->stats().ok_.inc();
return Http::FilterHeadersStatus::Continue;
Expand All @@ -116,13 +139,55 @@ Http::FilterHeadersStatus Filter::decodeHeaders(Http::RequestHeaderMap& headers,
return Http::FilterHeadersStatus::StopIteration;
}

Http::FilterHeadersStatus Filter::encodeHeaders(Http::ResponseHeaderMap& headers, bool) {
const auto* config = getConfig();

if (config->enabled() && config->enableXRateLimitHeaders()) {
ASSERT(stored_descriptors_.has_value());
auto limit = maxTokens(stored_descriptors_.value());
auto remaining = remainingTokens(stored_descriptors_.value());
auto reset = remainingFillInterval(stored_descriptors_.value());

headers.addReferenceKey(
HttpFilters::Common::RateLimit::XRateLimitHeaders::get().XRateLimitLimit, limit);
headers.addReferenceKey(
HttpFilters::Common::RateLimit::XRateLimitHeaders::get().XRateLimitRemaining, remaining);
headers.addReferenceKey(
HttpFilters::Common::RateLimit::XRateLimitHeaders::get().XRateLimitReset, reset);
}

return Http::FilterHeadersStatus::Continue;
}

bool Filter::requestAllowed(absl::Span<const RateLimit::LocalDescriptor> request_descriptors) {
const auto* config = getConfig();
return config->rateLimitPerConnection()
? getPerConnectionRateLimiter().requestAllowed(request_descriptors)
: config->requestAllowed(request_descriptors);
}

uint32_t Filter::maxTokens(absl::Span<const RateLimit::LocalDescriptor> request_descriptors) {
const auto* config = getConfig();
return config->rateLimitPerConnection()
? getPerConnectionRateLimiter().maxTokens(request_descriptors)
: config->maxTokens(request_descriptors);
}

uint32_t Filter::remainingTokens(absl::Span<const RateLimit::LocalDescriptor> request_descriptors) {
const auto* config = getConfig();
return config->rateLimitPerConnection()
? getPerConnectionRateLimiter().remainingTokens(request_descriptors)
: config->remainingTokens(request_descriptors);
}

int64_t
Filter::remainingFillInterval(absl::Span<const RateLimit::LocalDescriptor> request_descriptors) {
const auto* config = getConfig();
return config->rateLimitPerConnection()
? getPerConnectionRateLimiter().remainingFillInterval(request_descriptors)
: config->remainingFillInterval(request_descriptors);
}

const Filters::Common::LocalRateLimit::LocalRateLimiterImpl& Filter::getPerConnectionRateLimiter() {
const auto* config = getConfig();
ASSERT(config->rateLimitPerConnection());
Expand Down
Loading