Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.next.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,12 @@ message = "Fix bug that can cause panics in paginators"
references = ["smithy-rs#1903", "smithy-rs#1902"]
meta = { "breaking" = false, "tada" = false, "bug" = true, "target" = "client"}
author = "rcoh"

[[smithy-rs]]
message = """
Operation metadata is now added to the property bag before sending requests allowing middlewares to behave
differently depending on the operation being sent.
"""
references = ["smithy-rs#1919"]
meta = { "breaking" = false, "tada" = false, "bug" = false, "target" = "client"}
author = "Velfi"
38 changes: 38 additions & 0 deletions aws/rust-runtime/aws-inlineable/tests/middleware_e2e_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use aws_http::retry::AwsResponseRetryClassifier;
use aws_http::user_agent::AwsUserAgent;
use aws_inlineable::middleware::DefaultMiddleware;
use aws_sig_auth::signer::OperationSigningConfig;
use aws_smithy_client::erase::DynConnector;

use aws_smithy_client::test_connection::TestConnection;
use aws_smithy_http::body::SdkBody;
Expand Down Expand Up @@ -112,6 +113,7 @@ fn test_operation() -> Operation<TestOperationParser, AwsResponseRetryClassifier
.unwrap();
Operation::new(req, TestOperationParser)
.with_retry_classifier(AwsResponseRetryClassifier::new())
.with_metadata(operation::Metadata::new("test-op", "test-service"))
}

#[cfg(any(feature = "native-tls", feature = "rustls"))]
Expand Down Expand Up @@ -148,3 +150,39 @@ async fn e2e_test() {

conn.assert_requests_match(&[]);
}

#[tokio::test]
async fn test_operation_metadata_is_available_to_middlewares() {
let conn = TestConnection::new(vec![(
http::Request::builder()
.header(USER_AGENT, "aws-sdk-rust/0.123.test os/windows/XPSP3 lang/rust/1.50.0")
.header("x-amz-user-agent", "aws-sdk-rust/0.123.test api/test-service/0.123 os/windows/XPSP3 lang/rust/1.50.0")
.header(AUTHORIZATION, "AWS4-HMAC-SHA256 Credential=access_key/20210215/test-region/test-service-signing/aws4_request, SignedHeaders=host;x-amz-date;x-amz-user-agent, Signature=da249491d7fe3da22c2e09cbf910f37aa5b079a3cedceff8403d0b18a7bfab75")
.header("x-amz-date", "20210215T184017Z")
.uri(Uri::from_static("https://test-service.test-region.amazonaws.com/"))
.body(SdkBody::from("request body")).unwrap(),
http::Response::builder()
.status(200)
.body("response body")
.unwrap(),
)]);
let client = aws_smithy_client::Client::builder()
.middleware_fn(|req| {
let metadata = req
.properties()
.get::<operation::Metadata>()
.cloned()
.unwrap();

assert_eq!("test-op", metadata.name());
assert_eq!("test-service", metadata.service());

req
})
.connector(DynConnector::new(conn))
.build();

let resp = client.call(test_operation()).await;
let resp = resp.expect("successful operation");
assert_eq!(resp, "Hello!");
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ open class MakeOperationGenerator(
) {
val operationName = symbolProvider.toSymbol(shape).name
val baseReturnType = buildOperationType(implBlockWriter, shape, customizations)
val returnType = "std::result::Result<$baseReturnType, ${implBlockWriter.format(runtimeConfig.operationBuildError())}>"
val returnType =
"std::result::Result<$baseReturnType, ${implBlockWriter.format(runtimeConfig.operationBuildError())}>"
val outputSymbol = symbolProvider.toSymbol(shape)

val takesOwnership = bodyGenerator.payloadMetadata(shape).takesOwnership
Expand All @@ -82,8 +83,10 @@ open class MakeOperationGenerator(

implBlockWriter.docs("Consumes the builder and constructs an Operation<#D>", outputSymbol)
Attribute.AllowUnusedMut.render(implBlockWriter) // For codegen simplicity
Attribute.Custom("allow(clippy::let_and_return)").render(implBlockWriter) // For codegen simplicity, allow `let x = ...; x`
Attribute.Custom("allow(clippy::needless_borrow)").render(implBlockWriter) // Allows builders that don’t consume the input borrow
Attribute.Custom("allow(clippy::let_and_return)")
.render(implBlockWriter) // For codegen simplicity, allow `let x = ...; x`
Attribute.Custom("allow(clippy::needless_borrow)")
.render(implBlockWriter) // Allows builders that don’t consume the input borrow
implBlockWriter.rustBlockTemplate(
"$fnType $functionName($self, _config: &#{config}::Config) -> $returnType",
*codegenScope,
Expand Down
3 changes: 2 additions & 1 deletion rust-runtime/aws-smithy-http-tower/src/parse_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ where
}

fn call(&mut self, req: Operation<ResponseHandler, RetryPolicy>) -> Self::Future {
let (req, parts) = req.into_request_response();
let (mut req, parts) = req.into_request_response();
let handler = parts.response_handler;
// send_operation records the full request-response lifecycle.
// NOTE: For operations that stream output, only the setup is captured in this span.
Expand All @@ -103,6 +103,7 @@ where
if let Some(metadata) = parts.metadata {
span.record("operation", &metadata.name());
span.record("service", &metadata.service());
req.properties_mut().insert(metadata);
}
let resp = self.inner.call(req);
let fut = async move {
Expand Down