Skip to content

Commit

Permalink
route: get all per filter config directly (#36028)
Browse files Browse the repository at this point in the history
Commit Message: route: get all per filter config directly
Additional Description:

1. used absl::string_view rather than `const std::string&` as input
parameter type. This allow the `mostSpecificPerFilterConfig()` and
`perFilterConfigs()` to take a string view as input parameter.
2. replace the `traversePerFilterConfig()` with `perFilterConfigs()`.
The `perFilterConfigs()` will return a vector (inlined) of configs
directly and needn't the caller to provide a callback function to
collect them. The new method is more straight forward and easier to use.
The new method didn't effect any exist logic, but reduce ~150 lines
code.

Risk Level: low.
Testing: n/a.
Docs Changes: n/a.
Release Notes: n/a.
Platform Specific Features: n/a.

---------

Signed-off-by: wangbaiping <[email protected]>
  • Loading branch information
wbpcode authored Sep 9, 2024
1 parent ed6c95f commit b916786
Show file tree
Hide file tree
Showing 32 changed files with 204 additions and 364 deletions.
8 changes: 3 additions & 5 deletions contrib/golang/filters/http/source/golang_filter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "source/common/grpc/status.h"
#include "source/common/http/headers.h"
#include "source/common/http/http1/codec_impl.h"
#include "source/common/http/utility.h"
#include "source/common/router/string_accessor_impl.h"
#include "source/extensions/filters/common/expr/context.h"

Expand Down Expand Up @@ -1377,16 +1378,13 @@ uint64_t Filter::getMergedConfigId() {
Http::StreamFilterCallbacks* callbacks = decoding_state_.getFilterCallbacks();

// get all of the per route config
std::list<const FilterConfigPerRoute*> route_config_list;
callbacks->traversePerFilterConfig(
[&route_config_list](const Router::RouteSpecificFilterConfig& cfg) {
route_config_list.push_back(dynamic_cast<const FilterConfigPerRoute*>(&cfg));
});
auto route_config_list = Http::Utility::getAllPerFilterConfig<FilterConfigPerRoute>(callbacks);

ENVOY_LOG(debug, "golang filter route config list length: {}.", route_config_list.size());

auto id = config_->getConfigId();
for (auto it : route_config_list) {
ASSERT(it != nullptr, "route config should not be null");
auto route_config = *it;
id = route_config.getPluginConfigId(id, config_->pluginName());
}
Expand Down
10 changes: 4 additions & 6 deletions envoy/http/filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -463,13 +463,11 @@ class StreamFilterCallbacks {
virtual const Router::RouteSpecificFilterConfig* mostSpecificPerFilterConfig() const PURE;

/**
* Find all the available per route filter configs, invoking the callback with each config (if
* it is present). Iteration of the configs is in order of specificity. That means that the
* callback will be called first for a config on a Virtual host, then a route, and finally a route
* entry (weighted cluster). If a config is not present, the callback will not be invoked.
* Return all the available per route filter configs. The configs is in order of specificity.
* That means that the config from a route configuration will be first, then the config from a
* virtual host, then the config from a route.
*/
virtual void traversePerFilterConfig(
std::function<void(const Router::RouteSpecificFilterConfig&)> cb) const PURE;
virtual Router::RouteSpecificFilterConfigs perFilterConfigs() const PURE;

/**
* Return the HTTP/1 stream encoder options if applicable. If the stream is not HTTP/1 returns
Expand Down
28 changes: 11 additions & 17 deletions envoy/router/router.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ class RouteSpecificFilterConfig {
virtual ~RouteSpecificFilterConfig() = default;
};
using RouteSpecificFilterConfigConstSharedPtr = std::shared_ptr<const RouteSpecificFilterConfig>;
using RouteSpecificFilterConfigs = absl::InlinedVector<const RouteSpecificFilterConfig*, 4>;

/**
* CorsPolicy for Route and VirtualHost.
Expand Down Expand Up @@ -686,18 +687,14 @@ class VirtualHost {
* hierarchy (Route --> VirtualHost --> RouteConfiguration). Or nullptr if none of them exist.
*/
virtual const RouteSpecificFilterConfig*
mostSpecificPerFilterConfig(const std::string& name) const PURE;
mostSpecificPerFilterConfig(absl::string_view name) const PURE;

/**
* Find all the available per route filter configs, invoking the callback with
* each config (if it is present). Iteration of the configs is in order of
* specificity. That means that the callback will be called first for a config on
* a route configuration, virtual host, route, and finally a route entry (weighted cluster). If
* a config is not present, the callback will not be invoked.
* Return all the available per route filter configs. The configs is in order of specificity.
* That means that the config from a route configuration will be first, then the config from a
* virtual host, then the config from a route.
*/
virtual void traversePerFilterConfig(
const std::string& filter_name,
std::function<void(const Router::RouteSpecificFilterConfig&)> cb) const PURE;
virtual Router::RouteSpecificFilterConfigs perFilterConfigs(absl::string_view name) const PURE;

/**
* @return const envoy::config::core::v3::Metadata& return the metadata provided in the config for
Expand Down Expand Up @@ -1248,17 +1245,14 @@ class Route {
* hierarchy(Route --> VirtualHost --> RouteConfiguration). Or nullptr if none of them exist.
*/
virtual const RouteSpecificFilterConfig*
mostSpecificPerFilterConfig(const std::string& name) const PURE;
mostSpecificPerFilterConfig(absl::string_view name) const PURE;

/**
* Find all the available per route filter configs, invoking the callback with each config (if
* it is present). Iteration of the configs is in order of specificity. That means that the
* callback will be called first for a config on a Virtual host, then a route, and finally a route
* entry (weighted cluster). If a config is not present, the callback will not be invoked.
* Return all the available per route filter configs. The configs is in order of specificity.
* That means that the config from a route configuration will be first, then the config from a
* virtual host, then the config from a route.
*/
virtual void traversePerFilterConfig(
const std::string& filter_name,
std::function<void(const Router::RouteSpecificFilterConfig&)> cb) const PURE;
virtual Router::RouteSpecificFilterConfigs perFilterConfigs(absl::string_view name) const PURE;

/**
* @return const envoy::config::core::v3::Metadata& return the metadata provided in the config for
Expand Down
3 changes: 1 addition & 2 deletions source/common/http/async_client_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -257,8 +257,7 @@ class AsyncStreamImpl : public virtual AsyncClient::Stream,
const Router::RouteSpecificFilterConfig* mostSpecificPerFilterConfig() const override {
return nullptr;
}
void traversePerFilterConfig(
std::function<void(const Router::RouteSpecificFilterConfig&)>) const override {}
Router::RouteSpecificFilterConfigs perFilterConfigs() const override { return {}; }
Http1StreamEncoderOptionsOptRef http1StreamEncoderOptions() override { return {}; }
OptRef<DownstreamStreamFilterCallbacks> downstreamCallbacks() override { return {}; }
OptRef<UpstreamStreamFilterCallbacks> upstreamCallbacks() override { return {}; }
Expand Down
9 changes: 3 additions & 6 deletions source/common/http/filter_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -284,16 +284,13 @@ ActiveStreamFilterBase::mostSpecificPerFilterConfig() const {
return current_route->mostSpecificPerFilterConfig(filter_context_.config_name);
}

void ActiveStreamFilterBase::traversePerFilterConfig(
std::function<void(const Router::RouteSpecificFilterConfig&)> cb) const {
Router::RouteSpecificFilterConfigs ActiveStreamFilterBase::perFilterConfigs() const {
Router::RouteConstSharedPtr current_route = getRoute();
if (current_route == nullptr) {
return;
return {};
}

current_route->traversePerFilterConfig(
filter_context_.config_name,
[&cb](const Router::RouteSpecificFilterConfig& config) { cb(config); });
return current_route->perFilterConfigs(filter_context_.config_name);
}

Http1StreamEncoderOptionsOptRef ActiveStreamFilterBase::http1StreamEncoderOptions() {
Expand Down
3 changes: 1 addition & 2 deletions source/common/http/filter_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,7 @@ struct ActiveStreamFilterBase : public virtual StreamFilterCallbacks,
void restoreContextOnContinue(ScopeTrackedObjectStack& tracked_object_stack) override;
void resetIdleTimer() override;
const Router::RouteSpecificFilterConfig* mostSpecificPerFilterConfig() const override;
void traversePerFilterConfig(
std::function<void(const Router::RouteSpecificFilterConfig&)> cb) const override;
Router::RouteSpecificFilterConfigs perFilterConfigs() const override;
Http1StreamEncoderOptionsOptRef http1StreamEncoderOptions() override;
OptRef<DownstreamStreamFilterCallbacks> downstreamCallbacks() override;
OptRef<UpstreamStreamFilterCallbacks> upstreamCallbacks() override;
Expand Down
16 changes: 8 additions & 8 deletions source/common/http/null_route_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,12 @@ struct NullVirtualHost : public Router::VirtualHost {
bool includeIsTimeoutRetryHeader() const override { return false; }
uint32_t retryShadowBufferLimit() const override { return std::numeric_limits<uint32_t>::max(); }
const Router::RouteSpecificFilterConfig*
mostSpecificPerFilterConfig(const std::string&) const override {
mostSpecificPerFilterConfig(absl::string_view) const override {
return nullptr;
}
void traversePerFilterConfig(
const std::string&,
std::function<void(const Router::RouteSpecificFilterConfig&)>) const override {}
Router::RouteSpecificFilterConfigs perFilterConfigs(absl::string_view) const override {
return {};
}
const envoy::config::core::v3::Metadata& metadata() const override {
return Router::DefaultRouteMetadataPack::get().proto_metadata_;
}
Expand Down Expand Up @@ -225,12 +225,12 @@ struct NullRouteImpl : public Router::Route {
const Router::Decorator* decorator() const override { return nullptr; }
const Router::RouteTracing* tracingConfig() const override { return nullptr; }
const Router::RouteSpecificFilterConfig*
mostSpecificPerFilterConfig(const std::string&) const override {
mostSpecificPerFilterConfig(absl::string_view) const override {
return nullptr;
}
void traversePerFilterConfig(
const std::string&,
std::function<void(const Router::RouteSpecificFilterConfig&)>) const override {}
Router::RouteSpecificFilterConfigs perFilterConfigs(absl::string_view) const override {
return {};
}
const envoy::config::core::v3::Metadata& metadata() const override {
return Router::DefaultRouteMetadataPack::get().proto_metadata_;
}
Expand Down
55 changes: 9 additions & 46 deletions source/common/http/utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -563,43 +563,6 @@ const ConfigType* resolveMostSpecificPerFilterConfig(const Http::StreamFilterCal
return dynamic_cast<const ConfigType*>(callbacks->mostSpecificPerFilterConfig());
}

/**
* Merge all the available per route filter configs into one. To perform the merge,
* the reduce function will be called on each two configs until a single merged config is left.
*
* @param reduce The first argument for this function will be the config from the previous level
* and the second argument is the config from the current level (the more specific one). The
* function should merge the second argument into the first argument.
*
* @return The merged config.
*/
template <class ConfigType>
absl::optional<ConfigType>
getMergedPerFilterConfig(const Http::StreamFilterCallbacks* callbacks,
std::function<void(ConfigType&, const ConfigType&)> reduce) {
static_assert(std::is_copy_constructible<ConfigType>::value,
"ConfigType must be copy constructible");
ASSERT(callbacks != nullptr);

absl::optional<ConfigType> merged;

callbacks->traversePerFilterConfig([&reduce,
&merged](const Router::RouteSpecificFilterConfig& cfg) {
const ConfigType* typed_cfg = dynamic_cast<const ConfigType*>(&cfg);
if (typed_cfg == nullptr) {
ENVOY_LOG_MISC(debug, "Failed to retrieve the correct type of route specific filter config");
return;
}
if (!merged) {
merged.emplace(*typed_cfg);
} else {
reduce(merged.value(), *typed_cfg);
}
});

return merged;
}

/**
* Return all the available per route filter configs.
*
Expand All @@ -609,20 +572,20 @@ getMergedPerFilterConfig(const Http::StreamFilterCallbacks* callbacks,
* and their lifetime is the same as the matched route.
*/
template <class ConfigType>
absl::InlinedVector<const ConfigType*, 3>
absl::InlinedVector<const ConfigType*, 4>
getAllPerFilterConfig(const Http::StreamFilterCallbacks* callbacks) {
ASSERT(callbacks != nullptr);

absl::InlinedVector<const ConfigType*, 3> all_configs;
callbacks->traversePerFilterConfig([&all_configs](const Router::RouteSpecificFilterConfig& cfg) {
const ConfigType* typed_cfg = dynamic_cast<const ConfigType*>(&cfg);
if (typed_cfg == nullptr) {
absl::InlinedVector<const ConfigType*, 4> all_configs;

for (const auto* config : callbacks->perFilterConfigs()) {
const ConfigType* typed_config = dynamic_cast<const ConfigType*>(config);
if (typed_config == nullptr) {
ENVOY_LOG_MISC(debug, "Failed to retrieve the correct type of route specific filter config");
return;
continue;
}

all_configs.push_back(typed_cfg);
});
all_configs.push_back(typed_config);
}

return all_configs;
}
Expand Down
40 changes: 21 additions & 19 deletions source/common/router/config_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1510,15 +1510,15 @@ absl::optional<bool> RouteEntryImplBase::filterDisabled(absl::string_view config
return vhost_->filterDisabled(config_name);
}

void RouteEntryImplBase::traversePerFilterConfig(
const std::string& filter_name,
std::function<void(const Router::RouteSpecificFilterConfig&)> cb) const {
vhost_->traversePerFilterConfig(filter_name, cb);
RouteSpecificFilterConfigs
RouteEntryImplBase::perFilterConfigs(absl::string_view filter_name) const {
auto result = vhost_->perFilterConfigs(filter_name);

auto maybe_route_config = per_filter_configs_->get(filter_name);
const auto* maybe_route_config = per_filter_configs_->get(filter_name);
if (maybe_route_config != nullptr) {
cb(*maybe_route_config);
result.push_back(maybe_route_config);
}
return result;
}

const envoy::config::core::v3::Metadata& RouteEntryImplBase::metadata() const {
Expand Down Expand Up @@ -1598,15 +1598,15 @@ Http::HeaderTransforms RouteEntryImplBase::WeightedClusterEntry::responseHeaderT
return transforms;
}

void RouteEntryImplBase::WeightedClusterEntry::traversePerFilterConfig(
const std::string& filter_name,
std::function<void(const Router::RouteSpecificFilterConfig&)> cb) const {
DynamicRouteEntry::traversePerFilterConfig(filter_name, cb);
RouteSpecificFilterConfigs
RouteEntryImplBase::WeightedClusterEntry::perFilterConfigs(absl::string_view filter_name) const {

auto result = DynamicRouteEntry::perFilterConfigs(filter_name);
const auto* cfg = per_filter_configs_->get(filter_name);
if (cfg) {
cb(*cfg);
if (cfg != nullptr) {
result.push_back(cfg);
}
return result;
}

UriTemplateMatcherRouteEntryImpl::UriTemplateMatcherRouteEntryImpl(
Expand Down Expand Up @@ -1910,23 +1910,25 @@ absl::optional<bool> CommonVirtualHostImpl::filterDisabled(absl::string_view con
}

const RouteSpecificFilterConfig*
CommonVirtualHostImpl::mostSpecificPerFilterConfig(const std::string& name) const {
CommonVirtualHostImpl::mostSpecificPerFilterConfig(absl::string_view name) const {
auto* per_filter_config = per_filter_configs_->get(name);
return per_filter_config != nullptr ? per_filter_config
: global_route_config_->perFilterConfig(name);
}
void CommonVirtualHostImpl::traversePerFilterConfig(
const std::string& filter_name,
std::function<void(const Router::RouteSpecificFilterConfig&)> cb) const {
RouteSpecificFilterConfigs
CommonVirtualHostImpl::perFilterConfigs(absl::string_view filter_name) const {
RouteSpecificFilterConfigs result;

// Parent first.
if (auto* maybe_rc_config = global_route_config_->perFilterConfig(filter_name);
maybe_rc_config != nullptr) {
cb(*maybe_rc_config);
result.push_back(maybe_rc_config);
}
if (auto* maybe_vhost_config = per_filter_configs_->get(filter_name);
maybe_vhost_config != nullptr) {
cb(*maybe_vhost_config);
result.push_back(maybe_vhost_config);
}
return result;
}

const envoy::config::core::v3::Metadata& CommonVirtualHostImpl::metadata() const {
Expand Down Expand Up @@ -2491,7 +2493,7 @@ PerFilterConfigs::PerFilterConfigs(
}
}

const RouteSpecificFilterConfig* PerFilterConfigs::get(const std::string& name) const {
const RouteSpecificFilterConfig* PerFilterConfigs::get(absl::string_view name) const {
auto it = configs_.find(name);
return it == configs_.end() ? nullptr : it->second.config_.get();
}
Expand Down
Loading

0 comments on commit b916786

Please sign in to comment.