Skip to content

Commit 05f9c5d

Browse files
authored
http: Parameterize header module (#941)
The module responsible for adding HTTP headers from target types expects the target to be coerced to a `HeaderValue`. This means that a target can only instrument a single header; and it creates some ambiguity. This change updates the header insertion module to use a Param-type to represent a key-value header pair, making uses clearer.
1 parent b453c04 commit 05f9c5d

File tree

4 files changed

+56
-35
lines changed

4 files changed

+56
-35
lines changed

linkerd/app/outbound/src/http/logical.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
use super::{Concrete, Logical};
1+
use super::{CanonicalDstHeader, Concrete, Logical};
22
use crate::{resolve, stack_labels, Outbound};
33
use linkerd_app_core::{
44
classify, config, profiles,
55
proxy::{core::Resolve, http},
6-
retry, svc, tls, Error, Never, CANONICAL_DST_HEADER, DST_OVERRIDE_HEADER,
6+
retry, svc, tls, Error, Never, DST_OVERRIDE_HEADER,
77
};
88
use tracing::debug_span;
99

@@ -146,7 +146,7 @@ impl<E> Outbound<E> {
146146
// Strips headers that may be set by this proxy and add an outbound
147147
// canonical-dst-header. The response body is boxed unify the profile
148148
// stack's response type. withthat of to endpoint stack.
149-
.push(http::NewHeaderFromTarget::layer(CANONICAL_DST_HEADER))
149+
.push(http::NewHeaderFromTarget::<CanonicalDstHeader, _>::layer())
150150
.push_on_response(
151151
svc::layers()
152152
.push(http::strip_header::request::layer(DST_OVERRIDE_HEADER))

linkerd/app/outbound/src/http/mod.rs

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use linkerd_app_core::{
1616
svc::Param,
1717
tls,
1818
transport_header::SessionProtocol,
19-
Conditional,
19+
Addr, Conditional, CANONICAL_DST_HEADER,
2020
};
2121
use std::{net::SocketAddr, str::FromStr, sync::Arc};
2222

@@ -25,6 +25,22 @@ pub type Logical = crate::target::Logical<Version>;
2525
pub type Concrete = crate::target::Concrete<Version>;
2626
pub type Endpoint = crate::target::Endpoint<Version>;
2727

28+
#[derive(Clone, Debug)]
29+
pub struct CanonicalDstHeader(pub Addr);
30+
31+
// === impl CanonicalDstHeader ===
32+
33+
impl Into<HeaderPair> for CanonicalDstHeader {
34+
fn into(self) -> HeaderPair {
35+
HeaderPair(
36+
HeaderName::from_static(CANONICAL_DST_HEADER),
37+
HeaderValue::from_str(&self.0.to_string()).expect("addr must be a valid header"),
38+
)
39+
}
40+
}
41+
42+
// === impl Accept ===
43+
2844
impl Param<Version> for Accept {
2945
fn param(&self) -> Version {
3046
self.protocol
@@ -40,6 +56,8 @@ impl Param<normalize_uri::DefaultAuthority> for Accept {
4056
}
4157
}
4258

59+
// === impl Logical ===
60+
4361
impl From<(Version, tcp::Logical)> for Logical {
4462
fn from((protocol, logical): (Version, tcp::Logical)) -> Self {
4563
Self {
@@ -50,6 +68,12 @@ impl From<(Version, tcp::Logical)> for Logical {
5068
}
5169
}
5270

71+
impl Param<CanonicalDstHeader> for Logical {
72+
fn param(&self) -> CanonicalDstHeader {
73+
CanonicalDstHeader(self.addr())
74+
}
75+
}
76+
5377
impl Param<Version> for Logical {
5478
fn param(&self) -> Version {
5579
self.protocol
@@ -85,6 +109,8 @@ impl Param<normalize_uri::DefaultAuthority> for Logical {
85109
}
86110
}
87111

112+
// === impl Endpoint ===
113+
88114
impl Param<client::Settings> for Endpoint {
89115
fn param(&self) -> client::Settings {
90116
match self.protocol {
@@ -109,14 +135,6 @@ impl Param<Option<SessionProtocol>> for Endpoint {
109135
}
110136
}
111137

112-
// Used to set the l5d-canonical-dst header.
113-
impl From<&'_ Logical> for header::HeaderValue {
114-
fn from(target: &'_ Logical) -> Self {
115-
header::HeaderValue::from_str(&target.addr().to_string())
116-
.expect("addr must be a valid header")
117-
}
118-
}
119-
120138
impl CanOverrideAuthority for Endpoint {
121139
fn override_authority(&self) -> Option<uri::Authority> {
122140
self.metadata.authority_override().cloned()
Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,53 @@
1-
use http::header::{HeaderValue, IntoHeaderName};
2-
use linkerd_stack::{layer, NewService};
1+
use crate::HeaderPair;
2+
use http::header::{HeaderName, HeaderValue};
3+
use linkerd_stack::{layer, NewService, Param};
34
use std::task::{Context, Poll};
45

56
/// Wraps an HTTP `Service` so that the Stack's `T -typed target` is cloned into
67
/// each request's headers.
78
#[derive(Clone, Debug)]
8-
pub struct NewHeaderFromTarget<H, M> {
9-
header: H,
10-
inner: M,
9+
pub struct NewHeaderFromTarget<H, N> {
10+
inner: N,
11+
_marker: std::marker::PhantomData<fn() -> H>,
1112
}
1213

1314
#[derive(Clone, Debug)]
14-
pub struct HeaderFromTarget<H, S> {
15-
header: H,
15+
pub struct HeaderFromTarget<S> {
16+
name: HeaderName,
1617
value: HeaderValue,
1718
inner: S,
1819
}
1920

2021
// === impl NewHeaderFromTarget ===
2122

22-
impl<H: Clone, N> NewHeaderFromTarget<H, N> {
23-
pub fn layer(header: H) -> impl layer::Layer<N, Service = Self> + Clone {
23+
impl<H, N> NewHeaderFromTarget<H, N> {
24+
pub fn layer() -> impl layer::Layer<N, Service = Self> + Clone {
2425
layer::mk(move |inner| Self {
2526
inner,
26-
header: header.clone(),
27+
_marker: std::marker::PhantomData,
2728
})
2829
}
2930
}
3031

3132
impl<H, T, N> NewService<T> for NewHeaderFromTarget<H, N>
3233
where
33-
H: IntoHeaderName + Clone,
34-
T: Clone + Send + Sync + 'static,
35-
HeaderValue: for<'t> From<&'t T>,
34+
H: Into<HeaderPair>,
35+
T: Param<H>,
3636
N: NewService<T>,
3737
{
38-
type Service = HeaderFromTarget<H, N::Service>;
38+
type Service = HeaderFromTarget<N::Service>;
3939

4040
fn new_service(&mut self, t: T) -> Self::Service {
41-
HeaderFromTarget {
42-
value: (&t).into(),
43-
inner: self.inner.new_service(t),
44-
header: self.header.clone(),
45-
}
41+
let HeaderPair(name, value) = t.param().into();
42+
let inner = self.inner.new_service(t);
43+
HeaderFromTarget { name, value, inner }
4644
}
4745
}
4846

4947
// === impl HeaderFromTarget ===
5048

51-
impl<H, S, B> tower::Service<http::Request<B>> for HeaderFromTarget<H, S>
49+
impl<S, B> tower::Service<http::Request<B>> for HeaderFromTarget<S>
5250
where
53-
H: IntoHeaderName + Clone,
5451
S: tower::Service<http::Request<B>>,
5552
{
5653
type Response = S::Response;
@@ -65,7 +62,7 @@ where
6562
#[inline]
6663
fn call(&mut self, mut req: http::Request<B>) -> Self::Future {
6764
req.headers_mut()
68-
.insert(self.header.clone(), self.value.clone());
65+
.insert(self.name.clone(), self.value.clone());
6966
self.inner.call(req)
7067
}
7168
}

linkerd/proxy/http/src/lib.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,17 @@ pub use self::{
3636
timeout::MakeTimeoutLayer,
3737
version::Version,
3838
};
39-
pub use http::{header, uri, Request, Response, StatusCode};
39+
pub use http::{
40+
header::{self, HeaderName, HeaderValue},
41+
uri, Request, Response, StatusCode,
42+
};
4043
pub use hyper::body::HttpBody;
4144
pub use linkerd_http_box::{BoxBody, BoxRequest, BoxResponse};
4245
use std::str::FromStr;
4346

47+
#[derive(Clone, Debug)]
48+
pub struct HeaderPair(pub HeaderName, pub HeaderValue);
49+
4450
pub trait HasH2Reason {
4551
fn h2_reason(&self) -> Option<::h2::Reason>;
4652
}

0 commit comments

Comments
 (0)