Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
4 changes: 4 additions & 0 deletions changelogs/current.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ minor_behavior_changes:
change: |
Enable obsolete line folding in BalsaParser (for behavior parity with http-parser, the
previously used HTTP/1 parser).
- area: proxy status
change: |
Add more conversion in the proxy status utility. It can be disabled by the runtime guard
``envoy.reloadable_features.proxy_status_mapping_more_core_response_flags``.

bug_fixes:
# *Changes expected to improve the state of the world and are unlikely to have negative effects*
Expand Down
1 change: 1 addition & 0 deletions source/common/runtime/runtime_features.cc
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ 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_original_dst_rely_on_idle_timeout);
RUNTIME_GUARD(envoy_reloadable_features_proxy_status_mapping_more_core_response_flags);
RUNTIME_GUARD(envoy_reloadable_features_proxy_status_upstream_request_timeout);
RUNTIME_GUARD(envoy_reloadable_features_quic_fix_filter_manager_uaf);
// Ignore the automated "remove this flag" issue: we should keep this for 1 year. Confirm with
Expand Down
47 changes: 38 additions & 9 deletions source/common/stream_info/utility.cc
Original file line number Diff line number Diff line change
Expand Up @@ -440,15 +440,44 @@ ProxyStatusUtils::fromStreamInfo(const StreamInfo& stream_info) {
return ProxyStatusError::ConnectionTimeout;
}
return ProxyStatusError::HttpResponseTimeout;
} else if (stream_info.hasResponseFlag(CoreResponseFlag::LocalReset)) {
return ProxyStatusError::ConnectionTimeout;
} else if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamRemoteReset)) {
return ProxyStatusError::ConnectionTerminated;
} else if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamConnectionFailure)) {
return ProxyStatusError::ConnectionRefused;
} else if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamConnectionTermination)) {
return ProxyStatusError::ConnectionTerminated;
} else if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamOverflow)) {
}

if (Runtime::runtimeFeatureEnabled(
"envoy.reloadable_features.proxy_status_mapping_more_core_response_flags")) {
if (stream_info.hasResponseFlag(CoreResponseFlag::DurationTimeout)) {
return ProxyStatusError::ConnectionTimeout;
} else if (stream_info.hasResponseFlag(CoreResponseFlag::LocalReset)) {
return ProxyStatusError::ConnectionTimeout;
} else if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamRemoteReset)) {
return ProxyStatusError::ConnectionTerminated;
} else if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamConnectionFailure)) {
return ProxyStatusError::ConnectionRefused;
} else if (stream_info.hasResponseFlag(CoreResponseFlag::UnauthorizedExternalService)) {
return ProxyStatusError::ConnectionRefused;
} else if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamConnectionTermination)) {
return ProxyStatusError::ConnectionTerminated;
} else if (stream_info.hasResponseFlag(CoreResponseFlag::DownstreamConnectionTermination)) {
return ProxyStatusError::ConnectionTerminated;
} else if (stream_info.hasResponseFlag(CoreResponseFlag::OverloadManager)) {
return ProxyStatusError::ConnectionLimitReached;
} else if (stream_info.hasResponseFlag(CoreResponseFlag::DropOverLoad)) {
return ProxyStatusError::ConnectionLimitReached;
} else if (stream_info.hasResponseFlag(CoreResponseFlag::FaultInjected)) {
return ProxyStatusError::HttpRequestError;
}
} else {
if (stream_info.hasResponseFlag(CoreResponseFlag::LocalReset)) {
return ProxyStatusError::ConnectionTimeout;
} else if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamRemoteReset)) {
return ProxyStatusError::ConnectionTerminated;
} else if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamConnectionFailure)) {
return ProxyStatusError::ConnectionRefused;
} else if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamConnectionTermination)) {
return ProxyStatusError::ConnectionTerminated;
}
}

if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamOverflow)) {
return ProxyStatusError::ConnectionLimitReached;
} else if (stream_info.hasResponseFlag(CoreResponseFlag::NoRouteFound)) {
return ProxyStatusError::DestinationNotFound;
Expand Down
37 changes: 37 additions & 0 deletions test/common/http/conn_manager_impl_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4430,6 +4430,43 @@ TEST_F(ProxyStatusTest, PopulateProxyStatusWithDetailsAndResponseCode) {
EXPECT_EQ(altered_headers->getStatusValue(), "504");
}

TEST_F(ProxyStatusTest, PopulateUnauthorizedProxyStatus) {
TestScopedRuntime scoped_runtime;
scoped_runtime.mergeValues(
{{"envoy.reloadable_features.proxy_status_mapping_more_core_response_flags", "true"}});
proxy_status_config_ = std::make_unique<HttpConnectionManagerProto::ProxyStatusConfig>();
proxy_status_config_->set_remove_details(false);

initialize();

const ResponseHeaderMap* altered_headers = sendRequestWith(
403, StreamInfo::CoreResponseFlag::UnauthorizedExternalService, /*details=*/"bar");

ASSERT_TRUE(altered_headers);
ASSERT_TRUE(altered_headers->ProxyStatus());
EXPECT_EQ(altered_headers->getProxyStatusValue(),
"custom_server_name; error=connection_refused; details=\"bar; UAEX\"");
EXPECT_EQ(altered_headers->getStatusValue(), "403");
}

TEST_F(ProxyStatusTest, NoPopulateUnauthorizedProxyStatus) {
TestScopedRuntime scoped_runtime;
scoped_runtime.mergeValues(
{{"envoy.reloadable_features.proxy_status_mapping_more_core_response_flags", "false"}});
proxy_status_config_ = std::make_unique<HttpConnectionManagerProto::ProxyStatusConfig>();
proxy_status_config_->set_remove_details(false);

initialize();

const ResponseHeaderMap* altered_headers = sendRequestWith(
403, StreamInfo::CoreResponseFlag::UnauthorizedExternalService, /*details=*/"bar");

ASSERT_TRUE(altered_headers);
ASSERT_FALSE(altered_headers->ProxyStatus());
EXPECT_EQ(altered_headers->getProxyStatusValue(), "");
EXPECT_EQ(altered_headers->getStatusValue(), "403");
}

TEST_F(ProxyStatusTest, PopulateProxyStatusWithDetails) {
TestScopedRuntime scoped_runtime;
scoped_runtime.mergeValues(
Expand Down
45 changes: 45 additions & 0 deletions test/common/stream_info/utility_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -368,16 +368,61 @@ TEST(ProxyStatusFromStreamInfo, TestAll) {
TestScopedRuntime scoped_runtime;
scoped_runtime.mergeValues(
{{"envoy.reloadable_features.proxy_status_upstream_request_timeout", "true"}});
scoped_runtime.mergeValues(
{{"envoy.reloadable_features.proxy_status_mapping_more_core_response_flags", "false"}});
for (const auto& [response_flag, proxy_status_error] :
std::vector<std::pair<ResponseFlag, ProxyStatusError>>{
{CoreResponseFlag::FailedLocalHealthCheck, ProxyStatusError::DestinationUnavailable},
{CoreResponseFlag::NoHealthyUpstream, ProxyStatusError::DestinationUnavailable},
{CoreResponseFlag::UpstreamRequestTimeout, ProxyStatusError::HttpResponseTimeout},
{CoreResponseFlag::LocalReset, ProxyStatusError::ConnectionTimeout},
{CoreResponseFlag::UpstreamRemoteReset, ProxyStatusError::ConnectionTerminated},
{CoreResponseFlag::UpstreamConnectionFailure, ProxyStatusError::ConnectionRefused},
{CoreResponseFlag::UpstreamConnectionTermination,
ProxyStatusError::ConnectionTerminated},
{CoreResponseFlag::UpstreamOverflow, ProxyStatusError::ConnectionLimitReached},
{CoreResponseFlag::NoRouteFound, ProxyStatusError::DestinationNotFound},
{CoreResponseFlag::RateLimited, ProxyStatusError::ConnectionLimitReached},
{CoreResponseFlag::RateLimitServiceError, ProxyStatusError::ConnectionLimitReached},
{CoreResponseFlag::UpstreamRetryLimitExceeded, ProxyStatusError::DestinationUnavailable},
{CoreResponseFlag::StreamIdleTimeout, ProxyStatusError::HttpResponseTimeout},
{CoreResponseFlag::InvalidEnvoyRequestHeaders, ProxyStatusError::HttpRequestError},
{CoreResponseFlag::DownstreamProtocolError, ProxyStatusError::HttpRequestError},
{CoreResponseFlag::UpstreamMaxStreamDurationReached,
ProxyStatusError::HttpResponseTimeout},
{CoreResponseFlag::NoFilterConfigFound, ProxyStatusError::ProxyConfigurationError},
{CoreResponseFlag::UpstreamProtocolError, ProxyStatusError::HttpProtocolError},
{CoreResponseFlag::NoClusterFound, ProxyStatusError::DestinationUnavailable},
{CoreResponseFlag::DnsResolutionFailed, ProxyStatusError::DnsError}}) {
NiceMock<MockStreamInfo> stream_info;
ON_CALL(stream_info, hasResponseFlag(response_flag)).WillByDefault(Return(true));
EXPECT_THAT(ProxyStatusUtils::fromStreamInfo(stream_info), proxy_status_error);
}
}

TEST(ProxyStatusFromStreamInfo, TestNewAll) {
TestScopedRuntime scoped_runtime;
scoped_runtime.mergeValues(
{{"envoy.reloadable_features.proxy_status_upstream_request_timeout", "true"}});
scoped_runtime.mergeValues(
{{"envoy.reloadable_features.proxy_status_mapping_more_core_response_flags", "true"}});
for (const auto& [response_flag, proxy_status_error] :
std::vector<std::pair<ResponseFlag, ProxyStatusError>>{
{CoreResponseFlag::FailedLocalHealthCheck, ProxyStatusError::DestinationUnavailable},
{CoreResponseFlag::NoHealthyUpstream, ProxyStatusError::DestinationUnavailable},
{CoreResponseFlag::UpstreamRequestTimeout, ProxyStatusError::HttpResponseTimeout},
{CoreResponseFlag::DurationTimeout, ProxyStatusError::ConnectionTimeout},
{CoreResponseFlag::LocalReset, ProxyStatusError::ConnectionTimeout},
{CoreResponseFlag::UpstreamRemoteReset, ProxyStatusError::ConnectionTerminated},
{CoreResponseFlag::UpstreamConnectionFailure, ProxyStatusError::ConnectionRefused},
{CoreResponseFlag::UnauthorizedExternalService, ProxyStatusError::ConnectionRefused},
{CoreResponseFlag::UpstreamConnectionTermination,
ProxyStatusError::ConnectionTerminated},
{CoreResponseFlag::DownstreamConnectionTermination,
ProxyStatusError::ConnectionTerminated},
{CoreResponseFlag::OverloadManager, ProxyStatusError::ConnectionLimitReached},
{CoreResponseFlag::DropOverLoad, ProxyStatusError::ConnectionLimitReached},
{CoreResponseFlag::FaultInjected, ProxyStatusError::HttpRequestError},
{CoreResponseFlag::UpstreamOverflow, ProxyStatusError::ConnectionLimitReached},
{CoreResponseFlag::NoRouteFound, ProxyStatusError::DestinationNotFound},
{CoreResponseFlag::RateLimited, ProxyStatusError::ConnectionLimitReached},
Expand Down