Skip to content

Commit 5d57d34

Browse files
authored
http: Use the endpoint type to inform URI normalization (#404)
Currently, the `http::normalize_uri` middleware determines absolute-form authorities by reading request extensions. This hidden coupling makes changing things fairly difficult. Instead, we can use the target types, which already hold the relevant info, to determine the absolute-form authority if needed.
1 parent 588609b commit 5d57d34

File tree

7 files changed

+120
-83
lines changed

7 files changed

+120
-83
lines changed

linkerd/addr/src/lib.rs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,14 @@ impl Addr {
7474
}
7575
}
7676

77-
pub fn as_authority(&self) -> http::uri::Authority {
77+
pub fn to_http_authority(&self) -> http::uri::Authority {
7878
match self {
79-
Addr::Name(n) => n.as_authority(),
80-
Addr::Socket(a) => http::uri::Authority::from_str(&format!("{}", a))
79+
Addr::Name(n) => n.as_http_authority(),
80+
Addr::Socket(ref a) if a.port() == 80 => {
81+
http::uri::Authority::from_str(&a.ip().to_string())
82+
.expect("SocketAddr must be valid authority")
83+
}
84+
Addr::Socket(a) => http::uri::Authority::from_str(&a.to_string())
8185
.expect("SocketAddr must be valid authority"),
8286
}
8387
}
@@ -113,6 +117,12 @@ impl fmt::Display for Addr {
113117
}
114118
}
115119

120+
impl From<SocketAddr> for Addr {
121+
fn from(sa: SocketAddr) -> Self {
122+
Addr::Socket(sa)
123+
}
124+
}
125+
116126
impl From<NameAddr> for Addr {
117127
fn from(na: NameAddr) -> Self {
118128
Addr::Name(na)
@@ -175,9 +185,14 @@ impl NameAddr {
175185
self.name.is_localhost()
176186
}
177187

178-
pub fn as_authority(&self) -> http::uri::Authority {
179-
http::uri::Authority::from_str(&format!("{}", self))
180-
.expect("NameAddr must be valid authority")
188+
pub fn as_http_authority(&self) -> http::uri::Authority {
189+
if self.port == 80 {
190+
http::uri::Authority::from_str(self.name.as_ref())
191+
.expect("NameAddr must be valid authority")
192+
} else {
193+
http::uri::Authority::from_str(&self.to_string())
194+
.expect("NameAddr must be valid authority")
195+
}
181196
}
182197
}
183198

linkerd/app/core/src/control.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ pub mod add_origin {
8888
}
8989

9090
fn call(&mut self, target: ControlAddr) -> Self::Future {
91-
let authority = target.addr.as_authority();
91+
let authority = target.addr.to_http_authority();
9292
let inner = self.inner.call(target);
9393
MakeFuture {
9494
inner,

linkerd/app/inbound/src/endpoint.rs

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
1-
use http;
21
use indexmap::IndexMap;
32
use linkerd2_app_core::{
43
classify,
54
dst::{DstAddr, Route},
65
metric_labels::EndpointLabels,
7-
proxy::{http::settings, identity, tap},
6+
proxy::{http, identity, tap},
87
router,
98
transport::{connect, tls},
10-
Conditional, NameAddr,
9+
Addr, Conditional, NameAddr,
1110
};
1211
use std::fmt;
1312
use std::net::SocketAddr;
@@ -18,7 +17,7 @@ use tracing::debug;
1817
pub struct Endpoint {
1918
pub addr: SocketAddr,
2019
pub dst_name: Option<NameAddr>,
21-
pub http_settings: settings::Settings,
20+
pub http_settings: http::Settings,
2221
pub tls_client_id: tls::PeerIdentity,
2322
}
2423

@@ -34,7 +33,7 @@ impl From<SocketAddr> for Endpoint {
3433
Self {
3534
addr,
3635
dst_name: None,
37-
http_settings: settings::Settings::NotHttp,
36+
http_settings: http::Settings::NotHttp,
3837
tls_client_id: Conditional::None(tls::ReasonForNoPeerName::NotHttp.into()),
3938
}
4039
}
@@ -52,8 +51,26 @@ impl tls::HasPeerIdentity for Endpoint {
5251
}
5352
}
5453

55-
impl settings::HasSettings for Endpoint {
56-
fn http_settings(&self) -> &settings::Settings {
54+
impl http::normalize_uri::ShouldNormalizeUri for Endpoint {
55+
fn should_normalize_uri(&self) -> Option<http::uri::Authority> {
56+
if let http::Settings::Http1 {
57+
was_absolute_form: false,
58+
..
59+
} = self.http_settings
60+
{
61+
return Some(
62+
self.dst_name
63+
.as_ref()
64+
.map(|dst| dst.as_http_authority())
65+
.unwrap_or_else(|| Addr::from(self.addr).to_http_authority()),
66+
);
67+
}
68+
None
69+
}
70+
}
71+
72+
impl http::settings::HasSettings for Endpoint {
73+
fn http_settings(&self) -> &http::Settings {
5774
&self.http_settings
5875
}
5976
}

linkerd/app/outbound/src/endpoint.rs

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ use linkerd2_app_core::{
44
metric_labels::{prefix_labels, EndpointLabels},
55
proxy::{
66
api_resolve::{Metadata, ProtocolHint},
7-
http::{identity_from_header, settings},
7+
http::{self, identity_from_header},
88
identity,
99
resolve::map_endpoint::MapEndpoint,
1010
tap,
1111
},
1212
transport::{connect, tls},
13-
Conditional, NameAddr, L5D_REQUIRE_ID,
13+
Addr, Conditional, NameAddr, L5D_REQUIRE_ID,
1414
};
1515
use std::net::SocketAddr;
1616
use std::sync::Arc;
@@ -22,7 +22,7 @@ pub struct Endpoint {
2222
pub addr: SocketAddr,
2323
pub identity: tls::PeerIdentity,
2424
pub metadata: Metadata,
25-
pub http_settings: settings::Settings,
25+
pub http_settings: http::Settings,
2626
}
2727

2828
#[derive(Copy, Clone, Debug)]
@@ -36,13 +36,13 @@ impl Endpoint {
3636
}
3737

3838
match self.http_settings {
39-
settings::Settings::Http2 => false,
40-
settings::Settings::Http1 {
39+
http::Settings::Http2 => false,
40+
http::Settings::Http1 {
4141
keep_alive: _,
4242
wants_h1_upgrade,
4343
was_absolute_form: _,
4444
} => !wants_h1_upgrade,
45-
settings::Settings::NotHttp => {
45+
http::Settings::NotHttp => {
4646
unreachable!(
4747
"Endpoint::can_use_orig_proto called when NotHttp: {:?}",
4848
self,
@@ -58,7 +58,7 @@ impl Endpoint {
5858
.addrs
5959
.target_addr_if_not_local()?;
6060

61-
let http_settings = settings::Settings::from_request(req);
61+
let http_settings = http::Settings::from_request(req);
6262
let identity = match identity_from_header(req, L5D_REQUIRE_ID) {
6363
Some(require_id) => Conditional::Some(require_id),
6464
None => {
@@ -85,7 +85,7 @@ impl From<SocketAddr> for Endpoint {
8585
dst_concrete: None,
8686
identity: Conditional::None(tls::ReasonForNoPeerName::NotHttp.into()),
8787
metadata: Metadata::empty(),
88-
http_settings: settings::Settings::NotHttp,
88+
http_settings: http::Settings::NotHttp,
8989
}
9090
}
9191
}
@@ -119,8 +119,26 @@ impl connect::HasPeerAddr for Endpoint {
119119
}
120120
}
121121

122-
impl settings::HasSettings for Endpoint {
123-
fn http_settings(&self) -> &settings::Settings {
122+
impl http::normalize_uri::ShouldNormalizeUri for Endpoint {
123+
fn should_normalize_uri(&self) -> Option<http::uri::Authority> {
124+
if let http::Settings::Http1 {
125+
was_absolute_form: false,
126+
..
127+
} = self.http_settings
128+
{
129+
return Some(
130+
self.dst_logical
131+
.as_ref()
132+
.map(|dst| dst.as_http_authority())
133+
.unwrap_or_else(|| Addr::from(self.addr).to_http_authority()),
134+
);
135+
}
136+
None
137+
}
138+
}
139+
140+
impl http::settings::HasSettings for Endpoint {
141+
fn http_settings(&self) -> &http::Settings {
124142
&self.http_settings
125143
}
126144
}

linkerd/proxy/http/src/h1.rs

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
use super::upgrade::HttpConnect;
2-
use bytes::BytesMut;
32
use http;
43
use http::header::{CONNECTION, HOST, UPGRADE};
54
use http::uri::{Authority, Parts, Scheme, Uri};
6-
use linkerd2_proxy_transport::tls;
7-
use std::fmt::Write;
85
use std::mem;
96
use tracing::{debug, trace};
107

@@ -19,24 +16,9 @@ pub fn normalize_our_view_of_uri<B>(req: &mut http::Request<B>) {
1916
);
2017

2118
// try to parse the Host header
22-
if let Some(auth) = authority_from_host(&req) {
23-
trace!("using host header");
24-
set_authority(req.uri_mut(), auth);
25-
return;
26-
}
27-
28-
// last resort is to use the so_original_dst
29-
if let Some(addr) = req
30-
.extensions()
31-
.get::<tls::accept::Meta>()
32-
.map(|s| s.addrs.target_addr())
33-
{
34-
trace!(target.addr = %addr, "using target address");
35-
let mut bytes = BytesMut::with_capacity(31);
36-
write!(&mut bytes, "{}", addr).expect("socket address display is under 31 bytes");
37-
let auth =
38-
Authority::from_shared(bytes.freeze()).expect("socket address is valid authority");
39-
set_authority(req.uri_mut(), auth);
19+
if let Some(host) = authority_from_host(&req) {
20+
trace!(%host, "normalizing URI");
21+
set_authority(req.uri_mut(), host);
4022
return;
4123
}
4224

@@ -45,6 +27,7 @@ pub fn normalize_our_view_of_uri<B>(req: &mut http::Request<B>) {
4527

4628
/// Convert any URI into its origin-form (relative path part only).
4729
pub fn set_origin_form(uri: &mut Uri) {
30+
trace!(%uri, "Setting origin form");
4831
let mut parts = mem::replace(uri, Uri::default()).into_parts();
4932
parts.scheme = None;
5033
parts.authority = None;
@@ -56,7 +39,7 @@ pub fn authority_from_host<B>(req: &http::Request<B>) -> Option<Authority> {
5639
super::authority_from_header(req, HOST)
5740
}
5841

59-
fn set_authority(uri: &mut http::Uri, auth: Authority) {
42+
pub fn set_authority(uri: &mut http::Uri, auth: Authority) {
6043
let mut parts = Parts::from(mem::replace(uri, Uri::default()));
6144

6245
parts.authority = Some(auth);

linkerd/proxy/http/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ pub use self::{
3333
settings::Settings,
3434
version::Version,
3535
};
36-
pub use http::{Request, Response};
36+
pub use http::{header, uri, Request, Response};
3737

3838
pub trait HasH2Reason {
3939
fn h2_reason(&self) -> Option<::h2::Reason>;

0 commit comments

Comments
 (0)