Skip to content

Add HttpsConnectorBuilder #145

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,10 @@ futures-util = { version = "0.3.1", default-features = false }

[features]
default = ["native-tokio"]
http2 = ["hyper/http2"]
webpki-tokio = ["tokio-runtime", "webpki-roots"]
native-tokio = ["tokio-runtime", "rustls-native-certs"]
tokio-runtime = ["hyper/runtime", "ct-logs"]
tokio-runtime = ["hyper/tcp", "ct-logs"]

[[example]]
name = "client"
Expand Down
2 changes: 1 addition & 1 deletion examples/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ async fn run_client() -> io::Result<()> {
hyper_rustls::HttpsConnector::from((http, tls))
}
// Default HTTPS connector.
None => hyper_rustls::HttpsConnector::with_native_roots(),
None => hyper_rustls::HttpsConnectorBuilder::with_native_roots().build(),
};

// Build the hyper client from the HTTPS connector.
Expand Down
71 changes: 64 additions & 7 deletions src/connector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,36 @@ impl HttpsConnector<HttpConnector> {
/// Construct a new `HttpsConnector` using the OS root store
#[cfg(feature = "rustls-native-certs")]
#[cfg_attr(docsrs, doc(cfg(feature = "rustls-native-certs")))]
pub fn with_native_roots() -> Self {
HttpsConnectorBuilder::with_native_roots()
.enable_cert_transparency()
.build()
}

/// Construct a new `HttpsConnector` using the `webpki_roots`
#[cfg(feature = "webpki-roots")]
#[cfg_attr(docsrs, doc(cfg(feature = "webpki-roots")))]
pub fn with_webpki_roots() -> Self {
HttpsConnectorBuilder::with_webpki_roots()
.enable_cert_transparency()
.build()
}
}

/// A builder that will configure an `HttpsConnector`
///
/// This builder ensures configuration is consistent.
///
/// An alternative way of building an `HttpsConnector`
/// is to use From/Into.
pub struct HttpsConnectorBuilder {
tls_config: ClientConfig,
}

impl HttpsConnectorBuilder {
/// Configure using the OS root store for certificate trust
#[cfg(feature = "rustls-native-certs")]
#[cfg_attr(docsrs, doc(cfg(feature = "rustls-native-certs")))]
pub fn with_native_roots() -> Self {
let mut config = ClientConfig::new();
config.root_store = match rustls_native_certs::load_native_certs() {
Expand All @@ -43,27 +73,54 @@ impl HttpsConnector<HttpConnector> {
if config.root_store.is_empty() {
panic!("no CA certificates found");
}
Self::build(config)
Self { tls_config: config }
}

/// Construct a new `HttpsConnector` using the `webpki_roots`
/// Configure using a custom `rustls::RootCertStore` for certificate trust
pub fn with_custom_roots(roots: rustls::RootCertStore) -> Self {
let mut config = ClientConfig::new();
config.root_store = roots;
Self { tls_config: config }
}

/// Configure using `webpki_roots` for certificate trust
#[cfg(feature = "webpki-roots")]
#[cfg_attr(docsrs, doc(cfg(feature = "webpki-roots")))]
pub fn with_webpki_roots() -> Self {
let mut config = ClientConfig::new();
config
.root_store
.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
Self::build(config)
Self { tls_config: config }
}

fn build(mut config: ClientConfig) -> Self {
/// Enable HTTP2
/// This advertises http2 support in ALPN
#[cfg(feature = "http2")]
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
pub fn enable_http2(mut self) -> Self {
self.tls_config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
self
}

/// Enable certificate transparency
#[cfg(feature = "ct-logs")]
pub fn enable_cert_transparency(mut self) -> Self {
self.tls_config.ct_logs = Some(&ct_logs::LOGS);
self
}

/// Built an HttpsConnector<HttpConnector>
#[cfg(feature = "tokio-runtime")]
pub fn build(self) -> HttpsConnector<HttpConnector> {
let mut http = HttpConnector::new();
http.enforce_http(false);
self.wrap_connector(http)
}

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

Expand Down
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
//!
//! let mut rt = tokio::runtime::Runtime::new().unwrap();
//! let url = ("https://hyper.rs").parse().unwrap();
//! let https = hyper_rustls::HttpsConnector::with_native_roots();
//! let https = hyper_rustls::HttpsConnectorBuilder::with_native_roots().build();
//!
//! let client: Client<_, hyper::Body> = Client::builder().build(https);
//!
Expand All @@ -27,5 +27,5 @@
mod connector;
mod stream;

pub use crate::connector::HttpsConnector;
pub use crate::connector::{HttpsConnector, HttpsConnectorBuilder};
pub use crate::stream::MaybeHttpsStream;