Skip to content

Commit db41b50

Browse files
committed
Add HttpsConnectorBuilder
This gives more control over various rustls features, as well as ensures that enabling connector features like http2 can only be done when the appropriate crate features are enabled. Adds an hyper-rustls/http2 feature.
1 parent 3f16ac4 commit db41b50

File tree

4 files changed

+51
-17
lines changed

4 files changed

+51
-17
lines changed

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,10 @@ futures-util = { version = "0.3.1", default-features = false }
2828

2929
[features]
3030
default = ["native-tokio"]
31+
http2 = ["hyper/http2"]
3132
webpki-tokio = ["tokio-runtime", "webpki-roots"]
3233
native-tokio = ["tokio-runtime", "rustls-native-certs"]
33-
tokio-runtime = ["hyper/runtime", "ct-logs"]
34+
tokio-runtime = ["hyper/tcp", "ct-logs"]
3435

3536
[[example]]
3637
name = "client"

examples/client.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ async fn run_client() -> io::Result<()> {
5555
hyper_rustls::HttpsConnector::from((http, tls))
5656
}
5757
// Default HTTPS connector.
58-
None => hyper_rustls::HttpsConnector::with_native_roots(),
58+
None => hyper_rustls::HttpsConnectorBuilder::with_native_roots().build(),
5959
};
6060

6161
// Build the hyper client from the HTTPS connector.

src/connector.rs

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,18 @@ pub struct HttpsConnector<T> {
2222
tls_config: Arc<ClientConfig>,
2323
}
2424

25-
#[cfg(all(
26-
any(feature = "rustls-native-certs", feature = "webpki-roots"),
27-
feature = "tokio-runtime"
28-
))]
29-
impl HttpsConnector<HttpConnector> {
30-
/// Construct a new `HttpsConnector` using the OS root store
25+
/// A builder that will configure an `HttpsConnector`
26+
///
27+
/// This builder ensures configuration is consistent.
28+
///
29+
/// An alternative way of building an `HttpsConnector`
30+
/// is to use From/Into.
31+
pub struct HttpsConnectorBuilder {
32+
tls_config: ClientConfig,
33+
}
34+
35+
impl HttpsConnectorBuilder {
36+
/// Configure using the OS root store for certificate trust
3137
#[cfg(feature = "rustls-native-certs")]
3238
#[cfg_attr(docsrs, doc(cfg(feature = "rustls-native-certs")))]
3339
pub fn with_native_roots() -> Self {
@@ -43,27 +49,54 @@ impl HttpsConnector<HttpConnector> {
4349
if config.root_store.is_empty() {
4450
panic!("no CA certificates found");
4551
}
46-
Self::build(config)
52+
Self { tls_config: config }
53+
}
54+
55+
/// Configure using a custom `rustls::RootCertStore` for certificate trust
56+
pub fn with_custom_roots(roots: rustls::RootCertStore) -> Self {
57+
let mut config = ClientConfig::new();
58+
config.root_store = roots;
59+
Self { tls_config: config }
4760
}
4861

49-
/// Construct a new `HttpsConnector` using the `webpki_roots`
62+
/// Configure using `webpki_roots` for certificate trust
5063
#[cfg(feature = "webpki-roots")]
5164
#[cfg_attr(docsrs, doc(cfg(feature = "webpki-roots")))]
5265
pub fn with_webpki_roots() -> Self {
5366
let mut config = ClientConfig::new();
5467
config
5568
.root_store
5669
.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
57-
Self::build(config)
70+
Self { tls_config: config }
5871
}
5972

60-
fn build(mut config: ClientConfig) -> Self {
73+
/// Enable HTTP2
74+
/// This advertises http2 support in ALPN
75+
#[cfg(feature = "http2")]
76+
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
77+
pub fn enable_http2(mut self) -> Self {
78+
self.tls_config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
79+
self
80+
}
81+
82+
/// Enable certificate transparency
83+
#[cfg(feature = "ct-logs")]
84+
pub fn enable_ct_logs(mut self) -> Self {
85+
self.tls_config.ct_logs = Some(&ct_logs::LOGS);
86+
self
87+
}
88+
89+
/// Built an HttpsConnector<HttpConnector>
90+
#[cfg(feature = "tokio-runtime")]
91+
pub fn build(self) -> HttpsConnector<HttpConnector> {
6192
let mut http = HttpConnector::new();
6293
http.enforce_http(false);
94+
self.wrap_connector(http)
95+
}
6396

64-
config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
65-
config.ct_logs = Some(&ct_logs::LOGS);
66-
(http, config).into()
97+
/// Built an HttpsConnector with a custom lower-level connector
98+
pub fn wrap_connector<H>(self, conn: H) -> HttpsConnector<H> {
99+
(conn, self.tls_config).into()
67100
}
68101
}
69102

src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
//!
1212
//! let mut rt = tokio::runtime::Runtime::new().unwrap();
1313
//! let url = ("https://hyper.rs").parse().unwrap();
14-
//! let https = hyper_rustls::HttpsConnector::with_native_roots();
14+
//! let https = hyper_rustls::HttpsConnectorBuilder::with_native_roots().build();
1515
//!
1616
//! let client: Client<_, hyper::Body> = Client::builder().build(https);
1717
//!
@@ -27,5 +27,5 @@
2727
mod connector;
2828
mod stream;
2929

30-
pub use crate::connector::HttpsConnector;
30+
pub use crate::connector::{HttpsConnector, HttpsConnectorBuilder};
3131
pub use crate::stream::MaybeHttpsStream;

0 commit comments

Comments
 (0)