mirror of https://github.com/smithy-lang/smithy-rs
wip
This commit is contained in:
parent
04354ad3b0
commit
2b0920a8d5
|
@ -358,15 +358,9 @@ impl Signer for SigV4Signer {
|
|||
});
|
||||
|
||||
let signable_request = SignableRequest::new(
|
||||
request.method().as_str(),
|
||||
request.method(),
|
||||
request.uri().to_string(),
|
||||
request.headers().iter().map(|(k, v)| {
|
||||
(
|
||||
k.as_str(),
|
||||
// use from_utf8 instead of to_str because we _do_ allow non-ascii header values
|
||||
std::str::from_utf8(v.as_bytes()).expect("only utf-8 headers are signable"),
|
||||
)
|
||||
}),
|
||||
request.headers().iter(),
|
||||
signable_body,
|
||||
)?;
|
||||
sign(signable_request, &signing_params)?
|
||||
|
@ -392,7 +386,7 @@ impl Signer for SigV4Signer {
|
|||
.expect("failed to send deferred signer");
|
||||
}
|
||||
}
|
||||
signing_instructions.apply_to_request(request);
|
||||
// signing_instructions.apply_to_request(request);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
*/
|
||||
|
||||
use crate::query::fmt_string as percent_encode_query;
|
||||
use http::uri::InvalidUri;
|
||||
use http::Uri;
|
||||
|
||||
/// Utility for updating the query string in a [`Uri`].
|
||||
|
@ -15,6 +16,10 @@ pub struct QueryWriter {
|
|||
}
|
||||
|
||||
impl QueryWriter {
|
||||
pub fn new_from_string(uri: &str) -> Result<Self, InvalidUri> {
|
||||
Ok(Self::new(&Uri::try_from(uri)?))
|
||||
}
|
||||
|
||||
/// Creates a new `QueryWriter` based off the given `uri`.
|
||||
pub fn new(uri: &Uri) -> Self {
|
||||
let new_path_and_query = uri
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
*/
|
||||
|
||||
use aws_smithy_http::body::SdkBody;
|
||||
use aws_smithy_http::endpoint::error::InvalidEndpointError;
|
||||
use http as http0;
|
||||
use http::uri::PathAndQuery;
|
||||
use http0::header::Iter;
|
||||
use http0::{Extensions, HeaderMap, Method};
|
||||
use std::borrow::Cow;
|
||||
|
@ -28,6 +30,55 @@ pub struct Uri {
|
|||
parsed: http0::Uri,
|
||||
}
|
||||
|
||||
impl Uri {
|
||||
/// Sets `endpoint` as the endpoint for a URL.
|
||||
///
|
||||
/// An `endpoint` MUST contain a scheme and authority.
|
||||
/// An `endpoint` MAY contain a port and path.
|
||||
///
|
||||
/// An `endpoint` MUST NOT contain a query
|
||||
pub fn set_endpoint(&mut self, endpoint: &str) -> Result<(), HttpError> {
|
||||
let endpoint: http0::Uri = endpoint.parse().map_err(HttpError::invalid_uri)?;
|
||||
let endpoint = endpoint.into_parts();
|
||||
let authority = endpoint
|
||||
.authority
|
||||
.ok_or_else(|| HttpError::new("endpoint must contain authority"))?;
|
||||
let scheme = endpoint
|
||||
.scheme
|
||||
.ok_or_else(|| HttpError::new("endpoint must have scheme"))?;
|
||||
let new_uri = http0::Uri::builder()
|
||||
.authority(authority)
|
||||
.scheme(scheme.clone())
|
||||
.path_and_query(merge_paths(endpoint.path_and_query, &self.parsed).as_ref())
|
||||
.build()
|
||||
.map_err(HttpError::new)?;
|
||||
self.as_string = new_uri.to_string();
|
||||
self.parsed = new_uri;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn merge_paths<'a>(endpoint_path: Option<PathAndQuery>, uri: &'a http0::Uri) -> Cow<'a, str> {
|
||||
let uri_path_and_query = uri.path_and_query().map(|pq| pq.as_str()).unwrap_or("");
|
||||
let endpoint_path = match endpoint_path {
|
||||
None => return Cow::Borrowed(uri_path_and_query),
|
||||
Some(path) => path,
|
||||
};
|
||||
if let Some(query) = endpoint_path.query() {
|
||||
tracing::warn!(query = %query, "query specified in endpoint will be ignored during endpoint resolution");
|
||||
}
|
||||
let endpoint_path = endpoint_path.path();
|
||||
if endpoint_path.is_empty() {
|
||||
Cow::Borrowed(uri_path_and_query)
|
||||
} else {
|
||||
let ep_no_slash = endpoint_path.strip_suffix('/').unwrap_or(endpoint_path);
|
||||
let uri_path_no_slash = uri_path_and_query
|
||||
.strip_prefix('/')
|
||||
.unwrap_or(uri_path_and_query);
|
||||
Cow::Owned(format!("{}/{}", ep_no_slash, uri_path_no_slash))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<String> for Uri {
|
||||
type Error = HttpError;
|
||||
|
||||
|
@ -121,6 +172,11 @@ impl<B> Request<B> {
|
|||
&self.uri.as_string
|
||||
}
|
||||
|
||||
/// Returns a mutable reference the the URI of this http::Request
|
||||
pub fn uri_mut(&mut self) -> &mut Uri {
|
||||
&mut self.uri
|
||||
}
|
||||
|
||||
/// Sets the URI of this request
|
||||
pub fn set_uri<U>(&mut self, uri: U) -> Result<(), U::Error>
|
||||
where
|
||||
|
@ -230,6 +286,13 @@ impl Headers {
|
|||
self.headers.get(key.as_ref()).map(|v| v.as_ref())
|
||||
}
|
||||
|
||||
/// Returns an iterator over the headers
|
||||
pub fn iter(&self) -> HeadersIter<'_> {
|
||||
HeadersIter {
|
||||
inner: self.headers.iter(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the total number of **values** stored in the map
|
||||
pub fn len(&self) -> usize {
|
||||
self.headers.len()
|
||||
|
@ -291,6 +354,13 @@ impl Headers {
|
|||
Ok(self.headers.append(key, value))
|
||||
}
|
||||
|
||||
/// Removes all headers with a given key
|
||||
///
|
||||
/// If there are multiple entries for this key, the first entry is returned
|
||||
pub fn remove(&mut self, key: &str) -> Option<HeaderValue> {
|
||||
self.headers.remove(key)
|
||||
}
|
||||
|
||||
/// Appends a value to a given key
|
||||
///
|
||||
/// # Panics
|
||||
|
@ -457,7 +527,9 @@ fn header_value(value: MaybeStatic) -> Result<HeaderValue, HttpError> {
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use http::HeaderValue;
|
||||
use aws_smithy_http::body::SdkBody;
|
||||
use http::header::{AUTHORIZATION, CONTENT_LENGTH};
|
||||
use http::{HeaderValue, Uri};
|
||||
|
||||
#[test]
|
||||
fn headers_can_be_any_string() {
|
||||
|
@ -467,4 +539,24 @@ mod test {
|
|||
.parse::<HeaderValue>()
|
||||
.expect_err("cannot contain control characters");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_clone_clones_all_data() {
|
||||
let request = ::http::Request::builder()
|
||||
.uri(Uri::from_static("https://www.amazon.com"))
|
||||
.method("POST")
|
||||
.header(CONTENT_LENGTH, 456)
|
||||
.header(AUTHORIZATION, "Token: hello")
|
||||
.body(SdkBody::from("hello world!"))
|
||||
.expect("valid request");
|
||||
let request: super::Request = request.try_into().unwrap();
|
||||
let cloned = request.try_clone().expect("request is cloneable");
|
||||
|
||||
assert_eq!("https://www.amazon.com/", cloned.uri());
|
||||
assert_eq!("POST", cloned.method());
|
||||
assert_eq!(2, cloned.headers().len());
|
||||
assert_eq!("Token: hello", cloned.headers().get(AUTHORIZATION).unwrap(),);
|
||||
assert_eq!("456", cloned.headers().get(CONTENT_LENGTH).unwrap());
|
||||
assert_eq!("hello world!".as_bytes(), cloned.body().bytes().unwrap());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -166,6 +166,14 @@ impl<I, O, E> InterceptorContext<I, O, E> {
|
|||
self.request = Some(request);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn set_http03_request(
|
||||
&mut self,
|
||||
request: http::Request<aws_smithy_http::body::SdkBody>,
|
||||
) {
|
||||
self.request = Some(request.try_into().expect("request could not be converted"));
|
||||
}
|
||||
|
||||
/// Retrieve the transmittable request for the operation being invoked.
|
||||
/// This will only be available once request marshalling has completed.
|
||||
pub fn request(&self) -> Option<&Request> {
|
||||
|
@ -429,26 +437,14 @@ impl fmt::Display for RewindResult {
|
|||
}
|
||||
|
||||
fn try_clone(request: &HttpRequest) -> Option<HttpRequest> {
|
||||
let cloned_body = request.body().try_clone()?;
|
||||
let mut cloned_request = ::http::Request::builder()
|
||||
.uri(request.uri().clone())
|
||||
.method(request.method());
|
||||
*cloned_request
|
||||
.headers_mut()
|
||||
.expect("builder has not been modified, headers must be valid") = request.headers().clone();
|
||||
Some(
|
||||
cloned_request
|
||||
.body(cloned_body)
|
||||
.expect("a clone of a valid request should be a valid request"),
|
||||
)
|
||||
request.try_clone()
|
||||
}
|
||||
|
||||
#[cfg(all(test, feature = "test-util"))]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use aws_smithy_http::body::SdkBody;
|
||||
use http::header::{AUTHORIZATION, CONTENT_LENGTH};
|
||||
use http::{HeaderValue, Uri};
|
||||
use http::HeaderValue;
|
||||
|
||||
#[test]
|
||||
fn test_success_transitions() {
|
||||
|
@ -461,7 +457,7 @@ mod tests {
|
|||
|
||||
context.enter_serialization_phase();
|
||||
let _ = context.take_input();
|
||||
context.set_request(http::Request::builder().body(SdkBody::empty()).unwrap());
|
||||
context.set_request(HttpRequest::new(SdkBody::empty()));
|
||||
|
||||
context.enter_before_transmit_phase();
|
||||
context.request();
|
||||
|
@ -502,7 +498,7 @@ mod tests {
|
|||
|
||||
context.enter_serialization_phase();
|
||||
let _ = context.take_input();
|
||||
context.set_request(
|
||||
context.set_http03_request(
|
||||
http::Request::builder()
|
||||
.header("test", "the-original-un-mutated-request")
|
||||
.body(SdkBody::empty())
|
||||
|
@ -512,7 +508,6 @@ mod tests {
|
|||
context.save_checkpoint();
|
||||
assert_eq!(context.rewind(&mut cfg), RewindResult::Unnecessary);
|
||||
// Modify the test header post-checkpoint to simulate modifying the request for signing or a mutating interceptor
|
||||
context.request_mut().unwrap().headers_mut().remove("test");
|
||||
context.request_mut().unwrap().headers_mut().insert(
|
||||
"test",
|
||||
HeaderValue::from_static("request-modified-after-signing"),
|
||||
|
@ -551,23 +546,4 @@ mod tests {
|
|||
let output = context.output_or_error.unwrap().expect("success");
|
||||
assert_eq!("output", output.downcast_ref::<String>().unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_clone_clones_all_data() {
|
||||
let request = ::http::Request::builder()
|
||||
.uri(Uri::from_static("https://www.amazon.com"))
|
||||
.method("POST")
|
||||
.header(CONTENT_LENGTH, 456)
|
||||
.header(AUTHORIZATION, "Token: hello")
|
||||
.body(SdkBody::from("hello world!"))
|
||||
.expect("valid request");
|
||||
let cloned = try_clone(&request).expect("request is cloneable");
|
||||
|
||||
assert_eq!(&Uri::from_static("https://www.amazon.com"), cloned.uri());
|
||||
assert_eq!("POST", cloned.method());
|
||||
assert_eq!(2, cloned.headers().len());
|
||||
assert_eq!("Token: hello", cloned.headers().get(AUTHORIZATION).unwrap(),);
|
||||
assert_eq!("456", cloned.headers().get(CONTENT_LENGTH).unwrap());
|
||||
assert_eq!("hello world!".as_bytes(), cloned.body().bytes().unwrap());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ use std::future::Future as StdFuture;
|
|||
use std::pin::Pin;
|
||||
|
||||
/// Type alias for the HTTP request type that the orchestrator uses.
|
||||
pub type HttpRequest = http::Request<SdkBody>;
|
||||
pub type HttpRequest = crate::client::http::Request<SdkBody>;
|
||||
|
||||
/// Type alias for the HTTP response type that the orchestrator uses.
|
||||
pub type HttpResponse = http::Response<SdkBody>;
|
||||
|
|
|
@ -419,13 +419,7 @@ mod tests {
|
|||
let resp = components
|
||||
.http_connector()
|
||||
.unwrap()
|
||||
.call(
|
||||
http::Request::builder()
|
||||
.method("GET")
|
||||
.uri("/")
|
||||
.body(SdkBody::empty())
|
||||
.unwrap(),
|
||||
)
|
||||
.call(HttpRequest::new(SdkBody::empty()))
|
||||
.await
|
||||
.unwrap();
|
||||
dbg!(&resp);
|
||||
|
|
|
@ -20,8 +20,6 @@ use aws_smithy_runtime_api::client::orchestrator::HttpRequest;
|
|||
use aws_smithy_runtime_api::client::runtime_components::{GetIdentityResolver, RuntimeComponents};
|
||||
use aws_smithy_types::base64::encode;
|
||||
use aws_smithy_types::config_bag::ConfigBag;
|
||||
use http::header::HeaderName;
|
||||
use http::HeaderValue;
|
||||
|
||||
/// Destination for the API key
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
|
@ -93,17 +91,20 @@ impl Signer for ApiKeySigner {
|
|||
.ok_or("HTTP ApiKey auth requires a `Token` identity")?;
|
||||
match self.location {
|
||||
ApiKeyLocation::Header => {
|
||||
request.headers_mut().append(
|
||||
HeaderName::try_from(&self.name).expect("valid API key header name"),
|
||||
HeaderValue::try_from(format!("{} {}", self.scheme, api_key.token())).map_err(
|
||||
|_| "API key contains characters that can't be included in a HTTP header",
|
||||
)?,
|
||||
);
|
||||
request
|
||||
.headers_mut()
|
||||
.try_append(
|
||||
self.name.clone(),
|
||||
format!("{} {}", self.scheme, api_key.token(),),
|
||||
)
|
||||
.map_err(|_| {
|
||||
"API key contains characters that can't be included in a HTTP header"
|
||||
})?;
|
||||
}
|
||||
ApiKeyLocation::Query => {
|
||||
let mut query = QueryWriter::new(request.uri());
|
||||
let mut query = QueryWriter::new_from_string(request.uri())?;
|
||||
query.insert(&self.name, api_key.token());
|
||||
*request.uri_mut() = query.build_uri();
|
||||
request.set_uri(query.build_uri()).expect("infallible");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -159,12 +160,11 @@ impl Signer for BasicAuthSigner {
|
|||
.data::<Login>()
|
||||
.ok_or("HTTP basic auth requires a `Login` identity")?;
|
||||
request.headers_mut().insert(
|
||||
http::header::AUTHORIZATION,
|
||||
HeaderValue::from_str(&format!(
|
||||
http::header::AUTHORIZATION.as_str(),
|
||||
format!(
|
||||
"Basic {}",
|
||||
encode(format!("{}:{}", login.user(), login.password()))
|
||||
))
|
||||
.expect("valid header value"),
|
||||
),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -217,12 +217,15 @@ impl Signer for BearerAuthSigner {
|
|||
let token = identity
|
||||
.data::<Token>()
|
||||
.ok_or("HTTP bearer auth requires a `Token` identity")?;
|
||||
request.headers_mut().insert(
|
||||
http::header::AUTHORIZATION,
|
||||
HeaderValue::from_str(&format!("Bearer {}", token.token())).map_err(|_| {
|
||||
request
|
||||
.headers_mut()
|
||||
.try_insert(
|
||||
http::header::AUTHORIZATION.as_str(),
|
||||
format!("Bearer {}", token.token()),
|
||||
)
|
||||
.map_err(|_| {
|
||||
"Bearer token contains characters that can't be included in a HTTP header"
|
||||
})?,
|
||||
);
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -297,6 +300,8 @@ mod tests {
|
|||
let mut request = http::Request::builder()
|
||||
.uri("http://example.com/Foobaz")
|
||||
.body(SdkBody::empty())
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
signer
|
||||
.sign_http_request(
|
||||
|
@ -327,6 +332,8 @@ mod tests {
|
|||
let mut request = http::Request::builder()
|
||||
.uri("http://example.com/Foobaz")
|
||||
.body(SdkBody::empty())
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
signer
|
||||
.sign_http_request(
|
||||
|
@ -350,7 +357,11 @@ mod tests {
|
|||
let runtime_components = RuntimeComponentsBuilder::for_tests().build().unwrap();
|
||||
let config_bag = ConfigBag::base();
|
||||
let identity = Identity::new(Login::new("Aladdin", "open sesame", None), None);
|
||||
let mut request = http::Request::builder().body(SdkBody::empty()).unwrap();
|
||||
let mut request = http::Request::builder()
|
||||
.body(SdkBody::empty())
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
signer
|
||||
.sign_http_request(
|
||||
|
@ -374,7 +385,11 @@ mod tests {
|
|||
let config_bag = ConfigBag::base();
|
||||
let runtime_components = RuntimeComponentsBuilder::for_tests().build().unwrap();
|
||||
let identity = Identity::new(Token::new("some-token", None), None);
|
||||
let mut request = http::Request::builder().body(SdkBody::empty()).unwrap();
|
||||
let mut request = http::Request::builder()
|
||||
.body(SdkBody::empty())
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
signer
|
||||
.sign_http_request(
|
||||
&mut request,
|
||||
|
|
|
@ -17,6 +17,7 @@ pub mod adapter {
|
|||
use aws_smithy_client::erase::DynConnector;
|
||||
use aws_smithy_runtime_api::client::connectors::HttpConnector;
|
||||
use aws_smithy_runtime_api::client::orchestrator::{BoxFuture, HttpRequest, HttpResponse};
|
||||
use std::future::ready;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
/// Adapts a [`DynConnector`] to the [`HttpConnector`] trait.
|
||||
|
@ -41,7 +42,11 @@ pub mod adapter {
|
|||
|
||||
impl HttpConnector for DynConnectorAdapter {
|
||||
fn call(&self, request: HttpRequest) -> BoxFuture<HttpResponse> {
|
||||
let future = self.dyn_connector.lock().unwrap().call_lite(request);
|
||||
let req = match request.into_http03x() {
|
||||
Err(e) => return Box::pin(ready(Err(Box::new(e) as _))),
|
||||
Ok(req) => req,
|
||||
};
|
||||
let future = self.dyn_connector.lock().unwrap().call_lite(req);
|
||||
future
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,8 +54,7 @@ impl Interceptor for ConnectionPoisoningInterceptor {
|
|||
let capture_smithy_connection = CaptureSmithyConnectionWrapper::new();
|
||||
context
|
||||
.request_mut()
|
||||
.extensions_mut()
|
||||
.insert(capture_smithy_connection.clone_inner());
|
||||
.add_extension(capture_smithy_connection.clone_inner());
|
||||
cfg.interceptor_state().store_put(capture_smithy_connection);
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -11,7 +11,7 @@ use aws_smithy_http::result::ConnectorError;
|
|||
use aws_smithy_protocol_test::{assert_ok, validate_body, MediaType};
|
||||
use aws_smithy_runtime_api::client::connectors::HttpConnector;
|
||||
use aws_smithy_runtime_api::client::orchestrator::{BoxFuture, HttpRequest, HttpResponse};
|
||||
use http::header::{HeaderName, CONTENT_TYPE};
|
||||
use http::header::CONTENT_TYPE;
|
||||
use std::fmt::Debug;
|
||||
use std::ops::Deref;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
@ -146,7 +146,7 @@ struct ValidateRequest {
|
|||
}
|
||||
|
||||
impl ValidateRequest {
|
||||
fn assert_matches(&self, index: usize, ignore_headers: &[HeaderName]) {
|
||||
fn assert_matches(&self, index: usize, ignore_headers: &[&str]) {
|
||||
let (actual, expected) = (&self.actual, &self.expected);
|
||||
assert_eq!(
|
||||
actual.uri(),
|
||||
|
@ -154,14 +154,13 @@ impl ValidateRequest {
|
|||
"Request #{index} - URI doesn't match expected value"
|
||||
);
|
||||
for (name, value) in expected.headers() {
|
||||
if !ignore_headers.contains(name) {
|
||||
if !ignore_headers.contains(&name) {
|
||||
let actual_header = actual
|
||||
.headers()
|
||||
.get(name)
|
||||
.unwrap_or_else(|| panic!("Request #{index} - Header {name:?} is missing"));
|
||||
assert_eq!(
|
||||
actual_header.to_str().unwrap(),
|
||||
value.to_str().unwrap(),
|
||||
actual_header, value,
|
||||
"Request #{index} - Header {name:?} doesn't match expected value",
|
||||
);
|
||||
}
|
||||
|
@ -171,7 +170,7 @@ impl ValidateRequest {
|
|||
let media_type = if actual
|
||||
.headers()
|
||||
.get(CONTENT_TYPE)
|
||||
.map(|v| v.to_str().unwrap().contains("json"))
|
||||
.map(|v| v.contains("json"))
|
||||
.unwrap_or(false)
|
||||
{
|
||||
MediaType::Json
|
||||
|
@ -225,7 +224,7 @@ impl TestConnector {
|
|||
/// A list of headers that should be ignored when comparing requests can be passed
|
||||
/// for cases where headers are non-deterministic or are irrelevant to the test.
|
||||
#[track_caller]
|
||||
pub fn assert_requests_match(&self, ignore_headers: &[HeaderName]) {
|
||||
pub fn assert_requests_match(&self, ignore_headers: &[&str]) {
|
||||
for (i, req) in self.requests().iter().enumerate() {
|
||||
req.assert_matches(i, ignore_headers)
|
||||
}
|
||||
|
|
|
@ -437,7 +437,7 @@ mod tests {
|
|||
use crate::client::test_util::{
|
||||
deserializer::CannedResponseDeserializer, serializer::CannedRequestSerializer,
|
||||
};
|
||||
use ::http::{Request, Response, StatusCode};
|
||||
use ::http::{Response, StatusCode};
|
||||
use aws_smithy_runtime_api::client::auth::static_resolver::StaticAuthSchemeOptionResolver;
|
||||
use aws_smithy_runtime_api::client::auth::{
|
||||
AuthSchemeOptionResolverParams, SharedAuthSchemeOptionResolver,
|
||||
|
@ -465,11 +465,7 @@ mod tests {
|
|||
use tracing_test::traced_test;
|
||||
|
||||
fn new_request_serializer() -> CannedRequestSerializer {
|
||||
CannedRequestSerializer::success(
|
||||
Request::builder()
|
||||
.body(SdkBody::empty())
|
||||
.expect("request is valid"),
|
||||
)
|
||||
CannedRequestSerializer::success(HttpRequest::new(SdkBody::empty()))
|
||||
}
|
||||
|
||||
fn new_response_deserializer() -> CannedResponseDeserializer {
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
use crate::client::auth::no_auth::NO_AUTH_SCHEME_ID;
|
||||
use aws_smithy_runtime_api::box_error::BoxError;
|
||||
use aws_smithy_runtime_api::client::auth::{
|
||||
AuthScheme, AuthSchemeEndpointConfig, AuthSchemeId, AuthSchemeOptionResolver,
|
||||
|
@ -125,15 +124,10 @@ fn extract_endpoint_auth_scheme_config(
|
|||
endpoint: &Endpoint,
|
||||
scheme_id: AuthSchemeId,
|
||||
) -> Result<AuthSchemeEndpointConfig<'_>, AuthOrchestrationError> {
|
||||
// TODO(P96049742): Endpoint config doesn't currently have a concept of optional auth or "no auth", so
|
||||
// we are short-circuiting lookup of endpoint auth scheme config if that is the selected scheme.
|
||||
if scheme_id == NO_AUTH_SCHEME_ID {
|
||||
return Ok(AuthSchemeEndpointConfig::empty());
|
||||
}
|
||||
let auth_schemes = match endpoint.properties().get("authSchemes") {
|
||||
Some(Document::Array(schemes)) => schemes,
|
||||
// no auth schemes:
|
||||
None => return Ok(AuthSchemeEndpointConfig::empty()),
|
||||
None => return Ok(AuthSchemeEndpointConfig::from(None)),
|
||||
_other => {
|
||||
return Err(AuthOrchestrationError::BadAuthSchemeEndpointConfig(
|
||||
"expected an array for `authSchemes` in endpoint config".into(),
|
||||
|
@ -199,7 +193,7 @@ mod tests {
|
|||
) -> Result<(), BoxError> {
|
||||
request
|
||||
.headers_mut()
|
||||
.insert(http::header::AUTHORIZATION, "success!".parse().unwrap());
|
||||
.insert(http::header::AUTHORIZATION.as_str(), "success!");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -229,7 +223,7 @@ mod tests {
|
|||
|
||||
let mut ctx = InterceptorContext::new(Input::doesnt_matter());
|
||||
ctx.enter_serialization_phase();
|
||||
ctx.set_request(http::Request::builder().body(SdkBody::empty()).unwrap());
|
||||
ctx.set_request(HttpRequest::new(SdkBody::empty()));
|
||||
let _ = ctx.take_input();
|
||||
ctx.enter_before_transmit_phase();
|
||||
|
||||
|
@ -275,7 +269,7 @@ mod tests {
|
|||
|
||||
let mut ctx = InterceptorContext::new(Input::doesnt_matter());
|
||||
ctx.enter_serialization_phase();
|
||||
ctx.set_request(http::Request::builder().body(SdkBody::empty()).unwrap());
|
||||
ctx.set_request(HttpRequest::new(SdkBody::empty()));
|
||||
let _ = ctx.take_input();
|
||||
ctx.enter_before_transmit_phase();
|
||||
|
||||
|
@ -324,7 +318,7 @@ mod tests {
|
|||
config_with_identity(HTTP_BEARER_AUTH_SCHEME_ID, Token::new("t", None));
|
||||
let mut ctx = InterceptorContext::new(Input::erase("doesnt-matter"));
|
||||
ctx.enter_serialization_phase();
|
||||
ctx.set_request(http::Request::builder().body(SdkBody::empty()).unwrap());
|
||||
ctx.set_request(HttpRequest::new(SdkBody::empty()));
|
||||
let _ = ctx.take_input();
|
||||
ctx.enter_before_transmit_phase();
|
||||
orchestrate_auth(&mut ctx, &runtime_components, &cfg)
|
||||
|
|
|
@ -4,10 +4,7 @@
|
|||
*/
|
||||
|
||||
use aws_smithy_http::endpoint::error::ResolveEndpointError;
|
||||
use aws_smithy_http::endpoint::{
|
||||
apply_endpoint as apply_endpoint_to_request_uri, EndpointPrefix, ResolveEndpoint,
|
||||
SharedEndpointResolver,
|
||||
};
|
||||
use aws_smithy_http::endpoint::{EndpointPrefix, ResolveEndpoint, SharedEndpointResolver};
|
||||
use aws_smithy_runtime_api::box_error::BoxError;
|
||||
use aws_smithy_runtime_api::client::endpoint::{EndpointResolver, EndpointResolverParams};
|
||||
use aws_smithy_runtime_api::client::interceptors::context::InterceptorContext;
|
||||
|
@ -15,8 +12,8 @@ use aws_smithy_runtime_api::client::orchestrator::{Future, HttpRequest};
|
|||
use aws_smithy_runtime_api::client::runtime_components::RuntimeComponents;
|
||||
use aws_smithy_types::config_bag::{ConfigBag, Storable, StoreReplace};
|
||||
use aws_smithy_types::endpoint::Endpoint;
|
||||
use http::header::HeaderName;
|
||||
use http::{HeaderValue, Uri};
|
||||
use http::Uri;
|
||||
use std::borrow::Cow;
|
||||
use std::fmt::Debug;
|
||||
use std::str::FromStr;
|
||||
use tracing::trace;
|
||||
|
@ -121,7 +118,6 @@ pub(super) async fn orchestrate_endpoint(
|
|||
.load::<EndpointResolverParams>()
|
||||
.expect("endpoint resolver params must be set");
|
||||
let endpoint_prefix = cfg.load::<EndpointPrefix>();
|
||||
tracing::debug!(endpoint_params = ?params, endpoint_prefix = ?endpoint_prefix, "resolving endpoint");
|
||||
let request = ctx.request_mut().expect("set during serialization");
|
||||
|
||||
let endpoint = runtime_components
|
||||
|
@ -141,31 +137,31 @@ fn apply_endpoint(
|
|||
endpoint: &Endpoint,
|
||||
endpoint_prefix: Option<&EndpointPrefix>,
|
||||
) -> Result<(), BoxError> {
|
||||
let uri: Uri = endpoint.url().parse().map_err(|err| {
|
||||
ResolveEndpointError::from_source("endpoint did not have a valid uri", err)
|
||||
})?;
|
||||
|
||||
apply_endpoint_to_request_uri(request.uri_mut(), &uri, endpoint_prefix).map_err(|err| {
|
||||
ResolveEndpointError::message(format!(
|
||||
"failed to apply endpoint `{:?}` to request `{:?}`",
|
||||
uri, request,
|
||||
))
|
||||
.with_source(Some(err.into()))
|
||||
})?;
|
||||
let prefixed_endpoint = match endpoint_prefix {
|
||||
Some(prefix) => Cow::Owned(format!("{}{}", prefix.as_str(), endpoint.url())),
|
||||
None => Cow::Borrowed(endpoint.url()),
|
||||
};
|
||||
request
|
||||
.uri_mut()
|
||||
.set_endpoint(prefixed_endpoint.as_ref())
|
||||
.map_err(|err| {
|
||||
ResolveEndpointError::message(format!(
|
||||
"failed to apply endpoint `{:?}` to request `{:?}`",
|
||||
endpoint.url(),
|
||||
request,
|
||||
))
|
||||
.with_source(Some(err.into()))
|
||||
})?;
|
||||
|
||||
for (header_name, header_values) in endpoint.headers() {
|
||||
request.headers_mut().remove(header_name);
|
||||
for value in header_values {
|
||||
request.headers_mut().insert(
|
||||
HeaderName::from_str(header_name).map_err(|err| {
|
||||
ResolveEndpointError::message("invalid header name")
|
||||
request
|
||||
.headers_mut()
|
||||
.try_insert(header_name.to_string(), value.to_string())
|
||||
.map_err(|err| {
|
||||
ResolveEndpointError::message("invalid header key or value value")
|
||||
.with_source(Some(err.into()))
|
||||
})?,
|
||||
HeaderValue::from_str(value).map_err(|err| {
|
||||
ResolveEndpointError::message("invalid header value")
|
||||
.with_source(Some(err.into()))
|
||||
})?,
|
||||
);
|
||||
})?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
@ -25,6 +25,5 @@ pub mod client;
|
|||
/// A data structure for persisting and sharing state between multiple clients.
|
||||
pub mod static_partition_map;
|
||||
|
||||
/// General testing utilities.
|
||||
#[cfg(feature = "test-util")]
|
||||
/// Test utilities
|
||||
pub mod test_util;
|
||||
|
|
|
@ -58,12 +58,9 @@ impl Interceptor for HttpChecksumRequiredInterceptor {
|
|||
.bytes()
|
||||
.expect("checksum can only be computed for non-streaming operations");
|
||||
let checksum = <md5::Md5 as md5::Digest>::digest(body_bytes);
|
||||
request.headers_mut().insert(
|
||||
HeaderName::from_static("content-md5"),
|
||||
base64::encode(&checksum[..])
|
||||
.parse()
|
||||
.expect("checksum is a valid header value"),
|
||||
);
|
||||
request
|
||||
.headers_mut()
|
||||
.insert("content-md5", base64::encode(&checksum[..]));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue