chore: checkpoint before Python removal

This commit is contained in:
2026-03-26 22:33:59 +00:00
parent 683cec9307
commit e568ddf82a
29972 changed files with 11269302 additions and 2 deletions

101
vendor/tokio-rustls/tests/badssl.rs vendored Normal file
View File

@@ -0,0 +1,101 @@
use std::io;
use std::net::ToSocketAddrs;
use std::sync::Arc;
use rustls::pki_types::ServerName;
use rustls::ClientConfig;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::TcpStream;
use tokio_rustls::client::TlsStream;
use tokio_rustls::TlsConnector;
async fn get(
config: Arc<ClientConfig>,
domain: &str,
port: u16,
vectored: bool,
) -> io::Result<(TlsStream<TcpStream>, String)> {
let connector = TlsConnector::from(config);
let input = format!("GET / HTTP/1.0\r\nHost: {}\r\n\r\n", domain);
let addr = (domain, port).to_socket_addrs()?.next().unwrap();
let domain = ServerName::try_from(domain).unwrap().to_owned();
let mut buf = Vec::new();
let stream = TcpStream::connect(&addr).await?;
let mut stream = connector.connect(domain, stream).await?;
utils::write(&mut stream, input.as_bytes(), vectored).await?;
stream.flush().await?;
stream.read_to_end(&mut buf).await?;
Ok((stream, String::from_utf8(buf).unwrap()))
}
#[tokio::test]
async fn test_tls12() -> io::Result<()> {
test_tls12_impl(false).await
}
#[tokio::test]
async fn test_tls12_vectored() -> io::Result<()> {
test_tls12_impl(true).await
}
async fn test_tls12_impl(vectored: bool) -> io::Result<()> {
let mut root_store = rustls::RootCertStore::empty();
root_store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
let config = rustls::ClientConfig::builder_with_protocol_versions(&[&rustls::version::TLS12])
.with_root_certificates(root_store)
.with_no_client_auth();
let config = Arc::new(config);
let domain = "tls-v1-2.badssl.com";
let (_, output) = get(config.clone(), domain, 1012, vectored).await?;
assert!(
output.contains("<title>tls-v1-2.badssl.com</title>"),
"failed badssl test, output: {}",
output
);
Ok(())
}
#[ignore]
#[should_panic]
#[test]
fn test_tls13() {
unimplemented!("todo https://github.com/chromium/badssl.com/pull/373");
}
#[tokio::test]
async fn test_modern() -> io::Result<()> {
test_modern_impl(false).await
}
#[tokio::test]
async fn test_modern_vectored() -> io::Result<()> {
test_modern_impl(true).await
}
async fn test_modern_impl(vectored: bool) -> io::Result<()> {
let mut root_store = rustls::RootCertStore::empty();
root_store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
let config = rustls::ClientConfig::builder()
.with_root_certificates(root_store)
.with_no_client_auth();
let config = Arc::new(config);
let domain = "mozilla-modern.badssl.com";
let (_, output) = get(config.clone(), domain, 443, vectored).await?;
assert!(
output.contains("<title>mozilla-modern.badssl.com</title>"),
"failed badssl test, output: {}",
output
);
Ok(())
}
// Include `utils` module
include!("utils.rs");

View File

@@ -0,0 +1,23 @@
-----BEGIN CERTIFICATE-----
MIIBszCCAVmgAwIBAgIUUg3keFcU1xXWK8BNVb1KynPulV8wCgYIKoZIzj0EAwIw
JjEkMCIGA1UEAwwbUnVzdGxzIFJvYnVzdCBSb290IC0gUnVuZyAyMCAXDTc1MDEw
MTAwMDAwMFoYDzQwOTYwMTAxMDAwMDAwWjAhMR8wHQYDVQQDDBZyY2dlbiBzZWxm
IHNpZ25lZCBjZXJ0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEud6w4gtZ0xbw
J3E69SSMy5TZfdIifl9L5ZY+hgEe4UiUsBWS32f6Y5NR5Jo8FO1f6o13b3+FvVHR
EHCGdvppL6NoMGYwFQYDVR0RBA4wDIIKZm9vYmFyLmNvbTAdBgNVHSUEFjAUBggr
BgEFBQcDAQYIKwYBBQUHAwIwHQYDVR0OBBYEFELvxbj5tD75n4pYFvJyr+c8qVEi
MA8GA1UdEwEB/wQFMAMBAQAwCgYIKoZIzj0EAwIDSAAwRQIhALxSSdUsrRFnwNMu
/doBqI8i8u5HdohVAheFTDwObkOMAiASSjULUtkWSD15u/7Sr01Wm9J1MpqW1pob
BVqU3CNRlA==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIBiTCCATCgAwIBAgIUHWiVYIvMMWoZEFYvSz46COf2FqowCgYIKoZIzj0EAwIw
HTEbMBkGA1UEAwwSUnVzdGxzIFJvYnVzdCBSb290MCAXDTc1MDEwMTAwMDAwMFoY
DzQwOTYwMTAxMDAwMDAwWjAmMSQwIgYDVQQDDBtSdXN0bHMgUm9idXN0IFJvb3Qg
LSBSdW5nIDIwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATAOCcBD7dXjmAZ3te5
D47cCJ9ec93PWv7BKYIL826CJsKfXQOGrBTthLm77hXLhHu6uv8E5QXNLZpfowLQ
Do1ao0MwQTAPBgNVHQ8BAf8EBQMDB4QAMB0GA1UdDgQWBBRdza76r11Ok9vRmlg6
Nn/wL/N+jTAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0cAMEQCIFmZrXeK
hnfkahocvkhhNT3cDv1LWf6WBoFaCiBwZXFPAiARaKRiSCMG7PCHmSqFe82TBVmL
odHGogAVax1Dh/aYAA==
-----END CERTIFICATE-----

View File

@@ -0,0 +1,5 @@
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgTbAQpfjAT46fgF4B
mP15n37woNG5ZNJmwcqsred/7tmhRANCAAS53rDiC1nTFvAncTr1JIzLlNl90iJ+
X0vllj6GAR7hSJSwFZLfZ/pjk1HkmjwU7V/qjXdvf4W9UdEQcIZ2+mkv
-----END PRIVATE KEY-----

71
vendor/tokio-rustls/tests/certs/main.rs vendored Normal file
View File

@@ -0,0 +1,71 @@
//! An ignored-by-default integration test that regenerates vendored certs.
//! Run with `cargo test -- --ignored` when test certificates need updating.
//! Suitable for test certificates only. Not a production CA ;-)
use rcgen::{
BasicConstraints, CertificateParams, DistinguishedName, DnType, ExtendedKeyUsagePurpose, IsCa,
Issuer, KeyPair, KeyUsagePurpose,
};
use std::fs::File;
use std::io::Write;
#[test]
#[ignore]
fn regenerate_certs() {
let root = {
let key = KeyPair::generate().unwrap();
let params = issuer_params("Rustls Robust Root");
let cert = params.self_signed(&key).unwrap();
(Issuer::new(params, key), cert)
};
let mut root_file = File::create("tests/certs/root.pem").unwrap();
root_file.write_all(root.1.pem().as_bytes()).unwrap();
let intermediate = {
let key = KeyPair::generate().unwrap();
let params = issuer_params("Rustls Robust Root - Rung 2");
let cert = params.signed_by(&key, &root.0).unwrap();
(Issuer::new(params, key), cert)
};
let end_entity_key = KeyPair::generate().unwrap();
let mut end_entity_params =
CertificateParams::new(vec![utils::TEST_SERVER_DOMAIN.to_string()]).unwrap();
end_entity_params.is_ca = IsCa::ExplicitNoCa;
end_entity_params.extended_key_usages = vec![
ExtendedKeyUsagePurpose::ServerAuth,
ExtendedKeyUsagePurpose::ClientAuth,
];
let end_entity = end_entity_params
.signed_by(&end_entity_key, &intermediate.0)
.unwrap();
let mut chain_file = File::create("tests/certs/chain.pem").unwrap();
chain_file.write_all(end_entity.pem().as_bytes()).unwrap();
chain_file
.write_all(intermediate.1.pem().as_bytes())
.unwrap();
let mut key_file = File::create("tests/certs/end.key").unwrap();
key_file
.write_all(end_entity_key.serialize_pem().as_bytes())
.unwrap();
}
fn issuer_params(common_name: &str) -> CertificateParams {
let mut issuer_name = DistinguishedName::new();
issuer_name.push(DnType::CommonName, common_name);
let mut issuer_params = CertificateParams::default();
issuer_params.distinguished_name = issuer_name;
issuer_params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained);
issuer_params.key_usages = vec![
KeyUsagePurpose::KeyCertSign,
KeyUsagePurpose::DigitalSignature,
];
issuer_params
}
// For the server name constant.
include!("../utils.rs");

View File

@@ -0,0 +1,11 @@
-----BEGIN CERTIFICATE-----
MIIBgDCCASegAwIBAgIUPHDUu9WL36yvTmFeNFZVe/qhClcwCgYIKoZIzj0EAwIw
HTEbMBkGA1UEAwwSUnVzdGxzIFJvYnVzdCBSb290MCAXDTc1MDEwMTAwMDAwMFoY
DzQwOTYwMTAxMDAwMDAwWjAdMRswGQYDVQQDDBJSdXN0bHMgUm9idXN0IFJvb3Qw
WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASW/VkDFs5iGDQvH8jaXYT4jMx66jo+
5CWKyMt4OlTDdBfKfnmQ9LYeK/PsYfJ8wVizuSlPzXi9je8SnyYejGP3o0MwQTAP
BgNVHQ8BAf8EBQMDB4QAMB0GA1UdDgQWBBRqY/oMENJbNo7y39iL6GW3tDs0rzAP
BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0cAMEQCIEUbrmSUjANju9nNpFop
PAl9Wh8tBxI5IY+BPh466+aUAiA1/9+prypt6s3Doo0GDsnoFGJi1UBivUg1qdik
cy4eNw==
-----END CERTIFICATE-----

109
vendor/tokio-rustls/tests/early-data.rs vendored Normal file
View File

@@ -0,0 +1,109 @@
#![cfg(feature = "early-data")]
use std::io::{self, Read, Write};
use std::net::{SocketAddr, TcpListener};
use std::sync::Arc;
use std::thread;
use rustls::pki_types::ServerName;
use rustls::{self, ClientConfig, ServerConnection, Stream};
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
use tokio::net::TcpStream;
use tokio_rustls::client::TlsStream;
use tokio_rustls::TlsConnector;
async fn send<S: AsyncRead + AsyncWrite + Unpin>(
config: Arc<ClientConfig>,
addr: SocketAddr,
wrapper: impl Fn(TcpStream) -> S,
data: &[u8],
vectored: bool,
) -> io::Result<(TlsStream<S>, Vec<u8>)> {
let connector = TlsConnector::from(config).early_data(true);
let stream = wrapper(TcpStream::connect(&addr).await?);
let domain = ServerName::try_from("foobar.com").unwrap();
let mut stream = connector.connect(domain, stream).await?;
utils::write(&mut stream, data, vectored).await?;
stream.flush().await?;
stream.shutdown().await?;
let mut buf = Vec::new();
stream.read_to_end(&mut buf).await?;
Ok((stream, buf))
}
#[tokio::test]
async fn test_0rtt() -> io::Result<()> {
test_0rtt_impl(|s| s, false).await
}
#[tokio::test]
async fn test_0rtt_vectored() -> io::Result<()> {
test_0rtt_impl(|s| s, true).await
}
#[tokio::test]
async fn test_0rtt_vectored_flush_pending() -> io::Result<()> {
test_0rtt_impl(utils::FlushWrapper::new, false).await
}
async fn test_0rtt_impl<S: AsyncRead + AsyncWrite + Unpin>(
wrapper: impl Fn(TcpStream) -> S,
vectored: bool,
) -> io::Result<()> {
let (mut server, mut client) = utils::make_configs();
server.max_early_data_size = 8192;
let server = Arc::new(server);
let listener = TcpListener::bind("127.0.0.1:0")?;
let server_port = listener.local_addr().unwrap().port();
thread::spawn(move || loop {
let (mut sock, _addr) = listener.accept().unwrap();
let server = Arc::clone(&server);
thread::spawn(move || {
let mut conn = ServerConnection::new(server).unwrap();
conn.complete_io(&mut sock).unwrap();
if let Some(mut early_data) = conn.early_data() {
let mut buf = Vec::new();
early_data.read_to_end(&mut buf).unwrap();
let mut stream = Stream::new(&mut conn, &mut sock);
stream.write_all(b"EARLY:").unwrap();
stream.write_all(&buf).unwrap();
}
let mut stream = Stream::new(&mut conn, &mut sock);
stream.write_all(b"LATE:").unwrap();
loop {
let mut buf = [0; 1024];
let n = stream.read(&mut buf).unwrap();
if n == 0 {
conn.send_close_notify();
conn.complete_io(&mut sock).unwrap();
break;
}
stream.write_all(&buf[..n]).unwrap();
}
});
});
client.enable_early_data = true;
let client = Arc::new(client);
let addr = SocketAddr::from(([127, 0, 0, 1], server_port));
let (io, buf) = send(client.clone(), addr, &wrapper, b"hello", vectored).await?;
assert!(!io.get_ref().1.is_early_data_accepted());
assert_eq!("LATE:hello", String::from_utf8_lossy(&buf));
let (io, buf) = send(client, addr, wrapper, b"world!", vectored).await?;
assert!(io.get_ref().1.is_early_data_accepted());
assert_eq!("EARLY:world!LATE:", String::from_utf8_lossy(&buf));
Ok(())
}
// Include `utils` module
include!("utils.rs");

327
vendor/tokio-rustls/tests/test.rs vendored Normal file
View File

@@ -0,0 +1,327 @@
use std::io::{Cursor, ErrorKind};
use std::net::SocketAddr;
use std::sync::mpsc::channel;
use std::sync::Arc;
use std::time::Duration;
use std::{io, thread};
use futures_util::future::TryFutureExt;
use lazy_static::lazy_static;
use rustls::pki_types::ServerName;
use rustls::ClientConfig;
use tokio::io::{copy, split, AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
use tokio::net::{TcpListener, TcpStream};
use tokio::sync::oneshot;
use tokio::{runtime, time};
use tokio_rustls::{LazyConfigAcceptor, TlsAcceptor, TlsConnector};
lazy_static! {
static ref TEST_SERVER: SocketAddr = {
let (config, _) = utils::make_configs();
let acceptor = TlsAcceptor::from(Arc::new(config));
let (send, recv) = channel();
thread::spawn(move || {
let runtime = runtime::Builder::new_current_thread()
.enable_io()
.build()
.unwrap();
let runtime = Arc::new(runtime);
let runtime2 = runtime.clone();
let done = async move {
let addr = SocketAddr::from(([127, 0, 0, 1], 0));
let listener = TcpListener::bind(&addr).await?;
send.send(listener.local_addr()?).unwrap();
loop {
let (stream, _) = listener.accept().await?;
let acceptor = acceptor.clone();
let fut = async move {
let stream = acceptor.accept(stream).await?;
let (mut reader, mut writer) = split(stream);
copy(&mut reader, &mut writer).await?;
Ok(()) as io::Result<()>
}
.unwrap_or_else(|err| eprintln!("server: {:?}", err));
runtime2.spawn(fut);
}
}
.unwrap_or_else(|err: io::Error| eprintln!("server: {:?}", err));
runtime.block_on(done);
});
recv.recv().unwrap()
};
}
async fn start_client<S: AsyncRead + AsyncWrite + Unpin>(
addr: SocketAddr,
domain: &str,
config: Arc<ClientConfig>,
wrapper: impl FnOnce(TcpStream) -> S,
use_buf_read: bool,
) -> io::Result<()> {
const FILE: &[u8] = include_bytes!("../README.md");
let domain = ServerName::try_from(domain).unwrap().to_owned();
let config = TlsConnector::from(config);
let mut buf = vec![0; FILE.len()];
let stream = wrapper(TcpStream::connect(&addr).await?);
let mut stream = config.connect(domain, stream).await?;
stream.write_all(FILE).await?;
stream.flush().await?;
if use_buf_read {
tokio::io::copy_buf(
&mut (&mut stream).take(FILE.len() as u64),
&mut Cursor::new(&mut buf),
)
.await?;
} else {
stream.read_exact(&mut buf).await?;
}
assert_eq!(buf, FILE);
Ok(())
}
async fn pass_impl<S: AsyncRead + AsyncWrite + Unpin>(
wrapper: impl FnOnce(TcpStream) -> S,
use_buf_read: bool,
) -> io::Result<()> {
// TODO: not sure how to resolve this right now but since
// TcpStream::bind now returns a future it creates a race
// condition until its ready sometimes.
use std::time::*;
tokio::time::sleep(Duration::from_secs(1)).await;
let (_, config) = utils::make_configs();
let config = Arc::new(config);
start_client(
*TEST_SERVER,
utils::TEST_SERVER_DOMAIN,
config,
wrapper,
use_buf_read,
)
.await?;
Ok(())
}
#[tokio::test]
async fn pass() -> io::Result<()> {
pass_impl(|stream| stream, false).await
}
#[tokio::test]
async fn pass_buf_read() -> io::Result<()> {
pass_impl(|stream| stream, true).await
}
#[tokio::test]
async fn fail() -> io::Result<()> {
let (_, config) = utils::make_configs();
let config = Arc::new(config);
assert_ne!(utils::TEST_SERVER_DOMAIN, "google.com");
let ret = start_client(*TEST_SERVER, "google.com", config, |stream| stream, false).await;
assert!(ret.is_err());
Ok(())
}
#[tokio::test]
async fn test_lazy_config_acceptor() -> io::Result<()> {
let (sconfig, cconfig) = utils::make_configs();
let (cstream, sstream) = tokio::io::duplex(1200);
let domain = ServerName::try_from("foobar.com").unwrap().to_owned();
tokio::spawn(async move {
let connector = crate::TlsConnector::from(Arc::new(cconfig));
let mut client = connector.connect(domain, cstream).await.unwrap();
client.write_all(b"hello, world!").await.unwrap();
let mut buf = Vec::new();
client.read_to_end(&mut buf).await.unwrap();
});
let acceptor = LazyConfigAcceptor::new(rustls::server::Acceptor::default(), sstream);
let start = acceptor.await.unwrap();
let ch = start.client_hello();
assert_eq!(ch.server_name(), Some("foobar.com"));
assert_eq!(
ch.alpn()
.map(|protos| protos.collect::<Vec<_>>())
.unwrap_or_default(),
Vec::<&[u8]>::new()
);
let mut stream = start.into_stream(Arc::new(sconfig)).await.unwrap();
let mut buf = [0; 13];
stream.read_exact(&mut buf).await.unwrap();
assert_eq!(&buf[..], b"hello, world!");
stream.write_all(b"bye").await.unwrap();
Ok(())
}
// This test is a follow-up from https://github.com/tokio-rs/tls/issues/85
#[tokio::test]
async fn lazy_config_acceptor_eof() {
let buf = Cursor::new(Vec::new());
let acceptor = LazyConfigAcceptor::new(rustls::server::Acceptor::default(), buf);
let accept_result = match time::timeout(Duration::from_secs(3), acceptor).await {
Ok(res) => res,
Err(_elapsed) => panic!("timeout"),
};
match accept_result {
Ok(_) => panic!("accepted a connection from zero bytes of data"),
Err(e) if e.kind() == ErrorKind::UnexpectedEof => {}
Err(e) => panic!("unexpected error: {:?}", e),
}
}
#[tokio::test]
async fn lazy_config_acceptor_take_io() -> Result<(), rustls::Error> {
let (mut cstream, sstream) = tokio::io::duplex(1200);
let (tx, rx) = oneshot::channel();
tokio::spawn(async move {
cstream.write_all(b"hello, world!").await.unwrap();
let mut buf = Vec::new();
cstream.read_to_end(&mut buf).await.unwrap();
tx.send(buf).unwrap();
});
let acceptor = LazyConfigAcceptor::new(rustls::server::Acceptor::default(), sstream);
futures_util::pin_mut!(acceptor);
if (acceptor.as_mut().await).is_ok() {
panic!("Expected Err(err)");
}
let server_msg = b"message from server";
let fatal_alert_decode_error = b"\x15\x03\x03\x00\x02\x02\x32";
let some_io = acceptor.take_io();
assert!(some_io.is_some(), "Expected Some(io)");
some_io.unwrap().write_all(server_msg).await.unwrap();
assert_eq!(
rx.await.unwrap(),
[&fatal_alert_decode_error[..], &server_msg[..]].concat()
);
assert!(
acceptor.take_io().is_none(),
"Should not be able to take twice"
);
Ok(())
}
#[tokio::test]
async fn acceptor_alert() {
let (sconfig, _) = utils::make_configs();
// this is the client hello from https://tls12.xargs.org/#client-hello/annotated with the minor
// version byte changed
let bad_hello = [
0x16, 0x03, 0x01, 0x00, 0xa5, 0x01, 0x00, 0x00, 0xa1, 0x03, 0x01, 0x00, 0x01, 0x02, 0x03,
0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x00, 0x00,
0x20, 0xcc, 0xa8, 0xcc, 0xa9, 0xc0, 0x2f, 0xc0, 0x30, 0xc0, 0x2b, 0xc0, 0x2c, 0xc0, 0x13,
0xc0, 0x09, 0xc0, 0x14, 0xc0, 0x0a, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x2f, 0x00, 0x35, 0xc0,
0x12, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x18, 0x00, 0x16, 0x00, 0x00,
0x13, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x75, 0x6c, 0x66, 0x68, 0x65, 0x69,
0x6d, 0x2e, 0x6e, 0x65, 0x74, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0a, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, 0x0b,
0x00, 0x02, 0x01, 0x00, 0x00, 0x0d, 0x00, 0x12, 0x00, 0x10, 0x04, 0x01, 0x04, 0x03, 0x05,
0x01, 0x05, 0x03, 0x06, 0x01, 0x06, 0x03, 0x02, 0x01, 0x02, 0x03, 0xff, 0x01, 0x00, 0x01,
0x00, 0x00, 0x12, 0x00, 0x00,
];
// Intentionally small so that we have to call alert.write several times
let (mut cstream, sstream) = tokio::io::duplex(2);
let (tx, rx) = oneshot::channel();
tokio::spawn(async move {
cstream.write_all(&bad_hello).await.unwrap();
let mut buf = Vec::new();
cstream.read_to_end(&mut buf).await.unwrap();
tx.send(buf).unwrap();
});
let accept = LazyConfigAcceptor::new(rustls::server::Acceptor::default(), sstream);
let Ok(Ok(start_handshake)) = time::timeout(Duration::from_secs(3), accept).await else {
panic!("timeout");
};
let err = start_handshake
.into_stream(Arc::new(sconfig))
.await
.unwrap_err();
assert_eq!(err.to_string(), "peer is incompatible: Tls12NotOffered");
let Ok(Ok(received)) = time::timeout(Duration::from_secs(3), rx).await else {
panic!("failed to receive");
};
assert_eq!(received, [0x15, 0x03, 0x03, 0x00, 0x02, 0x02, 0x46]);
}
#[tokio::test]
async fn lazy_config_acceptor_alert() {
// Intentionally small so that we have to call alert.write several times
let (mut cstream, sstream) = tokio::io::duplex(2);
let (tx, rx) = oneshot::channel();
tokio::spawn(async move {
// This is write instead of write_all because of the short duplex size, which is necessarily
// symmetrical. We never finish writing because the LazyConfigAcceptor returns an error
let _ = cstream.write(b"not tls").await;
let mut buf = Vec::new();
cstream.read_to_end(&mut buf).await.unwrap();
tx.send(buf).unwrap();
});
let acceptor = LazyConfigAcceptor::new(rustls::server::Acceptor::default(), sstream);
let Ok(accept_result) = time::timeout(Duration::from_secs(3), acceptor).await else {
panic!("timeout");
};
assert!(accept_result.is_err());
let Ok(Ok(received)) = time::timeout(Duration::from_secs(3), rx).await else {
panic!("failed to receive");
};
let fatal_alert_decode_error = b"\x15\x03\x03\x00\x02\x02\x32";
assert_eq!(received, fatal_alert_decode_error)
}
#[tokio::test]
async fn handshake_flush_pending() -> io::Result<()> {
pass_impl(utils::FlushWrapper::new, false).await
}
// Include `utils` module
include!("utils.rs");

154
vendor/tokio-rustls/tests/utils.rs vendored Normal file
View File

@@ -0,0 +1,154 @@
mod utils {
use std::collections::VecDeque;
use std::io::IoSlice;
use std::pin::Pin;
use std::task::{Context, Poll};
use rustls::{
pki_types::{pem::PemObject, CertificateDer, PrivateKeyDer},
ClientConfig, RootCertStore, ServerConfig,
};
use tokio::io::{self, AsyncRead, AsyncWrite, AsyncWriteExt};
#[allow(dead_code)]
pub(crate) fn make_configs() -> (ServerConfig, ClientConfig) {
// A test root certificate that is the trust anchor for the CHAIN.
const ROOT: &str = include_str!("certs/root.pem");
// A server certificate chain that includes both an end-entity server certificate
// and the intermediate certificate that issued it. The ROOT is configured
// out-of-band.
const CHAIN: &str = include_str!("certs/chain.pem");
// A private key corresponding to the end-entity server certificate in CHAIN.
const EE_KEY: &str = include_str!("certs/end.key");
let cert = CertificateDer::pem_slice_iter(CHAIN.as_bytes())
.collect::<Result<Vec<_>, _>>()
.unwrap();
let key = PrivateKeyDer::from_pem_slice(EE_KEY.as_bytes()).unwrap();
let sconfig = ServerConfig::builder()
.with_no_client_auth()
.with_single_cert(cert, key)
.unwrap();
let mut client_root_cert_store = RootCertStore::empty();
for root in CertificateDer::pem_slice_iter(ROOT.as_bytes()) {
client_root_cert_store.add(root.unwrap()).unwrap();
}
let cconfig = ClientConfig::builder()
.with_root_certificates(client_root_cert_store)
.with_no_client_auth();
(sconfig, cconfig)
}
#[allow(dead_code)]
pub(crate) async fn write<W: AsyncWrite + Unpin>(
w: &mut W,
data: &[u8],
vectored: bool,
) -> io::Result<()> {
if !vectored {
return w.write_all(data).await;
}
let mut data = data;
while !data.is_empty() {
let chunk_size = (data.len() / 4).max(1);
let vectors = data
.chunks(chunk_size)
.map(IoSlice::new)
.collect::<Vec<_>>();
let written = w.write_vectored(&vectors).await?;
data = &data[written..];
}
Ok(())
}
#[allow(dead_code)]
pub(crate) const TEST_SERVER_DOMAIN: &str = "foobar.com";
/// An IO wrapper that never flushes when writing, and always returns pending on first flush.
///
/// This is used to test that rustls always flushes to completion during handshake.
pub(crate) struct FlushWrapper<S> {
stream: S,
buf: VecDeque<Vec<u8>>,
queued: Vec<u8>,
}
impl<S> FlushWrapper<S> {
#[allow(dead_code)]
pub(crate) fn new(stream: S) -> Self {
Self {
stream,
buf: VecDeque::new(),
queued: Vec::new(),
}
}
}
impl<S: AsyncRead + Unpin> AsyncRead for FlushWrapper<S> {
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut tokio::io::ReadBuf<'_>,
) -> Poll<io::Result<()>> {
Pin::new(&mut self.get_mut().stream).poll_read(cx, buf)
}
}
impl<S: AsyncWrite + Unpin> FlushWrapper<S> {
fn poll_flush_inner<F>(
&mut self,
cx: &mut Context<'_>,
flush_inner: F,
) -> Poll<Result<(), io::Error>>
where
F: FnOnce(Pin<&mut S>, &mut Context<'_>) -> Poll<Result<(), io::Error>>,
{
loop {
let stream = Pin::new(&mut self.stream);
if !self.queued.is_empty() {
// write out the queued data
let n = std::task::ready!(stream.poll_write(cx, &self.queued))?;
self.queued = self.queued[n..].to_vec();
} else if let Some(buf) = self.buf.pop_front() {
// queue the flush, but don't trigger the write immediately.
self.queued = buf;
cx.waker().wake_by_ref();
return Poll::Pending;
} else {
// nothing more to flush to the inner stream, flush the inner stream instead.
return flush_inner(stream, cx);
}
}
}
}
impl<S: AsyncWrite + Unpin> AsyncWrite for FlushWrapper<S> {
fn poll_write(
self: Pin<&mut Self>,
_: &mut Context<'_>,
buf: &[u8],
) -> Poll<Result<usize, io::Error>> {
self.get_mut().buf.push_back(buf.to_vec());
Poll::Ready(Ok(buf.len()))
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
self.get_mut()
.poll_flush_inner(cx, |s, cx| s.poll_flush(cx))
}
fn poll_shutdown(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Result<(), io::Error>> {
self.get_mut()
.poll_flush_inner(cx, |s, cx| s.poll_shutdown(cx))
}
}
}