Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

router: add dynamic metadata header formatter #11858

Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
6830e99
router: add request metadata header formatter
Jul 1, 2020
57fa277
Merge remote-tracking branch 'upstream/master' into add-stream-info-d…
Jul 6, 2020
15c8aa4
Merge remote-tracking branch 'upstream/master' into add-stream-info-d…
Jul 6, 2020
1063eef
Merge remote-tracking branch 'upstream/master' into add-stream-info-d…
Jul 6, 2020
e2e9871
Merge remote-tracking branch 'upstream/master' into add-stream-info-d…
Jul 9, 2020
2183b77
Sort changelog
Jul 9, 2020
bcd3e4c
Merge remote-tracking branch 'upstream/master' into add-stream-info-d…
Jul 10, 2020
354777e
Merge remote-tracking branch 'upstream/master' into add-stream-info-d…
Jul 13, 2020
d6dc9fd
Merge remote-tracking branch 'upstream/master' into add-stream-info-d…
Jul 24, 2020
42b38c9
Merge remote-tracking branch 'upstream/master' into add-stream-info-d…
Jul 27, 2020
02afb1c
Fix changelog
Jul 27, 2020
fc4b267
Rename to DYNAMIC_METADATA()
Jul 27, 2020
b43c6c5
Merge remote-tracking branch 'upstream/master' into add-stream-info-d…
Jul 27, 2020
8edfca3
Kick CI
Jul 28, 2020
5ad945b
Merge remote-tracking branch 'upstream/master' into add-stream-info-d…
Jul 28, 2020
dc6057e
Merge remote-tracking branch 'upstream/master' into add-stream-info-d…
Jul 28, 2020
5c3d13c
Merge remote-tracking branch 'upstream/master' into add-stream-info-d…
Jul 29, 2020
d2982bd
Merge remote-tracking branch 'upstream/master' into add-stream-info-d…
Aug 10, 2020
db6b8b4
Merge remote-tracking branch 'upstream/master' into add-stream-info-d…
Aug 11, 2020
e725799
Sort changelog
Aug 11, 2020
039df88
Kick CI
Aug 11, 2020
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
8 changes: 7 additions & 1 deletion docs/root/configuration/http/http_conn_man/headers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,12 @@ Supported variable names are:
Upstream metadata cannot be added to request headers as the upstream host has not been selected
when custom request headers are generated.

%DYNAMIC_METADATA(["namespace", "key", ...])%
Similar to UPSTREAM_METADATA, populates the header with dynamic metadata available in a request
(e.g.: added by filters like the header-to-metadata filter).

This works both on request and response headers.

%UPSTREAM_REMOTE_ADDRESS%
Remote address of the upstream host. If the address is an IP address it includes both address
and port. The upstream remote address cannot be added to request headers as the upstream host
Expand Down Expand Up @@ -657,4 +663,4 @@ Supported variable names are:

%RESPONSE_CODE_DETAILS%
Response code details provides additional information about the HTTP response code, such as
who set it (the upstream or envoy) and why.
who set it (the upstream or envoy) and why.
1 change: 1 addition & 0 deletions docs/root/version_history/current.rst
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ New Features
* router: added new
:ref:`envoy-ratelimited<config_http_filters_router_retry_policy-envoy-ratelimited>`
retry policy, which allows retrying envoy's own rate limited responses.
* router: added support for DYNAMIC_METADATA :ref:`header formatter <config_http_conn_man_headers_custom_request_headers>`.
* stats: added optional histograms to :ref:`cluster stats <config_cluster_manager_cluster_stats_request_response_sizes>`
that track headers and body sizes of requests and responses.
* stats: allow configuring histogram buckets for stats sinks and admin endpoints that support it.
Expand Down
22 changes: 15 additions & 7 deletions source/common/router/header_formatter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ std::string formatPerRequestStateParseException(absl::string_view params) {
// (["a", "b", "c"])
// There must be at least 2 array elements (a metadata namespace and at least 1 key).
std::function<std::string(const Envoy::StreamInfo::StreamInfo&)>
parseUpstreamMetadataField(absl::string_view params_str) {
parseMetadataField(absl::string_view params_str, bool upstream = true) {
params_str = StringUtil::trim(params_str);
if (params_str.empty() || params_str.front() != '(' || params_str.back() != ')') {
throw EnvoyException(formatUpstreamMetadataParseException(params_str));
Expand All @@ -72,14 +72,20 @@ parseUpstreamMetadataField(absl::string_view params_str) {
throw EnvoyException(formatUpstreamMetadataParseException(params_str));
}

return [params](const Envoy::StreamInfo::StreamInfo& stream_info) -> std::string {
Upstream::HostDescriptionConstSharedPtr host = stream_info.upstreamHost();
if (!host) {
return std::string();
return [upstream, params](const Envoy::StreamInfo::StreamInfo& stream_info) -> std::string {
const envoy::config::core::v3::Metadata* metadata = nullptr;
if (upstream) {
Upstream::HostDescriptionConstSharedPtr host = stream_info.upstreamHost();
if (!host) {
return std::string();
}
metadata = host->metadata().get();
} else {
metadata = &(stream_info.dynamicMetadata());
}

const ProtobufWkt::Value* value =
&::Envoy::Config::Metadata::metadataValue(host->metadata().get(), params[0], params[1]);
&::Envoy::Config::Metadata::metadataValue(metadata, params[0], params[1]);
if (value->kind_case() == ProtobufWkt::Value::KIND_NOT_SET) {
// No kind indicates default ProtobufWkt::Value which means namespace or key not
// found.
Expand Down Expand Up @@ -339,8 +345,10 @@ StreamInfoHeaderFormatter::StreamInfoHeaderFormatter(absl::string_view field_nam
return formatted;
};
} else if (absl::StartsWith(field_name, "UPSTREAM_METADATA")) {
field_extractor_ = parseMetadataField(field_name.substr(STATIC_STRLEN("UPSTREAM_METADATA")));
} else if (absl::StartsWith(field_name, "DYNAMIC_METADATA")) {
field_extractor_ =
parseUpstreamMetadataField(field_name.substr(STATIC_STRLEN("UPSTREAM_METADATA")));
parseMetadataField(field_name.substr(STATIC_STRLEN("DYNAMIC_METADATA")), false);
} else if (absl::StartsWith(field_name, "PER_REQUEST_STATE")) {
field_extractor_ =
parsePerRequestStateField(field_name.substr(STATIC_STRLEN("PER_REQUEST_STATE")));
Expand Down
15 changes: 15 additions & 0 deletions test/common/router/header_formatter_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,21 @@ TEST_F(StreamInfoHeaderFormatterTest, TestFormatWithUpstreamMetadataVariableMiss
testFormatting(stream_info, "UPSTREAM_METADATA([\"namespace\", \"key\"])", "");
}

TEST_F(StreamInfoHeaderFormatterTest, TestFormatWithRequestMetadata) {
NiceMock<Envoy::StreamInfo::MockStreamInfo> stream_info;
envoy::config::core::v3::Metadata metadata;
ProtobufWkt::Struct struct_obj;

auto& fields_map = *struct_obj.mutable_fields();
fields_map["foo"] = ValueUtil::stringValue("bar");
(*metadata.mutable_filter_metadata())["envoy.lb"] = struct_obj;

EXPECT_CALL(stream_info, dynamicMetadata()).WillRepeatedly(ReturnRef(metadata));
EXPECT_CALL(Const(stream_info), dynamicMetadata()).WillRepeatedly(ReturnRef(metadata));

testFormatting(stream_info, "DYNAMIC_METADATA([\"envoy.lb\", \"foo\"])", "bar");
}

TEST_F(StreamInfoHeaderFormatterTest, TestFormatWithPerRequestStateVariable) {
Envoy::StreamInfo::FilterStateSharedPtr filter_state(
std::make_shared<Envoy::StreamInfo::FilterStateImpl>(
Expand Down