diff --git a/Cargo.toml b/Cargo.toml index cfc5314..c908326 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hyper-rustls" -version = "0.25.0" +version = "0.26.0" edition = "2021" rust-version = "1.63" license = "Apache-2.0 OR ISC OR MIT" @@ -11,32 +11,33 @@ repository = "https://github.com/rustls/hyper-rustls" documentation = "https://docs.rs/hyper-rustls/" [dependencies] -http = "0.2" -hyper = { version = "0.14", default-features = false, features = ["client"] } +http = "1" +hyper = { version = "1", default-features = false } +hyper-util = { version = "0.1", default-features = false, features = ["client-legacy", "tokio"] } log = { version = "0.4.4", optional = true } pki-types = { package = "rustls-pki-types", version = "1" } rustls-native-certs = { version = "0.7", optional = true } rustls = { version = "0.22", default-features = false } tokio = "1.0" tokio-rustls = { version = "0.25", default-features = false } +tower-service = "0.3" webpki-roots = { version = "0.26", optional = true } futures-util = { version = "0.3", default-features = false } [dev-dependencies] -hyper = { version = "0.14", features = ["full"] } +http-body-util = "0.1" +hyper-util = { version = "0.1", default-features = false, features = ["server-auto"] } rustls = { version = "0.22", default-features = false, features = ["tls12"] } rustls-pemfile = "2" tokio = { version = "1.0", features = ["io-std", "macros", "net", "rt-multi-thread"] } [features] -default = ["native-tokio", "http1", "tls12", "logging", "acceptor", "ring"] -acceptor = ["hyper/server", "ring", "tokio-runtime"] -http1 = ["hyper/http1"] -http2 = ["hyper/http2"] -webpki-tokio = ["tokio-runtime", "webpki-roots"] -native-tokio = ["tokio-runtime", "rustls-native-certs"] +default = ["native-tokio", "http1", "tls12", "logging", "ring"] +http1 = ["hyper-util/http1"] +http2 = ["hyper-util/http2"] +webpki-tokio = ["webpki-roots"] +native-tokio = ["rustls-native-certs"] ring = ["rustls/ring"] -tokio-runtime = ["hyper/runtime"] tls12 = ["tokio-rustls/tls12", "rustls/tls12"] logging = ["log", "tokio-rustls/logging", "rustls/logging"] @@ -48,7 +49,7 @@ required-features = ["native-tokio", "http1"] [[example]] name = "server" path = "examples/server.rs" -required-features = ["tokio-runtime", "acceptor"] +required-features = ["ring"] [package.metadata.docs.rs] all-features = true diff --git a/examples/client.rs b/examples/client.rs index 58c4c28..36d5c6f 100644 --- a/examples/client.rs +++ b/examples/client.rs @@ -2,8 +2,11 @@ //! //! First parameter is the mandatory URL to GET. //! Second parameter is an optional path to CA store. -use hyper::{body::to_bytes, client, Body, Uri}; +use http::Uri; +use http_body_util::{BodyExt, Empty}; +use hyper::body::Bytes; use hyper_rustls::ConfigBuilderExt; +use hyper_util::{client::legacy::Client, rt::TokioExecutor}; use rustls::RootCertStore; use std::str::FromStr; @@ -68,7 +71,7 @@ async fn run_client() -> io::Result<()> { .build(); // Build the hyper client from the HTTPS connector. - let client: client::Client<_, hyper::Body> = client::Client::builder().build(https); + let client: Client<_, Empty> = Client::builder(TokioExecutor::new()).build(https); // Prepare a chain of futures which sends a GET request, inspects // the returned headers, collects the whole body and prints it to @@ -81,10 +84,12 @@ async fn run_client() -> io::Result<()> { println!("Status:\n{}", res.status()); println!("Headers:\n{:#?}", res.headers()); - let body: Body = res.into_body(); - let body = to_bytes(body) + let body = res + .into_body() + .collect() .await - .map_err(|e| error(format!("Could not get body: {:?}", e)))?; + .map_err(|e| error(format!("Could not get body: {:?}", e)))? + .to_bytes(); println!("Body:\n{}", String::from_utf8_lossy(&body)); Ok(()) diff --git a/examples/server.rs b/examples/server.rs index 65519cf..ffdb38f 100644 --- a/examples/server.rs +++ b/examples/server.rs @@ -1,20 +1,25 @@ -//! Simple HTTPS echo service based on hyper-rustls +//! Simple HTTPS echo service based on hyper_util and rustls //! //! First parameter is the mandatory port to use. //! Certificate and private key are hardcoded to sample files. //! hyper will automatically use HTTP/2 if a client starts talking HTTP/2, //! otherwise HTTP/1.1 will be used. -#![cfg(feature = "acceptor")] - +use std::net::{Ipv4Addr, SocketAddr}; +use std::sync::Arc; use std::vec::Vec; use std::{env, fs, io}; -use hyper::server::conn::AddrIncoming; -use hyper::service::{make_service_fn, service_fn}; -use hyper::{Body, Method, Request, Response, Server, StatusCode}; -use hyper_rustls::TlsAcceptor; +use http::{Method, Request, Response, StatusCode}; +use http_body_util::{BodyExt, Full}; +use hyper::body::{Bytes, Incoming}; +use hyper::service::service_fn; +use hyper_util::rt::{TokioExecutor, TokioIo}; +use hyper_util::server::conn::auto::Builder; use pki_types::{CertificateDer, PrivateKeyDer}; +use rustls::ServerConfig; +use tokio::net::TcpListener; +use tokio_rustls::TlsAcceptor; fn main() { // Serve an echo service over HTTPS, with proper error handling. @@ -32,45 +37,70 @@ fn error(err: String) -> io::Error { async fn run_server() -> Result<(), Box> { // First parameter is port number (optional, defaults to 1337) let port = match env::args().nth(1) { - Some(ref p) => p.to_owned(), - None => "1337".to_owned(), + Some(ref p) => p.parse()?, + None => 1337, }; - let addr = format!("127.0.0.1:{}", port).parse()?; + let addr = SocketAddr::new(Ipv4Addr::LOCALHOST.into(), port); // Load public certificate. let certs = load_certs("examples/sample.pem")?; // Load private key. let key = load_private_key("examples/sample.rsa")?; - // Build TLS configuration. + + println!("Starting to serve on https://{}", addr); // Create a TCP listener via tokio. - let incoming = AddrIncoming::bind(&addr)?; - let acceptor = TlsAcceptor::builder() + let incoming = TcpListener::bind(&addr).await?; + + // Build TLS configuration. + let mut server_config = ServerConfig::builder() + .with_no_client_auth() .with_single_cert(certs, key) - .map_err(|e| error(format!("{}", e)))? - .with_all_versions_alpn() - .with_incoming(incoming); - let service = make_service_fn(|_| async { Ok::<_, io::Error>(service_fn(echo)) }); - let server = Server::builder(acceptor).serve(service); - - // Run the future, keep going until an error occurs. - println!("Starting to serve on https://{}.", addr); - server.await?; - Ok(()) + .map_err(|e| error(e.to_string()))?; + server_config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec(), b"http/1.0".to_vec()]; + let tls_acceptor = TlsAcceptor::from(Arc::new(server_config)); + + let service = service_fn(echo); + + loop { + let (tcp_stream, _remote_addr) = incoming.accept().await?; + + let tls_acceptor = tls_acceptor.clone(); + tokio::spawn(async move { + let tls_stream = match tls_acceptor.accept(tcp_stream).await { + Ok(tls_stream) => tls_stream, + Err(err) => { + eprintln!("failed to perform tls handshake: {err:#}"); + return; + } + }; + if let Err(err) = Builder::new(TokioExecutor::new()) + .serve_connection(TokioIo::new(tls_stream), service) + .await + { + eprintln!("failed to serve connection: {err:#}"); + } + }); + } } // Custom echo service, handling two different routes and a // catch-all 404 responder. -async fn echo(req: Request) -> Result, hyper::Error> { - let mut response = Response::new(Body::empty()); +async fn echo(req: Request) -> Result>, hyper::Error> { + let mut response = Response::new(Full::default()); match (req.method(), req.uri().path()) { // Help route. (&Method::GET, "/") => { - *response.body_mut() = Body::from("Try POST /echo\n"); + *response.body_mut() = Full::from("Try POST /echo\n"); } // Echo service route. (&Method::POST, "/echo") => { - *response.body_mut() = req.into_body(); + *response.body_mut() = Full::from( + req.into_body() + .collect() + .await? + .to_bytes(), + ); } // Catch-all 404. _ => { diff --git a/src/acceptor.rs b/src/acceptor.rs deleted file mode 100644 index 02e72d0..0000000 --- a/src/acceptor.rs +++ /dev/null @@ -1,169 +0,0 @@ -use core::task::{Context, Poll}; -use std::future::Future; -use std::io; -use std::pin::Pin; -use std::sync::Arc; - -use futures_util::ready; -use hyper::server::accept::Accept; -use hyper::server::conn::{AddrIncoming, AddrStream}; -use rustls::{ServerConfig, ServerConnection}; -use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; - -mod builder; -pub use builder::AcceptorBuilder; -use builder::WantsTlsConfig; - -/// A TLS acceptor that can be used with hyper servers. -pub struct TlsAcceptor { - config: Arc, - acceptor: A, -} - -/// An Acceptor for the `https` scheme. -impl TlsAcceptor { - /// Provides a builder for a `TlsAcceptor`. - pub fn builder() -> AcceptorBuilder { - AcceptorBuilder::new() - } - - /// Creates a new `TlsAcceptor` from a `ServerConfig` and an `AddrIncoming`. - pub fn new(config: Arc, incoming: AddrIncoming) -> Self { - Self { - config, - acceptor: incoming, - } - } -} - -impl Accept for TlsAcceptor -where - A: Accept + Unpin, - A::Conn: AsyncRead + AsyncWrite + Unpin, -{ - type Conn = TlsStream; - type Error = io::Error; - - fn poll_accept( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll>> { - let pin = self.get_mut(); - Poll::Ready(match ready!(Pin::new(&mut pin.acceptor).poll_accept(cx)) { - Some(Ok(sock)) => Some(Ok(TlsStream::new(sock, pin.config.clone()))), - Some(Err(e)) => Some(Err(e)), - None => None, - }) - } -} - -impl From<(C, I)> for TlsAcceptor -where - C: Into>, - I: Into, -{ - fn from((config, incoming): (C, I)) -> Self { - Self::new(config.into(), incoming.into()) - } -} - -/// A TLS stream constructed by a [`TlsAcceptor`]. -// tokio_rustls::server::TlsStream doesn't expose constructor methods, -// so we have to TlsAcceptor::accept and handshake to have access to it -// TlsStream implements AsyncRead/AsyncWrite by handshaking with tokio_rustls::Accept first -pub struct TlsStream { - state: State, -} - -impl TlsStream { - fn new(stream: C, config: Arc) -> Self { - let accept = tokio_rustls::TlsAcceptor::from(config).accept(stream); - Self { - state: State::Handshaking(accept), - } - } - /// Returns a reference to the underlying IO stream. - /// - /// This should always return `Some`, except if an error has already been yielded. - pub fn io(&self) -> Option<&C> { - match &self.state { - State::Handshaking(accept) => accept.get_ref(), - State::Streaming(stream) => Some(stream.get_ref().0), - } - } - - /// Returns a reference to the underlying [`rustls::ServerConnection']. - /// - /// This will start yielding `Some` only after the handshake has completed. - pub fn connection(&self) -> Option<&ServerConnection> { - match &self.state { - State::Handshaking(_) => None, - State::Streaming(stream) => Some(stream.get_ref().1), - } - } -} - -impl AsyncRead for TlsStream { - fn poll_read( - self: Pin<&mut Self>, - cx: &mut Context, - buf: &mut ReadBuf, - ) -> Poll> { - let pin = self.get_mut(); - let accept = match &mut pin.state { - State::Handshaking(accept) => accept, - State::Streaming(stream) => return Pin::new(stream).poll_read(cx, buf), - }; - - let mut stream = match ready!(Pin::new(accept).poll(cx)) { - Ok(stream) => stream, - Err(err) => return Poll::Ready(Err(err)), - }; - - let result = Pin::new(&mut stream).poll_read(cx, buf); - pin.state = State::Streaming(stream); - result - } -} - -impl AsyncWrite for TlsStream { - fn poll_write( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - let pin = self.get_mut(); - let accept = match &mut pin.state { - State::Handshaking(accept) => accept, - State::Streaming(stream) => return Pin::new(stream).poll_write(cx, buf), - }; - - let mut stream = match ready!(Pin::new(accept).poll(cx)) { - Ok(stream) => stream, - Err(err) => return Poll::Ready(Err(err)), - }; - - let result = Pin::new(&mut stream).poll_write(cx, buf); - pin.state = State::Streaming(stream); - result - } - - fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - match &mut self.state { - State::Handshaking(_) => Poll::Ready(Ok(())), - State::Streaming(stream) => Pin::new(stream).poll_flush(cx), - } - } - - fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - match &mut self.state { - State::Handshaking(_) => Poll::Ready(Ok(())), - State::Streaming(stream) => Pin::new(stream).poll_shutdown(cx), - } - } -} - -enum State { - Handshaking(tokio_rustls::Accept), - Streaming(tokio_rustls::server::TlsStream), -} diff --git a/src/acceptor/builder.rs b/src/acceptor/builder.rs deleted file mode 100644 index ec14f17..0000000 --- a/src/acceptor/builder.rs +++ /dev/null @@ -1,107 +0,0 @@ -use std::sync::Arc; - -use hyper::server::conn::AddrIncoming; -use pki_types::{CertificateDer, PrivateKeyDer}; -use rustls::ServerConfig; - -use super::TlsAcceptor; - -/// Builder for [`TlsAcceptor`] -pub struct AcceptorBuilder(State); - -/// State of a builder that needs a TLS client config next -pub struct WantsTlsConfig(()); - -impl AcceptorBuilder { - /// Creates a new [`AcceptorBuilder`] - pub fn new() -> Self { - Self(WantsTlsConfig(())) - } - - /// Passes a rustls [`ServerConfig`] to configure the TLS connection - pub fn with_tls_config(self, config: ServerConfig) -> AcceptorBuilder { - AcceptorBuilder(WantsAlpn(config)) - } - - /// Use rustls default crypto provider and safe defaults without - /// [client authentication][with_no_client_auth] - /// - /// [with_no_client_auth]: rustls::ConfigBuilder::with_no_client_auth - pub fn with_single_cert( - self, - cert_chain: Vec>, - key_der: PrivateKeyDer<'static>, - ) -> Result, rustls::Error> { - Ok(AcceptorBuilder(WantsAlpn( - ServerConfig::builder() - .with_no_client_auth() - .with_single_cert(cert_chain, key_der)?, - ))) - } -} - -impl Default for AcceptorBuilder { - fn default() -> Self { - Self::new() - } -} - -/// State of a builder that needs a incoming address next -pub struct WantsAlpn(ServerConfig); - -impl AcceptorBuilder { - /// Configure ALPN accept protocols in order - pub fn with_alpn_protocols( - mut self, - alpn_protocols: Vec>, - ) -> AcceptorBuilder { - self.0 .0.alpn_protocols = alpn_protocols; - AcceptorBuilder(WantsIncoming(self.0 .0)) - } - - /// Configure ALPN to accept HTTP/2 - pub fn with_http2_alpn(mut self) -> AcceptorBuilder { - self.0 .0.alpn_protocols = vec![b"h2".to_vec()]; - AcceptorBuilder(WantsIncoming(self.0 .0)) - } - - /// Configure ALPN to accept HTTP/1.0 - pub fn with_http10_alpn(mut self) -> AcceptorBuilder { - self.0 .0.alpn_protocols = vec![b"http/1.0".to_vec()]; - AcceptorBuilder(WantsIncoming(self.0 .0)) - } - - /// Configure ALPN to accept HTTP/1.1 - pub fn with_http11_alpn(mut self) -> AcceptorBuilder { - self.0 .0.alpn_protocols = vec![b"http/1.1".to_vec()]; - AcceptorBuilder(WantsIncoming(self.0 .0)) - } - - /// Configure ALPN to accept HTTP/2, HTTP/1.1, HTTP/1.0 in that order. - pub fn with_all_versions_alpn(mut self) -> AcceptorBuilder { - self.0 .0.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec(), b"http/1.0".to_vec()]; - AcceptorBuilder(WantsIncoming(self.0 .0)) - } -} - -/// State of a builder that needs a incoming address next -pub struct WantsIncoming(ServerConfig); - -impl AcceptorBuilder { - /// Passes a [`AddrIncoming`] to configure the TLS connection and - /// creates the [`TlsAcceptor`] - pub fn with_incoming(self, incoming: impl Into) -> TlsAcceptor { - self.with_acceptor(incoming.into()) - } - - /// Passes an acceptor implementing [`Accept`] to configure the TLS connection and - /// creates the [`TlsAcceptor`] - /// - /// [`Accept`]: hyper::server::accept::Accept - pub fn with_acceptor(self, acceptor: A) -> TlsAcceptor { - TlsAcceptor { - config: Arc::new(self.0 .0), - acceptor, - } - } -} diff --git a/src/connector.rs b/src/connector.rs index 6ce366c..60e6617 100644 --- a/src/connector.rs +++ b/src/connector.rs @@ -4,12 +4,13 @@ use std::sync::Arc; use std::task::{Context, Poll}; use std::{fmt, io}; -use hyper::client::connect::Connection; -use hyper::service::Service; -use hyper::Uri; +use http::Uri; +use hyper::rt; +use hyper_util::client::legacy::connect::Connection; +use hyper_util::rt::TokioIo; use pki_types::ServerName; -use tokio::io::{AsyncRead, AsyncWrite}; use tokio_rustls::TlsConnector; +use tower_service::Service; use crate::stream::MaybeHttpsStream; @@ -38,7 +39,7 @@ impl HttpsConnector { impl Service for HttpsConnector where T: Service, - T::Response: Connection + AsyncRead + AsyncWrite + Send + Unpin + 'static, + T::Response: Connection + rt::Read + rt::Write + Send + Unpin + 'static, T::Future: Send + 'static, T::Error: Into, { @@ -108,12 +109,12 @@ where let tcp = connecting_future .await .map_err(Into::into)?; - Ok(MaybeHttpsStream::Https( + Ok(MaybeHttpsStream::Https(TokioIo::new( TlsConnector::from(cfg) - .connect(hostname, tcp) + .connect(hostname, TokioIo::new(tcp)) .await .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?, - )) + ))) }) } } diff --git a/src/connector/builder.rs b/src/connector/builder.rs index 4e65f86..45a3daa 100644 --- a/src/connector/builder.rs +++ b/src/connector/builder.rs @@ -1,5 +1,4 @@ -#[cfg(feature = "tokio-runtime")] -use hyper::client::HttpConnector; +use hyper_util::client::legacy::connect::HttpConnector; #[cfg(any(feature = "rustls-native-certs", feature = "webpki-roots"))] use rustls::crypto::CryptoProvider; use rustls::ClientConfig; @@ -18,7 +17,7 @@ use crate::config::ConfigBuilderExt; /// ``` /// use hyper_rustls::HttpsConnectorBuilder; /// -/// # #[cfg(all(feature = "webpki-roots", feature = "tokio-runtime", feature = "http1"))] +/// # #[cfg(all(feature = "webpki-roots", feature = "http1"))] /// let https = HttpsConnectorBuilder::new() /// .with_webpki_roots() /// .https_only() @@ -170,7 +169,6 @@ impl WantsProtocols1 { } } - #[cfg(feature = "tokio-runtime")] fn build(self) -> HttpsConnector { let mut http = HttpConnector::new(); // HttpConnector won't enforce scheme, but HttpsConnector will @@ -257,7 +255,6 @@ impl ConnectorBuilder { } /// This builds an [`HttpsConnector`] built on hyper's default [`HttpConnector`] - #[cfg(feature = "tokio-runtime")] pub fn build(self) -> HttpsConnector { self.0.inner.build() } @@ -288,7 +285,6 @@ pub struct WantsProtocols3 { #[cfg(feature = "http2")] impl ConnectorBuilder { /// This builds an [`HttpsConnector`] built on hyper's default [`HttpConnector`] - #[cfg(feature = "tokio-runtime")] pub fn build(self) -> HttpsConnector { self.0.inner.build() } diff --git a/src/lib.rs b/src/lib.rs index a5d3c55..7cfbe49 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,9 +6,13 @@ //! ## Example client //! //! ```no_run -//! # #[cfg(all(feature = "rustls-native-certs", feature = "tokio-runtime", feature = "http1"))] +//! # #[cfg(all(feature = "rustls-native-certs", feature = "http1"))] //! # fn main() { -//! use hyper::{Body, Client, StatusCode, Uri}; +//! use http::StatusCode; +//! use http_body_util::Empty; +//! use hyper::body::Bytes; +//! use hyper_util::client::legacy::Client; +//! use hyper_util::rt::TokioExecutor; //! //! let mut rt = tokio::runtime::Runtime::new().unwrap(); //! let url = ("https://hyper.rs").parse().unwrap(); @@ -19,71 +23,18 @@ //! .enable_http1() //! .build(); //! -//! let client: Client<_, hyper::Body> = Client::builder().build(https); +//! let client: Client<_, Empty> = Client::builder(TokioExecutor::new()).build(https); //! //! let res = rt.block_on(client.get(url)).unwrap(); //! assert_eq!(res.status(), StatusCode::OK); //! # } -//! # #[cfg(not(all(feature = "rustls-native-certs", feature = "tokio-runtime", feature = "http1")))] -//! # fn main() {} -//! ``` -//! -//! ## Example server -//! -//! ```no_run -//! # #[cfg(all(feature = "rustls-native-certs", feature = "tokio-runtime", feature = "http1", feature = "acceptor"))] -//! # fn main() { -//! use std::io; -//! use std::fs::File; -//! -//! use hyper::server::conn::AddrIncoming; -//! use hyper::service::{make_service_fn, service_fn}; -//! use hyper::{Body, Method, Request, Response, Server, StatusCode}; -//! use hyper_rustls::TlsAcceptor; -//! use pki_types::{CertificateDer, PrivateKeyDer}; -//! -//! let mut rt = tokio::runtime::Runtime::new().unwrap(); -//! let addr = "127.0.0.1:1337".parse().unwrap(); -//! -//! // Load public certificate. -//! let certfile = File::open("examples/sample.pem").unwrap(); -//! let mut reader = io::BufReader::new(certfile); -//! -//! // Load and return certificate. -//! let certs = rustls_pemfile::certs(&mut reader).collect::, _>>().unwrap(); -//! -//! // Load private key. (see `examples/server.rs`) -//! let keyfile = File::open("examples/sample.rsa").unwrap(); -//! let mut reader = io::BufReader::new(keyfile); -//! -//! // Load and return a single private key. -//! let key = rustls_pemfile::private_key(&mut reader).unwrap().unwrap(); -//! let https = hyper_rustls::HttpsConnectorBuilder::new() -//! .with_native_roots() -//! .expect("no native root CA certificates found") -//! .https_only() -//! .enable_http1() -//! .build(); -//! -//! let incoming = AddrIncoming::bind(&addr).unwrap(); -//! let acceptor = TlsAcceptor::builder() -//! .with_single_cert(certs, key.into()).unwrap() -//! .with_all_versions_alpn() -//! .with_incoming(incoming); -//! let service = make_service_fn(|_| async { Ok::<_, io::Error>(service_fn(|_req|async {Ok::<_, io::Error>(Response::new(Body::empty()))})) }); -//! let server = Server::builder(acceptor).serve(service); -//! // server.await.unwrap(); -//! # } -//! # #[cfg(not(all(feature = "rustls-native-certs", feature = "tokio-runtime", feature = "http1")))] +//! # #[cfg(not(all(feature = "rustls-native-certs", feature = "http1")))] //! # fn main() {} //! ``` #![warn(missing_docs, unreachable_pub, clippy::use_self)] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] -#[cfg(feature = "acceptor")] -/// TLS acceptor implementing hyper's `Accept` trait. -pub mod acceptor; mod config; mod connector; mod stream; @@ -102,8 +53,6 @@ mod log { pub(crate) use debug; } -#[cfg(feature = "acceptor")] -pub use crate::acceptor::{AcceptorBuilder, TlsAcceptor}; pub use crate::config::ConfigBuilderExt; pub use crate::connector::builder::ConnectorBuilder as HttpsConnectorBuilder; pub use crate::connector::HttpsConnector; diff --git a/src/stream.rs b/src/stream.rs index a0e8c68..9f017bc 100644 --- a/src/stream.rs +++ b/src/stream.rs @@ -4,9 +4,10 @@ use std::io; use std::pin::Pin; use std::task::{Context, Poll}; -use hyper::client::connect::{Connected, Connection}; +use hyper::rt; +use hyper_util::client::legacy::connect::{Connected, Connection}; -use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; +use hyper_util::rt::TokioIo; use tokio_rustls::client::TlsStream; /// A stream that might be protected with TLS. @@ -15,19 +16,19 @@ pub enum MaybeHttpsStream { /// A stream over plain text. Http(T), /// A stream protected with TLS. - Https(TlsStream), + Https(TokioIo>>), } -impl Connection for MaybeHttpsStream { +impl Connection for MaybeHttpsStream { fn connected(&self) -> Connected { match self { Self::Http(s) => s.connected(), Self::Https(s) => { - let (tcp, tls) = s.get_ref(); + let (tcp, tls) = s.inner().get_ref(); if tls.alpn_protocol() == Some(b"h2") { - tcp.connected().negotiated_h2() + tcp.inner().connected().negotiated_h2() } else { - tcp.connected() + tcp.inner().connected() } } } @@ -49,18 +50,18 @@ impl From for MaybeHttpsStream { } } -impl From> for MaybeHttpsStream { - fn from(inner: TlsStream) -> Self { - Self::Https(inner) +impl From>> for MaybeHttpsStream { + fn from(inner: TlsStream>) -> Self { + Self::Https(TokioIo::new(inner)) } } -impl AsyncRead for MaybeHttpsStream { +impl rt::Read for MaybeHttpsStream { #[inline] fn poll_read( self: Pin<&mut Self>, cx: &mut Context, - buf: &mut ReadBuf<'_>, + buf: rt::ReadBufCursor<'_>, ) -> Poll> { match Pin::get_mut(self) { Self::Http(s) => Pin::new(s).poll_read(cx, buf), @@ -69,7 +70,7 @@ impl AsyncRead for MaybeHttpsStream { } } -impl AsyncWrite for MaybeHttpsStream { +impl rt::Write for MaybeHttpsStream { #[inline] fn poll_write( self: Pin<&mut Self>, diff --git a/tests/tests.rs b/tests/tests.rs index e9cb839..6730a28 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -42,7 +42,6 @@ fn client() { assert!(rc.status.success()); } -#[cfg(feature = "acceptor")] #[test] fn server() { let mut srv = server_command()