From 66fef4a9bcccd944e3b72b1e83f789e4131d4e52 Mon Sep 17 00:00:00 2001 From: Lucio Franco Date: Wed, 6 May 2020 17:30:01 -0400 Subject: [PATCH] Remove `tokio-tls` from master (#2497) --- .cirrus.yml | 2 +- Cargo.toml | 1 - azure-pipelines.yml | 1 - ci/azure-cross-compile.yml | 4 +- ci/patch.toml | 1 - tokio-tls/CHANGELOG.md | 43 -- tokio-tls/Cargo.toml | 66 --- tokio-tls/LICENSE | 25 - tokio-tls/README.md | 16 - tokio-tls/examples/download-rust-lang.rs | 40 -- tokio-tls/examples/identity.p12 | Bin 3386 -> 0 bytes tokio-tls/examples/tls-echo.rs | 55 -- tokio-tls/src/lib.rs | 364 ------------- tokio-tls/tests/bad.rs | 124 ----- tokio-tls/tests/google.rs | 102 ---- tokio-tls/tests/smoke.rs | 629 ----------------------- 16 files changed, 3 insertions(+), 1470 deletions(-) delete mode 100644 tokio-tls/CHANGELOG.md delete mode 100644 tokio-tls/Cargo.toml delete mode 100644 tokio-tls/LICENSE delete mode 100644 tokio-tls/README.md delete mode 100644 tokio-tls/examples/download-rust-lang.rs delete mode 100644 tokio-tls/examples/identity.p12 delete mode 100644 tokio-tls/examples/tls-echo.rs delete mode 100644 tokio-tls/src/lib.rs delete mode 100644 tokio-tls/tests/bad.rs delete mode 100644 tokio-tls/tests/google.rs delete mode 100644 tokio-tls/tests/smoke.rs diff --git a/.cirrus.yml b/.cirrus.yml index c2344c0c3..7a5f9a6d6 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -39,4 +39,4 @@ task: # i686_test_script: # - . $HOME/.cargo/env # - | - # cargo test --all --exclude tokio-tls --exclude tokio-macros --target i686-unknown-freebsd + # cargo test --all --exclude tokio-macros --target i686-unknown-freebsd diff --git a/Cargo.toml b/Cargo.toml index ebae0d3db..39d293664 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,6 @@ members = [ "tokio", "tokio-macros", "tokio-test", - "tokio-tls", "tokio-util", # Internal diff --git a/azure-pipelines.yml b/azure-pipelines.yml index cc50f3c88..b1396a955 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -26,7 +26,6 @@ jobs: crates: - tokio-macros - tokio-test - - tokio-tls - tokio-util - examples diff --git a/ci/azure-cross-compile.yml b/ci/azure-cross-compile.yml index 74acaee28..11c530ca1 100644 --- a/ci/azure-cross-compile.yml +++ b/ci/azure-cross-compile.yml @@ -37,8 +37,8 @@ jobs: # Always patch - template: azure-patch-crates.yml - - script: cross check --all --exclude tokio-tls --target $(target) + - script: cross check --all --target $(target) displayName: Check source - # - script: cross check --tests --all --exclude tokio-tls --target $(target) + # - script: cross check --tests --all --target $(target) # displayName: Check tests diff --git a/ci/patch.toml b/ci/patch.toml index 22311cf9a..1650e3b1d 100644 --- a/ci/patch.toml +++ b/ci/patch.toml @@ -4,5 +4,4 @@ tokio = { path = "tokio" } tokio-macros = { path = "tokio-macros" } tokio-test = { path = "tokio-test" } -tokio-tls = { path = "tokio-tls" } tokio-util = { path = "tokio-util" } diff --git a/tokio-tls/CHANGELOG.md b/tokio-tls/CHANGELOG.md deleted file mode 100644 index dc626a763..000000000 --- a/tokio-tls/CHANGELOG.md +++ /dev/null @@ -1,43 +0,0 @@ -# 0.3.1 (April 4, 2020) - -- Deprecate crate in favor of `tokio-native-tls`. - -# 0.3.0 (November 26, 2019) - -- Updates for tokio 0.2 release. - -# 0.3.0-alpha.6 (September 30, 2019) - -- Move to `futures-*-preview 0.3.0-alpha.19`. -- Move to `pin-project 0.4`. - -# 0.3.0-alpha.5 (September 19, 2019) - -### Added -- `TlsStream::get_ref` and `TlsStream::get_mut` ([#1537]). - -# 0.3.0-alpha.4 (August 30, 2019) - -### Changed -- Track `tokio` 0.2.0-alpha.4. - -# 0.3.0-alpha.2 (August 17, 2019) - -### Changed -- Update `futures` dependency to 0.3.0-alpha.18. - -# 0.3.0-alpha.1 (August 8, 2019) - -### Changed -- Switch to `async`, `await`, and `std::future`. - -# 0.2.1 (January 6, 2019) - -* Implement `Clone` for `TlsConnector` and `TlsAcceptor` ([#777]) - -# 0.2.0 (August 8, 2018) - -* Initial release with `tokio` support. - -[#1537]: https://github.com/tokio-rs/tokio/pull/1537 -[#777]: https://github.com/tokio-rs/tokio/pull/777 diff --git a/tokio-tls/Cargo.toml b/tokio-tls/Cargo.toml deleted file mode 100644 index 2ec01bfa7..000000000 --- a/tokio-tls/Cargo.toml +++ /dev/null @@ -1,66 +0,0 @@ -[package] -name = "tokio-tls" -# When releasing to crates.io: -# - Remove path dependencies -# - Update html_root_url. -# - Update doc url -# - Cargo.toml -# - README.md -# - Update CHANGELOG.md. -# - Create "v0.3.x" git tag. -version = "0.3.1" -edition = "2018" -authors = ["Tokio Contributors "] -license = "MIT" -repository = "https://github.com/tokio-rs/tokio" -homepage = "https://tokio.rs" -documentation = "https://docs.rs/tokio-tls/0.3.1/tokio_tls/" -description = """ -Deprecated in favor of `tokio-naitve-tls`. - -An implementation of TLS/SSL streams for Tokio giving an implementation of TLS -for nonblocking I/O streams. -""" -categories = ["asynchronous", "network-programming"] -maintenance = { status = "deprecated" } - -[badges] -travis-ci = { repository = "tokio-rs/tokio-tls" } - -[dependencies] -native-tls = "0.2" -tokio = { version = "0.2.0", path = "../tokio" } - -[dev-dependencies] -tokio = { version = "0.2.0", path = "../tokio", features = ["macros", "stream", "rt-core", "io-util", "net"] } -tokio-util = { version = "0.3.0", path = "../tokio-util", features = ["full"] } - -cfg-if = "0.1" -env_logger = { version = "0.6", default-features = false } -futures = { version = "0.3.0", features = ["async-await"] } - -[target.'cfg(all(not(target_os = "macos"), not(windows), not(target_os = "ios")))'.dev-dependencies] -openssl = "0.10" - -[target.'cfg(any(target_os = "macos", target_os = "ios"))'.dev-dependencies] -security-framework = "0.2" - -[target.'cfg(windows)'.dev-dependencies] -schannel = "0.1" - -[target.'cfg(windows)'.dev-dependencies.winapi] -version = "0.3" -features = [ - "lmcons", - "basetsd", - "minwinbase", - "minwindef", - "ntdef", - "sysinfoapi", - "timezoneapi", - "wincrypt", - "winerror", -] - -[package.metadata.docs.rs] -all-features = true diff --git a/tokio-tls/LICENSE b/tokio-tls/LICENSE deleted file mode 100644 index cdb28b4b5..000000000 --- a/tokio-tls/LICENSE +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2019 Tokio Contributors - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/tokio-tls/README.md b/tokio-tls/README.md deleted file mode 100644 index 6cfb9ec09..000000000 --- a/tokio-tls/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# tokio-tls - -**Deprecated** in favor of `tokio-native-tls`. - -An implementation of TLS/SSL streams for Tokio built on top of the [`native-tls` -crate] - -## License - -This project is licensed under the [MIT license](./LICENSE). - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in Tokio by you, shall be licensed as MIT, without any additional -terms or conditions. diff --git a/tokio-tls/examples/download-rust-lang.rs b/tokio-tls/examples/download-rust-lang.rs deleted file mode 100644 index 324c07753..000000000 --- a/tokio-tls/examples/download-rust-lang.rs +++ /dev/null @@ -1,40 +0,0 @@ -// #![warn(rust_2018_idioms)] - -use native_tls::TlsConnector; -use std::error::Error; -use std::net::ToSocketAddrs; -use tokio::io::{AsyncReadExt, AsyncWriteExt}; -use tokio::net::TcpStream; -use tokio_tls; - -#[tokio::main] -async fn main() -> Result<(), Box> { - let addr = "www.rust-lang.org:443" - .to_socket_addrs()? - .next() - .ok_or("failed to resolve www.rust-lang.org")?; - - let socket = TcpStream::connect(&addr).await?; - let cx = TlsConnector::builder().build()?; - let cx = tokio_tls::TlsConnector::from(cx); - - let mut socket = cx.connect("www.rust-lang.org", socket).await?; - - socket - .write_all( - "\ - GET / HTTP/1.0\r\n\ - Host: www.rust-lang.org\r\n\ - \r\n\ - " - .as_bytes(), - ) - .await?; - - let mut data = Vec::new(); - socket.read_to_end(&mut data).await?; - - // println!("data: {:?}", &data); - println!("{}", String::from_utf8_lossy(&data[..])); - Ok(()) -} diff --git a/tokio-tls/examples/identity.p12 b/tokio-tls/examples/identity.p12 deleted file mode 100644 index d16abb8c70627bd959667495e578fb6f010a7f1d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3386 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 CKSRy{ diff --git a/tokio-tls/examples/tls-echo.rs b/tokio-tls/examples/tls-echo.rs deleted file mode 100644 index 963095674..000000000 --- a/tokio-tls/examples/tls-echo.rs +++ /dev/null @@ -1,55 +0,0 @@ -#![warn(rust_2018_idioms)] - -// A tiny async TLS echo server with Tokio -use native_tls; -use native_tls::Identity; -use tokio; -use tokio::io::{AsyncReadExt, AsyncWriteExt}; -use tokio::net::TcpListener; -use tokio_tls; - -/** -an example to setup a tls server. -how to test: -wget https://127.0.0.1:12345 --no-check-certificate -*/ -#[tokio::main] -async fn main() -> Result<(), Box> { - // Bind the server's socket - let addr = "127.0.0.1:12345".to_string(); - let mut tcp: TcpListener = TcpListener::bind(&addr).await?; - - // Create the TLS acceptor. - let der = include_bytes!("identity.p12"); - let cert = Identity::from_pkcs12(der, "mypass")?; - let tls_acceptor = - tokio_tls::TlsAcceptor::from(native_tls::TlsAcceptor::builder(cert).build()?); - loop { - // Asynchronously wait for an inbound socket. - let (socket, remote_addr) = tcp.accept().await?; - let tls_acceptor = tls_acceptor.clone(); - println!("accept connection from {}", remote_addr); - tokio::spawn(async move { - // Accept the TLS connection. - let mut tls_stream = tls_acceptor.accept(socket).await.expect("accept error"); - // In a loop, read data from the socket and write the data back. - - let mut buf = [0; 1024]; - let n = tls_stream - .read(&mut buf) - .await - .expect("failed to read data from socket"); - - if n == 0 { - return; - } - println!("read={}", unsafe { - String::from_utf8_unchecked(buf[0..n].into()) - }); - tls_stream - .write_all(&buf[0..n]) - .await - .expect("failed to write data to socket"); - }); - } -} diff --git a/tokio-tls/src/lib.rs b/tokio-tls/src/lib.rs deleted file mode 100644 index 48c9d5220..000000000 --- a/tokio-tls/src/lib.rs +++ /dev/null @@ -1,364 +0,0 @@ -#![doc(html_root_url = "https://docs.rs/tokio-tls/0.3.1")] -#![warn( - missing_debug_implementations, - missing_docs, - rust_2018_idioms, - unreachable_pub -)] -#![deny(intra_doc_link_resolution_failure)] -#![doc(test( - no_crate_inject, - attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables)) -))] - -//! Async TLS streams -//! -//! > **Note:** This crate is **deprecated** and has been moved -//! into the [`tokio-native-tls`] crate. -//! -//! This library is an implementation of TLS streams using the most appropriate -//! system library by default for negotiating the connection. That is, on -//! Windows this library uses SChannel, on OSX it uses SecureTransport, and on -//! other platforms it uses OpenSSL. -//! -//! Each TLS stream implements the `Read` and `Write` traits to interact and -//! interoperate with the rest of the futures I/O ecosystem. Client connections -//! initiated from this crate verify hostnames automatically and by default. -//! -//! This crate primarily exports this ability through two newtypes, -//! `TlsConnector` and `TlsAcceptor`. These newtypes augment the -//! functionality provided by the `native-tls` crate, on which this crate is -//! built. Configuration of TLS parameters is still primarily done through the -//! `native-tls` crate. - -use tokio::io::{AsyncRead, AsyncWrite}; - -use native_tls::{Error, HandshakeError, MidHandshakeTlsStream}; -use std::fmt; -use std::future::Future; -use std::io::{self, Read, Write}; -use std::marker::Unpin; -use std::mem::MaybeUninit; -use std::pin::Pin; -use std::ptr::null_mut; -use std::task::{Context, Poll}; - -#[derive(Debug)] -struct AllowStd { - inner: S, - context: *mut (), -} - -/// A wrapper around an underlying raw stream which implements the TLS or SSL -/// protocol. -/// -/// A `TlsStream` represents a handshake that has been completed successfully -/// and both the server and the client are ready for receiving and sending -/// data. Bytes read from a `TlsStream` are decrypted from `S` and bytes written -/// to a `TlsStream` are encrypted when passing through to `S`. -#[derive(Debug)] -pub struct TlsStream(native_tls::TlsStream>); - -/// A wrapper around a `native_tls::TlsConnector`, providing an async `connect` -/// method. -#[derive(Clone)] -pub struct TlsConnector(native_tls::TlsConnector); - -/// A wrapper around a `native_tls::TlsAcceptor`, providing an async `accept` -/// method. -#[derive(Clone)] -pub struct TlsAcceptor(native_tls::TlsAcceptor); - -struct MidHandshake(Option>>); - -enum StartedHandshake { - Done(TlsStream), - Mid(MidHandshakeTlsStream>), -} - -struct StartedHandshakeFuture(Option>); -struct StartedHandshakeFutureInner { - f: F, - stream: S, -} - -struct Guard<'a, S>(&'a mut TlsStream) -where - AllowStd: Read + Write; - -impl Drop for Guard<'_, S> -where - AllowStd: Read + Write, -{ - fn drop(&mut self) { - (self.0).0.get_mut().context = null_mut(); - } -} - -// *mut () context is neither Send nor Sync -unsafe impl Send for AllowStd {} -unsafe impl Sync for AllowStd {} - -impl AllowStd -where - S: Unpin, -{ - fn with_context(&mut self, f: F) -> R - where - F: FnOnce(&mut Context<'_>, Pin<&mut S>) -> R, - { - unsafe { - assert!(!self.context.is_null()); - let waker = &mut *(self.context as *mut _); - f(waker, Pin::new(&mut self.inner)) - } - } -} - -impl Read for AllowStd -where - S: AsyncRead + Unpin, -{ - fn read(&mut self, buf: &mut [u8]) -> io::Result { - match self.with_context(|ctx, stream| stream.poll_read(ctx, buf)) { - Poll::Ready(r) => r, - Poll::Pending => Err(io::Error::from(io::ErrorKind::WouldBlock)), - } - } -} - -impl Write for AllowStd -where - S: AsyncWrite + Unpin, -{ - fn write(&mut self, buf: &[u8]) -> io::Result { - match self.with_context(|ctx, stream| stream.poll_write(ctx, buf)) { - Poll::Ready(r) => r, - Poll::Pending => Err(io::Error::from(io::ErrorKind::WouldBlock)), - } - } - - fn flush(&mut self) -> io::Result<()> { - match self.with_context(|ctx, stream| stream.poll_flush(ctx)) { - Poll::Ready(r) => r, - Poll::Pending => Err(io::Error::from(io::ErrorKind::WouldBlock)), - } - } -} - -fn cvt(r: io::Result) -> Poll> { - match r { - Ok(v) => Poll::Ready(Ok(v)), - Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => Poll::Pending, - Err(e) => Poll::Ready(Err(e)), - } -} - -impl TlsStream { - fn with_context(&mut self, ctx: &mut Context<'_>, f: F) -> R - where - F: FnOnce(&mut native_tls::TlsStream>) -> R, - AllowStd: Read + Write, - { - self.0.get_mut().context = ctx as *mut _ as *mut (); - let g = Guard(self); - f(&mut (g.0).0) - } - - /// Returns a shared reference to the inner stream. - pub fn get_ref(&self) -> &S - where - S: AsyncRead + AsyncWrite + Unpin, - { - &self.0.get_ref().inner - } - - /// Returns a mutable reference to the inner stream. - pub fn get_mut(&mut self) -> &mut S - where - S: AsyncRead + AsyncWrite + Unpin, - { - &mut self.0.get_mut().inner - } -} - -impl AsyncRead for TlsStream -where - S: AsyncRead + AsyncWrite + Unpin, -{ - unsafe fn prepare_uninitialized_buffer(&self, _: &mut [MaybeUninit]) -> bool { - // Note that this does not forward to `S` because the buffer is - // unconditionally filled in by OpenSSL, not the actual object `S`. - // We're decrypting bytes from `S` into the buffer above! - false - } - - fn poll_read( - mut self: Pin<&mut Self>, - ctx: &mut Context<'_>, - buf: &mut [u8], - ) -> Poll> { - self.with_context(ctx, |s| cvt(s.read(buf))) - } -} - -impl AsyncWrite for TlsStream -where - S: AsyncRead + AsyncWrite + Unpin, -{ - fn poll_write( - mut self: Pin<&mut Self>, - ctx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - self.with_context(ctx, |s| cvt(s.write(buf))) - } - - fn poll_flush(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll> { - self.with_context(ctx, |s| cvt(s.flush())) - } - - fn poll_shutdown(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll> { - match self.with_context(ctx, |s| s.shutdown()) { - Ok(()) => Poll::Ready(Ok(())), - Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => Poll::Pending, - Err(e) => Poll::Ready(Err(e)), - } - } -} - -async fn handshake(f: F, stream: S) -> Result, Error> -where - F: FnOnce( - AllowStd, - ) -> Result>, HandshakeError>> - + Unpin, - S: AsyncRead + AsyncWrite + Unpin, -{ - let start = StartedHandshakeFuture(Some(StartedHandshakeFutureInner { f, stream })); - - match start.await { - Err(e) => Err(e), - Ok(StartedHandshake::Done(s)) => Ok(s), - Ok(StartedHandshake::Mid(s)) => MidHandshake(Some(s)).await, - } -} - -impl Future for StartedHandshakeFuture -where - F: FnOnce( - AllowStd, - ) -> Result>, HandshakeError>> - + Unpin, - S: Unpin, - AllowStd: Read + Write, -{ - type Output = Result, Error>; - - fn poll( - mut self: Pin<&mut Self>, - ctx: &mut Context<'_>, - ) -> Poll, Error>> { - let inner = self.0.take().expect("future polled after completion"); - let stream = AllowStd { - inner: inner.stream, - context: ctx as *mut _ as *mut (), - }; - - match (inner.f)(stream) { - Ok(mut s) => { - s.get_mut().context = null_mut(); - Poll::Ready(Ok(StartedHandshake::Done(TlsStream(s)))) - } - Err(HandshakeError::WouldBlock(mut s)) => { - s.get_mut().context = null_mut(); - Poll::Ready(Ok(StartedHandshake::Mid(s))) - } - Err(HandshakeError::Failure(e)) => Poll::Ready(Err(e)), - } - } -} - -impl TlsConnector { - /// Connects the provided stream with this connector, assuming the provided - /// domain. - /// - /// This function will internally call `TlsConnector::connect` to connect - /// the stream and returns a future representing the resolution of the - /// connection operation. The returned future will resolve to either - /// `TlsStream` or `Error` depending if it's successful or not. - /// - /// This is typically used for clients who have already established, for - /// example, a TCP connection to a remote server. That stream is then - /// provided here to perform the client half of a connection to a - /// TLS-powered server. - pub async fn connect(&self, domain: &str, stream: S) -> Result, Error> - where - S: AsyncRead + AsyncWrite + Unpin, - { - handshake(move |s| self.0.connect(domain, s), stream).await - } -} - -impl fmt::Debug for TlsConnector { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TlsConnector").finish() - } -} - -impl From for TlsConnector { - fn from(inner: native_tls::TlsConnector) -> TlsConnector { - TlsConnector(inner) - } -} - -impl TlsAcceptor { - /// Accepts a new client connection with the provided stream. - /// - /// This function will internally call `TlsAcceptor::accept` to connect - /// the stream and returns a future representing the resolution of the - /// connection operation. The returned future will resolve to either - /// `TlsStream` or `Error` depending if it's successful or not. - /// - /// This is typically used after a new socket has been accepted from a - /// `TcpListener`. That socket is then passed to this function to perform - /// the server half of accepting a client connection. - pub async fn accept(&self, stream: S) -> Result, Error> - where - S: AsyncRead + AsyncWrite + Unpin, - { - handshake(move |s| self.0.accept(s), stream).await - } -} - -impl fmt::Debug for TlsAcceptor { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TlsAcceptor").finish() - } -} - -impl From for TlsAcceptor { - fn from(inner: native_tls::TlsAcceptor) -> TlsAcceptor { - TlsAcceptor(inner) - } -} - -impl Future for MidHandshake { - type Output = Result, Error>; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let mut_self = self.get_mut(); - let mut s = mut_self.0.take().expect("future polled after completion"); - - s.get_mut().context = cx as *mut _ as *mut (); - match s.handshake() { - Ok(stream) => Poll::Ready(Ok(TlsStream(stream))), - Err(HandshakeError::Failure(e)) => Poll::Ready(Err(e)), - Err(HandshakeError::WouldBlock(mut s)) => { - s.get_mut().context = null_mut(); - mut_self.0 = Some(s); - Poll::Pending - } - } - } -} diff --git a/tokio-tls/tests/bad.rs b/tokio-tls/tests/bad.rs deleted file mode 100644 index 87d4ca270..000000000 --- a/tokio-tls/tests/bad.rs +++ /dev/null @@ -1,124 +0,0 @@ -#![warn(rust_2018_idioms)] - -use cfg_if::cfg_if; -use env_logger; -use native_tls::TlsConnector; -use std::io::{self, Error}; -use std::net::ToSocketAddrs; -use tokio::net::TcpStream; -use tokio_tls; - -macro_rules! t { - ($e:expr) => { - match $e { - Ok(e) => e, - Err(e) => panic!("{} failed with {:?}", stringify!($e), e), - } - }; -} - -cfg_if! { - if #[cfg(feature = "force-rustls")] { - fn verify_failed(err: &Error, s: &str) { - let err = err.to_string(); - assert!(err.contains(s), "bad error: {}", err); - } - - fn assert_expired_error(err: &Error) { - verify_failed(err, "CertExpired"); - } - - fn assert_wrong_host(err: &Error) { - verify_failed(err, "CertNotValidForName"); - } - - fn assert_self_signed(err: &Error) { - verify_failed(err, "UnknownIssuer"); - } - - fn assert_untrusted_root(err: &Error) { - verify_failed(err, "UnknownIssuer"); - } - } else if #[cfg(any(feature = "force-openssl", - all(not(target_os = "macos"), - not(target_os = "windows"), - not(target_os = "ios"))))] { - fn verify_failed(err: &Error) { - assert!(format!("{}", err).contains("certificate verify failed")) - } - - use verify_failed as assert_expired_error; - use verify_failed as assert_wrong_host; - use verify_failed as assert_self_signed; - use verify_failed as assert_untrusted_root; - } else if #[cfg(any(target_os = "macos", target_os = "ios"))] { - - fn assert_invalid_cert_chain(err: &Error) { - assert!(format!("{}", err).contains("was not trusted.")) - } - - use crate::assert_invalid_cert_chain as assert_expired_error; - use crate::assert_invalid_cert_chain as assert_wrong_host; - use crate::assert_invalid_cert_chain as assert_self_signed; - use crate::assert_invalid_cert_chain as assert_untrusted_root; - } else { - fn assert_expired_error(err: &Error) { - let s = err.to_string(); - assert!(s.contains("system clock"), "error = {:?}", s); - } - - fn assert_wrong_host(err: &Error) { - let s = err.to_string(); - assert!(s.contains("CN name"), "error = {:?}", s); - } - - fn assert_self_signed(err: &Error) { - let s = err.to_string(); - assert!(s.contains("root certificate which is not trusted"), "error = {:?}", s); - } - - use assert_self_signed as assert_untrusted_root; - } -} - -async fn get_host(host: &'static str) -> Error { - drop(env_logger::try_init()); - - let addr = format!("{}:443", host); - let addr = t!(addr.to_socket_addrs()).next().unwrap(); - - let socket = t!(TcpStream::connect(&addr).await); - let builder = TlsConnector::builder(); - let cx = t!(builder.build()); - let cx = tokio_tls::TlsConnector::from(cx); - let res = cx - .connect(host, socket) - .await - .map_err(|e| Error::new(io::ErrorKind::Other, e)); - - assert!(res.is_err()); - res.err().unwrap() -} - -#[tokio::test] -async fn expired() { - assert_expired_error(&get_host("expired.badssl.com").await) -} - -// TODO: the OSX builders on Travis apparently fail this tests spuriously? -// passes locally though? Seems... bad! -#[tokio::test] -#[cfg_attr(all(target_os = "macos", feature = "force-openssl"), ignore)] -async fn wrong_host() { - assert_wrong_host(&get_host("wrong.host.badssl.com").await) -} - -#[tokio::test] -async fn self_signed() { - assert_self_signed(&get_host("self-signed.badssl.com").await) -} - -#[tokio::test] -async fn untrusted_root() { - assert_untrusted_root(&get_host("untrusted-root.badssl.com").await) -} diff --git a/tokio-tls/tests/google.rs b/tokio-tls/tests/google.rs deleted file mode 100644 index 13b78d318..000000000 --- a/tokio-tls/tests/google.rs +++ /dev/null @@ -1,102 +0,0 @@ -#![warn(rust_2018_idioms)] - -use cfg_if::cfg_if; -use env_logger; -use native_tls; -use native_tls::TlsConnector; -use std::io; -use std::net::ToSocketAddrs; -use tokio::io::{AsyncReadExt, AsyncWriteExt}; -use tokio::net::TcpStream; -use tokio_tls; - -macro_rules! t { - ($e:expr) => { - match $e { - Ok(e) => e, - Err(e) => panic!("{} failed with {:?}", stringify!($e), e), - } - }; -} - -cfg_if! { - if #[cfg(feature = "force-rustls")] { - fn assert_bad_hostname_error(err: &io::Error) { - let err = err.to_string(); - assert!(err.contains("CertNotValidForName"), "bad error: {}", err); - } - } else if #[cfg(any(feature = "force-openssl", - all(not(target_os = "macos"), - not(target_os = "windows"), - not(target_os = "ios"))))] { - fn assert_bad_hostname_error(err: &io::Error) { - let err = err.get_ref().unwrap(); - let err = err.downcast_ref::().unwrap(); - assert!(format!("{}", err).contains("certificate verify failed")); - } - } else if #[cfg(any(target_os = "macos", target_os = "ios"))] { - fn assert_bad_hostname_error(err: &io::Error) { - let err = err.get_ref().unwrap(); - let err = err.downcast_ref::().unwrap(); - assert!(format!("{}", err).contains("was not trusted.")); - } - } else { - fn assert_bad_hostname_error(err: &io::Error) { - let err = err.get_ref().unwrap(); - let err = err.downcast_ref::().unwrap(); - assert!(format!("{}", err).contains("CN name")); - } - } -} - -#[tokio::test] -async fn fetch_google() { - drop(env_logger::try_init()); - - // First up, resolve google.com - let addr = t!("google.com:443".to_socket_addrs()).next().unwrap(); - - let socket = TcpStream::connect(&addr).await.unwrap(); - - // Send off the request by first negotiating an SSL handshake, then writing - // of our request, then flushing, then finally read off the response. - let builder = TlsConnector::builder(); - let connector = t!(builder.build()); - let connector = tokio_tls::TlsConnector::from(connector); - let mut socket = t!(connector.connect("google.com", socket).await); - t!(socket.write_all(b"GET / HTTP/1.0\r\n\r\n").await); - let mut data = Vec::new(); - t!(socket.read_to_end(&mut data).await); - - // any response code is fine - assert!(data.starts_with(b"HTTP/1.0 ")); - - let data = String::from_utf8_lossy(&data); - let data = data.trim_end(); - assert!(data.ends_with("") || data.ends_with("")); -} - -fn native2io(e: native_tls::Error) -> io::Error { - io::Error::new(io::ErrorKind::Other, e) -} - -// see comment in bad.rs for ignore reason -#[cfg_attr(all(target_os = "macos", feature = "force-openssl"), ignore)] -#[tokio::test] -async fn wrong_hostname_error() { - drop(env_logger::try_init()); - - let addr = t!("google.com:443".to_socket_addrs()).next().unwrap(); - - let socket = t!(TcpStream::connect(&addr).await); - let builder = TlsConnector::builder(); - let connector = t!(builder.build()); - let connector = tokio_tls::TlsConnector::from(connector); - let res = connector - .connect("rust-lang.org", socket) - .await - .map_err(native2io); - - assert!(res.is_err()); - assert_bad_hostname_error(&res.err().unwrap()); -} diff --git a/tokio-tls/tests/smoke.rs b/tokio-tls/tests/smoke.rs deleted file mode 100644 index 8788dd6d4..000000000 --- a/tokio-tls/tests/smoke.rs +++ /dev/null @@ -1,629 +0,0 @@ -#![warn(rust_2018_idioms)] - -use cfg_if::cfg_if; -use env_logger; -use futures::join; -use native_tls; -use native_tls::{Identity, TlsAcceptor, TlsConnector}; -use std::io::Write; -use std::marker::Unpin; -use std::process::Command; -use std::ptr; -use tokio::io::{AsyncReadExt, AsyncWrite, AsyncWriteExt, Error, ErrorKind}; -use tokio::net::{TcpListener, TcpStream}; -use tokio::stream::StreamExt; -use tokio_tls; - -macro_rules! t { - ($e:expr) => { - match $e { - Ok(e) => e, - Err(e) => panic!("{} failed with {:?}", stringify!($e), e), - } - }; -} - -#[allow(dead_code)] -struct Keys { - cert_der: Vec, - pkey_der: Vec, - pkcs12_der: Vec, -} - -#[allow(dead_code)] -fn openssl_keys() -> &'static Keys { - static INIT: Once = Once::new(); - static mut KEYS: *mut Keys = ptr::null_mut(); - - INIT.call_once(|| { - let path = t!(env::current_exe()); - let path = path.parent().unwrap(); - let keyfile = path.join("test.key"); - let certfile = path.join("test.crt"); - let config = path.join("openssl.config"); - - File::create(&config) - .unwrap() - .write_all( - b"\ - [req]\n\ - distinguished_name=dn\n\ - [ dn ]\n\ - CN=localhost\n\ - [ ext ]\n\ - basicConstraints=CA:FALSE,pathlen:0\n\ - subjectAltName = @alt_names - extendedKeyUsage=serverAuth,clientAuth - [alt_names] - DNS.1 = localhost - ", - ) - .unwrap(); - - let subj = "/C=US/ST=Denial/L=Sprintfield/O=Dis/CN=localhost"; - let output = t!(Command::new("openssl") - .arg("req") - .arg("-nodes") - .arg("-x509") - .arg("-newkey") - .arg("rsa:2048") - .arg("-config") - .arg(&config) - .arg("-extensions") - .arg("ext") - .arg("-subj") - .arg(subj) - .arg("-keyout") - .arg(&keyfile) - .arg("-out") - .arg(&certfile) - .arg("-days") - .arg("1") - .output()); - assert!(output.status.success()); - - let crtout = t!(Command::new("openssl") - .arg("x509") - .arg("-outform") - .arg("der") - .arg("-in") - .arg(&certfile) - .output()); - assert!(crtout.status.success()); - let keyout = t!(Command::new("openssl") - .arg("rsa") - .arg("-outform") - .arg("der") - .arg("-in") - .arg(&keyfile) - .output()); - assert!(keyout.status.success()); - - let pkcs12out = t!(Command::new("openssl") - .arg("pkcs12") - .arg("-export") - .arg("-nodes") - .arg("-inkey") - .arg(&keyfile) - .arg("-in") - .arg(&certfile) - .arg("-password") - .arg("pass:foobar") - .output()); - assert!(pkcs12out.status.success()); - - let keys = Box::new(Keys { - cert_der: crtout.stdout, - pkey_der: keyout.stdout, - pkcs12_der: pkcs12out.stdout, - }); - unsafe { - KEYS = Box::into_raw(keys); - } - }); - unsafe { &*KEYS } -} - -cfg_if! { - if #[cfg(feature = "rustls")] { - use webpki; - use untrusted; - use std::env; - use std::fs::File; - use std::process::Command; - use std::sync::Once; - - use untrusted::Input; - use webpki::trust_anchor_util; - - fn server_cx() -> io::Result { - let mut cx = ServerContext::new(); - - let (cert, key) = keys(); - cx.config_mut() - .set_single_cert(vec![cert.to_vec()], key.to_vec()); - - Ok(cx) - } - - fn configure_client(cx: &mut ClientContext) { - let (cert, _key) = keys(); - let cert = Input::from(cert); - let anchor = trust_anchor_util::cert_der_as_trust_anchor(cert).unwrap(); - cx.config_mut().root_store.add_trust_anchors(&[anchor]); - } - - // Like OpenSSL we generate certificates on the fly, but for OSX we - // also have to put them into a specific keychain. We put both the - // certificates and the keychain next to our binary. - // - // Right now I don't know of a way to programmatically create a - // self-signed certificate, so we just fork out to the `openssl` binary. - fn keys() -> (&'static [u8], &'static [u8]) { - static INIT: Once = Once::new(); - static mut KEYS: *mut (Vec, Vec) = ptr::null_mut(); - - INIT.call_once(|| { - let (key, cert) = openssl_keys(); - let path = t!(env::current_exe()); - let path = path.parent().unwrap(); - let keyfile = path.join("test.key"); - let certfile = path.join("test.crt"); - let config = path.join("openssl.config"); - - File::create(&config).unwrap().write_all(b"\ - [req]\n\ - distinguished_name=dn\n\ - [ dn ]\n\ - CN=localhost\n\ - [ ext ]\n\ - basicConstraints=CA:FALSE,pathlen:0\n\ - subjectAltName = @alt_names - [alt_names] - DNS.1 = localhost - ").unwrap(); - - let subj = "/C=US/ST=Denial/L=Sprintfield/O=Dis/CN=localhost"; - let output = t!(Command::new("openssl") - .arg("req") - .arg("-nodes") - .arg("-x509") - .arg("-newkey").arg("rsa:2048") - .arg("-config").arg(&config) - .arg("-extensions").arg("ext") - .arg("-subj").arg(subj) - .arg("-keyout").arg(&keyfile) - .arg("-out").arg(&certfile) - .arg("-days").arg("1") - .output()); - assert!(output.status.success()); - - let crtout = t!(Command::new("openssl") - .arg("x509") - .arg("-outform").arg("der") - .arg("-in").arg(&certfile) - .output()); - assert!(crtout.status.success()); - let keyout = t!(Command::new("openssl") - .arg("rsa") - .arg("-outform").arg("der") - .arg("-in").arg(&keyfile) - .output()); - assert!(keyout.status.success()); - - let cert = crtout.stdout; - let key = keyout.stdout; - unsafe { - KEYS = Box::into_raw(Box::new((cert, key))); - } - }); - unsafe { - (&(*KEYS).0, &(*KEYS).1) - } - } - } else if #[cfg(any(feature = "force-openssl", - all(not(target_os = "macos"), - not(target_os = "windows"), - not(target_os = "ios"))))] { - use std::fs::File; - use std::env; - use std::sync::Once; - - fn contexts() -> (tokio_tls::TlsAcceptor, tokio_tls::TlsConnector) { - let keys = openssl_keys(); - - let pkcs12 = t!(Identity::from_pkcs12(&keys.pkcs12_der, "foobar")); - let srv = TlsAcceptor::builder(pkcs12); - - let cert = t!(native_tls::Certificate::from_der(&keys.cert_der)); - - let mut client = TlsConnector::builder(); - t!(client.add_root_certificate(cert).build()); - - (t!(srv.build()).into(), t!(client.build()).into()) - } - } else if #[cfg(any(target_os = "macos", target_os = "ios"))] { - use std::env; - use std::fs::File; - use std::sync::Once; - - fn contexts() -> (tokio_tls::TlsAcceptor, tokio_tls::TlsConnector) { - let keys = openssl_keys(); - - let pkcs12 = t!(Identity::from_pkcs12(&keys.pkcs12_der, "foobar")); - let srv = TlsAcceptor::builder(pkcs12); - - let cert = native_tls::Certificate::from_der(&keys.cert_der).unwrap(); - let mut client = TlsConnector::builder(); - client.add_root_certificate(cert); - - (t!(srv.build()).into(), t!(client.build()).into()) - } - } else { - use schannel; - use winapi; - - use std::env; - use std::fs::File; - use std::io; - use std::mem; - use std::sync::Once; - - use schannel::cert_context::CertContext; - use schannel::cert_store::{CertStore, CertAdd, Memory}; - use winapi::shared::basetsd::*; - use winapi::shared::lmcons::*; - use winapi::shared::minwindef::*; - use winapi::shared::ntdef::WCHAR; - use winapi::um::minwinbase::*; - use winapi::um::sysinfoapi::*; - use winapi::um::timezoneapi::*; - use winapi::um::wincrypt::*; - - const FRIENDLY_NAME: &str = "tokio-tls localhost testing cert"; - - fn contexts() -> (tokio_tls::TlsAcceptor, tokio_tls::TlsConnector) { - let cert = localhost_cert(); - let mut store = t!(Memory::new()).into_store(); - t!(store.add_cert(&cert, CertAdd::Always)); - let pkcs12_der = t!(store.export_pkcs12("foobar")); - let pkcs12 = t!(Identity::from_pkcs12(&pkcs12_der, "foobar")); - - let srv = TlsAcceptor::builder(pkcs12); - let client = TlsConnector::builder(); - (t!(srv.build()).into(), t!(client.build()).into()) - } - - // ==================================================================== - // Magic! - // - // Lots of magic is happening here to wrangle certificates for running - // these tests on Windows. For more information see the test suite - // in the schannel-rs crate as this is just coyping that. - // - // The general gist of this though is that the only way to add custom - // trusted certificates is to add it to the system store of trust. To - // do that we go through the whole rigamarole here to generate a new - // self-signed certificate and then insert that into the system store. - // - // This generates some dialogs, so we print what we're doing sometimes, - // and otherwise we just manage the ephemeral certificates. Because - // they're in the system store we always ensure that they're only valid - // for a small period of time (e.g. 1 day). - - fn localhost_cert() -> CertContext { - static INIT: Once = Once::new(); - INIT.call_once(|| { - for cert in local_root_store().certs() { - let name = match cert.friendly_name() { - Ok(name) => name, - Err(_) => continue, - }; - if name != FRIENDLY_NAME { - continue - } - if !cert.is_time_valid().unwrap() { - io::stdout().write_all(br#" - -The tokio-tls test suite is about to delete an old copy of one of its -certificates from your root trust store. This certificate was only valid for one -day and it is no longer needed. The host should be "localhost" and the -description should mention "tokio-tls". - - "#).unwrap(); - cert.delete().unwrap(); - } else { - return - } - } - - install_certificate().unwrap(); - }); - - for cert in local_root_store().certs() { - let name = match cert.friendly_name() { - Ok(name) => name, - Err(_) => continue, - }; - if name == FRIENDLY_NAME { - return cert - } - } - - panic!("couldn't find a cert"); - } - - fn local_root_store() -> CertStore { - if env::var("CI").is_ok() { - CertStore::open_local_machine("Root").unwrap() - } else { - CertStore::open_current_user("Root").unwrap() - } - } - - fn install_certificate() -> io::Result { - unsafe { - let mut provider = 0; - let mut hkey = 0; - - let mut buffer = "tokio-tls test suite".encode_utf16() - .chain(Some(0)) - .collect::>(); - let res = CryptAcquireContextW(&mut provider, - buffer.as_ptr(), - ptr::null_mut(), - PROV_RSA_FULL, - CRYPT_MACHINE_KEYSET); - if res != TRUE { - // create a new key container (since it does not exist) - let res = CryptAcquireContextW(&mut provider, - buffer.as_ptr(), - ptr::null_mut(), - PROV_RSA_FULL, - CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET); - if res != TRUE { - return Err(Error::last_os_error()) - } - } - - // create a new keypair (RSA-2048) - let res = CryptGenKey(provider, - AT_SIGNATURE, - 0x0800<<16 | CRYPT_EXPORTABLE, - &mut hkey); - if res != TRUE { - return Err(Error::last_os_error()); - } - - // start creating the certificate - let name = "CN=localhost,O=tokio-tls,OU=tokio-tls,\ - G=tokio_tls".encode_utf16() - .chain(Some(0)) - .collect::>(); - let mut cname_buffer: [WCHAR; UNLEN as usize + 1] = mem::zeroed(); - let mut cname_len = cname_buffer.len() as DWORD; - let res = CertStrToNameW(X509_ASN_ENCODING, - name.as_ptr(), - CERT_X500_NAME_STR, - ptr::null_mut(), - cname_buffer.as_mut_ptr() as *mut u8, - &mut cname_len, - ptr::null_mut()); - if res != TRUE { - return Err(Error::last_os_error()); - } - - let mut subject_issuer = CERT_NAME_BLOB { - cbData: cname_len, - pbData: cname_buffer.as_ptr() as *mut u8, - }; - let mut key_provider = CRYPT_KEY_PROV_INFO { - pwszContainerName: buffer.as_mut_ptr(), - pwszProvName: ptr::null_mut(), - dwProvType: PROV_RSA_FULL, - dwFlags: CRYPT_MACHINE_KEYSET, - cProvParam: 0, - rgProvParam: ptr::null_mut(), - dwKeySpec: AT_SIGNATURE, - }; - let mut sig_algorithm = CRYPT_ALGORITHM_IDENTIFIER { - pszObjId: szOID_RSA_SHA256RSA.as_ptr() as *mut _, - Parameters: mem::zeroed(), - }; - let mut expiration_date: SYSTEMTIME = mem::zeroed(); - GetSystemTime(&mut expiration_date); - let mut file_time: FILETIME = mem::zeroed(); - let res = SystemTimeToFileTime(&expiration_date, - &mut file_time); - if res != TRUE { - return Err(Error::last_os_error()); - } - let mut timestamp: u64 = file_time.dwLowDateTime as u64 | - (file_time.dwHighDateTime as u64) << 32; - // one day, timestamp unit is in 100 nanosecond intervals - timestamp += (1E9 as u64) / 100 * (60 * 60 * 24); - file_time.dwLowDateTime = timestamp as u32; - file_time.dwHighDateTime = (timestamp >> 32) as u32; - let res = FileTimeToSystemTime(&file_time, - &mut expiration_date); - if res != TRUE { - return Err(Error::last_os_error()); - } - - // create a self signed certificate - let cert_context = CertCreateSelfSignCertificate( - 0 as ULONG_PTR, - &mut subject_issuer, - 0, - &mut key_provider, - &mut sig_algorithm, - ptr::null_mut(), - &mut expiration_date, - ptr::null_mut()); - if cert_context.is_null() { - return Err(Error::last_os_error()); - } - - // TODO: this is.. a terrible hack. Right now `schannel` - // doesn't provide a public method to go from a raw - // cert context pointer to the `CertContext` structure it - // has, so we just fake it here with a transmute. This'll - // probably break at some point, but hopefully by then - // it'll have a method to do this! - struct MyCertContext(T); - impl Drop for MyCertContext { - fn drop(&mut self) {} - } - - let cert_context = MyCertContext(cert_context); - let cert_context: CertContext = mem::transmute(cert_context); - - cert_context.set_friendly_name(FRIENDLY_NAME)?; - - // install the certificate to the machine's local store - io::stdout().write_all(br#" - -The tokio-tls test suite is about to add a certificate to your set of root -and trusted certificates. This certificate should be for the domain "localhost" -with the description related to "tokio-tls". This certificate is only valid -for one day and will be automatically deleted if you re-run the tokio-tls -test suite later. - - "#).unwrap(); - local_root_store().add_cert(&cert_context, - CertAdd::ReplaceExisting)?; - Ok(cert_context) - } - } - } -} - -const AMT: usize = 128 * 1024; - -async fn copy_data(mut w: W) -> Result { - let mut data = vec![9; AMT as usize]; - let mut amt = 0; - while !data.is_empty() { - let written = w.write(&data).await?; - if written <= data.len() { - amt += written; - data.resize(data.len() - written, 0); - } else { - w.write_all(&data).await?; - amt += data.len(); - break; - } - - println!("remaining: {}", data.len()); - } - Ok(amt) -} - -#[tokio::test] -async fn client_to_server() { - drop(env_logger::try_init()); - - // Create a server listening on a port, then figure out what that port is - let mut srv = t!(TcpListener::bind("127.0.0.1:0").await); - let addr = t!(srv.local_addr()); - - let (server_cx, client_cx) = contexts(); - - // Create a future to accept one socket, connect the ssl stream, and then - // read all the data from it. - let server = async move { - let mut incoming = srv.incoming(); - let socket = t!(incoming.next().await.unwrap()); - let mut socket = t!(server_cx.accept(socket).await); - let mut data = Vec::new(); - t!(socket.read_to_end(&mut data).await); - data - }; - - // Create a future to connect to our server, connect the ssl stream, and - // then write a bunch of data to it. - let client = async move { - let socket = t!(TcpStream::connect(&addr).await); - let socket = t!(client_cx.connect("localhost", socket).await); - copy_data(socket).await - }; - - // Finally, run everything! - let (data, _) = join!(server, client); - // assert_eq!(amt, AMT); - assert!(data == vec![9; AMT]); -} - -#[tokio::test] -async fn server_to_client() { - drop(env_logger::try_init()); - - // Create a server listening on a port, then figure out what that port is - let mut srv = t!(TcpListener::bind("127.0.0.1:0").await); - let addr = t!(srv.local_addr()); - - let (server_cx, client_cx) = contexts(); - - let server = async move { - let mut incoming = srv.incoming(); - let socket = t!(incoming.next().await.unwrap()); - let socket = t!(server_cx.accept(socket).await); - copy_data(socket).await - }; - - let client = async move { - let socket = t!(TcpStream::connect(&addr).await); - let mut socket = t!(client_cx.connect("localhost", socket).await); - let mut data = Vec::new(); - t!(socket.read_to_end(&mut data).await); - data - }; - - // Finally, run everything! - let (_, data) = join!(server, client); - // assert_eq!(amt, AMT); - assert!(data == vec![9; AMT]); -} - -#[tokio::test] -async fn one_byte_at_a_time() { - const AMT: usize = 1024; - drop(env_logger::try_init()); - - let mut srv = t!(TcpListener::bind("127.0.0.1:0").await); - let addr = t!(srv.local_addr()); - - let (server_cx, client_cx) = contexts(); - - let server = async move { - let mut incoming = srv.incoming(); - let socket = t!(incoming.next().await.unwrap()); - let mut socket = t!(server_cx.accept(socket).await); - let mut amt = 0; - for b in std::iter::repeat(9).take(AMT) { - let data = [b as u8]; - t!(socket.write_all(&data).await); - amt += 1; - } - amt - }; - - let client = async move { - let socket = t!(TcpStream::connect(&addr).await); - let mut socket = t!(client_cx.connect("localhost", socket).await); - let mut data = Vec::new(); - loop { - let mut buf = [0; 1]; - match socket.read_exact(&mut buf).await { - Ok(_) => data.extend_from_slice(&buf), - Err(ref err) if err.kind() == ErrorKind::UnexpectedEof => break, - Err(err) => panic!(err), - } - } - data - }; - - let (amt, data) = join!(server, client); - assert_eq!(amt, AMT); - assert!(data == vec![9; AMT as usize]); -}