Loading aws/sdk/aws-models/s3-tests.smithy +38 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,7 @@ $version: "1.0" namespace com.amazonaws.s3 use smithy.test#httpResponseTests use smithy.test#httpRequestTests apply NotFound @httpResponseTests([ { Loading @@ -9,6 +10,7 @@ apply NotFound @httpResponseTests([ documentation: "This test case validates https://github.com/awslabs/smithy-rs/issues/456", params: { }, bodyMediaType: "application/xml", body: "", protocol: "aws.protocols#restXml", code: 404, Loading @@ -31,6 +33,42 @@ apply GetBucketLocation @httpResponseTests([ params: { "LocationConstraint": "us-west-2" }, bodyMediaType: "application/xml", protocol: "aws.protocols#restXml" } ]) apply PutBucketLifecycleConfiguration @httpRequestTests([ { id: "PutBucketLifecycleConfiguration", documentation: "This test validates that the content md5 header is set correctly", method: "PUT", protocol: "aws.protocols#restXml", uri: "/test-bucket", headers: { // we can assert this, but when this test is promoted, it can't assert // on the exact contents "content-md5": "b14bbeb8064f913b40c4975a03ef6e4a", }, bodyMediaType: "application/xml", body: """ <LifecycleConfiguration xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"> <Rule xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"> <Expiration xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"> <Days xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">1</Days> </Expiration> <ID xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">Expire</ID> <Status xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">Enabled</Status> </Rule> </LifecycleConfiguration> """, params: { "Bucket": "test-bucket", "LifecycleConfiguration": { "Rules": [ {"Expiration": { "Days": 1 }, "Status": "Enabled", "ID": "Expire" }, ] } } } ]) codegen-test/model/rest-xml-extras.smithy +29 −1 Original line number Diff line number Diff line Loading @@ -12,7 +12,13 @@ use smithy.test#httpRequestTests @restXml service RestXmlExtras { version: "2019-12-16", operations: [AttributeParty, XmlMapsFlattenedNestedXmlNamespace, EnumKeys, PrimitiveIntOpXml] operations: [ AttributeParty, XmlMapsFlattenedNestedXmlNamespace, EnumKeys, PrimitiveIntOpXml, ChecksumRequired ] } @httpRequestTests([{ Loading Loading @@ -175,3 +181,25 @@ map XmlMapsNestedNestedNamespaceInputOutputMap { @xmlName("V") value: String } @httpRequestTests([{ id: "ChecksumRequiredHeader", method: "POST", body: "<ChecksumRequiredInput><field>hello</field></ChecksumRequiredInput>", uri: "/ChecksumRequired", bodyMediaType: "application/xml", params: { field: "hello" }, headers: { "Content-Md5": "240240a9803ad7032101319e42a45c31" }, protocol: "aws.protocols#restXml" }]) @httpChecksumRequired @http(uri: "/ChecksumRequired", method: "POST") operation ChecksumRequired { input: ChecksumRequiredInput } structure ChecksumRequiredInput { field: String } codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/CargoDependency.kt +1 −0 Original line number Diff line number Diff line Loading @@ -183,6 +183,7 @@ data class CargoDependency( } companion object { val Md5 = CargoDependency("md5", CratesIo("0.7")) val FastRand = CargoDependency("fastrand", CratesIo("1")) val Http: CargoDependency = CargoDependency("http", CratesIo("0.2")) val Tower: CargoDependency = CargoDependency("tower", CratesIo("0.4"), optional = true) Loading codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/customizations/HttpChecksumRequiredGenerator.kt 0 → 100644 +62 −0 Original line number Diff line number Diff line /* * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0. */ package software.amazon.smithy.rust.codegen.smithy.customizations import software.amazon.smithy.codegen.core.CodegenException import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.model.traits.HttpChecksumRequiredTrait import software.amazon.smithy.rust.codegen.rustlang.CargoDependency import software.amazon.smithy.rust.codegen.rustlang.Writable import software.amazon.smithy.rust.codegen.rustlang.asType import software.amazon.smithy.rust.codegen.rustlang.rustTemplate import software.amazon.smithy.rust.codegen.rustlang.writable import software.amazon.smithy.rust.codegen.smithy.customize.OperationCustomization import software.amazon.smithy.rust.codegen.smithy.customize.OperationSection import software.amazon.smithy.rust.codegen.smithy.generators.ProtocolConfig import software.amazon.smithy.rust.codegen.smithy.generators.operationBuildError import software.amazon.smithy.rust.codegen.util.hasStreamingMember import software.amazon.smithy.rust.codegen.util.hasTrait import software.amazon.smithy.rust.codegen.util.inputShape class HttpChecksumRequiredGenerator( private val protocolConfig: ProtocolConfig, private val operationShape: OperationShape ) : OperationCustomization() { override fun section(section: OperationSection): Writable { if (!operationShape.hasTrait<HttpChecksumRequiredTrait>()) { return emptySection } if (operationShape.inputShape(protocolConfig.model).hasStreamingMember(protocolConfig.model)) { throw CodegenException("HttpChecksum required cannot be applied to a streaming shape") } return when (section) { is OperationSection.MutateRequest -> writable { rustTemplate( """ ${section.request} = ${section.request}.augment(|mut req, _| { let data = req .body() .bytes() .ok_or_else(||#{BuildError}::SerializationError( "checksum can only be computed for non-streaming operations".into()) )?; let checksum = #{md5}::compute(data); req.headers_mut().insert( #{http}::header::HeaderName::from_static("content-md5"), format!("{:x}", checksum).parse().expect("checksum is valid header value") ); Result::<_, #{BuildError}>::Ok(req) })?; """, "md5" to CargoDependency.Md5.asType(), "http" to CargoDependency.Http.asType(), "BuildError" to protocolConfig.runtimeConfig.operationBuildError() ) } else -> emptySection } } } codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/customize/RequiredCustomizations.kt +2 −1 Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.rust.codegen.smithy.customizations.AllowClippyLints import software.amazon.smithy.rust.codegen.smithy.customizations.CrateVersionGenerator import software.amazon.smithy.rust.codegen.smithy.customizations.EndpointPrefixGenerator import software.amazon.smithy.rust.codegen.smithy.customizations.HttpChecksumRequiredGenerator import software.amazon.smithy.rust.codegen.smithy.customizations.IdempotencyTokenGenerator import software.amazon.smithy.rust.codegen.smithy.customizations.SmithyTypesPubUseGenerator import software.amazon.smithy.rust.codegen.smithy.generators.LibRsCustomization Loading @@ -30,7 +31,7 @@ class RequiredCustomizations : RustCodegenDecorator { return baseCustomizations + IdempotencyTokenGenerator(protocolConfig, operation) + EndpointPrefixGenerator( protocolConfig, operation ) ) + HttpChecksumRequiredGenerator(protocolConfig, operation) } override fun libRsCustomizations( Loading Loading
aws/sdk/aws-models/s3-tests.smithy +38 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,7 @@ $version: "1.0" namespace com.amazonaws.s3 use smithy.test#httpResponseTests use smithy.test#httpRequestTests apply NotFound @httpResponseTests([ { Loading @@ -9,6 +10,7 @@ apply NotFound @httpResponseTests([ documentation: "This test case validates https://github.com/awslabs/smithy-rs/issues/456", params: { }, bodyMediaType: "application/xml", body: "", protocol: "aws.protocols#restXml", code: 404, Loading @@ -31,6 +33,42 @@ apply GetBucketLocation @httpResponseTests([ params: { "LocationConstraint": "us-west-2" }, bodyMediaType: "application/xml", protocol: "aws.protocols#restXml" } ]) apply PutBucketLifecycleConfiguration @httpRequestTests([ { id: "PutBucketLifecycleConfiguration", documentation: "This test validates that the content md5 header is set correctly", method: "PUT", protocol: "aws.protocols#restXml", uri: "/test-bucket", headers: { // we can assert this, but when this test is promoted, it can't assert // on the exact contents "content-md5": "b14bbeb8064f913b40c4975a03ef6e4a", }, bodyMediaType: "application/xml", body: """ <LifecycleConfiguration xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"> <Rule xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"> <Expiration xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"> <Days xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">1</Days> </Expiration> <ID xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">Expire</ID> <Status xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">Enabled</Status> </Rule> </LifecycleConfiguration> """, params: { "Bucket": "test-bucket", "LifecycleConfiguration": { "Rules": [ {"Expiration": { "Days": 1 }, "Status": "Enabled", "ID": "Expire" }, ] } } } ])
codegen-test/model/rest-xml-extras.smithy +29 −1 Original line number Diff line number Diff line Loading @@ -12,7 +12,13 @@ use smithy.test#httpRequestTests @restXml service RestXmlExtras { version: "2019-12-16", operations: [AttributeParty, XmlMapsFlattenedNestedXmlNamespace, EnumKeys, PrimitiveIntOpXml] operations: [ AttributeParty, XmlMapsFlattenedNestedXmlNamespace, EnumKeys, PrimitiveIntOpXml, ChecksumRequired ] } @httpRequestTests([{ Loading Loading @@ -175,3 +181,25 @@ map XmlMapsNestedNestedNamespaceInputOutputMap { @xmlName("V") value: String } @httpRequestTests([{ id: "ChecksumRequiredHeader", method: "POST", body: "<ChecksumRequiredInput><field>hello</field></ChecksumRequiredInput>", uri: "/ChecksumRequired", bodyMediaType: "application/xml", params: { field: "hello" }, headers: { "Content-Md5": "240240a9803ad7032101319e42a45c31" }, protocol: "aws.protocols#restXml" }]) @httpChecksumRequired @http(uri: "/ChecksumRequired", method: "POST") operation ChecksumRequired { input: ChecksumRequiredInput } structure ChecksumRequiredInput { field: String }
codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/CargoDependency.kt +1 −0 Original line number Diff line number Diff line Loading @@ -183,6 +183,7 @@ data class CargoDependency( } companion object { val Md5 = CargoDependency("md5", CratesIo("0.7")) val FastRand = CargoDependency("fastrand", CratesIo("1")) val Http: CargoDependency = CargoDependency("http", CratesIo("0.2")) val Tower: CargoDependency = CargoDependency("tower", CratesIo("0.4"), optional = true) Loading
codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/customizations/HttpChecksumRequiredGenerator.kt 0 → 100644 +62 −0 Original line number Diff line number Diff line /* * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0. */ package software.amazon.smithy.rust.codegen.smithy.customizations import software.amazon.smithy.codegen.core.CodegenException import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.model.traits.HttpChecksumRequiredTrait import software.amazon.smithy.rust.codegen.rustlang.CargoDependency import software.amazon.smithy.rust.codegen.rustlang.Writable import software.amazon.smithy.rust.codegen.rustlang.asType import software.amazon.smithy.rust.codegen.rustlang.rustTemplate import software.amazon.smithy.rust.codegen.rustlang.writable import software.amazon.smithy.rust.codegen.smithy.customize.OperationCustomization import software.amazon.smithy.rust.codegen.smithy.customize.OperationSection import software.amazon.smithy.rust.codegen.smithy.generators.ProtocolConfig import software.amazon.smithy.rust.codegen.smithy.generators.operationBuildError import software.amazon.smithy.rust.codegen.util.hasStreamingMember import software.amazon.smithy.rust.codegen.util.hasTrait import software.amazon.smithy.rust.codegen.util.inputShape class HttpChecksumRequiredGenerator( private val protocolConfig: ProtocolConfig, private val operationShape: OperationShape ) : OperationCustomization() { override fun section(section: OperationSection): Writable { if (!operationShape.hasTrait<HttpChecksumRequiredTrait>()) { return emptySection } if (operationShape.inputShape(protocolConfig.model).hasStreamingMember(protocolConfig.model)) { throw CodegenException("HttpChecksum required cannot be applied to a streaming shape") } return when (section) { is OperationSection.MutateRequest -> writable { rustTemplate( """ ${section.request} = ${section.request}.augment(|mut req, _| { let data = req .body() .bytes() .ok_or_else(||#{BuildError}::SerializationError( "checksum can only be computed for non-streaming operations".into()) )?; let checksum = #{md5}::compute(data); req.headers_mut().insert( #{http}::header::HeaderName::from_static("content-md5"), format!("{:x}", checksum).parse().expect("checksum is valid header value") ); Result::<_, #{BuildError}>::Ok(req) })?; """, "md5" to CargoDependency.Md5.asType(), "http" to CargoDependency.Http.asType(), "BuildError" to protocolConfig.runtimeConfig.operationBuildError() ) } else -> emptySection } } }
codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/customize/RequiredCustomizations.kt +2 −1 Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.rust.codegen.smithy.customizations.AllowClippyLints import software.amazon.smithy.rust.codegen.smithy.customizations.CrateVersionGenerator import software.amazon.smithy.rust.codegen.smithy.customizations.EndpointPrefixGenerator import software.amazon.smithy.rust.codegen.smithy.customizations.HttpChecksumRequiredGenerator import software.amazon.smithy.rust.codegen.smithy.customizations.IdempotencyTokenGenerator import software.amazon.smithy.rust.codegen.smithy.customizations.SmithyTypesPubUseGenerator import software.amazon.smithy.rust.codegen.smithy.generators.LibRsCustomization Loading @@ -30,7 +31,7 @@ class RequiredCustomizations : RustCodegenDecorator { return baseCustomizations + IdempotencyTokenGenerator(protocolConfig, operation) + EndpointPrefixGenerator( protocolConfig, operation ) ) + HttpChecksumRequiredGenerator(protocolConfig, operation) } override fun libRsCustomizations( Loading