Skip to content

Commit fe9cf83

Browse files
committed
chore[proxy-http]: Move utilities out of h1 module
Various utility functions are defined in the h1 module that are not strictly HTTP/1-specific. In preparation for additional reorganization of the http module, this change moves utility functions:
1 parent cf8ecb0 commit fe9cf83

File tree

7 files changed

+90
-98
lines changed

7 files changed

+90
-98
lines changed

linkerd/app/core/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,9 @@ pub fn http_request_authority_addr<B>(req: &http::Request<B>) -> Result<Addr, ad
7777
}
7878

7979
pub fn http_request_host_addr<B>(req: &http::Request<B>) -> Result<Addr, addr::Error> {
80-
use crate::proxy::http::h1;
80+
use crate::proxy::http;
8181

82-
h1::authority_from_host(req)
82+
http::authority_from_header(req, http::header::HOST)
8383
.ok_or(addr::Error::InvalidHost)
8484
.and_then(|a| Addr::from_authority_and_default_port(&a, DEFAULT_PORT))
8585
}

linkerd/proxy/http/src/glue.rs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{upgrade::Http11Upgrade, HasH2Reason};
1+
use crate::upgrade::Http11Upgrade;
22
use bytes::Bytes;
33
use futures::TryFuture;
44
use hyper::body::HttpBody;
@@ -180,14 +180,6 @@ where
180180
}
181181
}
182182

183-
// === impl Error ===
184-
185-
impl HasH2Reason for hyper::Error {
186-
fn h2_reason(&self) -> Option<h2::Reason> {
187-
(self as &(dyn std::error::Error + 'static)).h2_reason()
188-
}
189-
}
190-
191183
// === impl Connected ===
192184

193185
impl<C> AsyncRead for Connection<C>

linkerd/proxy/http/src/h1.rs

Lines changed: 4 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ use crate::{
44
};
55
use futures::prelude::*;
66
use http::{
7-
header::{CONNECTION, CONTENT_LENGTH, HOST, TRANSFER_ENCODING, UPGRADE},
8-
uri::{Authority, Parts, Scheme, Uri},
7+
header::{CONTENT_LENGTH, TRANSFER_ENCODING},
8+
uri::Uri,
99
};
1010
use linkerd_error::{Error, Result};
1111
use linkerd_http_box::BoxBody;
1212
use linkerd_stack::MakeConnection;
13-
use std::{mem, pin::Pin, time::Duration};
13+
use std::{pin::Pin, time::Duration};
1414
use tracing::{debug, trace};
1515

1616
#[derive(Copy, Clone, Debug)]
@@ -158,87 +158,14 @@ where
158158
upgrade.insert_half(hyper::upgrade::on(&mut rsp));
159159
}
160160
} else {
161-
strip_connection_headers(rsp.headers_mut());
161+
crate::strip_connection_headers(rsp.headers_mut());
162162
}
163163

164164
rsp.map(BoxBody::new)
165165
}))
166166
}
167167
}
168168

169-
// === HTTP/1 utils ===
170-
171-
/// Returns an Authority from a request's Host header.
172-
pub fn authority_from_host<B>(req: &http::Request<B>) -> Option<Authority> {
173-
super::authority_from_header(req, HOST)
174-
}
175-
176-
pub(crate) fn set_authority(uri: &mut http::Uri, auth: Authority) {
177-
let mut parts = Parts::from(mem::take(uri));
178-
179-
parts.authority = Some(auth);
180-
181-
// If this was an origin-form target (path only),
182-
// then we can't *only* set the authority, as that's
183-
// an illegal target (such as `example.com/docs`).
184-
//
185-
// But don't set a scheme if this was authority-form (CONNECT),
186-
// since that would change its meaning (like `https://example.com`).
187-
if parts.path_and_query.is_some() {
188-
parts.scheme = Some(Scheme::HTTP);
189-
}
190-
191-
let new = Uri::from_parts(parts).expect("absolute uri");
192-
193-
*uri = new;
194-
}
195-
196-
pub(crate) fn strip_connection_headers(headers: &mut http::HeaderMap) {
197-
if let Some(val) = headers.remove(CONNECTION) {
198-
if let Ok(conn_header) = val.to_str() {
199-
// A `Connection` header may have a comma-separated list of
200-
// names of other headers that are meant for only this specific
201-
// connection.
202-
//
203-
// Iterate these names and remove them as headers.
204-
for name in conn_header.split(',') {
205-
let name = name.trim();
206-
headers.remove(name);
207-
}
208-
}
209-
}
210-
211-
// Additionally, strip these "connection-level" headers always, since
212-
// they are otherwise illegal if upgraded to HTTP2.
213-
headers.remove(UPGRADE);
214-
headers.remove("proxy-connection");
215-
headers.remove("keep-alive");
216-
}
217-
218-
/// Checks requests to determine if they want to perform an HTTP upgrade.
219-
pub(crate) fn wants_upgrade<B>(req: &http::Request<B>) -> bool {
220-
// HTTP upgrades were added in 1.1, not 1.0.
221-
if req.version() != http::Version::HTTP_11 {
222-
return false;
223-
}
224-
225-
if let Some(upgrade) = req.headers().get(UPGRADE) {
226-
// If an `h2` upgrade over HTTP/1.1 were to go by the proxy,
227-
// and it succeeded, there would an h2 connection, but it would
228-
// be opaque-to-the-proxy, acting as just a TCP proxy.
229-
//
230-
// A user wouldn't be able to see any usual HTTP telemetry about
231-
// requests going over that connection. Instead of that confusion,
232-
// the proxy strips h2 upgrade headers.
233-
//
234-
// Eventually, the proxy will support h2 upgrades directly.
235-
return upgrade != "h2c";
236-
}
237-
238-
// HTTP/1.1 CONNECT requests are just like upgrades!
239-
req.method() == http::Method::CONNECT
240-
}
241-
242169
/// Checks responses to determine if they are successful HTTP upgrades.
243170
pub(crate) fn is_upgrade<B>(res: &http::Response<B>) -> bool {
244171
#[inline]

linkerd/proxy/http/src/lib.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,12 @@ impl HasH2Reason for ::h2::Error {
7979
}
8080
}
8181

82+
impl HasH2Reason for ::hyper::Error {
83+
fn h2_reason(&self) -> Option<h2::Reason> {
84+
(self as &(dyn std::error::Error + 'static)).h2_reason()
85+
}
86+
}
87+
8288
/// Returns an Authority from the value of `header`.
8389
pub fn authority_from_header<B, K>(req: &http::Request<B>, header: K) -> Option<Authority>
8490
where
@@ -87,3 +93,45 @@ where
8793
let v = req.headers().get(header)?;
8894
v.to_str().ok()?.parse().ok()
8995
}
96+
97+
fn set_authority(uri: &mut uri::Uri, auth: uri::Authority) {
98+
let mut parts = uri::Parts::from(std::mem::take(uri));
99+
100+
parts.authority = Some(auth);
101+
102+
// If this was an origin-form target (path only),
103+
// then we can't *only* set the authority, as that's
104+
// an illegal target (such as `example.com/docs`).
105+
//
106+
// But don't set a scheme if this was authority-form (CONNECT),
107+
// since that would change its meaning (like `https://example.com`).
108+
if parts.path_and_query.is_some() {
109+
parts.scheme = Some(http::uri::Scheme::HTTP);
110+
}
111+
112+
let new = http::uri::Uri::from_parts(parts).expect("absolute uri");
113+
114+
*uri = new;
115+
}
116+
117+
fn strip_connection_headers(headers: &mut http::HeaderMap) {
118+
if let Some(val) = headers.remove(header::CONNECTION) {
119+
if let Ok(conn_header) = val.to_str() {
120+
// A `Connection` header may have a comma-separated list of
121+
// names of other headers that are meant for only this specific
122+
// connection.
123+
//
124+
// Iterate these names and remove them as headers.
125+
for name in conn_header.split(',') {
126+
let name = name.trim();
127+
headers.remove(name);
128+
}
129+
}
130+
}
131+
132+
// Additionally, strip these "connection-level" headers always, since
133+
// they are otherwise illegal if upgraded to HTTP2.
134+
headers.remove(header::UPGRADE);
135+
headers.remove("proxy-connection");
136+
headers.remove("keep-alive");
137+
}

linkerd/proxy/http/src/normalize_uri.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,14 +115,15 @@ where
115115
if req.extensions().get::<h1::WasAbsoluteForm>().is_none()
116116
&& req.uri().authority().is_none()
117117
{
118-
let authority = match h1::authority_from_host(&req).or_else(|| self.default.clone())
118+
let authority = match crate::authority_from_header(&req, http::header::HOST)
119+
.or_else(|| self.default.clone())
119120
{
120121
Some(a) => a,
121122
None => return future::Either::Right(future::err(NoAuthority(()).into())),
122123
};
123124

124125
trace!(%authority, "Normalizing URI");
125-
h1::set_authority(req.uri_mut(), authority);
126+
crate::set_authority(req.uri_mut(), authority);
126127
}
127128
}
128129

linkerd/proxy/http/src/override_authority.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use super::h1;
21
use http::{header::AsHeaderName, uri::Authority};
32
use linkerd_stack::{layer, NewService, Param};
43
use std::{
@@ -85,7 +84,7 @@ where
8584
}
8685

8786
debug!(%authority, "Overriding");
88-
h1::set_authority(req.uri_mut(), authority);
87+
crate::set_authority(req.uri_mut(), authority);
8988
}
9089

9190
self.inner.call(req)

linkerd/proxy/http/src/upgrade.rs

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ use futures::{
77
};
88
use hyper::upgrade::OnUpgrade;
99
use linkerd_duplex::Duplex;
10-
use std::fmt;
11-
use std::mem;
12-
use std::sync::Arc;
13-
use std::task::{Context, Poll};
10+
use std::{
11+
fmt, mem,
12+
sync::Arc,
13+
task::{Context, Poll},
14+
};
1415
use tracing::instrument::Instrument;
1516
use tracing::{debug, info, trace};
1617
use try_lock::TryLock;
@@ -198,7 +199,7 @@ where
198199
return Either::Right(future::ok(res));
199200
}
200201

201-
let upgrade = if h1::wants_upgrade(&req) {
202+
let upgrade = if wants_upgrade(&req) {
202203
trace!("server request wants HTTP/1.1 upgrade");
203204
// Upgrade requests include several "connection" headers that
204205
// cannot be removed.
@@ -210,7 +211,7 @@ where
210211

211212
Some((halves.server, on_upgrade))
212213
} else {
213-
h1::strip_connection_headers(req.headers_mut());
214+
crate::strip_connection_headers(req.headers_mut());
214215
None
215216
};
216217

@@ -219,3 +220,27 @@ where
219220
Either::Left(self.service.call(req))
220221
}
221222
}
223+
224+
/// Checks requests to determine if they want to perform an HTTP upgrade.
225+
fn wants_upgrade<B>(req: &http::Request<B>) -> bool {
226+
// HTTP upgrades were added in 1.1, not 1.0.
227+
if req.version() != http::Version::HTTP_11 {
228+
return false;
229+
}
230+
231+
if let Some(upgrade) = req.headers().get(http::header::UPGRADE) {
232+
// If an `h2` upgrade over HTTP/1.1 were to go by the proxy,
233+
// and it succeeded, there would an h2 connection, but it would
234+
// be opaque-to-the-proxy, acting as just a TCP proxy.
235+
//
236+
// A user wouldn't be able to see any usual HTTP telemetry about
237+
// requests going over that connection. Instead of that confusion,
238+
// the proxy strips h2 upgrade headers.
239+
//
240+
// Eventually, the proxy will support h2 upgrades directly.
241+
return upgrade != "h2c";
242+
}
243+
244+
// HTTP/1.1 CONNECT requests are just like upgrades!
245+
req.method() == http::Method::CONNECT
246+
}

0 commit comments

Comments
 (0)