AWS SDK

AWS SDK

rev. c4f9295a7b4566dca79c361e3a2aa9e63cdf82e7

Files changed:

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-http-client/src/test_util/capture_request.rs

Renamed from tmp-codegen-diff/aws-sdk/sdk/aws-smithy-runtime/src/client/http/test_util/capture_request.rs

@@ -1,1 +69,68 @@
    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   
use aws_smithy_runtime_api::client::connector_metadata::ConnectorMetadata;
    7      7   
use aws_smithy_runtime_api::client::http::{
    8      8   
    HttpClient, HttpConnector, HttpConnectorFuture, HttpConnectorSettings, SharedHttpConnector,
    9      9   
};
   10         -
use aws_smithy_runtime_api::client::orchestrator::HttpRequest;
          10  +
use aws_smithy_runtime_api::client::orchestrator::{HttpRequest, HttpResponse};
   11     11   
use aws_smithy_runtime_api::client::runtime_components::RuntimeComponents;
          12  +
use aws_smithy_runtime_api::http::HttpError;
   12     13   
use aws_smithy_runtime_api::shared::IntoShared;
   13     14   
use aws_smithy_types::body::SdkBody;
   14     15   
use std::fmt::Debug;
   15     16   
use std::sync::{Arc, Mutex};
   16     17   
use tokio::sync::oneshot;
   17     18   
   18     19   
#[derive(Debug)]
   19     20   
struct Inner {
   20         -
    response: Option<http_02x::Response<SdkBody>>,
          21  +
    response: Option<HttpResponse>,
   21     22   
    sender: Option<oneshot::Sender<HttpRequest>>,
   22     23   
}
   23     24   
   24     25   
/// Test Connection to capture a single request
   25     26   
#[derive(Debug, Clone)]
   26     27   
pub struct CaptureRequestHandler(Arc<Mutex<Inner>>);
   27     28   
   28     29   
impl HttpConnector for CaptureRequestHandler {
   29     30   
    fn call(&self, request: HttpRequest) -> HttpConnectorFuture {
   30     31   
        let mut inner = self.0.lock().unwrap();
   31     32   
        if let Err(_e) = inner.sender.take().expect("already sent").send(request) {
   32     33   
            tracing::trace!("The receiver was already dropped");
   33     34   
        }
   34     35   
        HttpConnectorFuture::ready(Ok(inner
   35     36   
            .response
   36     37   
            .take()
   37         -
            .expect("could not handle second request")
   38         -
            .try_into()
   39         -
            .unwrap()))
          38  +
            .expect("could not handle second request")))
   40     39   
    }
   41     40   
}
   42     41   
   43     42   
impl HttpClient for CaptureRequestHandler {
   44     43   
    fn http_connector(
   45     44   
        &self,
   46     45   
        _: &HttpConnectorSettings,
   47     46   
        _: &RuntimeComponents,
   48     47   
    ) -> SharedHttpConnector {
   49     48   
        self.clone().into_shared()
@@ -74,73 +0,172 @@
   94     93   
///     .build();
   95     94   
/// let client = aws_sdk_sts::Client::from_conf(conf);
   96     95   
/// let _ = client.assume_role_with_saml().send().await;
   97     96   
/// // web identity should be unsigned
   98     97   
/// assert_eq!(
   99     98   
///     request.expect_request().headers().get("AUTHORIZATION"),
  100     99   
///     None
  101    100   
/// );
  102    101   
/// ```
  103    102   
pub fn capture_request(
  104         -
    response: Option<http_02x::Response<SdkBody>>,
         103  +
    response: Option<http_1x::Response<SdkBody>>,
         104  +
) -> (CaptureRequestHandler, CaptureRequestReceiver) {
         105  +
    capture_request_inner(response)
         106  +
}
         107  +
         108  +
fn capture_request_inner(
         109  +
    response: Option<impl TryInto<HttpResponse, Error = HttpError>>,
  105    110   
) -> (CaptureRequestHandler, CaptureRequestReceiver) {
  106    111   
    let (tx, rx) = oneshot::channel();
         112  +
    let http_resp: HttpResponse = match response {
         113  +
        Some(resp) => resp.try_into().expect("valid HttpResponse"),
         114  +
        None => http_1x::Response::builder()
         115  +
            .status(200)
         116  +
            .body(SdkBody::empty())
         117  +
            .expect("unreachable")
         118  +
            .try_into()
         119  +
            .expect("unreachable"),
         120  +
    };
  107    121   
    (
  108    122   
        CaptureRequestHandler(Arc::new(Mutex::new(Inner {
  109         -
            response: Some(response.unwrap_or_else(|| {
  110         -
                http_02x::Response::builder()
  111         -
                    .status(200)
  112         -
                    .body(SdkBody::empty())
  113         -
                    .expect("unreachable")
  114         -
            })),
         123  +
            response: Some(http_resp),
  115    124   
            sender: Some(tx),
  116    125   
        }))),
  117    126   
        CaptureRequestReceiver { receiver: rx },
  118    127   
    )
  119    128   
}
         129  +
         130  +
#[allow(missing_docs)]
         131  +
#[cfg(feature = "legacy-test-util")]
         132  +
pub fn legacy_capture_request(
         133  +
    response: Option<http_02x::Response<SdkBody>>,
         134  +
) -> (CaptureRequestHandler, CaptureRequestReceiver) {
         135  +
    capture_request_inner(response)
         136  +
}
         137  +
         138  +
#[cfg(test)]
         139  +
mod test {
         140  +
    use aws_smithy_runtime_api::client::http::HttpConnector;
         141  +
    use aws_smithy_runtime_api::client::orchestrator::HttpRequest;
         142  +
    use aws_smithy_types::body::SdkBody;
         143  +
         144  +
    #[cfg(feature = "legacy-test-util")]
         145  +
    #[tokio::test]
         146  +
    async fn test_can_plug_in_http_02x() {
         147  +
        use super::legacy_capture_request;
         148  +
        let (capture_client, _request) = legacy_capture_request(Some(
         149  +
            http_02x::Response::builder()
         150  +
                .status(202)
         151  +
                .body(SdkBody::empty())
         152  +
                .expect("unreachable"),
         153  +
        ));
         154  +
         155  +
        let resp = capture_client.call(HttpRequest::empty()).await.unwrap();
         156  +
        assert_eq!(202, resp.status().as_u16());
         157  +
    }
         158  +
         159  +
    #[tokio::test]
         160  +
    async fn test_can_plug_in_http_1x() {
         161  +
        use super::capture_request;
         162  +
        let (capture_client, _request) = capture_request(Some(
         163  +
            http_1x::Response::builder()
         164  +
                .status(202)
         165  +
                .body(SdkBody::empty())
         166  +
                .expect("unreachable"),
         167  +
        ));
         168  +
         169  +
        let resp = capture_client.call(HttpRequest::empty()).await.unwrap();
         170  +
        assert_eq!(202, resp.status().as_u16());
         171  +
    }
         172  +
}

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-http-client/src/test_util/dvr.rs

Renamed from tmp-codegen-diff/aws-sdk/sdk/aws-smithy-runtime/src/client/http/test_util/dvr.rs

@@ -101,101 +228,264 @@
  121    121   
/// An initial HTTP response roughly equivalent to `http::Response<()>`
  122    122   
///
  123    123   
/// The initial response phase of an HTTP request. The body will be
  124    124   
/// sent later as a separate action.
  125    125   
#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)]
  126    126   
pub struct Response {
  127    127   
    status: u16,
  128    128   
    headers: IndexMap<String, Vec<String>>,
  129    129   
}
  130    130   
         131  +
#[cfg(feature = "legacy-test-util")]
  131    132   
impl From<&Request> for http_02x::Request<()> {
  132    133   
    fn from(request: &Request) -> Self {
  133    134   
        let mut builder = http_02x::Request::builder().uri(request.uri.as_str());
  134    135   
        for (k, values) in request.headers.iter() {
  135    136   
            for v in values {
  136    137   
                builder = builder.header(k, v);
  137    138   
            }
  138    139   
        }
  139    140   
        builder.method(request.method.as_str()).body(()).unwrap()
  140    141   
    }
  141    142   
}
  142    143   
         144  +
impl From<&Request> for http_1x::Request<()> {
         145  +
    fn from(request: &Request) -> Self {
         146  +
        let mut builder = http_1x::Request::builder().uri(request.uri.as_str());
         147  +
        for (k, values) in request.headers.iter() {
         148  +
            for v in values {
         149  +
                builder = builder.header(k, v);
         150  +
            }
         151  +
        }
         152  +
        builder.method(request.method.as_str()).body(()).unwrap()
         153  +
    }
         154  +
}
         155  +
  143    156   
impl<'a> From<&'a HttpRequest> for Request {
  144    157   
    fn from(req: &'a HttpRequest) -> Self {
  145    158   
        let uri = req.uri().to_string();
  146    159   
        let headers = headers_to_map_http(req.headers());
  147    160   
        let method = req.method().to_string();
  148    161   
        Self {
  149    162   
            uri,
  150    163   
            headers,
  151    164   
            method,
  152    165   
        }
  153    166   
    }
  154    167   
}
  155    168   
  156    169   
fn headers_to_map_http(headers: &Headers) -> IndexMap<String, Vec<String>> {
  157    170   
    let mut out: IndexMap<_, Vec<_>> = IndexMap::new();
  158    171   
    for (header_name, header_value) in headers.iter() {
  159    172   
        let entry = out.entry(header_name.to_string()).or_default();
  160    173   
        entry.push(header_value.to_string());
  161    174   
    }
  162    175   
    out
  163    176   
}
  164    177   
  165         -
fn headers_to_map_02x(headers: &http_02x::HeaderMap) -> IndexMap<String, Vec<String>> {
         178  +
fn headers_to_map(headers: &Headers) -> IndexMap<String, Vec<String>> {
  166    179   
    let mut out: IndexMap<_, Vec<_>> = IndexMap::new();
  167    180   
    for (header_name, header_value) in headers.iter() {
  168    181   
        let entry = out.entry(header_name.to_string()).or_default();
  169    182   
        entry.push(
  170    183   
            std::str::from_utf8(header_value.as_ref())
  171    184   
                .unwrap()
  172    185   
                .to_string(),
  173    186   
        );
  174    187   
    }
  175    188   
    out
  176    189   
}
  177    190   
  178         -
fn headers_to_map(headers: &Headers) -> IndexMap<String, Vec<String>> {
         191  +
#[cfg(feature = "legacy-test-util")]
         192  +
fn headers_to_map_02x(headers: &http_02x::HeaderMap) -> IndexMap<String, Vec<String>> {
  179    193   
    let mut out: IndexMap<_, Vec<_>> = IndexMap::new();
  180    194   
    for (header_name, header_value) in headers.iter() {
  181    195   
        let entry = out.entry(header_name.to_string()).or_default();
  182    196   
        entry.push(
  183    197   
            std::str::from_utf8(header_value.as_ref())
  184    198   
                .unwrap()
  185    199   
                .to_string(),
  186    200   
        );
  187    201   
    }
  188    202   
    out
  189    203   
}
  190    204   
         205  +
#[cfg(feature = "legacy-test-util")]
  191    206   
impl<'a, B> From<&'a http_02x::Response<B>> for Response {
  192    207   
    fn from(resp: &'a http_02x::Response<B>) -> Self {
  193    208   
        let status = resp.status().as_u16();
  194    209   
        let headers = headers_to_map_02x(resp.headers());
  195    210   
        Self { status, headers }
  196    211   
    }
  197    212   
}
  198    213   
         214  +
fn headers_to_map_1x(headers: &http_1x::HeaderMap) -> IndexMap<String, Vec<String>> {
         215  +
    let mut out: IndexMap<_, Vec<_>> = IndexMap::new();
         216  +
    for (header_name, header_value) in headers.iter() {
         217  +
        let entry = out.entry(header_name.to_string()).or_default();
         218  +
        entry.push(
         219  +
            std::str::from_utf8(header_value.as_ref())
         220  +
                .unwrap()
         221  +
                .to_string(),
         222  +
        );
         223  +
    }
         224  +
    out
         225  +
}
         226  +
         227  +
impl<'a, B> From<&'a http_1x::Response<B>> for Response {
         228  +
    fn from(resp: &'a http_1x::Response<B>) -> Self {
         229  +
        let status = resp.status().as_u16();
         230  +
        let headers = headers_to_map_1x(resp.headers());
         231  +
        Self { status, headers }
         232  +
    }
         233  +
}
         234  +
  199    235   
impl From<&HttpResponse> for Response {
  200    236   
    fn from(resp: &HttpResponse) -> Self {
  201    237   
        Self {
  202    238   
            status: resp.status().into(),
  203    239   
            headers: headers_to_map(resp.headers()),
  204    240   
        }
  205    241   
    }
  206    242   
}
  207    243   
  208    244   
/// Error response wrapper
@@ -316,352 +375,412 @@
  336    372   
        };
  337    373   
        // content length is not added when it wasn't initially present
  338    374   
        let expected_length = "hello from example.com".len();
  339    375   
        assert_eq!(
  340    376   
            headers.get("content-length"),
  341    377   
            Some(&vec![expected_length.to_string()])
  342    378   
        );
  343    379   
        Ok(())
  344    380   
    }
  345    381   
         382  +
    #[cfg(feature = "legacy-test-util")]
  346    383   
    #[tokio::test]
  347    384   
    async fn turtles_all_the_way_down() -> Result<(), Box<dyn Error>> {
  348    385   
        // create a replaying connection from a recording, wrap a recording connection around it,
  349    386   
        // make a request, then verify that the same traffic was recorded.
  350    387   
        let network_traffic = fs::read_to_string("test-data/example.com.json")?;
  351    388   
        let mut network_traffic: NetworkTraffic = serde_json::from_str(&network_traffic)?;
  352    389   
        network_traffic.correct_content_lengths();
  353    390   
        let inner = ReplayingClient::new(network_traffic.events.clone());
  354    391   
        let connection = RecordingClient::new(SharedHttpConnector::new(inner.clone()));
  355    392   
        let req = http_02x::Request::post("https://www.example.com")

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-http-client/src/test_util/dvr/record.rs

Renamed from tmp-codegen-diff/aws-sdk/sdk/aws-smithy-runtime/src/client/http/test_util/dvr/record.rs

@@ -1,1 +169,170 @@
    8      8   
    Version,
    9      9   
};
   10     10   
use aws_smithy_runtime_api::client::connector_metadata::ConnectorMetadata;
   11     11   
use aws_smithy_runtime_api::client::http::{
   12     12   
    HttpClient, HttpConnector, HttpConnectorFuture, HttpConnectorSettings, SharedHttpConnector,
   13     13   
};
   14     14   
use aws_smithy_runtime_api::client::orchestrator::HttpRequest;
   15     15   
use aws_smithy_runtime_api::client::runtime_components::RuntimeComponents;
   16     16   
use aws_smithy_runtime_api::shared::IntoShared;
   17     17   
use aws_smithy_types::body::SdkBody;
   18         -
use http_body_04x::Body;
   19     18   
use std::path::Path;
   20     19   
use std::sync::atomic::{AtomicUsize, Ordering};
   21     20   
use std::sync::{Arc, Mutex, MutexGuard};
   22     21   
use std::{fs, io};
   23     22   
use tokio::task::JoinHandle;
   24     23   
   25     24   
/// Recording client
   26     25   
///
   27     26   
/// `RecordingClient` wraps an inner connection and records all traffic, enabling traffic replay.
   28     27   
///
   29     28   
/// # Example
   30     29   
///
   31     30   
/// ```rust,ignore
   32     31   
/// use aws_smithy_async::rt::sleep::default_async_sleep;
   33     32   
/// use aws_smithy_runtime::client::http::hyper_014::default_connector;
   34         -
/// use aws_smithy_runtime::client::http::test_util::dvr::RecordingClient;
          33  +
/// use aws_smithy_http_client::test_util::dvr::RecordingClient;
   35     34   
/// use aws_smithy_runtime_api::client::http::HttpConnectorSettingsBuilder;
   36     35   
/// use aws_sdk_s3::{Client, Config};
   37     36   
///
   38     37   
/// #[tokio::test]
   39     38   
/// async fn test_content_length_enforcement_is_not_applied_to_head_request() {
   40     39   
///     let settings = HttpConnectorSettingsBuilder::default().build();
   41     40   
///     let http_client = default_connector(&settings, default_async_sleep()).unwrap();
   42     41   
///     let http_client = RecordingClient::new(http_client);
   43     42   
///
   44     43   
///     // Since we need to send a real request for this,
   45     44   
///     // you'll need to use your real credentials.
   46     45   
///     let config = aws_config::load_defaults(BehaviorVersion::latest()).await;
   47     46   
///     let config = Config::from(&config).to_builder()
   48     47   
///         .http_client(http_client.clone())
   49     48   
///         .region(Region::new("us-east-1"))
   50     49   
///         .build();
   51     50   
///
   52     51   
///     let client = Client::from_conf(config);
   53     52   
///     let _resp = client
   54     53   
///         .head_object()
   55     54   
///         .key("some-test-file.txt")
   56     55   
///         .bucket("your-test-bucket")
   57     56   
///         .send()
   58     57   
///         .await
   59     58   
///         .unwrap();
   60     59   
///
   61     60   
///     // If the request you want to record has a body, don't forget to poll
   62     61   
///     // the body to completion BEFORE calling `dump_to_file`. Otherwise, your
   63     62   
///     // test json won't include the body.
   64     63   
///     // let _body = _resp.body.collect().await.unwrap();
   65     64   
///
   66     65   
///     // This path is relative to your project or workspace `Cargo.toml` file.
   67     66   
///     http_client.dump_to_file("tests/data/content-length-enforcement/head-object.json").unwrap();
   68     67   
/// }
   69     68   
/// ```
   70     69   
#[derive(Clone, Debug)]
   71     70   
pub struct RecordingClient {
   72     71   
    pub(crate) data: Arc<Mutex<Vec<Event>>>,
   73     72   
    pub(crate) num_events: Arc<AtomicUsize>,
   74     73   
    pub(crate) inner: SharedHttpConnector,
   75     74   
}
   76     75   
   77         -
#[cfg(feature = "tls-rustls")]
          76  +
#[cfg(feature = "legacy-rustls-ring")]
   78     77   
impl RecordingClient {
   79     78   
    /// Construct a recording connection wrapping a default HTTPS implementation without any timeouts.
   80     79   
    pub fn https() -> Self {
   81         -
        use crate::client::http::hyper_014::HyperConnector;
          80  +
        #[allow(deprecated)]
          81  +
        use crate::hyper_014::HyperConnector;
   82     82   
        Self {
   83     83   
            data: Default::default(),
   84     84   
            num_events: Arc::new(AtomicUsize::new(0)),
          85  +
            #[allow(deprecated)]
   85     86   
            inner: SharedHttpConnector::new(HyperConnector::builder().build_https()),
   86     87   
        }
   87     88   
    }
   88     89   
}
   89     90   
   90     91   
impl RecordingClient {
   91     92   
    /// Create a new recording connection from a connection
   92     93   
    pub fn new(underlying_connector: impl HttpConnector + 'static) -> Self {
   93     94   
        Self {
   94     95   
            data: Default::default(),
   95     96   
            num_events: Arc::new(AtomicUsize::new(0)),
   96     97   
            inner: underlying_connector.into_shared(),
   97     98   
        }
   98     99   
    }
   99    100   
  100    101   
    /// Return the traffic recorded by this connection
  101    102   
    pub fn events(&self) -> MutexGuard<'_, Vec<Event>> {
  102    103   
        self.data.lock().unwrap()
  103    104   
    }
  104    105   
  105    106   
    /// NetworkTraffic struct suitable for serialization
  106    107   
    pub fn network_traffic(&self) -> NetworkTraffic {
  107    108   
        NetworkTraffic {
  108    109   
            events: self.events().clone(),
  109    110   
            docs: Some("todo docs".into()),
  110    111   
            version: Version::V0,
  111    112   
        }
  112    113   
    }
  113    114   
  114    115   
    /// Dump the network traffic to a file
  115    116   
    pub fn dump_to_file(&self, path: impl AsRef<Path>) -> Result<(), io::Error> {
  116    117   
        fs::write(
  117    118   
            path,
  118    119   
            serde_json::to_string(&self.network_traffic()).unwrap(),
  119    120   
        )
  120    121   
    }
  121    122   
  122    123   
    fn next_id(&self) -> ConnectionId {
  123    124   
        ConnectionId(self.num_events.fetch_add(1, Ordering::Relaxed))
  124    125   
    }
  125    126   
}
  126    127   
  127    128   
fn record_body(
  128    129   
    body: &mut SdkBody,
  129    130   
    event_id: ConnectionId,
  130    131   
    direction: Direction,
  131    132   
    event_bus: Arc<Mutex<Vec<Event>>>,
  132    133   
) -> JoinHandle<()> {
  133         -
    let (sender, output_body) = hyper_0_14::Body::channel();
  134         -
    let real_body = std::mem::replace(body, SdkBody::from_body_0_4(output_body));
         134  +
    let (sender, output_body) = crate::test_util::body::channel_body();
         135  +
    let real_body = std::mem::replace(body, output_body);
  135    136   
    tokio::spawn(async move {
  136    137   
        let mut real_body = real_body;
  137    138   
        let mut sender = sender;
  138    139   
        loop {
  139         -
            let data = real_body.data().await;
         140  +
            let data = crate::test_util::body::next_data_frame(&mut real_body).await;
  140    141   
            match data {
  141    142   
                Some(Ok(data)) => {
  142    143   
                    event_bus.lock().unwrap().push(Event {
  143    144   
                        connection_id: event_id,
  144    145   
                        action: Action::Data {
  145    146   
                            data: BodyData::from(data.clone()),
  146    147   
                            direction,
  147    148   
                        },
  148    149   
                    });
  149    150   
                    // This happens if the real connection is closed during recording.

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-http-client/src/test_util/dvr/replay.rs

Renamed from tmp-codegen-diff/aws-sdk/sdk/aws-smithy-runtime/src/client/http/test_util/dvr/replay.rs

@@ -1,1 +90,90 @@
    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   
use super::{Action, ConnectionId, Direction, Event, NetworkTraffic};
    7         -
use crate::client::http::test_util::replay::DEFAULT_RELAXED_HEADERS;
           7  +
use crate::test_util::replay::DEFAULT_RELAXED_HEADERS;
    8      8   
use aws_smithy_protocol_test::MediaType;
    9      9   
use aws_smithy_runtime_api::client::connector_metadata::ConnectorMetadata;
   10     10   
use aws_smithy_runtime_api::client::http::{
   11     11   
    HttpClient, HttpConnector, HttpConnectorFuture, HttpConnectorSettings, SharedHttpConnector,
   12     12   
};
   13     13   
use aws_smithy_runtime_api::client::orchestrator::{HttpRequest, HttpResponse};
   14     14   
use aws_smithy_runtime_api::client::result::ConnectorError;
   15     15   
use aws_smithy_runtime_api::client::runtime_components::RuntimeComponents;
   16     16   
use aws_smithy_runtime_api::shared::IntoShared;
   17     17   
use aws_smithy_types::body::SdkBody;
   18     18   
use aws_smithy_types::error::display::DisplayErrorContext;
   19     19   
use bytes::{Bytes, BytesMut};
   20     20   
use std::collections::{HashMap, VecDeque};
   21     21   
use std::error::Error;
   22     22   
use std::fmt;
   23     23   
use std::ops::DerefMut;
   24     24   
use std::path::Path;
   25     25   
use std::sync::atomic::{AtomicUsize, Ordering};
   26     26   
use std::sync::{Arc, Mutex};
   27     27   
use tokio::task::JoinHandle;
   28     28   
   29     29   
/// Wrapper type to enable optionally waiting for a future to complete
   30     30   
#[derive(Debug)]
   31     31   
enum Waitable<T> {
   32     32   
    Loading(JoinHandle<T>),
   33     33   
    Value(T),
   34     34   
}
   35     35   
   36     36   
impl<T> Waitable<T> {
   37     37   
    /// Consumes the future and returns the value
   38     38   
    async fn take(self) -> T {
   39     39   
        match self {
   40     40   
            Waitable::Loading(f) => f.await.expect("join failed"),
   41     41   
            Waitable::Value(value) => value,
   42     42   
        }
   43     43   
    }
   44     44   
   45     45   
    /// Waits for the future to be ready
   46     46   
    async fn wait(&mut self) {
   47     47   
        match self {
   48     48   
            Waitable::Loading(f) => *self = Waitable::Value(f.await.expect("join failed")),
   49     49   
            Waitable::Value(_) => {}
   50     50   
        }
   51     51   
    }
   52     52   
}
   53     53   
   54     54   
/// Replay traffic recorded by a [`RecordingClient`](super::RecordingClient)
   55     55   
#[derive(Clone)]
   56     56   
pub struct ReplayingClient {
   57     57   
    live_events: Arc<Mutex<HashMap<ConnectionId, VecDeque<Event>>>>,
   58         -
    verifiable_events: Arc<HashMap<ConnectionId, http_02x::Request<Bytes>>>,
          58  +
    verifiable_events: Arc<HashMap<ConnectionId, http_1x::Request<Bytes>>>,
   59     59   
    num_events: Arc<AtomicUsize>,
   60         -
    recorded_requests: Arc<Mutex<HashMap<ConnectionId, Waitable<http_02x::Request<Bytes>>>>>,
          60  +
    recorded_requests: Arc<Mutex<HashMap<ConnectionId, Waitable<http_1x::Request<Bytes>>>>>,
   61     61   
}
   62     62   
   63     63   
// Ideally, this would just derive Debug, but that makes the tests in aws-config think they found AWS secrets
   64     64   
// when really it's just the test response data they're seeing from the Debug impl of this client.
   65     65   
// This is just a quick workaround. A better fix can be considered later.
   66     66   
impl fmt::Debug for ReplayingClient {
   67     67   
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
   68     68   
        f.write_str("test_util::dvr::ReplayingClient")
   69     69   
    }
   70     70   
}
@@ -180,180 +399,408 @@
  200    200   
                        "event {} validation failed with: {}",
  201    201   
                        conn_id.0,
  202    202   
                        DisplayErrorContext(&err)
  203    203   
                    )
  204    204   
                })?;
  205    205   
        }
  206    206   
        Ok(())
  207    207   
    }
  208    208   
  209    209   
    /// Return all the recorded requests for further analysis
         210  +
    #[cfg(feature = "legacy-test-util")]
  210    211   
    pub async fn take_requests(self) -> Vec<http_02x::Request<Bytes>> {
  211    212   
        let mut recorded_requests =
  212    213   
            std::mem::take(self.recorded_requests.lock().unwrap().deref_mut());
  213    214   
        let mut out = Vec::with_capacity(recorded_requests.len());
  214    215   
        for conn_id in 0..recorded_requests.len() {
  215    216   
            out.push(
  216    217   
                recorded_requests
  217    218   
                    .remove(&ConnectionId(conn_id))
  218    219   
                    .expect("should exist")
  219    220   
                    .take()
  220    221   
                    .await,
  221    222   
            )
  222    223   
        }
  223         -
        out
         224  +
        out.into_iter()
         225  +
            .map(|v1r| {
         226  +
                let mut builder = http_02x::Request::builder()
         227  +
                    .uri(v1r.uri().to_string())
         228  +
                    .method(v1r.method().as_str());
         229  +
                for (k, v) in v1r.headers().iter() {
         230  +
                    builder = builder.header(k.as_str(), v.as_bytes())
         231  +
                }
         232  +
                builder.body(v1r.into_body()).expect("valid conversion")
         233  +
            })
         234  +
            .collect()
  224    235   
    }
  225    236   
  226    237   
    /// Build a replay connection from a JSON file
  227    238   
    pub fn from_file(path: impl AsRef<Path>) -> Result<Self, Box<dyn Error>> {
  228    239   
        let events: NetworkTraffic =
  229    240   
            serde_json::from_str(&std::fs::read_to_string(path.as_ref())?)?;
  230    241   
        Ok(Self::new(events.events))
  231    242   
    }
  232    243   
  233    244   
    /// Build a replay connection from a sequence of events
  234    245   
    pub fn new(events: Vec<Event>) -> Self {
  235    246   
        let mut event_map: HashMap<_, VecDeque<_>> = HashMap::new();
  236    247   
        for event in events {
  237    248   
            let event_buffer = event_map.entry(event.connection_id).or_default();
  238    249   
            event_buffer.push_back(event);
  239    250   
        }
  240    251   
        let verifiable_events = event_map
  241    252   
            .iter()
  242    253   
            .map(|(id, events)| {
  243    254   
                let mut body = BytesMut::new();
  244    255   
                for event in events {
  245    256   
                    if let Action::Data {
  246    257   
                        direction: Direction::Request,
  247    258   
                        data,
  248    259   
                    } = &event.action
  249    260   
                    {
  250    261   
                        body.extend_from_slice(&data.copy_to_vec());
  251    262   
                    }
  252    263   
                }
  253    264   
                let initial_request = events.iter().next().expect("must have one event");
  254    265   
                let request = match &initial_request.action {
  255    266   
                    Action::Request { request } => {
  256         -
                        http_02x::Request::from(request).map(|_| Bytes::from(body))
         267  +
                        http_1x::Request::from(request).map(|_| Bytes::from(body))
  257    268   
                    }
  258    269   
                    _ => panic!("invalid first event"),
  259    270   
                };
  260    271   
                (*id, request)
  261    272   
            })
  262    273   
            .collect();
  263    274   
        let verifiable_events = Arc::new(verifiable_events);
  264    275   
  265    276   
        ReplayingClient {
  266    277   
            live_events: Arc::new(Mutex::new(event_map)),
  267    278   
            num_events: Arc::new(AtomicUsize::new(0)),
  268    279   
            recorded_requests: Default::default(),
  269    280   
            verifiable_events,
  270    281   
        }
  271    282   
    }
  272    283   
}
  273    284   
  274         -
async fn replay_body(events: VecDeque<Event>, mut sender: hyper_0_14::body::Sender) {
         285  +
async fn replay_body(events: VecDeque<Event>, mut sender: crate::test_util::body::Sender) {
  275    286   
    for event in events {
  276    287   
        match event.action {
  277    288   
            Action::Request { .. } => panic!(),
  278    289   
            Action::Response { .. } => panic!(),
  279    290   
            Action::Data {
  280    291   
                data,
  281    292   
                direction: Direction::Response,
  282    293   
            } => {
  283    294   
                sender
  284    295   
                    .send_data(Bytes::from(data.into_bytes()))
  285    296   
                    .await
  286    297   
                    .expect("this is in memory traffic that should not fail to send");
  287    298   
            }
  288    299   
            Action::Data {
  289    300   
                data: _data,
  290    301   
                direction: Direction::Request,
  291    302   
            } => {}
  292    303   
            Action::Eof {
  293    304   
                direction: Direction::Request,
  294    305   
                ..
  295    306   
            } => {}
  296    307   
            Action::Eof {
  297    308   
                direction: Direction::Response,
  298    309   
                ok: true,
  299    310   
                ..
  300    311   
            } => {
  301    312   
                drop(sender);
  302    313   
                break;
  303    314   
            }
  304    315   
            Action::Eof {
  305    316   
                direction: Direction::Response,
  306    317   
                ok: false,
  307    318   
                ..
  308    319   
            } => {
  309    320   
                sender.abort();
  310    321   
                break;
  311    322   
            }
  312    323   
        }
  313    324   
    }
  314    325   
}
  315    326   
  316    327   
impl HttpConnector for ReplayingClient {
  317    328   
    fn call(&self, mut request: HttpRequest) -> HttpConnectorFuture {
  318         -
        use http_body_04x::Body;
  319         -
  320    329   
        let event_id = self.next_id();
  321    330   
        tracing::debug!("received event {}: {request:?}", event_id.0);
  322    331   
        let mut events = match self.live_events.lock().unwrap().remove(&event_id) {
  323    332   
            Some(traffic) => traffic,
  324    333   
            None => {
  325    334   
                return HttpConnectorFuture::ready(Err(ConnectorError::other(
  326    335   
                    format!("no data for event {}. request: {:?}", event_id.0, request).into(),
  327    336   
                    None,
  328    337   
                )));
  329    338   
            }
  330    339   
        };
  331    340   
  332    341   
        let _initial_request = events.pop_front().unwrap();
  333         -
        let (sender, response_body) = hyper_0_14::Body::channel();
  334         -
        let body = SdkBody::from_body_0_4(response_body);
         342  +
        let (sender, body) = crate::test_util::body::channel_body();
  335    343   
        let recording = self.recorded_requests.clone();
  336    344   
        let recorded_request = tokio::spawn(async move {
  337    345   
            let mut data_read = vec![];
  338         -
            while let Some(data) = request.body_mut().data().await {
         346  +
            while let Some(data) = crate::test_util::body::next_data_frame(request.body_mut()).await
         347  +
            {
  339    348   
                data_read
  340    349   
                    .extend_from_slice(data.expect("in memory request should not fail").as_ref())
  341    350   
            }
  342    351   
            request
  343         -
                .try_into_http02x()
         352  +
                .try_into_http1x()
  344    353   
                .unwrap()
  345    354   
                .map(|_body| Bytes::from(data_read))
  346    355   
        });
  347    356   
        let mut recorded_request = Waitable::Loading(recorded_request);
  348    357   
        let fut = async move {
  349    358   
            let resp: Result<_, ConnectorError> = loop {
  350    359   
                let event = events
  351    360   
                    .pop_front()
  352    361   
                    .expect("no events, needed a response event");
  353    362   
                match event.action {
  354    363   
                    // to ensure deterministic behavior if the request EOF happens first in the log,
  355    364   
                    // wait for the request body to be done before returning a response.
  356    365   
                    Action::Eof {
  357    366   
                        direction: Direction::Request,
  358    367   
                        ..
  359    368   
                    } => {
  360    369   
                        recorded_request.wait().await;
  361    370   
                    }
  362    371   
                    Action::Request { .. } => panic!("invalid"),
  363    372   
                    Action::Response {
  364    373   
                        response: Err(error),
  365    374   
                    } => break Err(ConnectorError::other(error.0.into(), None)),
  366    375   
                    Action::Response {
  367    376   
                        response: Ok(response),
  368    377   
                    } => {
  369         -
                        let mut builder = http_02x::Response::builder().status(response.status);
         378  +
                        let mut builder = http_1x::Response::builder().status(response.status);
  370    379   
                        for (name, values) in response.headers {
  371    380   
                            for value in values {
  372    381   
                                builder = builder.header(&name, &value);
  373    382   
                            }
  374    383   
                        }
  375    384   
                        tokio::spawn(async move {
  376    385   
                            replay_body(events, sender).await;
  377    386   
                            // insert the finalized body into
  378    387   
                        });
  379    388   
                        break Ok(HttpResponse::try_from(

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-http-client/src/test_util/infallible.rs

Renamed from tmp-codegen-diff/aws-sdk/sdk/aws-smithy-runtime/src/client/http/test_util/infallible.rs

@@ -1,1 +83,84 @@
   14     14   
use aws_smithy_runtime_api::shared::IntoShared;
   15     15   
use aws_smithy_types::body::SdkBody;
   16     16   
use std::fmt;
   17     17   
use std::sync::Arc;
   18     18   
   19     19   
/// Create a [`SharedHttpClient`] from `Fn(http:Request) -> http::Response`
   20     20   
///
   21     21   
/// # Examples
   22     22   
///
   23     23   
/// ```rust
   24         -
/// use aws_smithy_runtime::client::http::test_util::infallible_client_fn;
   25         -
/// let http_client = infallible_client_fn(|_req| http_02x::Response::builder().status(200).body("OK!").unwrap());
          24  +
/// # use http_1x as http;
          25  +
/// use aws_smithy_http_client::test_util::infallible_client_fn;
          26  +
/// let http_client = infallible_client_fn(|_req| http::Response::builder().status(200).body("OK!").unwrap());
   26     27   
/// ```
   27     28   
pub fn infallible_client_fn<B>(
   28         -
    f: impl Fn(http_02x::Request<SdkBody>) -> http_02x::Response<B> + Send + Sync + 'static,
          29  +
    f: impl Fn(http_1x::Request<SdkBody>) -> http_1x::Response<B> + Send + Sync + 'static,
   29     30   
) -> SharedHttpClient
   30     31   
where
   31     32   
    B: Into<SdkBody>,
   32     33   
{
   33     34   
    InfallibleClientFn::new(f).into_shared()
   34     35   
}
   35     36   
   36     37   
#[derive(Clone)]
   37     38   
struct InfallibleClientFn {
   38     39   
    #[allow(clippy::type_complexity)]
   39     40   
    response: Arc<
   40         -
        dyn Fn(http_02x::Request<SdkBody>) -> Result<http_02x::Response<SdkBody>, ConnectorError>
          41  +
        dyn Fn(http_1x::Request<SdkBody>) -> Result<http_1x::Response<SdkBody>, ConnectorError>
   41     42   
            + Send
   42     43   
            + Sync,
   43     44   
    >,
   44     45   
}
   45     46   
   46     47   
impl fmt::Debug for InfallibleClientFn {
   47     48   
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
   48     49   
        f.debug_struct("InfallibleClientFn").finish()
   49     50   
    }
   50     51   
}
   51     52   
   52     53   
impl InfallibleClientFn {
   53     54   
    fn new<B: Into<SdkBody>>(
   54         -
        f: impl Fn(http_02x::Request<SdkBody>) -> http_02x::Response<B> + Send + Sync + 'static,
          55  +
        f: impl Fn(http_1x::Request<SdkBody>) -> http_1x::Response<B> + Send + Sync + 'static,
   55     56   
    ) -> Self {
   56     57   
        Self {
   57     58   
            response: Arc::new(move |request| Ok(f(request).map(|b| b.into()))),
   58     59   
        }
   59     60   
    }
   60     61   
}
   61     62   
   62     63   
impl HttpConnector for InfallibleClientFn {
   63     64   
    fn call(&self, request: HttpRequest) -> HttpConnectorFuture {
   64     65   
        HttpConnectorFuture::ready(
   65         -
            (self.response)(request.try_into_http02x().unwrap())
          66  +
            (self.response)(request.try_into_http1x().unwrap())
   66     67   
                .map(|res| HttpResponse::try_from(res).unwrap()),
   67     68   
        )
   68     69   
    }
   69     70   
}
   70     71   
   71     72   
impl HttpClient for InfallibleClientFn {
   72     73   
    fn http_connector(
   73     74   
        &self,
   74     75   
        _: &HttpConnectorSettings,
   75     76   
        _: &RuntimeComponents,

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-http-client/src/test_util/legacy_infallible.rs

@@ -0,1 +0,83 @@
           1  +
/*
           2  +
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
           3  +
 * SPDX-License-Identifier: Apache-2.0
           4  +
 */
           5  +
           6  +
use aws_smithy_runtime_api::client::connector_metadata::ConnectorMetadata;
           7  +
use aws_smithy_runtime_api::client::http::{
           8  +
    HttpClient, HttpConnector, HttpConnectorFuture, HttpConnectorSettings, SharedHttpClient,
           9  +
    SharedHttpConnector,
          10  +
};
          11  +
use aws_smithy_runtime_api::client::orchestrator::{HttpRequest, HttpResponse};
          12  +
use aws_smithy_runtime_api::client::result::ConnectorError;
          13  +
use aws_smithy_runtime_api::client::runtime_components::RuntimeComponents;
          14  +
use aws_smithy_runtime_api::shared::IntoShared;
          15  +
use aws_smithy_types::body::SdkBody;
          16  +
use std::fmt;
          17  +
use std::sync::Arc;
          18  +
          19  +
/// Create a [`SharedHttpClient`] from `Fn(http:Request) -> http::Response`
          20  +
///
          21  +
/// # Examples
          22  +
///
          23  +
/// ```rust
          24  +
/// use aws_smithy_http_client::test_util::legacy_infallible::infallible_client_fn;
          25  +
/// let http_client = infallible_client_fn(|_req| http_02x::Response::builder().status(200).body("OK!").unwrap());
          26  +
/// ```
          27  +
pub fn infallible_client_fn<B>(
          28  +
    f: impl Fn(http_02x::Request<SdkBody>) -> http_02x::Response<B> + Send + Sync + 'static,
          29  +
) -> SharedHttpClient
          30  +
where
          31  +
    B: Into<SdkBody>,
          32  +
{
          33  +
    InfallibleClientFn::new(f).into_shared()
          34  +
}
          35  +
          36  +
#[derive(Clone)]
          37  +
struct InfallibleClientFn {
          38  +
    #[allow(clippy::type_complexity)]
          39  +
    response: Arc<
          40  +
        dyn Fn(http_02x::Request<SdkBody>) -> Result<http_02x::Response<SdkBody>, ConnectorError>
          41  +
            + Send
          42  +
            + Sync,
          43  +
    >,
          44  +
}
          45  +
          46  +
impl fmt::Debug for InfallibleClientFn {
          47  +
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
          48  +
        f.debug_struct("InfallibleClientFn").finish()
          49  +
    }
          50  +
}
          51  +
          52  +
impl InfallibleClientFn {
          53  +
    fn new<B: Into<SdkBody>>(
          54  +
        f: impl Fn(http_02x::Request<SdkBody>) -> http_02x::Response<B> + Send + Sync + 'static,
          55  +
    ) -> Self {
          56  +
        Self {
          57  +
            response: Arc::new(move |request| Ok(f(request).map(|b| b.into()))),
          58  +
        }
          59  +
    }
          60  +
}
          61  +
          62  +
impl HttpConnector for InfallibleClientFn {
          63  +
    fn call(&self, request: HttpRequest) -> HttpConnectorFuture {
          64  +
        HttpConnectorFuture::ready(
          65  +
            (self.response)(request.try_into_http02x().unwrap())
          66  +
                .map(|res| HttpResponse::try_from(res).unwrap()),
          67  +
        )
          68  +
    }
          69  +
}
          70  +
          71  +
impl HttpClient for InfallibleClientFn {
          72  +
    fn http_connector(
          73  +
        &self,
          74  +
        _: &HttpConnectorSettings,
          75  +
        _: &RuntimeComponents,
          76  +
    ) -> SharedHttpConnector {
          77  +
        self.clone().into_shared()
          78  +
    }
          79  +
          80  +
    fn connector_metadata(&self) -> Option<ConnectorMetadata> {
          81  +
        Some(ConnectorMetadata::new("infallible-client", None))
          82  +
    }
          83  +
}

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-http-client/src/test_util/never.rs

Renamed from tmp-codegen-diff/aws-sdk/sdk/aws-smithy-runtime/src/client/http/test_util/never.rs

@@ -35,35 +176,246 @@
   55     55   
        self.clone().into_shared()
   56     56   
    }
   57     57   
   58     58   
    fn connector_metadata(&self) -> Option<ConnectorMetadata> {
   59     59   
        Some(ConnectorMetadata::new("never-client", None))
   60     60   
    }
   61     61   
}
   62     62   
   63     63   
/// A TCP connector that never connects.
   64     64   
// In the future, this can be available for multiple hyper version feature flags, with the impls gated between individual features
   65         -
#[cfg(feature = "connector-hyper-0-14-x")]
          65  +
#[cfg(any(feature = "hyper-014", feature = "default-client"))]
   66     66   
#[derive(Clone, Debug, Default)]
   67     67   
pub struct NeverTcpConnector;
   68     68   
   69         -
#[cfg(feature = "connector-hyper-0-14-x")]
          69  +
#[cfg(any(feature = "hyper-014", feature = "default-client"))]
   70     70   
impl NeverTcpConnector {
   71     71   
    /// Creates a new `NeverTcpConnector`.
   72     72   
    pub fn new() -> Self {
   73     73   
        Self
   74     74   
    }
   75     75   
}
   76     76   
   77         -
#[cfg(feature = "connector-hyper-0-14-x")]
          77  +
#[cfg(feature = "hyper-014")]
   78     78   
impl hyper_0_14::service::Service<http_02x::Uri> for NeverTcpConnector {
   79         -
    type Response = connection::NeverTcpConnection;
          79  +
    type Response = hyper_014_support::NeverTcpConnection;
   80     80   
    type Error = aws_smithy_runtime_api::box_error::BoxError;
   81     81   
    type Future = std::pin::Pin<
   82     82   
        Box<dyn std::future::Future<Output = Result<Self::Response, Self::Error>> + Send + Sync>,
   83     83   
    >;
   84     84   
   85     85   
    fn poll_ready(
   86     86   
        &mut self,
   87     87   
        _: &mut std::task::Context<'_>,
   88     88   
    ) -> std::task::Poll<Result<(), Self::Error>> {
   89     89   
        std::task::Poll::Ready(Ok(()))
   90     90   
    }
   91     91   
   92     92   
    fn call(&mut self, _: http_02x::Uri) -> Self::Future {
   93     93   
        Box::pin(async {
   94     94   
            Never::new().await;
   95     95   
            unreachable!()
   96     96   
        })
   97     97   
    }
   98     98   
}
   99     99   
  100         -
#[cfg(feature = "connector-hyper-0-14-x")]
  101         -
mod connection {
         100  +
#[cfg(feature = "default-client")]
         101  +
mod hyper1_support {
         102  +
    use super::NeverTcpConnector;
         103  +
    use aws_smithy_async::future::never::Never;
         104  +
    use aws_smithy_runtime_api::client::http::SharedHttpClient;
         105  +
    use aws_smithy_runtime_api::client::result::ConnectorError;
         106  +
    use http_1x::Uri;
         107  +
    use hyper_util::rt::TokioIo;
         108  +
    use std::future::Future;
         109  +
    use std::pin::Pin;
         110  +
    use std::task::{Context, Poll};
         111  +
    use tokio::net::TcpStream;
         112  +
         113  +
    impl tower::Service<Uri> for NeverTcpConnector {
         114  +
        type Response = TokioIo<TcpStream>;
         115  +
        type Error = ConnectorError;
         116  +
        type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
         117  +
         118  +
        fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
         119  +
            Poll::Ready(Ok(()))
         120  +
        }
         121  +
         122  +
        fn call(&mut self, _uri: Uri) -> Self::Future {
         123  +
            Box::pin(async move {
         124  +
                Never::new().await;
         125  +
                unreachable!()
         126  +
            })
         127  +
        }
         128  +
    }
         129  +
         130  +
    impl NeverTcpConnector {
         131  +
        /// Convert this connector into a usable HTTP client for testing
         132  +
        #[doc(hidden)]
         133  +
        pub fn into_client(self) -> SharedHttpClient {
         134  +
            crate::client::build_with_tcp_conn_fn(None, NeverTcpConnector::new)
         135  +
        }
         136  +
    }
         137  +
}
         138  +
         139  +
#[cfg(feature = "hyper-014")]
         140  +
mod hyper_014_support {
  102    141   
    use hyper_0_14::client::connect::{Connected, Connection};
  103    142   
    use std::io::Error;
  104    143   
    use std::pin::Pin;
  105    144   
    use std::task::{Context, Poll};
  106    145   
    use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
  107    146   
  108    147   
    /// A connection type that appeases hyper's trait bounds for a TCP connector, but will panic if any of its traits are used.
  109    148   
    #[non_exhaustive]
  110    149   
    #[derive(Debug, Default)]
  111    150   
    pub struct NeverTcpConnection;
  112    151   
  113    152   
    impl Connection for NeverTcpConnection {
  114    153   
        fn connected(&self) -> Connected {
  115    154   
            unreachable!()
  116    155   
        }
  117    156   
    }
  118    157   
  119    158   
    impl AsyncRead for NeverTcpConnection {
  120    159   
        fn poll_read(
  121    160   
            self: Pin<&mut Self>,
  122    161   
            _cx: &mut Context<'_>,
  123    162   
            _buf: &mut ReadBuf<'_>,
  124    163   
        ) -> Poll<std::io::Result<()>> {
  125    164   
            unreachable!()
  126    165   
        }
  127    166   
    }
  128    167   
  129    168   
    impl AsyncWrite for NeverTcpConnection {
  130    169   
        fn poll_write(
  131    170   
            self: Pin<&mut Self>,
  132    171   
            _cx: &mut Context<'_>,
  133    172   
            _buf: &[u8],
  134    173   
        ) -> Poll<Result<usize, Error>> {
  135    174   
            unreachable!()
  136    175   
        }
  137    176   
  138    177   
        fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), Error>> {
  139    178   
            unreachable!()
  140    179   
        }
  141    180   
  142    181   
        fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), Error>> {
  143    182   
            unreachable!()
  144    183   
        }
  145    184   
    }
  146    185   
}
  147    186   
  148         -
#[cfg(all(test, feature = "connector-hyper-0-14-x"))]
  149         -
#[tokio::test]
  150         -
async fn never_tcp_connector_plugs_into_hyper_014() {
  151         -
    use crate::client::http::hyper_014::HyperClientBuilder;
         187  +
#[cfg(test)]
         188  +
mod test {
  152    189   
    use aws_smithy_async::rt::sleep::TokioSleep;
  153    190   
    use aws_smithy_async::time::SystemTimeSource;
         191  +
    use aws_smithy_runtime_api::client::http::{HttpClient, HttpConnector, HttpConnectorSettings};
         192  +
    use aws_smithy_runtime_api::client::orchestrator::HttpRequest;
  154    193   
    use aws_smithy_runtime_api::client::runtime_components::RuntimeComponentsBuilder;
  155    194   
    use std::time::Duration;
  156    195   
  157         -
    // it should compile
  158         -
    let client = HyperClientBuilder::new().build(NeverTcpConnector::new());
  159         -
    let components = RuntimeComponentsBuilder::for_tests()
  160         -
        .with_sleep_impl(Some(TokioSleep::new()))
  161         -
        .with_time_source(Some(SystemTimeSource::new()))
  162         -
        .build()
  163         -
        .unwrap();
  164         -
    let http_connector = client.http_connector(
  165         -
        &HttpConnectorSettings::builder()
  166         -
            .connect_timeout(Duration::from_millis(100))
  167         -
            .build(),
  168         -
        &components,
  169         -
    );
  170         -
  171         -
    let err = http_connector
  172         -
        .call(HttpRequest::get("http://fakeuri.com").unwrap())
  173         -
        .await
  174         -
        .expect_err("it should time out");
  175         -
    assert!(dbg!(err).is_timeout());
         196  +
    #[cfg(feature = "hyper-014")]
         197  +
    #[tokio::test]
         198  +
    async fn never_tcp_connector_plugs_into_hyper_014() {
         199  +
        use super::NeverTcpConnector;
         200  +
        use crate::hyper_014::HyperClientBuilder;
         201  +
         202  +
        // it should compile
         203  +
        let client = HyperClientBuilder::new().build(NeverTcpConnector::new());
         204  +
        let components = RuntimeComponentsBuilder::for_tests()
         205  +
            .with_sleep_impl(Some(TokioSleep::new()))
         206  +
            .with_time_source(Some(SystemTimeSource::new()))
         207  +
            .build()
         208  +
            .unwrap();
         209  +
        let http_connector = client.http_connector(
         210  +
            &HttpConnectorSettings::builder()
         211  +
                .connect_timeout(Duration::from_millis(100))
         212  +
                .build(),
         213  +
            &components,
         214  +
        );
         215  +
         216  +
        let err = http_connector
         217  +
            .call(HttpRequest::get("http://fakeuri.com").unwrap())
         218  +
            .await
         219  +
            .expect_err("it should time out");
         220  +
        assert!(dbg!(err).is_timeout());
         221  +
    }
         222  +
         223  +
    #[cfg(feature = "default-client")]
         224  +
    #[tokio::test]
         225  +
    async fn never_tcp_connector_plugs_into_hyper_1() {
         226  +
        use super::NeverTcpConnector;
         227  +
        let client = NeverTcpConnector::new().into_client();
         228  +
        let components = RuntimeComponentsBuilder::for_tests()
         229  +
            .with_sleep_impl(Some(TokioSleep::new()))
         230  +
            .with_time_source(Some(SystemTimeSource::new()))
         231  +
            .build()
         232  +
            .unwrap();
         233  +
        let http_connector = client.http_connector(
         234  +
            &HttpConnectorSettings::builder()
         235  +
                .connect_timeout(Duration::from_millis(100))
         236  +
                .build(),
         237  +
            &components,
         238  +
        );
         239  +
         240  +
        let err = http_connector
         241  +
            .call(HttpRequest::get("http://fakeuri.com").unwrap())
         242  +
            .await
         243  +
            .expect_err("it should time out");
         244  +
        assert!(dbg!(err).is_timeout());
         245  +
    }
  176    246   
}

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-http-client/src/test_util/replay.rs

Renamed from tmp-codegen-diff/aws-sdk/sdk/aws-smithy-runtime/src/client/http/test_util/replay.rs

@@ -1,1 +45,45 @@
    5      5   
    6      6   
use aws_smithy_protocol_test::{assert_ok, validate_body, MediaType};
    7      7   
use aws_smithy_runtime_api::client::connector_metadata::ConnectorMetadata;
    8      8   
use aws_smithy_runtime_api::client::http::{
    9      9   
    HttpClient, HttpConnector, HttpConnectorFuture, HttpConnectorSettings, SharedHttpConnector,
   10     10   
};
   11     11   
use aws_smithy_runtime_api::client::orchestrator::{HttpRequest, HttpResponse};
   12     12   
use aws_smithy_runtime_api::client::result::ConnectorError;
   13     13   
use aws_smithy_runtime_api::client::runtime_components::RuntimeComponents;
   14     14   
use aws_smithy_runtime_api::shared::IntoShared;
   15         -
use http_02x::header::CONTENT_TYPE;
          15  +
use http_1x::header::CONTENT_TYPE;
   16     16   
use std::ops::Deref;
   17     17   
use std::sync::{Arc, Mutex, MutexGuard};
   18     18   
   19     19   
type ReplayEvents = Vec<ReplayEvent>;
   20     20   
   21     21   
pub(crate) const DEFAULT_RELAXED_HEADERS: &[&str] = &["x-amz-user-agent", "authorization"];
   22     22   
   23     23   
/// Test data for the [`StaticReplayClient`].
   24     24   
///
   25     25   
/// Each `ReplayEvent` represents one HTTP request and response
@@ -92,92 +181,182 @@
  112    112   
/// the actual request was. The actual request is recorded, but otherwise not validated against what
  113    113   
/// is in the [`ReplayEvent`]. Later, after the client is finished being used, the
  114    114   
/// [`assert_requests_match`] method can be used to validate the requests.
  115    115   
///
  116    116   
/// This utility is simpler than [DVR], and thus, is good for tests that don't need
  117    117   
/// to record and replay real traffic.
  118    118   
///
  119    119   
/// # Example
  120    120   
///
  121    121   
/// ```no_run
  122         -
/// use aws_smithy_runtime::client::http::test_util::{ReplayEvent, StaticReplayClient};
         122  +
/// # use http_1x as http;
         123  +
/// use aws_smithy_http_client::test_util::{ReplayEvent, StaticReplayClient};
  123    124   
/// use aws_smithy_types::body::SdkBody;
  124    125   
///
  125    126   
/// let http_client = StaticReplayClient::new(vec![
  126    127   
///     // Event that covers the first request/response
  127    128   
///     ReplayEvent::new(
  128    129   
///         // If `assert_requests_match` is called later, then this request will be matched
  129    130   
///         // against the actual request that was made.
  130         -
///         http_02x::Request::builder().uri("http://localhost:1234/foo").body(SdkBody::empty()).unwrap(),
         131  +
///         http::Request::builder().uri("http://localhost:1234/foo").body(SdkBody::empty()).unwrap(),
  131    132   
///         // This response will be given to the first request regardless of whether it matches the request above.
  132         -
///         http_02x::Response::builder().status(200).body(SdkBody::empty()).unwrap(),
         133  +
///         http::Response::builder().status(200).body(SdkBody::empty()).unwrap(),
  133    134   
///     ),
  134    135   
///     // The next ReplayEvent covers the second request/response pair...
  135    136   
/// ]);
  136    137   
///
  137    138   
/// # /*
  138    139   
/// let config = my_generated_client::Config::builder()
  139    140   
///     .http_client(http_client.clone())
  140    141   
///     .build();
  141    142   
/// let client = my_generated_client::Client::from_conf(config);
  142    143   
/// # */
  143    144   
///
  144    145   
/// // Do stuff with client...
  145    146   
///
  146    147   
/// // When you're done, assert the requests match what you expected
  147    148   
/// http_client.assert_requests_match(&[]);
  148    149   
/// ```
  149    150   
///
  150    151   
/// [`assert_requests_match`]: StaticReplayClient::assert_requests_match
  151         -
/// [DVR]: crate::client::http::test_util::dvr
         152  +
/// [DVR]: crate::test_util::dvr
  152    153   
#[derive(Clone, Debug)]
  153    154   
pub struct StaticReplayClient {
  154    155   
    data: Arc<Mutex<ReplayEvents>>,
  155    156   
    requests: Arc<Mutex<Vec<ValidateRequest>>>,
  156    157   
}
  157    158   
  158    159   
impl StaticReplayClient {
  159    160   
    /// Creates a new event connector.
  160    161   
    pub fn new(mut data: ReplayEvents) -> Self {
  161    162   
        data.reverse();
@@ -254,255 +300,301 @@
  274    275   
        self.clone().into_shared()
  275    276   
    }
  276    277   
  277    278   
    fn connector_metadata(&self) -> Option<ConnectorMetadata> {
  278    279   
        Some(ConnectorMetadata::new("static-replay-client", None))
  279    280   
    }
  280    281   
}
  281    282   
  282    283   
#[cfg(test)]
  283    284   
mod test {
  284         -
    use crate::client::http::test_util::{ReplayEvent, StaticReplayClient};
         285  +
    use crate::test_util::{ReplayEvent, StaticReplayClient};
  285    286   
    use aws_smithy_types::body::SdkBody;
  286    287   
  287    288   
    #[test]
  288    289   
    fn create_from_either_http_type() {
  289    290   
        let _client = StaticReplayClient::new(vec![ReplayEvent::new(
  290         -
            http1::Request::builder()
         291  +
            http_1x::Request::builder()
  291    292   
                .uri("test")
  292    293   
                .body(SdkBody::from("hello"))
  293    294   
                .unwrap(),
  294         -
            http1::Response::builder()
         295  +
            http_1x::Response::builder()
  295    296   
                .status(200)
  296    297   
                .body(SdkBody::from("hello"))
  297    298   
                .unwrap(),
  298    299   
        )]);
  299    300   
    }
  300    301   
}

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-http-client/src/test_util/wire.rs

Renamed from tmp-codegen-diff/aws-sdk/sdk/aws-smithy-runtime/src/client/http/test_util/wire.rs

@@ -1,1 +0,425 @@
    5      5   
    6      6   
//! Utilities for mocking at the socket level
    7      7   
//!
    8      8   
//! Other tools in this module actually operate at the `http::Request` / `http::Response` level. This
    9      9   
//! is useful, but it shortcuts the HTTP implementation (e.g. Hyper). [`WireMockServer`] binds
   10     10   
//! to an actual socket on the host.
   11     11   
//!
   12     12   
//! # Examples
   13     13   
//! ```no_run
   14     14   
//! use aws_smithy_runtime_api::client::http::HttpConnectorSettings;
   15         -
//! use aws_smithy_runtime::client::http::test_util::wire::{check_matches, ReplayedEvent, WireMockServer};
   16         -
//! use aws_smithy_runtime::{match_events, ev};
          15  +
//! use aws_smithy_http_client::test_util::wire::{check_matches, ReplayedEvent, WireMockServer};
          16  +
//! use aws_smithy_http_client::{match_events, ev};
   17     17   
//! # async fn example() {
   18     18   
//!
   19     19   
//! // This connection binds to a local address
   20     20   
//! let mock = WireMockServer::start(vec![
   21     21   
//!     ReplayedEvent::status(503),
   22     22   
//!     ReplayedEvent::status(200)
   23     23   
//! ]).await;
   24     24   
//!
   25     25   
//! # /*
   26     26   
//! // Create a client using the wire mock
   27     27   
//! let config = my_generated_client::Config::builder()
   28     28   
//!     .http_client(mock.http_client())
   29     29   
//!     .build();
   30     30   
//! let client = Client::from_conf(config);
   31     31   
//!
   32     32   
//! // ... do something with <client>
   33     33   
//! # */
   34     34   
//!
   35     35   
//! // assert that you got the events you expected
   36     36   
//! match_events!(ev!(dns), ev!(connect), ev!(http(200)))(&mock.events());
   37     37   
//! # }
   38     38   
//! ```
   39     39   
   40     40   
#![allow(missing_docs)]
   41     41   
   42         -
use crate::client::http::hyper_014::HyperClientBuilder;
   43     42   
use aws_smithy_async::future::never::Never;
   44     43   
use aws_smithy_async::future::BoxFuture;
   45     44   
use aws_smithy_runtime_api::client::http::SharedHttpClient;
   46         -
use aws_smithy_runtime_api::shared::IntoShared;
   47     45   
use bytes::Bytes;
   48         -
use hyper_0_14::client::connect::dns::Name;
   49         -
use hyper_0_14::server::conn::AddrStream;
   50         -
use hyper_0_14::service::{make_service_fn, service_fn, Service};
          46  +
use http_body_util::Full;
          47  +
use hyper::service::service_fn;
          48  +
use hyper_util::client::legacy::connect::dns::Name;
          49  +
use hyper_util::rt::{TokioExecutor, TokioIo};
          50  +
use hyper_util::server::graceful::{GracefulConnection, GracefulShutdown};
   51     51   
use std::collections::HashSet;
   52     52   
use std::convert::Infallible;
   53     53   
use std::error::Error;
          54  +
use std::future::Future;
   54     55   
use std::iter::Once;
   55         -
use std::net::{SocketAddr, TcpListener};
          56  +
use std::net::SocketAddr;
   56     57   
use std::sync::{Arc, Mutex};
   57     58   
use std::task::{Context, Poll};
   58         -
use tokio::spawn;
          59  +
use tokio::net::TcpListener;
   59     60   
use tokio::sync::oneshot;
   60     61   
   61     62   
/// An event recorded by [`WireMockServer`].
   62     63   
#[non_exhaustive]
   63     64   
#[derive(Debug, Clone)]
   64     65   
pub enum RecordedEvent {
   65     66   
    DnsLookup(String),
   66     67   
    NewConnection,
   67     68   
    Response(ReplayedEvent),
   68     69   
}
   69     70   
   70     71   
type Matcher = (
   71     72   
    Box<dyn Fn(&RecordedEvent) -> Result<(), Box<dyn Error>>>,
   72     73   
    &'static str,
   73     74   
);
   74     75   
   75     76   
/// This method should only be used by the macro
   76     77   
pub fn check_matches(events: &[RecordedEvent], matchers: &[Matcher]) {
   77     78   
    let mut events_iter = events.iter();
   78     79   
    let mut matcher_iter = matchers.iter();
   79     80   
    let mut idx = -1;
   80     81   
    loop {
   81     82   
        idx += 1;
   82     83   
        let bail = |err: Box<dyn Error>| panic!("failed on event {}:\n  {}", idx, err);
   83     84   
        match (events_iter.next(), matcher_iter.next()) {
   84     85   
            (Some(event), Some((matcher, _msg))) => matcher(event).unwrap_or_else(bail),
   85     86   
            (None, None) => return,
   86     87   
            (Some(event), None) => {
   87     88   
                bail(format!("got {:?} but no more events were expected", event).into())
   88     89   
            }
   89     90   
            (None, Some((_expect, msg))) => {
   90     91   
                bail(format!("expected {:?} but no more events were expected", msg).into())
   91     92   
            }
   92     93   
        }
   93     94   
    }
   94     95   
}
   95     96   
   96     97   
#[macro_export]
   97     98   
macro_rules! matcher {
   98     99   
    ($expect:tt) => {
   99    100   
        (
  100         -
            Box::new(
  101         -
                |event: &$crate::client::http::test_util::wire::RecordedEvent| {
  102         -
                    if !matches!(event, $expect) {
  103         -
                        return Err(format!(
  104         -
                            "expected `{}` but got {:?}",
  105         -
                            stringify!($expect),
  106         -
                            event
  107         -
                        )
  108         -
                        .into());
  109         -
                    }
  110         -
                    Ok(())
  111         -
                },
  112         -
            ),
         101  +
            Box::new(|event: &$crate::test_util::wire::RecordedEvent| {
         102  +
                if !matches!(event, $expect) {
         103  +
                    return Err(
         104  +
                        format!("expected `{}` but got {:?}", stringify!($expect), event).into(),
         105  +
                    );
         106  +
                }
         107  +
                Ok(())
         108  +
            }),
  113    109   
            stringify!($expect),
  114    110   
        )
  115    111   
    };
  116    112   
}
  117    113   
  118    114   
/// Helper macro to generate a series of test expectations
  119    115   
#[macro_export]
  120    116   
macro_rules! match_events {
  121    117   
        ($( $expect:pat),*) => {
  122    118   
            |events| {
  123         -
                $crate::client::http::test_util::wire::check_matches(events, &[$( $crate::matcher!($expect) ),*]);
         119  +
                $crate::test_util::wire::check_matches(events, &[$( $crate::matcher!($expect) ),*]);
  124    120   
            }
  125    121   
        };
  126    122   
    }
  127    123   
  128    124   
/// Helper to generate match expressions for events
  129    125   
#[macro_export]
  130    126   
macro_rules! ev {
  131    127   
    (http($status:expr)) => {
  132         -
        $crate::client::http::test_util::wire::RecordedEvent::Response(
  133         -
            $crate::client::http::test_util::wire::ReplayedEvent::HttpResponse {
         128  +
        $crate::test_util::wire::RecordedEvent::Response(
         129  +
            $crate::test_util::wire::ReplayedEvent::HttpResponse {
  134    130   
                status: $status,
  135    131   
                ..
  136    132   
            },
  137    133   
        )
  138    134   
    };
  139    135   
    (dns) => {
  140         -
        $crate::client::http::test_util::wire::RecordedEvent::DnsLookup(_)
         136  +
        $crate::test_util::wire::RecordedEvent::DnsLookup(_)
  141    137   
    };
  142    138   
    (connect) => {
  143         -
        $crate::client::http::test_util::wire::RecordedEvent::NewConnection
         139  +
        $crate::test_util::wire::RecordedEvent::NewConnection
  144    140   
    };
  145    141   
    (timeout) => {
  146         -
        $crate::client::http::test_util::wire::RecordedEvent::Response(
  147         -
            $crate::client::http::test_util::wire::ReplayedEvent::Timeout,
         142  +
        $crate::test_util::wire::RecordedEvent::Response(
         143  +
            $crate::test_util::wire::ReplayedEvent::Timeout,
  148    144   
        )
  149    145   
    };
  150    146   
}
  151    147   
  152    148   
pub use {ev, match_events, matcher};
  153    149   
  154    150   
#[non_exhaustive]
  155    151   
#[derive(Clone, Debug, PartialEq, Eq)]
  156    152   
pub enum ReplayedEvent {
  157    153   
    Timeout,
  158    154   
    HttpResponse { status: u16, body: Bytes },
  159    155   
}
  160    156   
  161    157   
impl ReplayedEvent {
  162    158   
    pub fn ok() -> Self {
  163    159   
        Self::HttpResponse {
  164    160   
            status: 200,
  165    161   
            body: Bytes::new(),
  166    162   
        }
  167    163   
    }
  168    164   
  169    165   
    pub fn with_body(body: impl AsRef<[u8]>) -> Self {
  170    166   
        Self::HttpResponse {
  171    167   
            status: 200,
  172    168   
            body: Bytes::copy_from_slice(body.as_ref()),
  173    169   
        }
  174    170   
    }
  175    171   
  176    172   
    pub fn status(status: u16) -> Self {
  177    173   
        Self::HttpResponse {
  178    174   
            status,
  179    175   
            body: Bytes::new(),
  180    176   
        }
  181    177   
    }
  182    178   
}
  183    179   
  184    180   
/// Test server that binds to 127.0.0.1:0
  185    181   
///
  186         -
/// See the [module docs](crate::client::http::test_util::wire) for a usage example.
         182  +
/// See the [module docs](crate::test_util::wire) for a usage example.
  187    183   
///
  188    184   
/// Usage:
  189    185   
/// - Call [`WireMockServer::start`] to start the server
  190    186   
/// - Use [`WireMockServer::http_client`] or [`dns_resolver`](WireMockServer::dns_resolver) to configure your client.
  191    187   
/// - Make requests to [`endpoint_url`](WireMockServer::endpoint_url).
  192    188   
/// - Once the test is complete, retrieve a list of events from [`WireMockServer::events`]
  193    189   
#[derive(Debug)]
  194    190   
pub struct WireMockServer {
  195    191   
    event_log: Arc<Mutex<Vec<RecordedEvent>>>,
  196    192   
    bind_addr: SocketAddr,
  197    193   
    // when the sender is dropped, that stops the server
  198    194   
    shutdown_hook: oneshot::Sender<()>,
  199    195   
}
  200    196   
         197  +
#[derive(Debug, Clone)]
         198  +
struct SharedGraceful {
         199  +
    graceful: Arc<Mutex<Option<hyper_util::server::graceful::GracefulShutdown>>>,
         200  +
}
         201  +
         202  +
impl SharedGraceful {
         203  +
    fn new() -> Self {
         204  +
        Self {
         205  +
            graceful: Arc::new(Mutex::new(Some(GracefulShutdown::new()))),
         206  +
        }
         207  +
    }
         208  +
         209  +
    fn watch<C: GracefulConnection>(&self, conn: C) -> impl Future<Output = C::Output> {
         210  +
        let graceful = self.graceful.lock().unwrap();
         211  +
        graceful
         212  +
            .as_ref()
         213  +
            .expect("graceful not shutdown")
         214  +
            .watch(conn)
         215  +
    }
         216  +
         217  +
    async fn shutdown(&self) {
         218  +
        let graceful = { self.graceful.lock().unwrap().take() };
         219  +
         220  +
        if let Some(graceful) = graceful {
         221  +
            graceful.shutdown().await;
         222  +
        }
         223  +
    }
         224  +
}
         225  +
  201    226   
impl WireMockServer {
  202    227   
    /// Start a wire mock server with the given events to replay.
  203    228   
    pub async fn start(mut response_events: Vec<ReplayedEvent>) -> Self {
  204         -
        let listener = TcpListener::bind("127.0.0.1:0").unwrap();
  205         -
        let (tx, rx) = oneshot::channel();
         229  +
        let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
         230  +
        let (tx, mut rx) = oneshot::channel();
  206    231   
        let listener_addr = listener.local_addr().unwrap();
  207    232   
        response_events.reverse();
  208    233   
        let response_events = Arc::new(Mutex::new(response_events));
  209    234   
        let handler_events = response_events;
  210    235   
        let wire_events = Arc::new(Mutex::new(vec![]));
  211    236   
        let wire_log_for_service = wire_events.clone();
  212    237   
        let poisoned_conns: Arc<Mutex<HashSet<SocketAddr>>> = Default::default();
  213         -
        let make_service = make_service_fn(move |connection: &AddrStream| {
         238  +
        let graceful = SharedGraceful::new();
         239  +
        let conn_builder = Arc::new(hyper_util::server::conn::auto::Builder::new(
         240  +
            TokioExecutor::new(),
         241  +
        ));
         242  +
         243  +
        let server = async move {
  214    244   
            let poisoned_conns = poisoned_conns.clone();
  215    245   
            let events = handler_events.clone();
  216    246   
            let wire_log = wire_log_for_service.clone();
  217         -
            let remote_addr = connection.remote_addr();
  218         -
            tracing::info!("established connection: {:?}", connection);
  219         -
            wire_log.lock().unwrap().push(RecordedEvent::NewConnection);
  220         -
            async move {
  221         -
                Ok::<_, Infallible>(service_fn(move |_: http_02x::Request<hyper_0_14::Body>| {
  222         -
                    if poisoned_conns.lock().unwrap().contains(&remote_addr) {
  223         -
                        tracing::error!("poisoned connection {:?} was reused!", &remote_addr);
  224         -
                        panic!("poisoned connection was reused!");
  225         -
                    }
  226         -
                    let next_event = events.clone().lock().unwrap().pop();
  227         -
                    let wire_log = wire_log.clone();
  228         -
                    let poisoned_conns = poisoned_conns.clone();
  229         -
                    async move {
  230         -
                        let next_event = next_event
  231         -
                            .unwrap_or_else(|| panic!("no more events! Log: {:?}", wire_log));
  232         -
                        wire_log
  233         -
                            .lock()
  234         -
                            .unwrap()
  235         -
                            .push(RecordedEvent::Response(next_event.clone()));
  236         -
                        if next_event == ReplayedEvent::Timeout {
  237         -
                            tracing::info!("{} is poisoned", remote_addr);
  238         -
                            poisoned_conns.lock().unwrap().insert(remote_addr);
  239         -
                        }
  240         -
                        tracing::debug!("replying with {:?}", next_event);
  241         -
                        let event = generate_response_event(next_event).await;
  242         -
                        dbg!(event)
         247  +
            loop {
         248  +
                tokio::select! {
         249  +
                    Ok((stream, remote_addr)) = listener.accept() => {
         250  +
                        tracing::info!("established connection: {:?}", remote_addr);
         251  +
                        let poisoned_conns = poisoned_conns.clone();
         252  +
                        let events = events.clone();
         253  +
                        let wire_log = wire_log.clone();
         254  +
                        wire_log.lock().unwrap().push(RecordedEvent::NewConnection);
         255  +
                        let io = TokioIo::new(stream);
         256  +
         257  +
                        let svc = service_fn(move |_req| {
         258  +
                            let poisoned_conns = poisoned_conns.clone();
         259  +
                            let events = events.clone();
         260  +
                            let wire_log = wire_log.clone();
         261  +
                            if poisoned_conns.lock().unwrap().contains(&remote_addr) {
         262  +
                                tracing::error!("poisoned connection {:?} was reused!", &remote_addr);
         263  +
                                panic!("poisoned connection was reused!");
         264  +
                            }
         265  +
                            let next_event = events.clone().lock().unwrap().pop();
         266  +
                            async move {
         267  +
                                let next_event = next_event
         268  +
                                    .unwrap_or_else(|| panic!("no more events! Log: {:?}", wire_log));
         269  +
         270  +
                                wire_log
         271  +
                                    .lock()
         272  +
                                    .unwrap()
         273  +
                                    .push(RecordedEvent::Response(next_event.clone()));
         274  +
         275  +
                                if next_event == ReplayedEvent::Timeout {
         276  +
                                    tracing::info!("{} is poisoned", remote_addr);
         277  +
                                    poisoned_conns.lock().unwrap().insert(remote_addr);
         278  +
                                }
         279  +
                                tracing::debug!("replying with {:?}", next_event);
         280  +
                                let event = generate_response_event(next_event).await;
         281  +
                                dbg!(event)
         282  +
                            }
         283  +
                        });
         284  +
         285  +
                        let conn_builder = conn_builder.clone();
         286  +
                        let graceful = graceful.clone();
         287  +
                        tokio::spawn(async move {
         288  +
                            let conn = conn_builder.serve_connection(io, svc);
         289  +
                            let fut = graceful.watch(conn);
         290  +
                            if let Err(e) = fut.await {
         291  +
                                panic!("Error serving connection: {:?}", e);
         292  +
                            }
         293  +
                        });
         294  +
                    },
         295  +
                    _ = &mut rx => {
         296  +
                        tracing::info!("wire server: shutdown signalled");
         297  +
                        graceful.shutdown().await;
         298  +
                        tracing::info!("wire server: shutdown complete!");
         299  +
                        break;
  243    300   
                    }
  244         -
                }))
         301  +
                }
  245    302   
            }
  246         -
        });
  247         -
        let server = hyper_0_14::Server::from_tcp(listener)
  248         -
            .unwrap()
  249         -
            .serve(make_service)
  250         -
            .with_graceful_shutdown(async {
  251         -
                rx.await.ok();
  252         -
                tracing::info!("server shutdown!");
  253         -
            });
  254         -
        spawn(server);
         303  +
        };
         304  +
         305  +
        tokio::spawn(server);
  255    306   
        Self {
  256    307   
            event_log: wire_events,
  257    308   
            bind_addr: listener_addr,
  258    309   
            shutdown_hook: tx,
  259    310   
        }
  260    311   
    }
  261    312   
  262    313   
    /// Retrieve the events recorded by this connection
  263    314   
    pub fn events(&self) -> Vec<RecordedEvent> {
  264    315   
        self.event_log.lock().unwrap().clone()
  265    316   
    }
  266    317   
  267    318   
    fn bind_addr(&self) -> SocketAddr {
  268    319   
        self.bind_addr
  269    320   
    }
  270    321   
  271    322   
    pub fn dns_resolver(&self) -> LoggingDnsResolver {
  272    323   
        let event_log = self.event_log.clone();
  273    324   
        let bind_addr = self.bind_addr;
  274         -
        LoggingDnsResolver {
         325  +
        LoggingDnsResolver(InnerDnsResolver {
  275    326   
            log: event_log,
  276    327   
            socket_addr: bind_addr,
  277         -
        }
         328  +
        })
  278    329   
    }
  279    330   
  280    331   
    /// Prebuilt [`HttpClient`](aws_smithy_runtime_api::client::http::HttpClient) with correctly wired DNS resolver.
  281    332   
    ///
  282    333   
    /// **Note**: This must be used in tandem with [`Self::dns_resolver`]
  283    334   
    pub fn http_client(&self) -> SharedHttpClient {
  284         -
        HyperClientBuilder::new()
  285         -
            .build(hyper_0_14::client::HttpConnector::new_with_resolver(
  286         -
                self.dns_resolver(),
  287         -
            ))
  288         -
            .into_shared()
         335  +
        let resolver = self.dns_resolver();
         336  +
        crate::client::build_with_tcp_conn_fn(None, move || {
         337  +
            hyper_util::client::legacy::connect::HttpConnector::new_with_resolver(
         338  +
                resolver.clone().0,
         339  +
            )
         340  +
        })
  289    341   
    }
  290    342   
  291    343   
    /// Endpoint to use when connecting
  292    344   
    ///
  293    345   
    /// This works in tandem with the [`Self::dns_resolver`] to bind to the correct local IP Address
  294    346   
    pub fn endpoint_url(&self) -> String {
  295    347   
        format!(
  296    348   
            "http://this-url-is-converted-to-localhost.com:{}",
  297    349   
            self.bind_addr().port()
  298    350   
        )
  299    351   
    }
  300    352   
  301    353   
    /// Shuts down the mock server.
  302    354   
    pub fn shutdown(self) {
  303    355   
        let _ = self.shutdown_hook.send(());
  304    356   
    }
  305    357   
}
  306    358   
  307    359   
async fn generate_response_event(
  308    360   
    event: ReplayedEvent,
  309         -
) -> Result<http_02x::Response<hyper_0_14::Body>, Infallible> {
         361  +
) -> Result<http_1x::Response<Full<Bytes>>, Infallible> {
  310    362   
    let resp = match event {
  311         -
        ReplayedEvent::HttpResponse { status, body } => http_02x::Response::builder()
         363  +
        ReplayedEvent::HttpResponse { status, body } => http_1x::Response::builder()
  312    364   
            .status(status)
  313         -
            .body(hyper_0_14::Body::from(body))
         365  +
            .body(Full::new(body))
  314    366   
            .unwrap(),
  315    367   
        ReplayedEvent::Timeout => {
  316    368   
            Never::new().await;
  317    369   
            unreachable!()
  318    370   
        }
  319    371   
    };
  320    372   
    Ok::<_, Infallible>(resp)
  321    373   
}
  322    374   
  323    375   
/// DNS resolver that keeps a log of all lookups
  324    376   
///
  325    377   
/// Regardless of what hostname is requested, it will always return the same socket address.
  326    378   
#[derive(Clone, Debug)]
  327         -
pub struct LoggingDnsResolver {
         379  +
pub struct LoggingDnsResolver(InnerDnsResolver);
         380  +
         381  +
// internal implementation so we don't have to expose hyper_util
         382  +
#[derive(Clone, Debug)]
         383  +
struct InnerDnsResolver {
  328    384   
    log: Arc<Mutex<Vec<RecordedEvent>>>,
  329    385   
    socket_addr: SocketAddr,
  330    386   
}
  331    387   
  332         -
impl Service<Name> for LoggingDnsResolver {
         388  +
impl tower::Service<Name> for InnerDnsResolver {
  333    389   
    type Response = Once<SocketAddr>;
  334    390   
    type Error = Infallible;
  335    391   
    type Future = BoxFuture<'static, Self::Response, Self::Error>;
  336    392   
  337    393   
    fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
  338    394   
        Poll::Ready(Ok(()))
  339    395   
    }
  340    396   
  341    397   
    fn call(&mut self, req: Name) -> Self::Future {
  342    398   
        let socket_addr = self.socket_addr;
  343    399   
        let log = self.log.clone();
  344    400   
        Box::pin(async move {
  345    401   
            println!("looking up {:?}, replying with {:?}", req, socket_addr);
  346    402   
            log.lock()
  347    403   
                .unwrap()
  348    404   
                .push(RecordedEvent::DnsLookup(req.to_string()));
  349    405   
            Ok(std::iter::once(socket_addr))
  350    406   
        })
  351    407   
    }
  352    408   
}
         409  +
         410  +
#[cfg(all(feature = "legacy-test-util", feature = "hyper-014"))]
         411  +
impl hyper_0_14::service::Service<hyper_0_14::client::connect::dns::Name> for LoggingDnsResolver {
         412  +
    type Response = Once<SocketAddr>;
         413  +
    type Error = Infallible;
         414  +
    type Future = BoxFuture<'static, Self::Response, Self::Error>;
         415  +
         416  +
    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
         417  +
        self.0.poll_ready(cx)
         418  +
    }
         419  +
         420  +
    fn call(&mut self, req: hyper_0_14::client::connect::dns::Name) -> Self::Future {
         421  +
        use std::str::FromStr;
         422  +
        let adapter = Name::from_str(req.as_str()).expect("valid conversion");
         423  +
        self.0.call(adapter)
         424  +
    }
         425  +
}

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-http-client/tests/openssl.cnf

@@ -0,1 +0,23 @@
           1  +
[ v3_end ]
           2  +
basicConstraints = critical,CA:false
           3  +
keyUsage = nonRepudiation, digitalSignature
           4  +
subjectKeyIdentifier = hash
           5  +
authorityKeyIdentifier = keyid:always,issuer:always
           6  +
subjectAltName = @alt_names
           7  +
           8  +
[ v3_client ]
           9  +
basicConstraints = critical,CA:false
          10  +
keyUsage = nonRepudiation, digitalSignature
          11  +
extendedKeyUsage = critical, clientAuth
          12  +
subjectKeyIdentifier = hash
          13  +
authorityKeyIdentifier = keyid:always,issuer:always
          14  +
          15  +
[ v3_inter ]
          16  +
subjectKeyIdentifier = hash
          17  +
extendedKeyUsage = critical, serverAuth, clientAuth
          18  +
basicConstraints = CA:true
          19  +
keyUsage = cRLSign, keyCertSign, digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment, keyAgreement, keyCertSign, cRLSign
          20  +
          21  +
[ alt_names ]
          22  +
DNS.1 = sdktest.com
          23  +
DNS.2 = localhost

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-http-client/tests/regen-certificates.sh

@@ -0,1 +0,72 @@
           1  +
#!/bin/bash
           2  +
#
           3  +
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
           4  +
# SPDX-License-Identifier: Apache-2.0
           5  +
#
           6  +
set -xe
           7  +
           8  +
# The files generated by this script are used in unit tests that create TLS
           9  +
# connections between a localhost server and client. Run this script if any
          10  +
# certificates used for tests are expired.
          11  +
          12  +
# Files generated by this script:
          13  +
# server.rsa - private RSA server key
          14  +
# server.pem - certificate chain containing certificates [server, intermediate, CA]
          15  +
          16  +
# generate the root CA certificate and key
          17  +
openssl req -nodes \
          18  +
          -x509 \
          19  +
          -days 3650 \
          20  +
          -newkey rsa:4096 \
          21  +
          -keyout ca.key \
          22  +
          -out ca.cert \
          23  +
          -sha256 \
          24  +
          -batch \
          25  +
          -subj "/CN=SDK RSA CA"
          26  +
          27  +
# generate intermediate authority cert and key
          28  +
openssl req -nodes \
          29  +
          -newkey rsa:3072 \
          30  +
          -keyout inter.key \
          31  +
          -out inter.req \
          32  +
          -sha256 \
          33  +
          -batch \
          34  +
          -subj "/CN=SDK RSA level 2 intermediate"
          35  +
          36  +
# generate key and signing request for server
          37  +
openssl req -nodes \
          38  +
          -newkey rsa:2048 \
          39  +
          -keyout server.key \
          40  +
          -out server.req \
          41  +
          -sha256 \
          42  +
          -batch \
          43  +
          -subj "/CN=sdktest.com"
          44  +
          45  +
openssl rsa \
          46  +
          -in server.key \
          47  +
          -out server.rsa
          48  +
          49  +
# sign intermediate cert with CA root
          50  +
openssl x509 -req \
          51  +
            -in inter.req \
          52  +
            -out inter.cert \
          53  +
            -CA ca.cert \
          54  +
            -CAkey ca.key \
          55  +
            -sha256 \
          56  +
            -days 3650 \
          57  +
            -set_serial 123 \
          58  +
            -extensions v3_inter -extfile openssl.cnf
          59  +
          60  +
# sign server cert with intermediate
          61  +
openssl x509 -req \
          62  +
            -in server.req \
          63  +
            -out server.cert \
          64  +
            -CA inter.cert \
          65  +
            -CAkey inter.key \
          66  +
            -sha256 \
          67  +
            -days 2000 \
          68  +
            -set_serial 456 \
          69  +
            -extensions v3_end -extfile openssl.cnf
          70  +
          71  +
cat server.cert inter.cert ca.cert > server.pem
          72  +
rm *.key *.cert *.req

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-http-client/tests/server.pem

@@ -0,1 +0,80 @@
           1  +
-----BEGIN CERTIFICATE-----
           2  +
MIID2TCCAkGgAwIBAgICAcgwDQYJKoZIhvcNAQELBQAwJzElMCMGA1UEAwwcU0RL
           3  +
IFJTQSBsZXZlbCAyIGludGVybWVkaWF0ZTAeFw0yNTAyMTkxNDUzMDJaFw0zMDA4
           4  +
MTIxNDUzMDJaMBYxFDASBgNVBAMMC3Nka3Rlc3QuY29tMIIBIjANBgkqhkiG9w0B
           5  +
AQEFAAOCAQ8AMIIBCgKCAQEAq0qAhLP/7uVfR5zv8d41eciCEco2kKjqoN9NlUy8
           6  +
xt8fNUFvFdSqEsrPMyycyfPg9HBhJHhCBtVQSxmr/y/IEkvbf5P5aq2CnVKKMjGm
           7  +
xlqUm+mHmtDYZkJp/2nnK3ZFm9/b1oqs6XvfEJ3R2eqFf454a8SRHX1gVdj+LFnm
           8  +
EVfUkVBSZCMJm9EOL9HL2I6tDPzXvJpEZMzu/pHouMNeSBBeQDGQN7vZo36cb2wG
           9  +
PCTwHCh/DjZpKtJK8eKRDipIbjQr3upNbLxva36/V70xM6rTy9ac+GT/IUh0Dh0q
          10  +
nXgjntez5grtlz4DrQBBhNhGAAliOTGvk74kPjzHYFy8FQIDAQABo4GfMIGcMAwG
          11  +
A1UdEwEB/wQCMAAwCwYDVR0PBAQDAgbAMB0GA1UdDgQWBBTF0O0/x6KcdOoqlv0T
          12  +
//HVFq2RODA9BgNVHSMENjA0gBQFk2G/rf1Iob6rw0H6lQ/uzbfLaKEZpBcwFTET
          13  +
MBEGA1UEAwwKU0RLIFJTQSBDQYIBezAhBgNVHREEGjAYggtzZGt0ZXN0LmNvbYIJ
          14  +
bG9jYWxob3N0MA0GCSqGSIb3DQEBCwUAA4IBgQAHDCVmgHAuUkJCyNJefN+GLj9s
          15  +
hCzoSScWSSuyUTOP+N2cT9SOIyjdBb0uLaj4E/Casf/fEvqd/qSz2pBZtXXG3udP
          16  +
NOfO7ZXOuAW/DqMKL7B/JYvybr2ugJefB7+fVqEdJ/lKZ6DT517nO+V9BRZRrcyR
          17  +
vx5gM4j46p2qkN9yiAvimE37hBUIkjKCdejXA4IVr90Z6kG2yGo1XIFp8fDAEoSm
          18  +
u5h5ftuyGvy3kXg8e1quVs38yeh3Vcxk60g8MpFrbUBZjYd3mBN0wnQAOmsK592k
          19  +
3mEJIDN5NfFvuap/Tl0SAqsP7vfIy7t3Wu5aJoH5VlepmKOhHVnbwhd61pd2ZeHs
          20  +
zvo8dLsfgowGiSItvdw+pg0PUsozXG0JH7o8igzEfIiRJ237pX8U1/Lr1v5fKYhL
          21  +
pfZoGVfpH2oK6uUE4TzAK7bf9tGCKkvqx0MhvQ1Y6tjbp3l/+vxDTSgoo5Oh4XJ+
          22  +
gRxRIoosMVJffwwy+sbfMs5rqCTC7DrqHoFb+3I=
          23  +
-----END CERTIFICATE-----
          24  +
-----BEGIN CERTIFICATE-----
          25  +
MIIEtjCCAp6gAwIBAgIBezANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDDApTREsg
          26  +
UlNBIENBMB4XDTI1MDIxOTE0NTMwMloXDTM1MDIxNzE0NTMwMlowJzElMCMGA1UE
          27  +
AwwcU0RLIFJTQSBsZXZlbCAyIGludGVybWVkaWF0ZTCCAaIwDQYJKoZIhvcNAQEB
          28  +
BQADggGPADCCAYoCggGBALpfp+sVFpcJxmK7v/aCL5R5sjWzfkwUABhYNWsk+26x
          29  +
ioayPUZ3IMnKYvzGXmX2a6pjPJeP5HpFIvFnezac/tHHEk8zgATVGGbC1gO6aKT+
          30  +
o1UYKICcwHuhwG6BZ3hoFqjuBY8wk+zIgV9pd+907E0oZOy+TutCtk3dHPBYYbJO
          31  +
NS8pQDw804ckKpEa34NQcLN9D3FBsgMXX6/pYyvzpD2fDgo6X6lDOWVZ31mtgmwP
          32  +
jV6Be/y2r7Z/aA9fePfSTxSZnsNpwS5tkVwVG8v42ph7rVNJ/zaBsfXfCbbRV0q8
          33  +
HjJAzWGtXbPH4Ojj6MEOSjGK+rusIOZmqQAbvJ0fMH4soW5FjYWsngEuDYOrWRlB
          34  +
bkv4ixeMfaz8rwC0fkLIJWFOZnHt0nmVtEVsGRc0ndTrQDlaqIJq87cL0cYkqYZE
          35  +
vn2I0lmkIgna9OTCDbvBUaglYrxLe8e41OSvvcVrFmSxvx1GcWjuU1Q08P3JcBmP
          36  +
9uhhjW53TYoarFhKjrO+WQIDAQABo38wfTAdBgNVHQ4EFgQUBZNhv639SKG+q8NB
          37  +
+pUP7s23y2gwIAYDVR0lAQH/BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1Ud
          38  +
EwQFMAMBAf8wCwYDVR0PBAQDAgH+MB8GA1UdIwQYMBaAFOCtnMCd873GJzp4HbZs
          39  +
uuxho+wIMA0GCSqGSIb3DQEBCwUAA4ICAQBvCShvDdnp+pSRzK4sJS/AgElhIDVR
          40  +
QrFfnhOxElVWxXSYEXVegwj1qKhgM+de9k9eKH/dM7mr5Ry9N6GfTjtRuf4fDp8W
          41  +
Zj6bnqQoNz1vTPmX5ymnEipRwg5BeQtfmHVf++uor4Ch6Xx5lp9mlyCkZqEgHKkz
          42  +
UietQNkZjalnIex/nBr+2kHD1dh2ZTefsTOHofnz+gsg3tNjjvzf+YMOw7aifQvI
          43  +
2uoQVDjb2FBq24LSpBAc9r2sU2CKHD4/4Ei11QRI29gNgOJiiUArAV6P13mdCVMY
          44  +
ue92chdLg3/AYctAUXE7NXMXeqZdOlST65GgEg36tays3l7JqlF+FaPqzuJnB+kt
          45  +
pzYDdt1pFxV0Ep8RsyWm7TbYsRVqzx0eueReVKQQBBjM2+8uD8X3bZB/0QtPknBo
          46  +
6x0S90g32BL4dPn/mHLLbKTNWPQ9dGmIBHvZocw5UxRYhiFLx+Wurw+V8CWmoU2g
          47  +
kEiTAaA/5jiZNR02sz6H7CC70FN0vHYREiivqvNMhLbmWxORrCL/TdmwdwfEMCT4
          48  +
ozEzyGHFUVatCTUeiWxI2YXg1oNHLQU5gfy8gxfygNjG8r3A/L1SOoCsS2Cw/FcW
          49  +
LJXtCyJoVzM1oLSzPbvUpe4fbnhQ/5hcM2+Tfm2DsNb9RVLjbl5t6EUTuVwKP8us
          50  +
y0Qg67cAE/Grlw==
          51  +
-----END CERTIFICATE-----
          52  +
-----BEGIN CERTIFICATE-----
          53  +
MIIFCzCCAvOgAwIBAgIUbOKEL90YNxD9QGi6wIP6zs5AzCMwDQYJKoZIhvcNAQEL
          54  +
BQAwFTETMBEGA1UEAwwKU0RLIFJTQSBDQTAeFw0yNTAyMTkxNDUzMDFaFw0zNTAy
          55  +
MTcxNDUzMDFaMBUxEzARBgNVBAMMClNESyBSU0EgQ0EwggIiMA0GCSqGSIb3DQEB
          56  +
AQUAA4ICDwAwggIKAoICAQDKHnrAedyOnngswWm1oeOgcfjUHo4EMHMgTn6b6vnj
          57  +
KRV5idN9iIl0rI/QuyZeGcvEkarSZZMnkme1cnhOpLvelPEgCRqMI+02VodEpVer
          58  +
7i2QIxqpCzf2VfZMAQ5cNyuBeN+IS+FDViPge71eypmBnF1CHu5d9lfI8y8PVVfJ
          59  +
QRsP1M/bWCLIgGs7ZjHNt+cA+ZBTBHID66aXx4egW59MPBCq9SH9FC0PfvJqJjkU
          60  +
QNfiSCpn4XKYRraucQ9LChNlaJqu58HPnCMX+B9/g3MuQ9qCNUq7m/p4ILre0rcJ
          61  +
mz30RMGFXhyp+94DRwJBDUsWVny9fVhbMtSQKcGd51nBrrn1xcWC0+NNEWkf4VLt
          62  +
sp3OPOGw/b+njgshxOdi2oPmSumRhHmMC98nl7iWT41Hy/uvLuTpd8KStN/2VIFt
          63  +
7lsCRnPoIUezM34oZvsIiMsEm93AFPfQtWaKm/8GvSzGBHZ0ba8op9ZVL879yaSN
          64  +
B1oHrR6OzgpfiekB8Jg3OLFSxwtgDuKJeAiorFXMiSIfqZxBfzsOQCU4UhlY38xR
          65  +
SVYZMRxmHq06Mi9tVGak60RHV4opu9ixlm5sUbv0NliIzHbOHjry85z+iNSttjqu
          66  +
Wv3w6jVeIHJcZeYHXZYNx8nGMWEI3JpVBNaF9ycvVpvV1hC5GM/Egn5qggpAjiL+
          67  +
uwIDAQABo1MwUTAdBgNVHQ4EFgQU4K2cwJ3zvcYnOngdtmy67GGj7AgwHwYDVR0j
          68  +
BBgwFoAU4K2cwJ3zvcYnOngdtmy67GGj7AgwDwYDVR0TAQH/BAUwAwEB/zANBgkq
          69  +
hkiG9w0BAQsFAAOCAgEAifwXv/ezBA8BbdV+7IcdA9R5Yz/fENQ8n5u8U0Mmpu2v
          70  +
mcGpuqJOQlH6Yr5cs0zS9BRmNaMYlVWNnJxMz/3m+uaqohiFf98SgxhT+RGFRohx
          71  +
jSPI6jE19vKbi1RMvv8yf8DLIjnc8d5e8kOEWNleOarVtkpAhze5nyKVyYkIyyER
          72  +
zL2RKslmWzxsG0ae0HZ5T5U1voIUG5Y8WyE662egR7INLE3HMUklYljIUJNXClqe
          73  +
sMfDyvl735z8S93r7sRFv3x+2YZpIzJZGk0ZbyWxfpwAVfr+ktf01BZ+lASXCmDX
          74  +
94TPHswhoC4HQyxziyf2CLHvpnRczS57/bSVgatYELN4oU2sPicHqPTntrSA6Yhq
          75  +
+qswrShiF47MXZeiXrddjcWTRQZOs30dmBvTj7CufAYek7r+9KeK0j+ETs/yr5Q4
          76  +
NQd7/7kkS/4GIKx0uf/+WJJhMDD8qJfWlZDV4kZ+laz49ksjES19IPKoalugst06
          77  +
SquAqOCKiOQxWeD+QQvdUu9Yac8jNEt3th1z29MoJ02QHSrKe1CmFu7jXcgvWTVI
          78  +
1dhO2YJ4UNvGaFK3rWU8sDvgFnV6Hpw7y1YAgVYtterSPMAyAGdSFDvZKuo2Bq2N
          79  +
juj9U9BUS1Xrl1cj8RjpZ0g0gYYF+BX2qwDCqi9qkxHel/oCzG80QAY0dnM+JT4=
          80  +
-----END CERTIFICATE-----

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-http-client/tests/server.rsa

@@ -0,1 +0,28 @@
           1  +
-----BEGIN PRIVATE KEY-----
           2  +
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCrSoCEs//u5V9H
           3  +
nO/x3jV5yIIRyjaQqOqg302VTLzG3x81QW8V1KoSys8zLJzJ8+D0cGEkeEIG1VBL
           4  +
Gav/L8gSS9t/k/lqrYKdUooyMabGWpSb6Yea0NhmQmn/aecrdkWb39vWiqzpe98Q
           5  +
ndHZ6oV/jnhrxJEdfWBV2P4sWeYRV9SRUFJkIwmb0Q4v0cvYjq0M/Ne8mkRkzO7+
           6  +
kei4w15IEF5AMZA3u9mjfpxvbAY8JPAcKH8ONmkq0krx4pEOKkhuNCve6k1svG9r
           7  +
fr9XvTEzqtPL1pz4ZP8hSHQOHSqdeCOe17PmCu2XPgOtAEGE2EYACWI5Ma+TviQ+
           8  +
PMdgXLwVAgMBAAECggEAIRG6myQXIpuE2BIL3vGr+E2GEwIro6UA2zsRQuQ0Q966
           9  +
qzDtTdUnWoZuFy6jPHgJc5eooX5YHPKc1ErqAlPKuAGOKGS8j+RcpZvUU1lznbLK
          10  +
IwmkZPax+JgU17st5p2oVa4TxqkyNcd06sPVSlF1IYmzZPbnnz5f1WMVuyFGAg3W
          11  +
CsFevfTtdpzgN8fWE6EnpSO1OY9Sa0xc+k94U6b1Coi2i6loUfKXP/iFStsGlDW3
          12  +
Dkl2egptPHi4oDcUuobJrOFr61XgOrTrYlFOrzZOgykgzAEyKN/nF3q2vAIbZSPq
          13  +
MkJTw+TFGypVkMBmMTBb83CnaBWDmsicY1WJ4DjXAQKBgQDo8wgCNzNGDaqcFR2F
          14  +
ZSYdqsGeSQzxjBnxnyMp/1ewb5cYFrE86ORXND7TfmJECJNEIhNLv5ytu8Z/cDsm
          15  +
envwlotj8J+u0cVp3t916GEWyNBZaZM/40ivDxMCAWTeryleGbQ0ytmnDPOdPS93
          16  +
6tIImk6vKiyae3iM4eKx3o/hgQKBgQC8PZHcWrXt1OYOn/VrMeYfGp57HNeHddrA
          17  +
noVIL5Ysx0pnAMhyZi69orJUYX9n1d0DwiXbagS1mTuqJK2t+0EUe5tKHalUY3Ew
          18  +
CL0XGskN3526l1CKzD/vFfx28Q3lGdpxwFSNIil+85hk8BMDAu6nvzVTWd0ol/Ll
          19  +
FmhIj2R8lQKBgQCMPsTzkIguBMxSa+P6C4uHEObAhPpl8hMshMKG5lPExWoR9pd+
          20  +
NDhEyA+LBOvkScVfn6Q+Vn3dms9GqiryX4t+rSP+Zz+74E8aDjQ6qEzLitrk+crN
          21  +
C+kWe9zVuEEiUBJ3tMHphrbC++kvIUcSyyzoQP5eNuXjm7JYHyZ8L6IwAQKBgCir
          22  +
KKsx0eJrP7TjLDOXmT8ZEipJBeuXM8avuN3qoghUmid8zNGib/C6iMqgMdVuKAza
          23  +
0jEAS7osO+67c+aFxP624cr2c5Hu1hJpoOiv+cYMjNg2Pslt7VYrKttLoxPfLQms
          24  +
YtgHDG4IFOGh2ImrBYKqVcwHOze89FY4LBmZGT2tAoGADKA9beP/o5vXu2BmdEPF
          25  +
c4XUb5gvbI7Zv7xhF6CGOsryBkz8yF5WaAreNcG1uwPzqAyV6kk6Fgaa7XDa9Mhf
          26  +
3QMe/ncGWI3NjQaB6E+7rJMQ/UDIr4Cs5ThZMkXvrR9GPhpULQi3iPepcIT79Jvn
          27  +
o40e3/lYe5+59N2kVfwac0U=
          28  +
-----END PRIVATE KEY-----

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

Renamed from tmp-codegen-diff/aws-sdk/sdk/aws-smithy-experimental/tests/smoke_test_clients.rs

@@ -1,1 +98,120 @@
    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(
    7         -
    feature = "crypto-ring",
    8         -
    feature = "crypto-aws-lc",
    9         -
    feature = "crypto-aws-lc-fips"
           7  +
    feature = "rustls-ring",
           8  +
    feature = "rustls-aws-lc",
           9  +
    feature = "rustls-aws-lc-fips",
          10  +
    feature = "s2n-tls",
   10     11   
))]
   11     12   
   12     13   
use aws_smithy_async::time::SystemTimeSource;
   13         -
use aws_smithy_experimental::hyper_1_0::{CryptoMode, HyperClientBuilder};
          14  +
use aws_smithy_http_client::{tls, Builder};
   14     15   
use aws_smithy_runtime_api::client::dns::{DnsFuture, ResolveDns, ResolveDnsError};
   15     16   
use aws_smithy_runtime_api::client::http::{HttpClient, HttpConnector, HttpConnectorSettings};
   16     17   
use aws_smithy_runtime_api::client::orchestrator::HttpRequest;
   17     18   
use aws_smithy_runtime_api::client::runtime_components::RuntimeComponentsBuilder;
   18     19   
use hyper_util::client::legacy::connect::dns::{GaiResolver, Name};
   19     20   
use std::error::Error;
   20     21   
use std::str::FromStr;
   21     22   
use std::sync::Arc;
   22     23   
use tower::Service;
   23     24   
   24         -
#[cfg(feature = "crypto-ring")]
          25  +
#[cfg(feature = "rustls-ring")]
   25     26   
#[tokio::test]
   26     27   
async fn ring_client() {
   27         -
    let client = HyperClientBuilder::new()
   28         -
        .crypto_mode(CryptoMode::Ring)
          28  +
    let client = Builder::new()
          29  +
        .tls_provider(tls::Provider::Rustls(
          30  +
            tls::rustls_provider::CryptoMode::Ring,
          31  +
        ))
   29     32   
        .build_https();
   30     33   
    smoke_test_client(&client).await.unwrap();
   31     34   
}
   32     35   
   33         -
#[cfg(feature = "crypto-aws-lc-fips")]
          36  +
#[cfg(feature = "rustls-aws-lc-fips")]
   34     37   
#[tokio::test]
   35     38   
async fn aws_lc_fips_client() {
   36         -
    let client = HyperClientBuilder::new()
   37         -
        .crypto_mode(CryptoMode::AwsLcFips)
          39  +
    let client = Builder::new()
          40  +
        .tls_provider(tls::Provider::Rustls(
          41  +
            tls::rustls_provider::CryptoMode::AwsLcFips,
          42  +
        ))
   38     43   
        .build_https();
   39     44   
    smoke_test_client(&client).await.unwrap();
   40     45   
}
   41     46   
   42         -
#[cfg(feature = "crypto-aws-lc")]
          47  +
#[cfg(feature = "rustls-aws-lc")]
   43     48   
#[tokio::test]
   44     49   
async fn aws_lc_client() {
   45         -
    let client = HyperClientBuilder::new()
   46         -
        .crypto_mode(CryptoMode::AwsLc)
          50  +
    let client = Builder::new()
          51  +
        .tls_provider(tls::Provider::Rustls(
          52  +
            tls::rustls_provider::CryptoMode::AwsLc,
          53  +
        ))
   47     54   
        .build_https();
   48     55   
    smoke_test_client(&client).await.unwrap();
   49     56   
}
   50     57   
   51         -
#[cfg(feature = "crypto-ring")]
          58  +
#[cfg(feature = "s2n-tls")]
          59  +
#[tokio::test]
          60  +
async fn s2n_tls_client() {
          61  +
    let client = Builder::new()
          62  +
        .tls_provider(tls::Provider::S2nTls)
          63  +
        .build_https();
          64  +
    smoke_test_client(&client).await.unwrap();
          65  +
}
          66  +
          67  +
#[cfg(any(feature = "rustls-ring", feature = "s2n-tls"))]
   52     68   
#[tokio::test]
   53     69   
async fn custom_dns_client() {
   54     70   
    use std::sync::atomic::{AtomicUsize, Ordering};
   55     71   
    #[derive(Debug, Clone)]
   56     72   
    struct PassThroughResolver {
   57     73   
        inner: GaiResolver,
   58     74   
        count: Arc<AtomicUsize>,
   59     75   
    }
   60     76   
    impl ResolveDns for PassThroughResolver {
   61     77   
        fn resolve_dns<'a>(&'a self, _name: &'a str) -> DnsFuture<'a> {
   62     78   
            let mut inner = self.inner.clone();
   63     79   
            let name = Name::from_str(_name).unwrap();
   64     80   
            let count = self.count.clone();
   65     81   
            DnsFuture::new(async move {
   66     82   
                count.fetch_add(1, Ordering::Relaxed);
   67         -
                let result = inner
   68         -
                    .call(name)
   69         -
                    .await
   70         -
                    .map_err(|err| ResolveDnsError::new(err))?;
          83  +
                let result = inner.call(name).await.map_err(ResolveDnsError::new)?;
   71     84   
                Ok(result.map(|addr| addr.ip()).collect::<Vec<_>>())
   72     85   
            })
   73     86   
        }
   74     87   
    }
   75         -
    let resolver = PassThroughResolver {
   76         -
        inner: GaiResolver::new(),
   77         -
        count: Default::default(),
   78         -
    };
   79         -
    let client = HyperClientBuilder::new()
   80         -
        .crypto_mode(CryptoMode::Ring)
   81         -
        .build_with_resolver(resolver.clone());
   82         -
    smoke_test_client(&client).await.unwrap();
   83         -
    assert_eq!(resolver.count.load(Ordering::Relaxed), 1);
          88  +
          89  +
    let providers = [
          90  +
        #[cfg(feature = "rustls-ring")]
          91  +
        tls::Provider::Rustls(tls::rustls_provider::CryptoMode::Ring),
          92  +
        #[cfg(feature = "s2n-tls")]
          93  +
        tls::Provider::S2nTls,
          94  +
    ];
          95  +
          96  +
    for provider in providers {
          97  +
        let resolver = PassThroughResolver {
          98  +
            inner: GaiResolver::new(),
          99  +
            count: Default::default(),
         100  +
        };
         101  +
        let client = Builder::new()
         102  +
            .tls_provider(provider)
         103  +
            .build_with_resolver(resolver.clone());
         104  +
        smoke_test_client(&client).await.unwrap();
         105  +
        assert_eq!(resolver.count.load(Ordering::Relaxed), 1);
         106  +
    }
   84    107   
}
   85    108   
   86         -
#[cfg(feature = "crypto-ring")]
   87    109   
async fn smoke_test_client(client: &dyn HttpClient) -> Result<(), Box<dyn Error>> {
   88    110   
    let connector_settings = HttpConnectorSettings::builder().build();
   89    111   
    let runtime_components = RuntimeComponentsBuilder::for_tests()
   90    112   
        .with_time_source(Some(SystemTimeSource::new()))
   91    113   
        .build()
   92    114   
        .unwrap();
   93    115   
    let connector = client.http_connector(&connector_settings, &runtime_components);
   94    116   
    let _response = connector
   95    117   
        .call(HttpRequest::get("https://amazon.com").unwrap())
   96    118   
        .await?;

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

@@ -0,1 +0,268 @@
           1  +
/*
           2  +
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
           3  +
 * SPDX-License-Identifier: Apache-2.0
           4  +
 */
           5  +
           6  +
#![cfg(any(
           7  +
    feature = "rustls-ring",
           8  +
    feature = "rustls-aws-lc",
           9  +
    feature = "rustls-aws-lc-fips",
          10  +
    feature = "s2n-tls",
          11  +
))]
          12  +
          13  +
use aws_smithy_async::time::SystemTimeSource;
          14  +
use aws_smithy_http_client::tls;
          15  +
use aws_smithy_http_client::tls::{TlsContext, TrustStore};
          16  +
use aws_smithy_runtime_api::box_error::BoxError;
          17  +
use aws_smithy_runtime_api::client::http::{HttpClient, HttpConnector, HttpConnectorSettings};
          18  +
use aws_smithy_runtime_api::client::orchestrator::HttpRequest;
          19  +
use aws_smithy_runtime_api::client::runtime_components::RuntimeComponentsBuilder;
          20  +
use aws_smithy_types::byte_stream::ByteStream;
          21  +
use http_1x::{Method, Request, Response, StatusCode};
          22  +
use http_body_util::{BodyExt, Full};
          23  +
use hyper::body::{Bytes, Incoming};
          24  +
use hyper::service::service_fn;
          25  +
use hyper_util::rt::{TokioExecutor, TokioIo};
          26  +
use hyper_util::server::conn::auto::Builder;
          27  +
use rustls::ServerConfig;
          28  +
use rustls_pki_types::{CertificateDer, PrivateKeyDer};
          29  +
use std::net::SocketAddr;
          30  +
use std::sync::Arc;
          31  +
use std::{fs, io};
          32  +
use tokio::net::TcpListener;
          33  +
use tokio::task::JoinHandle;
          34  +
use tokio_rustls::TlsAcceptor;
          35  +
use tracing::{debug, error};
          36  +
          37  +
struct TestServer {
          38  +
    _handle: JoinHandle<()>,
          39  +
    listen_addr: SocketAddr,
          40  +
}
          41  +
          42  +
async fn server() -> Result<TestServer, BoxError> {
          43  +
    // Set process wide crypto provider
          44  +
    let _ = rustls::crypto::aws_lc_rs::default_provider().install_default();
          45  +
          46  +
    let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
          47  +
    let addr = listener.local_addr().unwrap();
          48  +
          49  +
    // load public certificate.
          50  +
    let certs = load_certs("tests/server.pem")?;
          51  +
          52  +
    // load private key.
          53  +
    let key = load_private_key("tests/server.rsa")?;
          54  +
          55  +
    debug!("Starting to serve on https://{}", addr);
          56  +
          57  +
    // TLS config
          58  +
    let mut server_config = ServerConfig::builder()
          59  +
        .with_no_client_auth()
          60  +
        .with_single_cert(certs, key)
          61  +
        .map_err(|e| error(e.to_string()))?;
          62  +
          63  +
    server_config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec(), b"http/1.0".to_vec()];
          64  +
    let tls_acceptor = TlsAcceptor::from(Arc::new(server_config));
          65  +
    let service = service_fn(echo);
          66  +
          67  +
    let server = async move {
          68  +
        loop {
          69  +
            let (tcp_stream, remote_addr) = listener.accept().await.unwrap();
          70  +
            debug!("accepted connection from: {}", remote_addr);
          71  +
          72  +
            let tls_acceptor = tls_acceptor.clone();
          73  +
            tokio::spawn(async move {
          74  +
                let tls_stream = match tls_acceptor.accept(tcp_stream).await {
          75  +
                    Ok(tls_stream) => tls_stream,
          76  +
                    Err(err) => {
          77  +
                        error!("failed to perform tls handshake: {err:#}");
          78  +
                        return;
          79  +
                    }
          80  +
                };
          81  +
                if let Err(err) = Builder::new(TokioExecutor::new())
          82  +
                    .serve_connection(TokioIo::new(tls_stream), service)
          83  +
                    .await
          84  +
                {
          85  +
                    error!("failed to serve connection: {err:#}");
          86  +
                }
          87  +
            });
          88  +
        }
          89  +
    };
          90  +
          91  +
    let server_task = tokio::spawn(server);
          92  +
          93  +
    Ok(TestServer {
          94  +
        _handle: server_task,
          95  +
        listen_addr: addr,
          96  +
    })
          97  +
}
          98  +
          99  +
// Custom echo service, handling two different routes and a
         100  +
// catch-all 404 responder.
         101  +
async fn echo(req: Request<Incoming>) -> Result<Response<Full<Bytes>>, hyper::Error> {
         102  +
    let mut response = Response::new(Full::default());
         103  +
    match (req.method(), req.uri().path()) {
         104  +
        // default route.
         105  +
        (&Method::GET, "/") => {
         106  +
            *response.body_mut() = Full::from("Hello TLS!");
         107  +
        }
         108  +
        // echo service route.
         109  +
        (&Method::POST, "/echo") => {
         110  +
            *response.body_mut() = Full::from(req.into_body().collect().await?.to_bytes());
         111  +
        }
         112  +
        // Catch-all 404.
         113  +
        _ => {
         114  +
            *response.status_mut() = StatusCode::NOT_FOUND;
         115  +
        }
         116  +
    };
         117  +
    Ok(response)
         118  +
}
         119  +
         120  +
fn error(err: String) -> io::Error {
         121  +
    io::Error::new(io::ErrorKind::Other, err)
         122  +
}
         123  +
         124  +
// Load public certificate from file.
         125  +
fn load_certs(filename: &str) -> io::Result<Vec<CertificateDer<'static>>> {
         126  +
    let certfile = fs::File::open(filename)
         127  +
        .map_err(|e| error(format!("failed to open {}: {}", filename, e)))?;
         128  +
    let mut reader = io::BufReader::new(certfile);
         129  +
    rustls_pemfile::certs(&mut reader).collect()
         130  +
}
         131  +
         132  +
// Load private key from file.
         133  +
fn load_private_key(filename: &str) -> io::Result<PrivateKeyDer<'static>> {
         134  +
    // Open keyfile.
         135  +
    let keyfile = fs::File::open(filename)
         136  +
        .map_err(|e| error(format!("failed to open {}: {}", filename, e)))?;
         137  +
    let mut reader = io::BufReader::new(keyfile);
         138  +
         139  +
    // Load and return a single private key.
         140  +
    rustls_pemfile::private_key(&mut reader).map(|key| key.unwrap())
         141  +
}
         142  +
         143  +
fn tls_context_from_pem(filename: &str) -> TlsContext {
         144  +
    let pem_contents = fs::read(filename).unwrap();
         145  +
    let trust_store = TrustStore::empty().with_pem_certificate(pem_contents);
         146  +
    TlsContext::builder()
         147  +
        .with_trust_store(trust_store)
         148  +
        .build()
         149  +
        .unwrap()
         150  +
}
         151  +
         152  +
#[cfg(feature = "rustls-aws-lc")]
         153  +
#[should_panic(expected = "InvalidCertificate(UnknownIssuer)")]
         154  +
#[tokio::test]
         155  +
async fn test_rustls_aws_lc_native_ca() {
         156  +
    let client = aws_smithy_http_client::Builder::new()
         157  +
        .tls_provider(tls::Provider::Rustls(
         158  +
            tls::rustls_provider::CryptoMode::AwsLc,
         159  +
        ))
         160  +
        .build_https();
         161  +
         162  +
    run_tls_test(&client).await.unwrap()
         163  +
}
         164  +
         165  +
#[cfg(feature = "rustls-aws-lc")]
         166  +
#[tokio::test]
         167  +
async fn test_rustls_aws_lc_custom_ca() {
         168  +
    let client = aws_smithy_http_client::Builder::new()
         169  +
        .tls_provider(tls::Provider::Rustls(
         170  +
            tls::rustls_provider::CryptoMode::AwsLc,
         171  +
        ))
         172  +
        .tls_context(tls_context_from_pem("tests/server.pem"))
         173  +
        .build_https();
         174  +
         175  +
    run_tls_test(&client).await.unwrap()
         176  +
}
         177  +
         178  +
#[cfg(feature = "rustls-aws-lc-fips")]
         179  +
#[should_panic(expected = "InvalidCertificate(UnknownIssuer)")]
         180  +
#[tokio::test]
         181  +
async fn test_rustls_aws_lc_fips_native_ca() {
         182  +
    let client = aws_smithy_http_client::Builder::new()
         183  +
        .tls_provider(tls::Provider::Rustls(
         184  +
            tls::rustls_provider::CryptoMode::AwsLcFips,
         185  +
        ))
         186  +
        .build_https();
         187  +
         188  +
    run_tls_test(&client).await.unwrap()
         189  +
}
         190  +
         191  +
#[cfg(feature = "rustls-aws-lc-fips")]
         192  +
#[tokio::test]
         193  +
async fn test_rustls_aws_lc_fips_custom_ca() {
         194  +
    let client = aws_smithy_http_client::Builder::new()
         195  +
        .tls_provider(tls::Provider::Rustls(
         196  +
            tls::rustls_provider::CryptoMode::AwsLcFips,
         197  +
        ))
         198  +
        .tls_context(tls_context_from_pem("tests/server.pem"))
         199  +
        .build_https();
         200  +
         201  +
    run_tls_test(&client).await.unwrap()
         202  +
}
         203  +
         204  +
#[cfg(feature = "rustls-ring")]
         205  +
#[should_panic(expected = "InvalidCertificate(UnknownIssuer)")]
         206  +
#[tokio::test]
         207  +
async fn test_rustls_ring_native_ca() {
         208  +
    let client = aws_smithy_http_client::Builder::new()
         209  +
        .tls_provider(tls::Provider::Rustls(
         210  +
            tls::rustls_provider::CryptoMode::Ring,
         211  +
        ))
         212  +
        .build_https();
         213  +
         214  +
    run_tls_test(&client).await.unwrap()
         215  +
}
         216  +
         217  +
#[cfg(feature = "rustls-ring")]
         218  +
#[tokio::test]
         219  +
async fn test_rustls_ring_custom_ca() {
         220  +
    let client = aws_smithy_http_client::Builder::new()
         221  +
        .tls_provider(tls::Provider::Rustls(
         222  +
            tls::rustls_provider::CryptoMode::Ring,
         223  +
        ))
         224  +
        .tls_context(tls_context_from_pem("tests/server.pem"))
         225  +
        .build_https();
         226  +
         227  +
    run_tls_test(&client).await.unwrap()
         228  +
}
         229  +
         230  +
#[cfg(feature = "s2n-tls")]
         231  +
#[should_panic(expected = "Certificate is untrusted")]
         232  +
#[tokio::test]
         233  +
async fn test_s2n_native_ca() {
         234  +
    let client = aws_smithy_http_client::Builder::new()
         235  +
        .tls_provider(tls::Provider::S2nTls)
         236  +
        .build_https();
         237  +
         238  +
    run_tls_test(&client).await.unwrap()
         239  +
}
         240  +
         241  +
#[cfg(feature = "s2n-tls")]
         242  +
#[tokio::test]
         243  +
async fn test_s2n_tls_custom_ca() {
         244  +
    let client = aws_smithy_http_client::Builder::new()
         245  +
        .tls_provider(tls::Provider::S2nTls)
         246  +
        .tls_context(tls_context_from_pem("tests/server.pem"))
         247  +
        .build_https();
         248  +
    run_tls_test(&client).await.unwrap()
         249  +
}
         250  +
         251  +
async fn run_tls_test(client: &dyn HttpClient) -> Result<(), BoxError> {
         252  +
    let server = server().await?;
         253  +
    let endpoint = format!("https://localhost:{}/", server.listen_addr.port());
         254  +
         255  +
    let connector_settings = HttpConnectorSettings::builder().build();
         256  +
    let runtime_components = RuntimeComponentsBuilder::for_tests()
         257  +
        .with_time_source(Some(SystemTimeSource::new()))
         258  +
        .build()
         259  +
        .unwrap();
         260  +
    let connector = client.http_connector(&connector_settings, &runtime_components);
         261  +
    let mut response = connector.call(HttpRequest::get(endpoint).unwrap()).await?;
         262  +
         263  +
    let sdk_body = response.take_body();
         264  +
    let body_stream = ByteStream::new(sdk_body);
         265  +
    let resp_bytes = body_stream.collect().await?.into_bytes();
         266  +
    assert_eq!(b"Hello TLS!", &resp_bytes[..]);
         267  +
    Ok(())
         268  +
}