Skip to content

Commit 67c49c9

Browse files
committed
HttpsConnector: add tls_server_name to allow overriding TLS handshake
1 parent 5cdd3f2 commit 67c49c9

2 files changed

Lines changed: 55 additions & 2 deletions

File tree

examples/client-tls-server-name.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//! HTTPS GET client with custome TLS server name based on hyper-tls
2+
//!
3+
//! First parameter is the URL to GET.
4+
//! Second parameter is the TLS server name to negociate.
5+
use bytes::Bytes;
6+
use http_body_util::BodyExt;
7+
8+
use http_body_util::Empty;
9+
use hyper_tls::HttpsConnector;
10+
use hyper_util::{client::legacy::Client, rt::TokioExecutor};
11+
use tokio::io::{self, AsyncWriteExt as _};
12+
13+
#[tokio::main(flavor = "current_thread")]
14+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
15+
let mut args = std::env::args().skip(1);
16+
17+
let (Some(url), Some(server_name)) = (args.next(), args.next()) else {
18+
println!("Usage: client <url> <server_name>");
19+
return Ok(());
20+
};
21+
22+
let https = HttpsConnector::new().with_tls_server_name(server_name);
23+
24+
let client = Client::builder(TokioExecutor::new()).build::<_, Empty<Bytes>>(https);
25+
26+
let mut res = client.get(url.parse()?).await?;
27+
28+
println!("Status:\n{}", res.status());
29+
println!("Headers:\n{:#?}", res.headers());
30+
31+
while let Some(frame) = res.body_mut().frame().await {
32+
let frame = frame?;
33+
34+
if let Some(d) = frame.data_ref() {
35+
io::stdout().write_all(d).await?;
36+
}
37+
}
38+
39+
Ok(())
40+
}

src/client.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ pub struct HttpsConnector<T> {
2020
force_https: bool,
2121
http: T,
2222
tls: TlsConnector,
23+
tls_server_name: Option<String>,
2324
}
2425

2526
impl HttpsConnector<HttpConnector> {
@@ -55,6 +56,15 @@ impl HttpsConnector<HttpConnector> {
5556
http.enforce_http(false);
5657
HttpsConnector::from((http, tls))
5758
}
59+
60+
/// Get a HttpsConnector with a TLS server name override.
61+
///
62+
/// This is useful in cases where you can't work around the URL's host but know the name you
63+
/// expect from the remote server's certificate.
64+
pub fn with_tls_server_name(mut self, server_name: impl Into<String>) -> Self {
65+
self.tls_server_name = Some(server_name.into());
66+
self
67+
}
5868
}
5969

6070
impl<T: Default> Default for HttpsConnector<T> {
@@ -98,6 +108,7 @@ impl<T> From<(T, TlsConnector)> for HttpsConnector<T> {
98108
force_https: false,
99109
http: args.0,
100110
tls: args.1,
111+
tls_server_name: None,
101112
}
102113
}
103114
}
@@ -137,8 +148,10 @@ where
137148
return err(ForceHttpsButUriNotHttps.into());
138149
}
139150

140-
let host = dst
141-
.host()
151+
let host = self
152+
.tls_server_name
153+
.as_deref()
154+
.or_else(|| dst.host())
142155
.unwrap_or("")
143156
.trim_matches(|c| c == '[' || c == ']')
144157
.to_owned();

0 commit comments

Comments
 (0)