diff --git a/linkerd/app/outbound/src/http/endpoint.rs b/linkerd/app/outbound/src/http/endpoint.rs index 3022ef96f9..351c741721 100644 --- a/linkerd/app/outbound/src/http/endpoint.rs +++ b/linkerd/app/outbound/src/http/endpoint.rs @@ -1,4 +1,4 @@ -use super::{NewRequireIdentity, ProxyConnectionClose}; +use super::{NewRequireIdentity, NewStripProxyError, ProxyConnectionClose}; use crate::Outbound; use linkerd_app_core::{ classify, config, errors, http_tracing, metrics, @@ -49,6 +49,9 @@ impl Outbound { // Set the TLS status on responses so that the stack can detect whether the request // was sent over a meshed connection. .push_http_response_insert_target::() + // If the outbound proxy is not configured to emit headers, then strip the + // `l5d-proxy-errors` header if set by the peer. + .push(NewStripProxyError::layer(config.emit_headers)) // Tear down server connections when a peer proxy generates an error. // TODO(ver) this should only be honored when forwarding and not when the connection // is part of a balancer. diff --git a/linkerd/app/outbound/src/http/mod.rs b/linkerd/app/outbound/src/http/mod.rs index 2c96b2fcfa..7adaadd3a2 100644 --- a/linkerd/app/outbound/src/http/mod.rs +++ b/linkerd/app/outbound/src/http/mod.rs @@ -4,8 +4,12 @@ pub mod logical; mod proxy_connection_close; mod require_id_header; mod server; +mod strip_proxy_error; -use self::{proxy_connection_close::ProxyConnectionClose, require_id_header::NewRequireIdentity}; +use self::{ + proxy_connection_close::ProxyConnectionClose, require_id_header::NewRequireIdentity, + strip_proxy_error::NewStripProxyError, +}; pub(crate) use self::{require_id_header::IdentityRequired, server::ServerRescue}; use crate::tcp; pub use linkerd_app_core::proxy::http::*; diff --git a/linkerd/app/outbound/src/http/strip_proxy_error.rs b/linkerd/app/outbound/src/http/strip_proxy_error.rs new file mode 100644 index 0000000000..0fe28c07e8 --- /dev/null +++ b/linkerd/app/outbound/src/http/strip_proxy_error.rs @@ -0,0 +1,40 @@ +use linkerd_app_core::{ + errors::respond::L5D_PROXY_ERROR, + proxy::http, + svc::{self, NewService}, +}; + +#[derive(Clone, Debug)] +pub struct NewStripProxyError { + strip: bool, + inner: N, +} + +impl NewStripProxyError { + pub fn layer(emit_headers: bool) -> impl svc::layer::Layer + Clone { + svc::layer::mk(move |inner| Self { + strip: !emit_headers, + inner, + }) + } +} + +impl NewService for NewStripProxyError +where + N: NewService, +{ + type Service = svc::Either< + N::Service, + http::strip_header::response::StripHeader<&'static str, N::Service>, + >; + + fn new_service(&self, target: T) -> Self::Service { + let inner = self.inner.new_service(target); + + if self.strip { + return svc::Either::B(http::StripHeader::response(L5D_PROXY_ERROR, inner)); + }; + + svc::Either::A(inner) + } +} diff --git a/linkerd/proxy/http/src/lib.rs b/linkerd/proxy/http/src/lib.rs index 89dbc9ff63..38af6cff6b 100644 --- a/linkerd/proxy/http/src/lib.rs +++ b/linkerd/proxy/http/src/lib.rs @@ -33,6 +33,7 @@ pub use self::{ override_authority::{AuthorityOverride, NewOverrideAuthority}, retain::Retain, server::NewServeHttp, + strip_header::StripHeader, timeout::{NewTimeout, ResponseTimeout, ResponseTimeoutError}, version::Version, }; diff --git a/linkerd/proxy/http/src/strip_header.rs b/linkerd/proxy/http/src/strip_header.rs index e7756ddfc8..f95752c3da 100644 --- a/linkerd/proxy/http/src/strip_header.rs +++ b/linkerd/proxy/http/src/strip_header.rs @@ -97,17 +97,13 @@ pub mod response { /// stripped. pub enum RspHeader {} - type StripHeader = super::StripHeader; + pub type StripHeader = super::StripHeader; pub fn layer(header: H) -> impl layer::Layer> + Clone where H: AsHeaderName + Clone, { - layer::mk(move |inner| StripHeader { - inner, - header: header.clone(), - _marker: PhantomData, - }) + layer::mk(move |inner| StripHeader::response(header.clone(), inner)) } #[pin_project] @@ -117,6 +113,16 @@ pub mod response { header: H, } + impl StripHeader { + pub fn response(header: H, inner: S) -> Self { + Self { + inner, + header, + _marker: PhantomData, + } + } + } + impl tower::Service for StripHeader where H: AsHeaderName + Clone,