Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
40 changes: 36 additions & 4 deletions api/envoy/extensions/filters/http/ext_proc/v3/ext_proc.proto
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE;
// **Current Implementation Status:**
// All options and processing modes are implemented except for the following:
//
// * Request and response attributes are not sent and not processed.
// * Dynamic metadata in responses from the external processor is ignored.
// * "async mode" is not implemented.

// The filter communicates with an external gRPC service called an "external processor"
Expand Down Expand Up @@ -99,7 +97,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE;
// <arch_overview_advanced_filter_state_sharing>` object in a namespace matching the filter
// name.
//
// [#next-free-field: 15]
// [#next-free-field: 17]
message ExternalProcessor {
// Configuration for the gRPC service that the filter will communicate with.
// The filter supports both the "Envoy" and "Google" gRPC clients.
Expand Down Expand Up @@ -200,6 +198,11 @@ message ExternalProcessor {
// :ref:`mode_override <envoy_v3_api_field_service.ext_proc.v3.ProcessingResponse.mode_override>`.
// If not set, ``mode_override`` API in the response message will be ignored.
bool allow_mode_override = 14;

reserved 15;

// Options related to the sending and receiving of dynamic metadata
MetadataOptions metadata_options = 16;
}

// The HeaderForwardingRules structure specifies what headers are
Expand All @@ -224,6 +227,32 @@ message HeaderForwardingRules {
type.matcher.v3.ListStringMatcher disallowed_headers = 2;
}

// The MetadataOptions structure defines options for the sending and receiving of
// dynamic metadata. Specifically, which namespaces to send to the server, whether
// metadata returned by the server may be written, and how that metadata may be written.
message MetadataOptions {
message MetadataNamespaces {
// Specifies a list of metadata namespaces whose values, if present,
// will be passed to the ext_proc service as an opaque *protobuf::Struct*.
repeated string untyped = 1;

// Specifies a list of metadata namespaces whose values, if present,
// will be passed to the ext_proc service as a *protobuf::Any*. This allows
// envoy and the external processing server to share the protobuf message
// definition for safe parsing.
repeated string typed = 2;
}

// Describes which typed or untyped dynamic metadata namespaces to forward to
// the external processing server.
MetadataNamespaces forwarding_namespaces = 1;

// Describes which typed or untyped dynamic metadata namespaces to accept from
// the external processing server. Set to empty or leave unset to disallow writing
// any received dynamic metadata. Receiving of typed metadata is not supported.
MetadataNamespaces receiving_namespaces = 2;
}

// Extra settings that may be added to per-route configuration for a
// virtual host or cluster.
message ExtProcPerRoute {
Expand All @@ -242,7 +271,7 @@ message ExtProcPerRoute {
}

// Overrides that may be set on a per-route basis
// [#next-free-field: 6]
// [#next-free-field: 7]
message ExtProcOverrides {
// Set a different processing mode for this route than the default.
ProcessingMode processing_mode = 1;
Expand All @@ -263,4 +292,7 @@ message ExtProcOverrides {

// Set a different gRPC service for this route than the default.
config.core.v3.GrpcService grpc_service = 5;

// Options related to the sending and receiving of dynamic metadata
MetadataOptions metadata_options = 6;
}
11 changes: 7 additions & 4 deletions api/envoy/service/ext_proc/v3/external_processor.proto
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ service ExternalProcessor {

// This represents the different types of messages that Envoy can send
// to an external processing server.
// [#next-free-field: 8]
// [#next-free-field: 9]
message ProcessingRequest {
// Specify whether the filter that sent this request is running in synchronous
// or asynchronous mode. The choice of synchronous or asynchronous mode
Expand Down Expand Up @@ -115,6 +115,9 @@ message ProcessingRequest {
// in the filter configuration.
HttpTrailers response_trailers = 7;
}

// Dynamic metadata associated with the request.
config.core.v3.Metadata metadata_context = 8;
}

// For every ProcessingRequest received by the server with the ``async_mode`` field
Expand Down Expand Up @@ -158,9 +161,9 @@ message ProcessingResponse {
ImmediateResponse immediate_response = 7;
}

// [#not-implemented-hide:]
// Optional metadata that will be emitted as dynamic metadata to be consumed by the next
// filter. This metadata will be placed in the namespace ``envoy.filters.http.ext_proc``.
// Optional metadata that will be emitted as dynamic metadata to be consumed by
// following filters. This metadata will be placed in the namespace(s) specified by the top-level
// field name(s) of the struct.
google.protobuf.Struct dynamic_metadata = 8;

// Override how parts of the HTTP request and response are processed
Expand Down
15 changes: 0 additions & 15 deletions changelogs/current.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,27 +12,12 @@ minor_behavior_changes:

bug_fixes:
# *Changes expected to improve the state of the world and are unlikely to have negative effects*
- area: buffer
change: |
Fixed a bug (https://github.com/envoyproxy/envoy/issues/28760) that the internal listener causes an undefined
behavior due to the unintended release of the buffer memory.
- area: http
change: |
Fixed recursion when HTTP connection is disconnected due to a high number of premature resets.
- area: grpc
change: |
Fixed a bug in gRPC async client cache which intermittently causes CPU spikes due to busy loop in timer expiration.
- area: tracing
change: |
Fixed a bug that caused the Datadog tracing extension to drop traces that
should be kept on account of an extracted sampling decision.

removed_config_or_runtime:
# *Normally occurs at the end of the* :ref:`deprecation period <deprecated>`

new_features:
- area: tap
change: |
added :ref:`custom_sink <envoy_v3_api_field_config.tap.v3.OutputSink.custom_sink>` type to enable writing tap data
out to a custom sink extension.

Expand Down
7 changes: 7 additions & 0 deletions source/common/http/filter_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -867,6 +867,13 @@ FilterManager::commonDecodePrefix(ActiveStreamDecoderFilter* filter,
}

void DownstreamFilterManager::onLocalReply(StreamFilterBase::LocalReplyData& data) {
if (Runtime::runtimeFeatureEnabled(
"envoy.reloadable_features.on_local_reply_createfilterchain")) {
// To ensure we have filters over which we can iterate and call onLocalReply.
// If the filter chain already exists this will be a no-op.
createFilterChain();
}

state_.under_on_local_reply_ = true;
filter_manager_callbacks_.onLocalReply(data.code_);

Expand Down
4 changes: 4 additions & 0 deletions source/common/runtime/runtime_features.cc
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ RUNTIME_GUARD(envoy_reloadable_features_enable_intermediate_ca);
RUNTIME_GUARD(envoy_reloadable_features_enable_update_listener_socket_options);
RUNTIME_GUARD(envoy_reloadable_features_expand_agnostic_stream_lifetime);
RUNTIME_GUARD(envoy_reloadable_features_finish_reading_on_decode_trailers);
RUNTIME_GUARD(envoy_reloadable_features_fix_hash_key);
RUNTIME_GUARD(envoy_reloadable_features_ext_authz_http_send_original_xff);
RUNTIME_GUARD(envoy_reloadable_features_ext_proc_disable_response_processing_on_local_reply);
RUNTIME_GUARD(envoy_reloadable_features_format_ports_as_numbers);
RUNTIME_GUARD(envoy_reloadable_features_handle_uppercase_scheme);
RUNTIME_GUARD(envoy_reloadable_features_http1_allow_codec_error_response_after_1xx_headers);
Expand All @@ -64,6 +67,7 @@ RUNTIME_GUARD(envoy_reloadable_features_oauth_header_passthrough_fix);
RUNTIME_GUARD(envoy_reloadable_features_oauth_make_token_cookie_httponly);
RUNTIME_GUARD(envoy_reloadable_features_oauth_use_standard_max_age_value);
RUNTIME_GUARD(envoy_reloadable_features_oauth_use_url_encoding);
RUNTIME_GUARD(envoy_reloadable_features_on_local_reply_createfilterchain);
RUNTIME_GUARD(envoy_reloadable_features_original_dst_rely_on_idle_timeout);
RUNTIME_GUARD(envoy_reloadable_features_overload_manager_error_unknown_action);
RUNTIME_GUARD(envoy_reloadable_features_prohibit_route_refresh_after_response_headers_sent);
Expand Down
8 changes: 7 additions & 1 deletion source/extensions/filters/common/expr/context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,13 @@ absl::optional<CelValue> ResponseWrapper::operator[](CelValue key) const {
}
auto value = key.StringOrDie().value();
if (value == Code) {
auto code = info_.responseCode();
absl::optional<uint32_t> code;
uint32_t maybecode;
if (info_.responseCode().has_value()) {
code.emplace(info_.responseCode().value());
} else if (headers_.value_ != nullptr && absl::SimpleAtoi(headers_.value_->getStatusValue(), &maybecode)) {
code.emplace(maybecode);
}
if (code.has_value()) {
return CelValue::CreateInt64(code.value());
}
Expand Down
2 changes: 1 addition & 1 deletion source/extensions/filters/common/expr/evaluator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ ActivationPtr createActivation(const StreamInfo::StreamInfo& info,
response_trailers);
}

BuilderPtr createBuilder(Protobuf::Arena* arena) {
Extensions::Filters::Common::Expr::BuilderPtr createBuilder(Protobuf::Arena* arena) {
ASSERT_IS_MAIN_OR_TEST_THREAD();
google::api::expr::runtime::InterpreterOptions options;

Expand Down
2 changes: 1 addition & 1 deletion source/extensions/filters/common/expr/evaluator.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ using BuilderInstanceSharedPtr = std::shared_ptr<BuilderInstance>;
// Creates an expression builder. The optional arena is used to enable constant folding
// for intermediate evaluation results.
// Throws an exception if fails to construct an expression builder.
BuilderPtr createBuilder(Protobuf::Arena* arena);
Filters::Common::Expr::BuilderPtr createBuilder(Protobuf::Arena* arena);

// Gets the singleton expression builder. Must be called on the main thread.
BuilderInstanceSharedPtr getBuilder(Server::Configuration::CommonFactoryContext& context);
Expand Down
25 changes: 24 additions & 1 deletion source/extensions/filters/http/ext_proc/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ envoy_cc_library(
"ext_proc.h",
"processor_state.h",
],
copts = select({
"//bazel:windows_x86_64": [],
"//conditions:default": [
"-DUSE_CEL_PARSER",
],
}),
deps = [
":client_interface",
":mutation_utils_lib",
Expand All @@ -31,23 +37,40 @@ envoy_cc_library(
"//source/common/runtime:runtime_features_lib",
"//source/extensions/filters/common/mutation_rules:mutation_rules_lib",
"//source/extensions/filters/http/common:pass_through_filter_lib",
"//source/extensions/filters/common/expr:evaluator_lib",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings:str_format",
"@com_google_cel_cpp//eval/public:builtin_func_registrar",
"@com_google_cel_cpp//eval/public:cel_expr_builder_factory",
"@envoy_api//envoy/config/common/mutation_rules/v3:pkg_cc_proto",
"@envoy_api//envoy/config/core/v3:pkg_cc_proto",
"@envoy_api//envoy/extensions/filters/http/ext_proc/v3:pkg_cc_proto",
"@envoy_api//envoy/service/ext_proc/v3:pkg_cc_proto",
],
] + select(
{
"//bazel:windows_x86_64": [],
"//conditions:default": [
"@com_google_cel_cpp//parser",
],
},
),
)

envoy_cc_extension(
name = "config",
srcs = ["config.cc"],
hdrs = ["config.h"],
copts = select({
"//bazel:windows_x86_64": [],
"//conditions:default": [
"-DUSE_CEL_PARSER",
],
}),
deps = [
":client_lib",
":ext_proc",
"//source/extensions/filters/http/common:factory_base_lib",
"//source/extensions/filters/common/expr:evaluator_lib",
"@envoy_api//envoy/extensions/filters/http/ext_proc/v3:pkg_cc_proto",
],
)
Expand Down
10 changes: 8 additions & 2 deletions source/extensions/filters/http/ext_proc/config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,16 @@ namespace ExternalProcessing {
Http::FilterFactoryCb ExternalProcessingFilterConfig::createFilterFactoryFromProtoTyped(
const envoy::extensions::filters::http::ext_proc::v3::ExternalProcessor& proto_config,
const std::string& stats_prefix, Server::Configuration::FactoryContext& context) {
if (expr_builder_ == nullptr) {
expr_builder_ = Extensions::Filters::Common::Expr::createBuilder(nullptr);
}
const uint32_t message_timeout_ms =
PROTOBUF_GET_MS_OR_DEFAULT(proto_config, message_timeout, DefaultMessageTimeoutMs);
const uint32_t max_message_timeout_ms =
PROTOBUF_GET_MS_OR_DEFAULT(proto_config, max_message_timeout, DefaultMaxMessageTimeoutMs);
const auto filter_config =
std::make_shared<FilterConfig>(proto_config, std::chrono::milliseconds(message_timeout_ms),
max_message_timeout_ms, context.scope(), stats_prefix);
max_message_timeout_ms, context.scope(), stats_prefix, *expr_builder_);

return [filter_config, grpc_service = proto_config.grpc_service(),
&context](Http::FilterChainFactoryCallbacks& callbacks) {
Expand All @@ -40,13 +43,16 @@ Http::FilterFactoryCb
ExternalProcessingFilterConfig::createFilterFactoryFromProtoWithServerContextTyped(
const envoy::extensions::filters::http::ext_proc::v3::ExternalProcessor& proto_config,
const std::string& stats_prefix, Server::Configuration::ServerFactoryContext& server_context) {
if (expr_builder_ == nullptr) {
expr_builder_ = Extensions::Filters::Common::Expr::createBuilder(nullptr);
}
const uint32_t message_timeout_ms =
PROTOBUF_GET_MS_OR_DEFAULT(proto_config, message_timeout, DefaultMessageTimeoutMs);
const uint32_t max_message_timeout_ms =
PROTOBUF_GET_MS_OR_DEFAULT(proto_config, max_message_timeout, DefaultMaxMessageTimeoutMs);
const auto filter_config =
std::make_shared<FilterConfig>(proto_config, std::chrono::milliseconds(message_timeout_ms),
max_message_timeout_ms, server_context.scope(), stats_prefix);
max_message_timeout_ms, server_context.scope(), stats_prefix, *expr_builder_);

return [filter_config, grpc_service = proto_config.grpc_service(),
&server_context](Http::FilterChainFactoryCallbacks& callbacks) {
Expand Down
6 changes: 5 additions & 1 deletion source/extensions/filters/http/ext_proc/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "envoy/extensions/filters/http/ext_proc/v3/ext_proc.pb.validate.h"

#include "source/extensions/filters/http/common/factory_base.h"
#include "source/extensions/filters/common/expr/evaluator.h"

namespace Envoy {
namespace Extensions {
Expand All @@ -23,13 +24,16 @@ class ExternalProcessingFilterConfig
static constexpr uint64_t DefaultMessageTimeoutMs = 200;
static constexpr uint64_t DefaultMaxMessageTimeoutMs = 0;

// Expression builder must outlive the compiled expression.
Filters::Common::Expr::BuilderPtr expr_builder_;

Http::FilterFactoryCb createFilterFactoryFromProtoTyped(
const envoy::extensions::filters::http::ext_proc::v3::ExternalProcessor& proto_config,
const std::string& stats_prefix, Server::Configuration::FactoryContext& context) override;

Router::RouteSpecificFilterConfigConstSharedPtr createRouteSpecificFilterConfigTyped(
const envoy::extensions::filters::http::ext_proc::v3::ExtProcPerRoute& proto_config,
Server::Configuration::ServerFactoryContext& context,
Server::Configuration::ServerFactoryContext&,
ProtobufMessage::ValidationVisitor& validator) override;

Http::FilterFactoryCb createFilterFactoryFromProtoWithServerContextTyped(
Expand Down
Loading