AWS SDK

AWS SDK

rev. 9e1d64f49d144bf9ef92d93ae2361b7075c24670 (ignoring whitespace)

Files changed:

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-http-client/tests/tls.rs

@@ -1,1 +541,764 @@
    1      1   
/*
    2      2   
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
    3      3   
 * SPDX-License-Identifier: Apache-2.0
    4      4   
 */
    5      5   
    6      6   
#![cfg(any(feature = "__rustls", feature = "s2n-tls",))]
    7      7   
    8      8   
mod common {
           9  +
    #[allow(dead_code)]
          10  +
    pub(crate) mod client;
    9     11   
    pub(crate) mod tls;
   10     12   
}
   11     13   
   12     14   
use aws_smithy_async::time::SystemTimeSource;
   13     15   
#[cfg(all(feature = "rustls-aws-lc", feature = "rt-tokio"))]
   14     16   
use aws_smithy_http_client::pool::{Client as PoolClient, ConnectionPool};
   15     17   
use aws_smithy_http_client::tls;
   16     18   
#[cfg(any(feature = "rustls-aws-lc", feature = "s2n-tls"))]
   17     19   
use aws_smithy_http_client::tls::{ServerName, TlsContext};
   18     20   
use aws_smithy_runtime_api::box_error::BoxError;
   19     21   
use aws_smithy_runtime_api::client::http::{HttpClient, HttpConnector, HttpConnectorSettings};
   20     22   
use aws_smithy_runtime_api::client::orchestrator::HttpRequest;
   21     23   
use aws_smithy_runtime_api::client::runtime_components::RuntimeComponentsBuilder;
   22     24   
use aws_smithy_types::byte_stream::ByteStream;
          25  +
#[cfg(feature = "rt-tokio")]
          26  +
use common::client::PartitionedConnectionPool;
          27  +
use common::client::{BackendConfig, HttpsClientBackend, HyperUtilLegacyPool};
   23     28   
use common::tls as test_tls;
   24     29   
use http_1x::{Method, Request, Response, StatusCode};
   25     30   
use http_body_util::{BodyExt, Full};
   26     31   
use hyper::body::{Bytes, Incoming};
   27     32   
use hyper::service::service_fn;
   28     33   
use hyper_util::rt::{TokioExecutor, TokioIo};
   29     34   
use hyper_util::server::conn::auto::Builder;
   30     35   
use std::net::SocketAddr;
   31     36   
use std::sync::Arc;
   32     37   
use std::time::Duration;
   33     38   
use tokio::net::TcpListener;
   34     39   
use tokio::task::JoinHandle;
   35     40   
use tracing::{debug, error};
   36     41   
   37         -
struct TestServer {
   38         -
    _handle: JoinHandle<()>,
   39         -
    listen_addr: SocketAddr,
   40         -
    conn_count: Arc<()>,
          42  +
/// HTTPS echo server with configurable ALPN and observable connection lifetime.
          43  +
struct TlsEchoServer {
          44  +
    task: JoinHandle<()>,
          45  +
    addr: SocketAddr,
          46  +
    active_connections: Arc<()>,
   41     47   
}
   42     48   
   43         -
impl TestServer {
   44         -
    /// Return the number of active connections to this server
   45         -
    fn conn_count(&self) -> usize {
   46         -
        // 1 reference for the struct MockProxyServer, 1 reference for the
   47         -
        // socket task.
   48         -
        Arc::strong_count(&self.conn_count)
   49         -
            .checked_sub(2)
   50         -
            .expect("de-count 2 refs")
          49  +
impl TlsEchoServer {
          50  +
    /// Starts a server advertising HTTP/2 and HTTP/1 protocols.
          51  +
    async fn start() -> Result<Self, BoxError> {
          52  +
        Self::start_with_alpn(&[b"h2", b"http/1.1", b"http/1.0"]).await
   51     53   
    }
   52         -
}
   53         -
   54         -
async fn server() -> Result<TestServer, BoxError> {
   55         -
    server_with_alpn(&[b"h2", b"http/1.1", b"http/1.0"]).await
   56         -
}
   57         -
   58         -
async fn server_with_alpn(alpn_protocols: &[&[u8]]) -> Result<TestServer, BoxError> {
   59         -
    let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
   60         -
    let addr = listener.local_addr().unwrap();
   61     54   
          55  +
    /// Starts a server advertising the given ALPN protocols in order.
          56  +
    async fn start_with_alpn(alpn_protocols: &[&[u8]]) -> Result<Self, BoxError> {
          57  +
        let listener = TcpListener::bind("127.0.0.1:0").await?;
          58  +
        let addr = listener.local_addr()?;
   62     59   
        debug!("Starting to serve on https://{}", addr);
   63     60   
   64         -
    let tls_acceptor = test_tls::server_tls_acceptor(alpn_protocols)?;
          61  +
        let tls_acceptor = test_tls::SERVER_IDENTITY.acceptor(alpn_protocols)?;
   65     62   
        let service = service_fn(echo);
          63  +
        let active_connections = Arc::new(());
          64  +
        let listener_connections = active_connections.clone();
   66     65   
   67         -
    let conn_count = Arc::new(());
   68         -
    let server_conn_count = conn_count.clone();
   69         -
   70         -
    let server = async move {
          66  +
        let task = tokio::spawn(async move {
   71     67   
            loop {
   72     68   
                let (tcp_stream, remote_addr) = listener.accept().await.unwrap();
   73     69   
                debug!("accepted connection from: {}", remote_addr);
   74     70   
   75     71   
                let tls_acceptor = tls_acceptor.clone();
   76         -
            let connection_conn_count = server_conn_count.clone();
          72  +
                let connection = listener_connections.clone();
   77     73   
                tokio::spawn(async move {
   78         -
                let _connection_conn_count = connection_conn_count;
          74  +
                    let _connection = connection;
   79     75   
                    let tls_stream = match tls_acceptor.accept(tcp_stream).await {
   80     76   
                        Ok(tls_stream) => tls_stream,
   81     77   
                        Err(err) => {
   82     78   
                            error!("failed to perform tls handshake: {err:#}");
   83     79   
                            return;
   84     80   
                        }
   85     81   
                    };
   86     82   
                    if let Err(err) = Builder::new(TokioExecutor::new())
   87     83   
                        .serve_connection(TokioIo::new(tls_stream), service)
   88     84   
                        .await
   89     85   
                    {
   90     86   
                        error!("failed to serve connection: {err:#}");
   91     87   
                    }
   92     88   
                });
   93     89   
            }
   94         -
    };
   95         -
   96         -
    let server_task = tokio::spawn(server);
          90  +
        });
   97     91   
   98         -
    Ok(TestServer {
   99         -
        _handle: server_task,
  100         -
        listen_addr: addr,
  101         -
        conn_count,
          92  +
        Ok(Self {
          93  +
            task,
          94  +
            addr,
          95  +
            active_connections,
  102     96   
        })
          97  +
    }
          98  +
          99  +
    fn addr(&self) -> SocketAddr {
         100  +
        self.addr
         101  +
    }
         102  +
         103  +
    /// Returns the number of accepted connections that remain open.
         104  +
    fn active_connection_count(&self) -> usize {
         105  +
        // The server value and listener task each hold one baseline reference.
         106  +
        Arc::strong_count(&self.active_connections)
         107  +
            .checked_sub(2)
         108  +
            .expect("active connection reference count includes both owners")
         109  +
    }
         110  +
}
         111  +
         112  +
impl Drop for TlsEchoServer {
         113  +
    fn drop(&mut self) {
         114  +
        self.task.abort();
         115  +
    }
  103    116   
}
  104    117   
  105         -
// Custom echo service, handling two different routes and a
  106         -
// catch-all 404 responder.
         118  +
/// Handles the request paths exercised by the TLS contracts.
  107    119   
async fn echo(req: Request<Incoming>) -> Result<Response<Full<Bytes>>, hyper::Error> {
  108    120   
    let mut response = Response::new(Full::default());
  109    121   
    match (req.method(), req.uri().path()) {
  110    122   
        // default route.
  111    123   
        (&Method::GET, "/") => {
  112    124   
            *response.body_mut() = Full::from("Hello TLS!");
  113    125   
        }
  114    126   
        // echo service route.
  115    127   
        (&Method::POST, "/echo") => {
  116    128   
            *response.body_mut() = Full::from(req.into_body().collect().await?.to_bytes());
  117    129   
        }
  118    130   
        // Catch-all 404.
  119    131   
        _ => {
  120    132   
            *response.status_mut() = StatusCode::NOT_FOUND;
  121    133   
        }
  122    134   
    };
  123    135   
    Ok(response)
  124    136   
}
  125    137   
         138  +
async fn native_ca_rejects_test_certificate(
         139  +
    backend: &dyn HttpsClientBackend,
         140  +
    provider: tls::Provider,
         141  +
    expected_error: &str,
         142  +
) {
         143  +
    let client = backend.build_https(
         144  +
        BackendConfig::default(),
         145  +
        provider,
         146  +
        tls::TlsContext::default(),
         147  +
    );
         148  +
    let error = run_tls_test(&client)
         149  +
        .await
         150  +
        .expect_err("the native trust store must reject the test certificate");
         151  +
    let error = format!("{error:?}");
         152  +
    assert!(
         153  +
        error.contains(expected_error),
         154  +
        "expected TLS error containing {expected_error:?}, got {error}"
         155  +
    );
         156  +
}
         157  +
         158  +
async fn custom_ca_accepts_test_certificate(
         159  +
    backend: &dyn HttpsClientBackend,
         160  +
    provider: tls::Provider,
         161  +
) {
         162  +
    let client = backend.build_https(
         163  +
        BackendConfig::default(),
         164  +
        provider,
         165  +
        test_tls::SERVER_IDENTITY.client_context(),
         166  +
    );
         167  +
    run_tls_test(&client).await.unwrap();
         168  +
}
         169  +
         170  +
#[cfg(feature = "rustls-aws-lc")]
         171  +
fn rustls_aws_lc() -> tls::Provider {
         172  +
    tls::Provider::Rustls(tls::rustls_provider::CryptoMode::AwsLc)
         173  +
}
         174  +
  126    175   
#[cfg(feature = "rustls-aws-lc")]
  127         -
#[should_panic(expected = "InvalidCertificate(UnknownIssuer)")]
  128    176   
#[tokio::test]
  129         -
async fn test_rustls_aws_lc_native_ca() {
  130         -
    let client = aws_smithy_http_client::Builder::new()
  131         -
        .tls_provider(tls::Provider::Rustls(
  132         -
            tls::rustls_provider::CryptoMode::AwsLc,
  133         -
        ))
  134         -
        .build_https();
         177  +
async fn test_rustls_aws_lc_native_ca_with_hyper_util_legacy_pool() {
         178  +
    native_ca_rejects_test_certificate(
         179  +
        &HyperUtilLegacyPool,
         180  +
        rustls_aws_lc(),
         181  +
        "InvalidCertificate(UnknownIssuer)",
         182  +
    )
         183  +
    .await;
         184  +
}
  135    185   
  136         -
    run_tls_test(&client).await.unwrap()
         186  +
#[cfg(feature = "rustls-aws-lc")]
         187  +
#[cfg(feature = "rt-tokio")]
         188  +
#[tokio::test]
         189  +
async fn test_rustls_aws_lc_native_ca_with_partitioned_connection_pool() {
         190  +
    native_ca_rejects_test_certificate(
         191  +
        &PartitionedConnectionPool,
         192  +
        rustls_aws_lc(),
         193  +
        "InvalidCertificate(UnknownIssuer)",
         194  +
    )
         195  +
    .await;
  137    196   
}
  138    197   
  139    198   
#[cfg(feature = "rustls-aws-lc")]
  140    199   
#[tokio::test]
  141         -
async fn test_rustls_aws_lc_custom_ca() {
  142         -
    let client = aws_smithy_http_client::Builder::new()
  143         -
        .tls_provider(tls::Provider::Rustls(
  144         -
            tls::rustls_provider::CryptoMode::AwsLc,
  145         -
        ))
  146         -
        .tls_context(test_tls::server_tls_context())
  147         -
        .build_https();
         200  +
async fn test_rustls_aws_lc_custom_ca_with_hyper_util_legacy_pool() {
         201  +
    custom_ca_accepts_test_certificate(&HyperUtilLegacyPool, rustls_aws_lc()).await;
         202  +
}
  148    203   
  149         -
    run_tls_test(&client).await.unwrap()
         204  +
#[cfg(feature = "rustls-aws-lc")]
         205  +
#[cfg(feature = "rt-tokio")]
         206  +
#[tokio::test]
         207  +
async fn test_rustls_aws_lc_custom_ca_with_partitioned_connection_pool() {
         208  +
    custom_ca_accepts_test_certificate(&PartitionedConnectionPool, rustls_aws_lc()).await;
  150    209   
}
  151    210   
  152    211   
#[cfg(all(feature = "rustls-aws-lc", feature = "rt-tokio"))]
  153    212   
#[tokio::test]
  154    213   
async fn partitioned_pool_falls_back_to_h1_after_alpn() {
  155         -
    let server = server_with_alpn(&[b"http/1.1"]).await.unwrap();
         214  +
    let server = TlsEchoServer::start_with_alpn(&[b"http/1.1"])
         215  +
        .await
         216  +
        .unwrap();
  156    217   
    let pool = ConnectionPool::builder()
  157    218   
        .tls_provider(tls::Provider::Rustls(
  158    219   
            tls::rustls_provider::CryptoMode::AwsLc,
  159    220   
        ))
  160         -
        .tls_context(test_tls::server_tls_context())
         221  +
        .tls_context(test_tls::SERVER_IDENTITY.client_context())
  161    222   
        .build_https()
  162    223   
        .expect("valid HTTPS pool");
  163    224   
    let client = PoolClient::new(&pool).expect("anonymous partition exists");
  164    225   
    let connector_settings = HttpConnectorSettings::builder().build();
  165    226   
    let runtime_components = RuntimeComponentsBuilder::for_tests()
  166    227   
        .with_time_source(Some(SystemTimeSource::new()))
  167    228   
        .build()
  168    229   
        .unwrap();
  169    230   
    let connector = client.http_connector(&connector_settings, &runtime_components);
  170         -
    let endpoint = format!("https://localhost:{}/", server.listen_addr.port());
         231  +
    let endpoint = format!("https://localhost:{}/", server.addr().port());
  171    232   
  172    233   
    for _ in 0..2 {
  173    234   
        let mut response = connector
  174    235   
            .call(HttpRequest::get(&endpoint).unwrap())
  175    236   
            .await
  176    237   
            .expect("HTTP/1 request over TLS should succeed");
  177    238   
        let body = ByteStream::new(response.take_body())
  178    239   
            .collect()
  179    240   
            .await
  180    241   
            .expect("response body should be readable")
  181    242   
            .into_bytes();
  182    243   
        assert_eq!(b"Hello TLS!", &body[..]);
  183    244   
    }
  184         -
    assert_eq!(1, server.conn_count());
         245  +
    assert_eq!(1, server.active_connection_count());
  185    246   
}
  186    247   
  187    248   
#[cfg(all(feature = "rustls-aws-lc", feature = "rt-tokio"))]
  188    249   
#[tokio::test]
  189    250   
async fn partitioned_pool_narrows_alpn_for_h1_required_request() {
  190         -
    let server = server_with_alpn(&[b"h2", b"http/1.1"]).await.unwrap();
         251  +
    let server = TlsEchoServer::start_with_alpn(&[b"h2", b"http/1.1"])
         252  +
        .await
         253  +
        .unwrap();
  191    254   
    let pool = ConnectionPool::builder()
  192    255   
        .tls_provider(tls::Provider::Rustls(
  193    256   
            tls::rustls_provider::CryptoMode::AwsLc,
  194    257   
        ))
  195         -
        .tls_context(test_tls::server_tls_context())
         258  +
        .tls_context(test_tls::SERVER_IDENTITY.client_context())
  196    259   
        .build_https()
  197    260   
        .expect("valid HTTPS pool");
  198    261   
    let client = PoolClient::new(&pool).expect("anonymous partition exists");
  199    262   
    let connector_settings = HttpConnectorSettings::builder().build();
  200    263   
    let runtime_components = RuntimeComponentsBuilder::for_tests()
  201    264   
        .with_time_source(Some(SystemTimeSource::new()))
  202    265   
        .build()
  203    266   
        .unwrap();
  204    267   
    let connector = client.http_connector(&connector_settings, &runtime_components);
  205         -
    let endpoint = format!("https://localhost:{}/", server.listen_addr.port());
         268  +
    let endpoint = format!("https://localhost:{}/", server.addr().port());
  206    269   
    let mut request = HttpRequest::new(ByteStream::default().into_inner());
  207    270   
    request
  208    271   
        .set_method("CONNECT")
  209    272   
        .expect("CONNECT is a valid HTTP method");
  210    273   
    request
  211    274   
        .set_uri(endpoint.as_str())
  212    275   
        .expect("valid server URI");
  213    276   
  214    277   
    let response = connector
  215    278   
        .call(request)
  216    279   
        .await
  217    280   
        .expect("HTTP/1-required request should narrow the ALPN offer");
  218    281   
  219    282   
    assert_eq!(StatusCode::NOT_FOUND.as_u16(), response.status().as_u16());
  220         -
    assert_eq!(1, server.conn_count());
         283  +
    assert_eq!(1, server.active_connection_count());
  221    284   
}
  222    285   
  223    286   
#[cfg(feature = "rustls-aws-lc")]
  224         -
#[tokio::test(start_paused = false)]
  225         -
// can't have paused clock due to <https://github.com/hyperium/hyper/issues/3950>
  226         -
async fn test_rustls_aws_lc_custom_ca_with_timeout() {
         287  +
async fn custom_ca_connection_obeys_idle_timeout(backend: &dyn HttpsClientBackend) {
  227    288   
    const TIMEOUT: Duration = Duration::from_secs(10);
  228         -
    let client = aws_smithy_http_client::Builder::new()
  229         -
        .pool_idle_timeout(TIMEOUT)
  230         -
        .tls_provider(tls::Provider::Rustls(
  231         -
            tls::rustls_provider::CryptoMode::AwsLc,
  232         -
        ))
  233         -
        .tls_context(test_tls::server_tls_context())
  234         -
        .build_https();
  235         -
         289  +
    let client = backend.build_https(
         290  +
        BackendConfig {
         291  +
            pool_idle_timeout: Some(TIMEOUT),
         292  +
            ..Default::default()
         293  +
        },
         294  +
        rustls_aws_lc(),
         295  +
        test_tls::SERVER_IDENTITY.client_context(),
         296  +
    );
  236    297   
    run_tls_test_with_idle_timeout(&client, Some(TIMEOUT))
  237    298   
        .await
  238         -
        .unwrap()
         299  +
        .unwrap();
         300  +
}
         301  +
         302  +
#[cfg(feature = "rustls-aws-lc")]
         303  +
#[tokio::test(start_paused = false)]
         304  +
// can't have paused clock due to <https://github.com/hyperium/hyper/issues/3950>
         305  +
async fn test_rustls_aws_lc_custom_ca_idle_timeout_with_hyper_util_legacy_pool() {
         306  +
    custom_ca_connection_obeys_idle_timeout(&HyperUtilLegacyPool).await;
         307  +
}
         308  +
         309  +
#[cfg(feature = "rustls-aws-lc")]
         310  +
#[cfg(feature = "rt-tokio")]
         311  +
#[tokio::test(start_paused = false)]
         312  +
// can't have paused clock due to <https://github.com/hyperium/hyper/issues/3950>
         313  +
async fn test_rustls_aws_lc_custom_ca_idle_timeout_with_partitioned_connection_pool() {
         314  +
    custom_ca_connection_obeys_idle_timeout(&PartitionedConnectionPool).await;
         315  +
}
         316  +
         317  +
#[cfg(feature = "rustls-aws-lc-fips")]
         318  +
fn rustls_aws_lc_fips() -> tls::Provider {
         319  +
    tls::Provider::Rustls(tls::rustls_provider::CryptoMode::AwsLcFips)
  239    320   
}
  240    321   
  241    322   
#[cfg(feature = "rustls-aws-lc-fips")]
  242         -
#[should_panic(expected = "InvalidCertificate(UnknownIssuer)")]
  243    323   
#[tokio::test]
  244         -
async fn test_rustls_aws_lc_fips_native_ca() {
  245         -
    let client = aws_smithy_http_client::Builder::new()
  246         -
        .tls_provider(tls::Provider::Rustls(
  247         -
            tls::rustls_provider::CryptoMode::AwsLcFips,
  248         -
        ))
  249         -
        .build_https();
         324  +
async fn test_rustls_aws_lc_fips_native_ca_with_hyper_util_legacy_pool() {
         325  +
    native_ca_rejects_test_certificate(
         326  +
        &HyperUtilLegacyPool,
         327  +
        rustls_aws_lc_fips(),
         328  +
        "InvalidCertificate(UnknownIssuer)",
         329  +
    )
         330  +
    .await;
         331  +
}
  250    332   
  251         -
    run_tls_test(&client).await.unwrap()
         333  +
#[cfg(feature = "rustls-aws-lc-fips")]
         334  +
#[cfg(feature = "rt-tokio")]
         335  +
#[tokio::test]
         336  +
async fn test_rustls_aws_lc_fips_native_ca_with_partitioned_connection_pool() {
         337  +
    native_ca_rejects_test_certificate(
         338  +
        &PartitionedConnectionPool,
         339  +
        rustls_aws_lc_fips(),
         340  +
        "InvalidCertificate(UnknownIssuer)",
         341  +
    )
         342  +
    .await;
  252    343   
}
  253    344   
  254    345   
#[cfg(feature = "rustls-aws-lc-fips")]
  255    346   
#[tokio::test]
  256         -
async fn test_rustls_aws_lc_fips_custom_ca() {
  257         -
    let client = aws_smithy_http_client::Builder::new()
  258         -
        .tls_provider(tls::Provider::Rustls(
  259         -
            tls::rustls_provider::CryptoMode::AwsLcFips,
  260         -
        ))
  261         -
        .tls_context(test_tls::server_tls_context())
  262         -
        .build_https();
         347  +
async fn test_rustls_aws_lc_fips_custom_ca_with_hyper_util_legacy_pool() {
         348  +
    custom_ca_accepts_test_certificate(&HyperUtilLegacyPool, rustls_aws_lc_fips()).await;
         349  +
}
  263    350   
  264         -
    run_tls_test(&client).await.unwrap()
         351  +
#[cfg(feature = "rustls-aws-lc-fips")]
         352  +
#[cfg(feature = "rt-tokio")]
         353  +
#[tokio::test]
         354  +
async fn test_rustls_aws_lc_fips_custom_ca_with_partitioned_connection_pool() {
         355  +
    custom_ca_accepts_test_certificate(&PartitionedConnectionPool, rustls_aws_lc_fips()).await;
         356  +
}
         357  +
         358  +
#[cfg(feature = "rustls-ring")]
         359  +
fn rustls_ring() -> tls::Provider {
         360  +
    tls::Provider::Rustls(tls::rustls_provider::CryptoMode::Ring)
  265    361   
}
  266    362   
  267    363   
#[cfg(feature = "rustls-ring")]
  268         -
#[should_panic(expected = "InvalidCertificate(UnknownIssuer)")]
  269    364   
#[tokio::test]
  270         -
async fn test_rustls_ring_native_ca() {
  271         -
    let client = aws_smithy_http_client::Builder::new()
  272         -
        .tls_provider(tls::Provider::Rustls(
  273         -
            tls::rustls_provider::CryptoMode::Ring,
  274         -
        ))
  275         -
        .build_https();
         365  +
async fn test_rustls_ring_native_ca_with_hyper_util_legacy_pool() {
         366  +
    native_ca_rejects_test_certificate(
         367  +
        &HyperUtilLegacyPool,
         368  +
        rustls_ring(),
         369  +
        "InvalidCertificate(UnknownIssuer)",
         370  +
    )
         371  +
    .await;
         372  +
}
  276    373   
  277         -
    run_tls_test(&client).await.unwrap()
         374  +
#[cfg(feature = "rustls-ring")]
         375  +
#[cfg(feature = "rt-tokio")]
         376  +
#[tokio::test]
         377  +
async fn test_rustls_ring_native_ca_with_partitioned_connection_pool() {
         378  +
    native_ca_rejects_test_certificate(
         379  +
        &PartitionedConnectionPool,
         380  +
        rustls_ring(),
         381  +
        "InvalidCertificate(UnknownIssuer)",
         382  +
    )
         383  +
    .await;
  278    384   
}
  279    385   
  280    386   
#[cfg(feature = "rustls-ring")]
  281    387   
#[tokio::test]
  282         -
async fn test_rustls_ring_custom_ca() {
  283         -
    let client = aws_smithy_http_client::Builder::new()
  284         -
        .tls_provider(tls::Provider::Rustls(
  285         -
            tls::rustls_provider::CryptoMode::Ring,
  286         -
        ))
  287         -
        .tls_context(test_tls::server_tls_context())
  288         -
        .build_https();
         388  +
async fn test_rustls_ring_custom_ca_with_hyper_util_legacy_pool() {
         389  +
    custom_ca_accepts_test_certificate(&HyperUtilLegacyPool, rustls_ring()).await;
         390  +
}
  289    391   
  290         -
    run_tls_test(&client).await.unwrap()
         392  +
#[cfg(feature = "rustls-ring")]
         393  +
#[cfg(feature = "rt-tokio")]
         394  +
#[tokio::test]
         395  +
async fn test_rustls_ring_custom_ca_with_partitioned_connection_pool() {
         396  +
    custom_ca_accepts_test_certificate(&PartitionedConnectionPool, rustls_ring()).await;
  291    397   
}
  292    398   
  293    399   
#[cfg(all(aws_sdk_unstable, feature = "rustls-ring"))]
  294         -
#[should_panic(expected = "InvalidCertificate(UnknownIssuer)")]
  295         -
#[tokio::test]
  296         -
async fn test_rustls_custom_provider_native_ca() {
  297         -
    let provider = rustls::crypto::ring::default_provider();
  298         -
    let client = aws_smithy_http_client::Builder::new()
  299         -
        .tls_provider(tls::Provider::Rustls(
  300         -
            tls::rustls_provider::CryptoMode::Custom(provider),
         400  +
fn rustls_custom_provider() -> tls::Provider {
         401  +
    tls::Provider::Rustls(tls::rustls_provider::CryptoMode::Custom(
         402  +
        rustls::crypto::ring::default_provider(),
  301    403   
    ))
  302         -
        .build_https();
  303         -
  304         -
    run_tls_test(&client).await.unwrap()
  305    404   
}
  306    405   
  307    406   
#[cfg(all(aws_sdk_unstable, feature = "rustls-ring"))]
  308    407   
#[tokio::test]
  309         -
async fn test_rustls_custom_provider_custom_ca() {
  310         -
    let ring_provider = rustls::crypto::ring::default_provider();
  311         -
    let client = aws_smithy_http_client::Builder::new()
  312         -
        .tls_provider(tls::Provider::Rustls(
  313         -
            tls::rustls_provider::CryptoMode::Custom(ring_provider),
  314         -
        ))
  315         -
        .tls_context(test_tls::server_tls_context())
  316         -
        .build_https();
  317         -
    run_tls_test(&client).await.unwrap()
         408  +
async fn test_rustls_custom_provider_native_ca_with_hyper_util_legacy_pool() {
         409  +
    native_ca_rejects_test_certificate(
         410  +
        &HyperUtilLegacyPool,
         411  +
        rustls_custom_provider(),
         412  +
        "InvalidCertificate(UnknownIssuer)",
         413  +
    )
         414  +
    .await;
  318    415   
}
  319    416   
  320         -
#[cfg(feature = "s2n-tls")]
  321         -
#[should_panic(expected = "Certificate is untrusted")]
         417  +
#[cfg(all(aws_sdk_unstable, feature = "rustls-ring"))]
         418  +
#[cfg(feature = "rt-tokio")]
  322    419   
#[tokio::test]
  323         -
async fn test_s2n_native_ca() {
  324         -
    let client = aws_smithy_http_client::Builder::new()
  325         -
        .tls_provider(tls::Provider::S2nTls)
  326         -
        .build_https();
  327         -
  328         -
    run_tls_test(&client).await.unwrap()
         420  +
async fn test_rustls_custom_provider_native_ca_with_partitioned_connection_pool() {
         421  +
    native_ca_rejects_test_certificate(
         422  +
        &PartitionedConnectionPool,
         423  +
        rustls_custom_provider(),
         424  +
        "InvalidCertificate(UnknownIssuer)",
         425  +
    )
         426  +
    .await;
  329    427   
}
  330    428   
  331         -
#[cfg(feature = "s2n-tls")]
         429  +
#[cfg(all(aws_sdk_unstable, feature = "rustls-ring"))]
  332    430   
#[tokio::test]
  333         -
async fn test_s2n_tls_custom_ca() {
  334         -
    let client = aws_smithy_http_client::Builder::new()
  335         -
        .tls_provider(tls::Provider::S2nTls)
  336         -
        .tls_context(test_tls::server_tls_context())
  337         -
        .build_https();
  338         -
    run_tls_test(&client).await.unwrap()
         431  +
async fn test_rustls_custom_provider_custom_ca_with_hyper_util_legacy_pool() {
         432  +
    custom_ca_accepts_test_certificate(&HyperUtilLegacyPool, rustls_custom_provider()).await;
  339    433   
}
  340    434   
  341         -
// Test: connecting to 127.0.0.1 fails (cert SANs only contain "localhost" and "sdktest.com")
  342         -
#[cfg(feature = "rustls-aws-lc")]
  343         -
#[should_panic(expected = "InvalidCertificate")]
         435  +
#[cfg(all(aws_sdk_unstable, feature = "rustls-ring"))]
         436  +
#[cfg(feature = "rt-tokio")]
  344    437   
#[tokio::test]
  345         -
async fn test_additional_server_names_ip_without_alt_names_fails() {
  346         -
    let client = aws_smithy_http_client::Builder::new()
  347         -
        .tls_provider(tls::Provider::Rustls(
  348         -
            tls::rustls_provider::CryptoMode::AwsLc,
  349         -
        ))
  350         -
        .tls_context(test_tls::server_tls_context())
  351         -
        .build_https();
  352         -
  353         -
    run_tls_test_to_ip(&client).await.unwrap()
         438  +
async fn test_rustls_custom_provider_custom_ca_with_partitioned_connection_pool() {
         439  +
    custom_ca_accepts_test_certificate(&PartitionedConnectionPool, rustls_custom_provider()).await;
  354    440   
}
  355    441   
  356         -
// Test: connecting to 127.0.0.1 with a non-matching additional server name fails (cert SANs only contain "localhost" and "sdktest.com")
  357         -
#[cfg(feature = "rustls-aws-lc")]
  358         -
#[should_panic(expected = "InvalidCertificate")]
         442  +
#[cfg(feature = "s2n-tls")]
  359    443   
#[tokio::test]
  360         -
async fn test_additional_server_names_with_wrong_alt_name_fails() {
  361         -
    let client = aws_smithy_http_client::Builder::new()
  362         -
        .tls_provider(tls::Provider::Rustls(
  363         -
            tls::rustls_provider::CryptoMode::AwsLc,
  364         -
        ))
  365         -
        .tls_context(server_tls_context_with_additional_server_names(&[
  366         -
            "wrong.example.com",
  367         -
        ]))
  368         -
        .build_https();
  369         -
  370         -
    run_tls_test_to_ip(&client).await.unwrap()
         444  +
async fn test_s2n_native_ca_with_hyper_util_legacy_pool() {
         445  +
    native_ca_rejects_test_certificate(
         446  +
        &HyperUtilLegacyPool,
         447  +
        tls::Provider::S2nTls,
         448  +
        "Certificate is untrusted",
         449  +
    )
         450  +
    .await;
  371    451   
}
  372    452   
  373         -
// Test: connecting to 127.0.0.1 succeeds when "localhost" is configured as an additional server name
  374         -
#[cfg(feature = "rustls-aws-lc")]
         453  +
#[cfg(feature = "s2n-tls")]
         454  +
#[cfg(feature = "rt-tokio")]
  375    455   
#[tokio::test]
  376         -
async fn test_additional_server_names_with_matching_alt_name_succeeds() {
  377         -
    let client = aws_smithy_http_client::Builder::new()
  378         -
        .tls_provider(tls::Provider::Rustls(
  379         -
            tls::rustls_provider::CryptoMode::AwsLc,
  380         -
        ))
  381         -
        .tls_context(server_tls_context_with_additional_server_names(&[
  382         -
            "localhost",
  383         -
        ]))
  384         -
        .build_https();
  385         -
  386         -
    run_tls_test_to_ip(&client).await.unwrap()
         456  +
async fn test_s2n_native_ca_with_partitioned_connection_pool() {
         457  +
    native_ca_rejects_test_certificate(
         458  +
        &PartitionedConnectionPool,
         459  +
        tls::Provider::S2nTls,
         460  +
        "Certificate is untrusted",
         461  +
    )
         462  +
    .await;
  387    463   
}
  388    464   
  389         -
// Test: connecting to localhost (which matches the cert) still works when additional server names are configured
  390         -
#[cfg(feature = "rustls-aws-lc")]
         465  +
#[cfg(feature = "s2n-tls")]
  391    466   
#[tokio::test]
  392         -
async fn test_additional_server_names_primary_name_still_works() {
  393         -
    let client = aws_smithy_http_client::Builder::new()
  394         -
        .tls_provider(tls::Provider::Rustls(
  395         -
            tls::rustls_provider::CryptoMode::AwsLc,
  396         -
        ))
  397         -
        .tls_context(server_tls_context_with_additional_server_names(&[
  398         -
            "sdktest.com",
  399         -
        ]))
  400         -
        .build_https();
  401         -
  402         -
    // Connect via localhost — primary name verification should pass without needing the fallback
  403         -
    run_tls_test(&client).await.unwrap()
         467  +
async fn test_s2n_tls_custom_ca_with_hyper_util_legacy_pool() {
         468  +
    custom_ca_accepts_test_certificate(&HyperUtilLegacyPool, tls::Provider::S2nTls).await;
  404    469   
}
  405    470   
  406         -
/// A [`TlsContext`] trusting the test server certificate and accepting the given
  407         -
/// names in addition to the one the request is addressed to.
  408         -
///
  409         -
/// The test certificate's SANs are `localhost` and `sdktest.com`, so a request to
  410         -
/// `127.0.0.1` only passes verification when one of those is supplied here.
  411         -
#[cfg(any(feature = "rustls-aws-lc", feature = "s2n-tls"))]
  412         -
fn server_tls_context_with_additional_server_names(additional_server_names: &[&str]) -> TlsContext {
  413         -
    let additional_server_names = additional_server_names
  414         -
        .iter()
  415         -
        .map(|name| {
  416         -
            ServerName::try_from(name.to_string()).expect("additional server name is valid")
  417         -
        })
  418         -
        .collect();
  419         -
    TlsContext::builder()
  420         -
        .with_trust_store(test_tls::server_trust_store())
  421         -
        .with_additional_server_names(additional_server_names)
  422         -
        .build()
  423         -
        .expect("failed to build TlsContext with test server certificate")
         471  +
#[cfg(feature = "s2n-tls")]
         472  +
#[cfg(feature = "rt-tokio")]
         473  +
#[tokio::test]
         474  +
async fn test_s2n_tls_custom_ca_with_partitioned_connection_pool() {
         475  +
    custom_ca_accepts_test_certificate(&PartitionedConnectionPool, tls::Provider::S2nTls).await;
  424    476   
}
  425    477   
  426    478   
async fn run_tls_test(client: &dyn HttpClient) -> Result<(), BoxError> {
  427    479   
    run_tls_test_with_idle_timeout(client, None).await
  428    480   
}
  429    481   
  430    482   
async fn run_tls_test_with_idle_timeout(
  431    483   
    client: &dyn HttpClient,
  432    484   
    pool_timeout: Option<Duration>,
  433    485   
) -> Result<(), BoxError> {
  434         -
    let server = server().await?;
         486  +
    let server = TlsEchoServer::start().await?;
  435    487   
    let start = tokio::time::Instant::now();
  436         -
    assert_eq!(server.conn_count(), 0); // calibrate conn_count
  437         -
    let endpoint = format!("https://localhost:{}/", server.listen_addr.port());
         488  +
    assert_eq!(server.active_connection_count(), 0);
         489  +
    let endpoint = format!("https://localhost:{}/", server.addr().port());
  438    490   
  439    491   
    let connector_settings = HttpConnectorSettings::builder().build();
  440    492   
    let runtime_components = RuntimeComponentsBuilder::for_tests()
  441    493   
        .with_time_source(Some(SystemTimeSource::new()))
  442    494   
        .build()
  443    495   
        .unwrap();
  444    496   
    let connector = client.http_connector(&connector_settings, &runtime_components);
  445    497   
    let mut response = connector.call(HttpRequest::get(endpoint).unwrap()).await?;
  446    498   
  447    499   
    let sdk_body = response.take_body();
  448    500   
    let body_stream = ByteStream::new(sdk_body);
  449    501   
    let resp_bytes = body_stream.collect().await?.into_bytes();
  450    502   
    assert_eq!(b"Hello TLS!", &resp_bytes[..]);
  451    503   
  452    504   
    if let Some(pool_timeout) = pool_timeout {
  453         -
        assert_eq!(server.conn_count(), 1);
         505  +
        assert_eq!(server.active_connection_count(), 1);
  454    506   
        tokio::time::sleep_until(start + pool_timeout - Duration::from_secs(1)).await;
  455         -
        assert_eq!(server.conn_count(), 1);
         507  +
        assert_eq!(server.active_connection_count(), 1);
  456    508   
        tokio::time::sleep(Duration::from_secs(2)).await;
  457         -
        assert_eq!(server.conn_count(), 0);
         509  +
        assert_eq!(server.active_connection_count(), 0);
  458    510   
    }
  459    511   
    Ok(())
  460    512   
}
  461    513   
  462    514   
/// Like `run_tls_test` but connects via 127.0.0.1 instead of localhost.
  463    515   
/// The test cert's SANs only include "localhost" and "sdktest.com", so
  464    516   
/// connecting by IP will fail hostname verification unless additional
  465    517   
/// server names are configured.
  466    518   
#[cfg(any(feature = "rustls-aws-lc", feature = "s2n-tls"))]
  467    519   
async fn run_tls_test_to_ip(client: &dyn HttpClient) -> Result<(), BoxError> {
  468         -
    let server = server().await?;
  469         -
    let endpoint = format!("https://127.0.0.1:{}/", server.listen_addr.port());
         520  +
    let server = TlsEchoServer::start().await?;
         521  +
    let endpoint = format!("https://127.0.0.1:{}/", server.addr().port());
  470    522   
  471    523   
    let connector_settings = HttpConnectorSettings::builder().build();
  472    524   
    let runtime_components = RuntimeComponentsBuilder::for_tests()
  473    525   
        .with_time_source(Some(SystemTimeSource::new()))
  474    526   
        .build()
  475    527   
        .unwrap();
  476    528   
    let connector = client.http_connector(&connector_settings, &runtime_components);
  477    529   
    let mut response = connector.call(HttpRequest::get(endpoint).unwrap()).await?;
  478    530   
  479    531   
    let sdk_body = response.take_body();
  480    532   
    let body_stream = ByteStream::new(sdk_body);
  481    533   
    let resp_bytes = body_stream.collect().await?.into_bytes();
  482    534   
    assert_eq!(b"Hello TLS!", &resp_bytes[..]);
  483    535   
    Ok(())
  484    536   
}
  485    537   
  486         -
// Test: connecting to 127.0.0.1 fails with s2n-tls (cert SANs only contain "localhost" and "sdktest.com")
  487         -
#[cfg(feature = "s2n-tls")]
  488         -
#[should_panic(expected = "Certificate is not valid for the supplied hostname")]
  489         -
#[tokio::test]
  490         -
async fn test_s2n_additional_server_names_ip_without_alt_names_fails() {
  491         -
    let client = aws_smithy_http_client::Builder::new()
  492         -
        .tls_provider(tls::Provider::S2nTls)
  493         -
        .tls_context(test_tls::server_tls_context())
  494         -
        .build_https();
         538  +
#[cfg(any(feature = "rustls-aws-lc", feature = "s2n-tls"))]
         539  +
mod additional_server_names {
         540  +
    //! Certificate-name contracts for each TLS provider and client backend.
  495    541   
  496         -
    run_tls_test_to_ip(&client).await.unwrap()
  497         -
}
         542  +
    use super::*;
  498    543   
  499         -
// Test: connecting to 127.0.0.1 with a non-matching additional server name fails with s2n-tls
  500         -
#[cfg(feature = "s2n-tls")]
  501         -
#[should_panic(expected = "Certificate is not valid for the supplied hostname")]
  502         -
#[tokio::test]
  503         -
async fn test_s2n_additional_server_names_with_wrong_alt_name_fails() {
  504         -
    let client = aws_smithy_http_client::Builder::new()
  505         -
        .tls_provider(tls::Provider::S2nTls)
  506         -
        .tls_context(server_tls_context_with_additional_server_names(&[
  507         -
            "wrong.example.com",
  508         -
        ]))
  509         -
        .build_https();
         544  +
    fn client_context(additional_server_names: &[&str]) -> TlsContext {
         545  +
        let additional_server_names = additional_server_names
         546  +
            .iter()
         547  +
            .map(|name| {
         548  +
                ServerName::try_from(name.to_string()).expect("additional server name is valid")
         549  +
            })
         550  +
            .collect();
         551  +
        test_tls::SERVER_IDENTITY
         552  +
            .client_context_builder()
         553  +
            .with_additional_server_names(additional_server_names)
         554  +
            .build()
         555  +
            .expect("additional server names produce a valid client context")
         556  +
    }
  510    557   
  511         -
    run_tls_test_to_ip(&client).await.unwrap()
  512         -
}
         558  +
    async fn assert_ip_rejected(
         559  +
        backend: &dyn HttpsClientBackend,
         560  +
        provider: tls::Provider,
         561  +
        tls_context: TlsContext,
         562  +
        expected_error: &str,
         563  +
    ) {
         564  +
        let client = backend.build_https(BackendConfig::default(), provider, tls_context);
         565  +
        let error = run_tls_test_to_ip(&client)
         566  +
            .await
         567  +
            .expect_err("the certificate must not validate for the request IP");
         568  +
        let error = format!("{error:?}");
         569  +
        assert!(
         570  +
            error.contains(expected_error),
         571  +
            "expected TLS error containing {expected_error:?}, got {error}"
         572  +
        );
         573  +
    }
  513    574   
  514         -
// Test: connecting to 127.0.0.1 succeeds with s2n-tls when "localhost" is configured as an additional server name
  515         -
#[cfg(feature = "s2n-tls")]
  516         -
#[tokio::test]
  517         -
async fn test_s2n_additional_server_names_with_matching_alt_name_succeeds() {
  518         -
    let client = aws_smithy_http_client::Builder::new()
  519         -
        .tls_provider(tls::Provider::S2nTls)
  520         -
        .tls_context(server_tls_context_with_additional_server_names(&[
  521         -
            "localhost",
  522         -
        ]))
  523         -
        .build_https();
         575  +
    async fn assert_ip_accepted(backend: &dyn HttpsClientBackend, provider: tls::Provider) {
         576  +
        let client = backend.build_https(
         577  +
            BackendConfig::default(),
         578  +
            provider,
         579  +
            client_context(&["localhost"]),
         580  +
        );
         581  +
        run_tls_test_to_ip(&client).await.unwrap();
         582  +
    }
  524    583   
  525         -
    run_tls_test_to_ip(&client).await.unwrap()
  526         -
}
         584  +
    async fn assert_primary_name_accepted(
         585  +
        backend: &dyn HttpsClientBackend,
         586  +
        provider: tls::Provider,
         587  +
    ) {
         588  +
        let client = backend.build_https(
         589  +
            BackendConfig::default(),
         590  +
            provider,
         591  +
            client_context(&["sdktest.com"]),
         592  +
        );
         593  +
        run_tls_test(&client).await.unwrap();
         594  +
    }
  527    595   
  528         -
// Test: connecting to localhost (which matches the cert) still works with s2n-tls when additional server names are configured
  529         -
#[cfg(feature = "s2n-tls")]
  530         -
#[tokio::test]
  531         -
async fn test_s2n_additional_server_names_primary_name_still_works() {
  532         -
    let client = aws_smithy_http_client::Builder::new()
  533         -
        .tls_provider(tls::Provider::S2nTls)
  534         -
        .tls_context(server_tls_context_with_additional_server_names(&[
  535         -
            "sdktest.com",
  536         -
        ]))
  537         -
        .build_https();
  538         -
  539         -
    // Connect via localhost — primary name verification should pass without needing the fallback
  540         -
    run_tls_test(&client).await.unwrap()
         596  +
    #[cfg(feature = "rustls-aws-lc")]
         597  +
    mod rustls_aws_lc {
         598  +
        use super::*;
         599  +
        use crate::rustls_aws_lc as provider;
         600  +
         601  +
        const CERTIFICATE_ERROR: &str = "InvalidCertificate";
         602  +
         603  +
        async fn missing_name_is_rejected(backend: &dyn HttpsClientBackend) {
         604  +
            assert_ip_rejected(
         605  +
                backend,
         606  +
                provider(),
         607  +
                test_tls::SERVER_IDENTITY.client_context(),
         608  +
                CERTIFICATE_ERROR,
         609  +
            )
         610  +
            .await;
         611  +
        }
         612  +
         613  +
        async fn wrong_name_is_rejected(backend: &dyn HttpsClientBackend) {
         614  +
            assert_ip_rejected(
         615  +
                backend,
         616  +
                provider(),
         617  +
                client_context(&["wrong.example.com"]),
         618  +
                CERTIFICATE_ERROR,
         619  +
            )
         620  +
            .await;
         621  +
        }
         622  +
         623  +
        async fn matching_name_is_accepted(backend: &dyn HttpsClientBackend) {
         624  +
            assert_ip_accepted(backend, provider()).await;
         625  +
        }
         626  +
         627  +
        async fn primary_name_is_preserved(backend: &dyn HttpsClientBackend) {
         628  +
            assert_primary_name_accepted(backend, provider()).await;
         629  +
        }
         630  +
         631  +
        mod hyper_util_legacy_pool {
         632  +
            use super::*;
         633  +
         634  +
            #[tokio::test]
         635  +
            async fn test_missing_name_is_rejected() {
         636  +
                missing_name_is_rejected(&HyperUtilLegacyPool).await;
         637  +
            }
         638  +
         639  +
            #[tokio::test]
         640  +
            async fn test_wrong_name_is_rejected() {
         641  +
                wrong_name_is_rejected(&HyperUtilLegacyPool).await;
         642  +
            }
         643  +
         644  +
            #[tokio::test]
         645  +
            async fn test_matching_name_is_accepted() {
         646  +
                matching_name_is_accepted(&HyperUtilLegacyPool).await;
         647  +
            }
         648  +
         649  +
            #[tokio::test]
         650  +
            async fn test_primary_name_is_preserved() {
         651  +
                primary_name_is_preserved(&HyperUtilLegacyPool).await;
         652  +
            }
         653  +
        }
         654  +
         655  +
        #[cfg(feature = "rt-tokio")]
         656  +
        mod partitioned_connection_pool {
         657  +
            use super::*;
         658  +
         659  +
            #[tokio::test]
         660  +
            async fn test_missing_name_is_rejected() {
         661  +
                missing_name_is_rejected(&PartitionedConnectionPool).await;
         662  +
            }
         663  +
         664  +
            #[tokio::test]
         665  +
            async fn test_wrong_name_is_rejected() {
         666  +
                wrong_name_is_rejected(&PartitionedConnectionPool).await;
         667  +
            }
         668  +
         669  +
            #[tokio::test]
         670  +
            async fn test_matching_name_is_accepted() {
         671  +
                matching_name_is_accepted(&PartitionedConnectionPool).await;
         672  +
            }
         673  +
         674  +
            #[tokio::test]
         675  +
            async fn test_primary_name_is_preserved() {
         676  +
                primary_name_is_preserved(&PartitionedConnectionPool).await;
         677  +
            }
         678  +
        }
         679  +
    }
         680  +
         681  +
    #[cfg(feature = "s2n-tls")]
         682  +
    mod s2n_tls {
         683  +
        use super::*;
         684  +
         685  +
        const CERTIFICATE_ERROR: &str = "Certificate is not valid for the supplied hostname";
         686  +
         687  +
        async fn missing_name_is_rejected(backend: &dyn HttpsClientBackend) {
         688  +
            assert_ip_rejected(
         689  +
                backend,
         690  +
                tls::Provider::S2nTls,
         691  +
                test_tls::SERVER_IDENTITY.client_context(),
         692  +
                CERTIFICATE_ERROR,
         693  +
            )
         694  +
            .await;
         695  +
        }
         696  +
         697  +
        async fn wrong_name_is_rejected(backend: &dyn HttpsClientBackend) {
         698  +
            assert_ip_rejected(
         699  +
                backend,
         700  +
                tls::Provider::S2nTls,
         701  +
                client_context(&["wrong.example.com"]),
         702  +
                CERTIFICATE_ERROR,
         703  +
            )
         704  +
            .await;
         705  +
        }
         706  +
         707  +
        async fn matching_name_is_accepted(backend: &dyn HttpsClientBackend) {
         708  +
            assert_ip_accepted(backend, tls::Provider::S2nTls).await;
         709  +
        }
         710  +
         711  +
        async fn primary_name_is_preserved(backend: &dyn HttpsClientBackend) {
         712  +
            assert_primary_name_accepted(backend, tls::Provider::S2nTls).await;
         713  +
        }
         714  +
         715  +
        mod hyper_util_legacy_pool {
         716  +
            use super::*;
         717  +
         718  +
            #[tokio::test]
         719  +
            async fn test_missing_name_is_rejected() {
         720  +
                missing_name_is_rejected(&HyperUtilLegacyPool).await;
         721  +
            }
         722  +
         723  +
            #[tokio::test]
         724  +
            async fn test_wrong_name_is_rejected() {
         725  +
                wrong_name_is_rejected(&HyperUtilLegacyPool).await;
         726  +
            }
         727  +
         728  +
            #[tokio::test]
         729  +
            async fn test_matching_name_is_accepted() {
         730  +
                matching_name_is_accepted(&HyperUtilLegacyPool).await;
         731  +
            }
         732  +
         733  +
            #[tokio::test]
         734  +
            async fn test_primary_name_is_preserved() {
         735  +
                primary_name_is_preserved(&HyperUtilLegacyPool).await;
         736  +
            }
         737  +
        }
         738  +
         739  +
        #[cfg(feature = "rt-tokio")]
         740  +
        mod partitioned_connection_pool {
         741  +
            use super::*;
         742  +
         743  +
            #[tokio::test]
         744  +
            async fn test_missing_name_is_rejected() {
         745  +
                missing_name_is_rejected(&PartitionedConnectionPool).await;
         746  +
            }
         747  +
         748  +
            #[tokio::test]
         749  +
            async fn test_wrong_name_is_rejected() {
         750  +
                wrong_name_is_rejected(&PartitionedConnectionPool).await;
         751  +
            }
         752  +
         753  +
            #[tokio::test]
         754  +
            async fn test_matching_name_is_accepted() {
         755  +
                matching_name_is_accepted(&PartitionedConnectionPool).await;
         756  +
            }
         757  +
         758  +
            #[tokio::test]
         759  +
            async fn test_primary_name_is_preserved() {
         760  +
                primary_name_is_preserved(&PartitionedConnectionPool).await;
         761  +
            }
         762  +
        }
         763  +
    }
  541    764   
}