Skip to content
Merged
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
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ script:
- if [[ $(rustup show active-toolchain) == stable* ]]; then cargo fmt -- --check; fi;
- cargo test --features tls
- cargo test --features rustls --no-default-features
- cargo test --features rustls-webpki --no-default-features
- cargo test --no-default-features
7 changes: 6 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,17 @@ hyper-rustls = { version="0.19", optional=true }

webpki = { version = "0.21", optional = true }
rustls-native-certs = { version = "0.1.0", optional = true }
webpki-roots = { version = "0.20.0", optional = true }
typed-headers = "0.2"

[dev-dependencies]
tokio = { version = "0.2.4", features = ["full"] }

[features]
tls = ["tokio-tls", "hyper-tls", "native-tls"]
rustls = ["tokio-rustls", "hyper-rustls", "webpki", "rustls-native-certs"]
# note that `rustls-base` is not a valid feature on its own - it will configure rustls without root
# certificates!
rustls-base = ["tokio-rustls", "hyper-rustls", "webpki"]
rustls = ["rustls-base", "rustls-native-certs"]
rustls-webpki = ["rustls-base", "webpki-roots"]
default = ["tls"]
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,19 @@ async fn main() -> Result<(), Box<dyn Error>> {
}
```

## Features

`hyper-proxy` exposes three main Cargo features, to configure which TLS implementation it uses to
connect to a proxy. It can also be configured without TLS support, by compiling without default
features entirely. The supported list of configurations is:

1. No TLS support (`default-features = false`)
2. TLS support via `native-tls` to link against the operating system's native TLS implementation
(default)
3. TLS support via `rustls` (`default-features = false, features = ["rustls"]`)
4. TLS support via `rustls`, using a statically-compiled set of CA certificates to bypass the
operating system's default store (`default-features = false, features = ["rustls-webpki"]`)

## Credits

Large part of the code comes from [reqwest][2].
Expand Down
34 changes: 22 additions & 12 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
//! let mut proxy = Proxy::new(Intercept::All, proxy_uri);
//! proxy.set_authorization(Credentials::basic("John Doe", "Agent1234").unwrap());
//! let connector = HttpConnector::new();
//! # #[cfg(not(any(feature = "tls", feature = "rustls")))]
//! # #[cfg(not(any(feature = "tls", feature = "rustls-base")))]
//! # let proxy_connector = ProxyConnector::from_proxy_unsecured(connector, proxy);
//! # #[cfg(any(feature = "tls", feature = "rustls"))]
//! # #[cfg(any(feature = "tls", feature = "rustls-base"))]
//! let proxy_connector = ProxyConnector::from_proxy(connector, proxy).unwrap();
//! proxy_connector
//! };
Expand Down Expand Up @@ -71,12 +71,12 @@ use tokio::io::{AsyncRead, AsyncWrite};
#[cfg(feature = "tls")]
use native_tls::TlsConnector as NativeTlsConnector;

#[cfg(feature = "rustls")]
#[cfg(feature = "rustls-base")]
use tokio_rustls::TlsConnector;
#[cfg(feature = "tls")]
use tokio_tls::TlsConnector;
use typed_headers::{Authorization, Credentials, HeaderMapExt, ProxyAuthorization};
#[cfg(feature = "rustls")]
#[cfg(feature = "rustls-base")]
use webpki::DNSNameRef;

type BoxError = Box<dyn std::error::Error + Send + Sync>;
Expand Down Expand Up @@ -229,10 +229,10 @@ pub struct ProxyConnector<C> {
#[cfg(feature = "tls")]
tls: Option<NativeTlsConnector>,

#[cfg(feature = "rustls")]
#[cfg(feature = "rustls-base")]
tls: Option<TlsConnector>,

#[cfg(not(any(feature = "tls", feature = "rustls")))]
#[cfg(not(any(feature = "tls", feature = "rustls-base")))]
tls: Option<()>,
}

Expand Down Expand Up @@ -268,11 +268,21 @@ impl<C> ProxyConnector<C> {
}

/// Create a new secured Proxies
#[cfg(feature = "rustls")]
#[cfg(feature = "rustls-base")]
pub fn new(connector: C) -> Result<Self, io::Error> {
let mut config = tokio_rustls::rustls::ClientConfig::new();

config.root_store = rustls_native_certs::load_native_certs()?;
#[cfg(feature = "rustls")]
{
config.root_store = rustls_native_certs::load_native_certs()?;
}

#[cfg(feature = "rustls-webpki")]
{
config
.root_store
.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
}

let cfg = Arc::new(config);
let tls = TlsConnector::from(cfg);
Expand All @@ -294,7 +304,7 @@ impl<C> ProxyConnector<C> {
}

/// Create a proxy connector and attach a particular proxy
#[cfg(any(feature = "tls", feature = "rustls"))]
#[cfg(any(feature = "tls", feature = "rustls-base"))]
pub fn from_proxy(connector: C, proxy: Proxy) -> Result<Self, io::Error> {
let mut c = ProxyConnector::new(connector)?;
c.proxies.push(proxy);
Expand Down Expand Up @@ -324,7 +334,7 @@ impl<C> ProxyConnector<C> {
}

/// Set or unset tls when tunneling
#[cfg(any(feature = "rustls"))]
#[cfg(any(feature = "rustls-base"))]
pub fn set_tls(&mut self, tls: Option<TlsConnector>) {
self.tls = tls;
}
Expand Down Expand Up @@ -415,7 +425,7 @@ where
Ok(ProxyStream::Secured(secure_stream))
}

#[cfg(feature = "rustls")]
#[cfg(feature = "rustls-base")]
Some(tls) => {
let dnsref =
mtry!(DNSNameRef::try_from_ascii_str(&host).map_err(io_err));
Expand All @@ -426,7 +436,7 @@ where
Ok(ProxyStream::Secured(secure_stream))
}

#[cfg(not(any(feature = "tls", feature = "rustls")))]
#[cfg(not(any(feature = "tls", feature = "rustls-base")))]
Some(_) => panic!("hyper-proxy was not built with TLS support"),

None => Ok(ProxyStream::Regular(tunnel_stream)),
Expand Down
14 changes: 7 additions & 7 deletions src/stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,22 @@ use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::io::{AsyncRead, AsyncWrite};

#[cfg(feature = "rustls")]
#[cfg(feature = "rustls-base")]
use tokio_rustls::client::TlsStream as RustlsStream;

#[cfg(feature = "tls")]
use tokio_tls::TlsStream;

use hyper::client::connect::{Connected, Connection};

#[cfg(feature = "rustls")]
#[cfg(feature = "rustls-base")]
type TlsStream<R> = RustlsStream<R>;

/// A Proxy Stream wrapper
pub enum ProxyStream<R> {
NoProxy(R),
Regular(R),
#[cfg(any(feature = "tls", feature = "rustls"))]
#[cfg(any(feature = "tls", feature = "rustls-base"))]
Secured(TlsStream<R>),
}

Expand All @@ -29,7 +29,7 @@ macro_rules! match_fn_pinned {
match $self.get_mut() {
ProxyStream::NoProxy(s) => Pin::new(s).$fn($ctx, $buf),
ProxyStream::Regular(s) => Pin::new(s).$fn($ctx, $buf),
#[cfg(any(feature = "tls", feature = "rustls"))]
#[cfg(any(feature = "tls", feature = "rustls-base"))]
ProxyStream::Secured(s) => Pin::new(s).$fn($ctx, $buf),
}
};
Expand All @@ -38,7 +38,7 @@ macro_rules! match_fn_pinned {
match $self.get_mut() {
ProxyStream::NoProxy(s) => Pin::new(s).$fn($ctx),
ProxyStream::Regular(s) => Pin::new(s).$fn($ctx),
#[cfg(any(feature = "tls", feature = "rustls"))]
#[cfg(any(feature = "tls", feature = "rustls-base"))]
ProxyStream::Secured(s) => Pin::new(s).$fn($ctx),
}
};
Expand All @@ -51,7 +51,7 @@ impl<R: AsyncRead + AsyncWrite + Unpin> AsyncRead for ProxyStream<R> {

ProxyStream::Regular(ref s) => s.prepare_uninitialized_buffer(buf),

#[cfg(any(feature = "tls", feature = "rustls"))]
#[cfg(any(feature = "tls", feature = "rustls-base"))]
ProxyStream::Secured(ref s) => s.prepare_uninitialized_buffer(buf),
}
}
Expand Down Expand Up @@ -111,7 +111,7 @@ impl<R: AsyncRead + AsyncWrite + Connection + Unpin> Connection for ProxyStream<
#[cfg(feature = "tls")]
ProxyStream::Secured(s) => s.get_ref().connected().proxy(true),

#[cfg(feature = "rustls")]
#[cfg(feature = "rustls-base")]
ProxyStream::Secured(s) => s.get_ref().0.connected().proxy(true),
}
}
Expand Down