Skip to content

Commit 427daf3

Browse files
committed
Refactor checksum interceptors
1 parent 0029768 commit 427daf3

File tree

5 files changed

+190
-204
lines changed

5 files changed

+190
-204
lines changed

codegen/aws-sdk-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/customization/flexiblechecksums/FlexibleChecksumsRequest.kt

Lines changed: 85 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,15 @@ import software.amazon.smithy.model.shapes.OperationShape
2222
import software.amazon.smithy.model.shapes.StructureShape
2323

2424
/**
25-
* Adds a middleware that enables sending flexible checksums during an HTTP request
25+
* Handles flexible checksum requests
2626
*/
2727
class FlexibleChecksumsRequest : KotlinIntegration {
28-
override fun enabledForService(model: Model, settings: KotlinSettings) = model
29-
.shapes<OperationShape>()
30-
.any { it.hasTrait<HttpChecksumTrait>() }
28+
override fun enabledForService(model: Model, settings: KotlinSettings) =
29+
model.isTraitApplied(HttpChecksumTrait::class.java)
3130

3231
override fun additionalServiceConfigProps(ctx: CodegenContext): List<ConfigProperty> =
3332
listOf(
33+
// Allows flexible checksum request configuration
3434
ConfigProperty {
3535
name = "requestChecksumCalculation"
3636
symbol = RuntimeTypes.SmithyClient.Config.HttpChecksumConfigOption
@@ -42,66 +42,96 @@ class FlexibleChecksumsRequest : KotlinIntegration {
4242
)
4343

4444
override fun customizeMiddleware(ctx: ProtocolGenerator.GenerationContext, resolved: List<ProtocolMiddleware>) =
45-
resolved + flexibleChecksumsRequestMiddleware + configBusinessMetrics
46-
47-
private val configBusinessMetrics = object : ProtocolMiddleware {
48-
override val name: String = "requestChecksumCalculationBusinessMetric"
49-
50-
override fun isEnabledFor(ctx: ProtocolGenerator.GenerationContext, op: OperationShape): Boolean =
51-
op.hasTrait<HttpChecksumTrait>()
52-
53-
override fun render(ctx: ProtocolGenerator.GenerationContext, op: OperationShape, writer: KotlinWriter) {
54-
writer.withBlock("when(config.requestChecksumCalculation) {", "}") {
55-
writer.write(
56-
"#T.WHEN_SUPPORTED -> op.context.#T(#T.FLEXIBLE_CHECKSUMS_REQ_WHEN_SUPPORTED)",
57-
RuntimeTypes.SmithyClient.Config.HttpChecksumConfigOption,
58-
RuntimeTypes.Core.BusinessMetrics.emitBusinessMetric,
59-
RuntimeTypes.Core.BusinessMetrics.SmithyBusinessMetric,
60-
)
61-
writer.write(
62-
"#T.WHEN_REQUIRED -> op.context.#T(#T.FLEXIBLE_CHECKSUMS_REQ_WHEN_REQUIRED)",
63-
RuntimeTypes.SmithyClient.Config.HttpChecksumConfigOption,
64-
RuntimeTypes.Core.BusinessMetrics.emitBusinessMetric,
65-
RuntimeTypes.Core.BusinessMetrics.SmithyBusinessMetric,
66-
)
67-
}
68-
}
69-
}
45+
resolved + requestChecksumCalculationBusinessMetric + httpChecksumDefaultAlgorithmMiddleware + flexibleChecksumsRequestMiddleware
46+
}
7047

71-
private val flexibleChecksumsRequestMiddleware = object : ProtocolMiddleware {
72-
override val name: String = "flexibleChecksumsRequestMiddleware"
48+
/**
49+
* Emits business metric based on `requestChecksumCalculation` client config
50+
*/
51+
private val requestChecksumCalculationBusinessMetric = object : ProtocolMiddleware {
52+
override val name: String = "requestChecksumCalculationBusinessMetric"
7353

74-
override fun isEnabledFor(ctx: ProtocolGenerator.GenerationContext, op: OperationShape): Boolean {
75-
val httpChecksumTrait = op.getTrait<HttpChecksumTrait>()
76-
val input = op.input.getOrNull()?.let { ctx.model.expectShape<StructureShape>(it) }
54+
override fun isEnabledFor(ctx: ProtocolGenerator.GenerationContext, op: OperationShape): Boolean =
55+
op.hasTrait<HttpChecksumTrait>()
7756

78-
return (httpChecksumTrait != null) &&
79-
(httpChecksumTrait.requestAlgorithmMember?.getOrNull() != null) &&
80-
(input?.memberNames?.any { it == httpChecksumTrait.requestAlgorithmMember.get() } == true)
57+
override fun render(ctx: ProtocolGenerator.GenerationContext, op: OperationShape, writer: KotlinWriter) {
58+
writer.withBlock("when(config.requestChecksumCalculation) {", "}") {
59+
// Supported
60+
writer.write(
61+
"#T.WHEN_SUPPORTED -> op.context.#T(#T.FLEXIBLE_CHECKSUMS_REQ_WHEN_SUPPORTED)",
62+
RuntimeTypes.SmithyClient.Config.HttpChecksumConfigOption,
63+
RuntimeTypes.Core.BusinessMetrics.emitBusinessMetric,
64+
RuntimeTypes.Core.BusinessMetrics.SmithyBusinessMetric,
65+
)
66+
// Required
67+
writer.write(
68+
"#T.WHEN_REQUIRED -> op.context.#T(#T.FLEXIBLE_CHECKSUMS_REQ_WHEN_REQUIRED)",
69+
RuntimeTypes.SmithyClient.Config.HttpChecksumConfigOption,
70+
RuntimeTypes.Core.BusinessMetrics.emitBusinessMetric,
71+
RuntimeTypes.Core.BusinessMetrics.SmithyBusinessMetric,
72+
)
8173
}
74+
}
75+
}
8276

83-
override fun render(ctx: ProtocolGenerator.GenerationContext, op: OperationShape, writer: KotlinWriter) {
84-
val inputSymbol = ctx.symbolProvider.toSymbol(ctx.model.expectShape(op.inputShape))
77+
/**
78+
* Adds default checksum algorithm to the execution context
79+
*/
80+
private val httpChecksumDefaultAlgorithmMiddleware = object : ProtocolMiddleware {
81+
override val name: String = "httpChecksumDefaultAlgorithmMiddleware"
82+
override val order: Byte = -2 // Before S3 Express (possibly) changes the default (-1) and before calculating checksum (0)
8583

86-
val httpChecksumTrait = op.getTrait<HttpChecksumTrait>()!!
84+
override fun isEnabledFor(ctx: ProtocolGenerator.GenerationContext, op: OperationShape): Boolean =
85+
requestChecksumsConfigured(ctx, op)
8786

88-
val requestAlgorithmMember = ctx.model.expectShape<StructureShape>(op.input.get())
89-
.members()
90-
.first { it.memberName == httpChecksumTrait.requestAlgorithmMember.get() }
87+
override fun render(ctx: ProtocolGenerator.GenerationContext, op: OperationShape, writer: KotlinWriter) {
88+
writer.write(
89+
"op.context[#T.DefaultChecksumAlgorithm] = #S",
90+
RuntimeTypes.HttpClient.Operation.HttpOperationContext,
91+
"CRC32",
92+
)
93+
}
94+
}
95+
96+
/**
97+
* Adds interceptor to handle flexible checksum request calculation
98+
*/
99+
private val flexibleChecksumsRequestMiddleware = object : ProtocolMiddleware {
100+
override val name: String = "flexibleChecksumsRequestMiddleware"
101+
102+
override fun isEnabledFor(ctx: ProtocolGenerator.GenerationContext, op: OperationShape): Boolean =
103+
requestChecksumsConfigured(ctx, op)
91104

92-
val requestAlgorithmMemberName = ctx.symbolProvider.toMemberName(requestAlgorithmMember)
93-
val requestChecksumRequired = httpChecksumTrait.isRequestChecksumRequired
105+
override fun render(ctx: ProtocolGenerator.GenerationContext, op: OperationShape, writer: KotlinWriter) {
106+
val httpChecksumTrait = op.getTrait<HttpChecksumTrait>()!!
107+
val requestChecksumRequired = httpChecksumTrait.isRequestChecksumRequired
108+
val requestAlgorithmMember = ctx.model.expectShape<StructureShape>(op.input.get())
109+
.members()
110+
.first { it.memberName == httpChecksumTrait.requestAlgorithmMember.get() }
111+
val requestAlgorithmMemberName = ctx.symbolProvider.toMemberName(requestAlgorithmMember)
94112

95-
writer.withBlock(
96-
"op.interceptors.add(#T<#T>(",
97-
"))",
98-
RuntimeTypes.HttpClient.Interceptors.FlexibleChecksumsRequestInterceptor,
99-
inputSymbol,
100-
) {
101-
writer.write("#L,", requestChecksumRequired)
102-
writer.write("config.requestChecksumCalculation,")
103-
writer.write("input.#L?.value,", requestAlgorithmMemberName)
104-
}
113+
writer.withBlock(
114+
"op.interceptors.add(#T(",
115+
"))",
116+
RuntimeTypes.HttpClient.Interceptors.FlexibleChecksumsRequestInterceptor,
117+
) {
118+
writer.write("#L,", requestChecksumRequired)
119+
writer.write("config.requestChecksumCalculation,")
120+
writer.write("input.#L?.value,", requestAlgorithmMemberName)
105121
}
106122
}
107123
}
124+
125+
/**
126+
* Determines if an operation is set up to send flexible request checksums
127+
*/
128+
private fun requestChecksumsConfigured(ctx: ProtocolGenerator.GenerationContext, op: OperationShape): Boolean {
129+
val httpChecksumTrait = op.getTrait<HttpChecksumTrait>()
130+
val inputShape = op.input.getOrNull()?.let { ctx.model.expectShape<StructureShape>(it) }
131+
132+
return (
133+
(httpChecksumTrait != null) &&
134+
(httpChecksumTrait.requestAlgorithmMember?.getOrNull() != null) &&
135+
(inputShape?.memberNames?.any { it == httpChecksumTrait.requestAlgorithmMember.get() } == true)
136+
)
137+
}

codegen/aws-sdk-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/customization/flexiblechecksums/FlexibleChecksumsResponse.kt

Lines changed: 55 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,15 @@ import software.amazon.smithy.model.shapes.OperationShape
1919
import software.amazon.smithy.model.shapes.StructureShape
2020

2121
/**
22-
* Adds a middleware which validates checksums returned in responses if the user has opted-in.
22+
* Handles flexible checksum responses
2323
*/
2424
class FlexibleChecksumsResponse : KotlinIntegration {
25-
override fun enabledForService(model: Model, settings: KotlinSettings) = model
26-
.shapes<OperationShape>()
27-
.any { it.hasTrait<HttpChecksumTrait>() }
25+
override fun enabledForService(model: Model, settings: KotlinSettings) =
26+
model.isTraitApplied(HttpChecksumTrait::class.java)
2827

2928
override fun additionalServiceConfigProps(ctx: CodegenContext): List<ConfigProperty> =
3029
listOf(
30+
// Allows flexible checksum response configuration
3131
ConfigProperty {
3232
name = "responseChecksumValidation"
3333
symbol = RuntimeTypes.SmithyClient.Config.HttpChecksumConfigOption
@@ -39,59 +39,66 @@ class FlexibleChecksumsResponse : KotlinIntegration {
3939
)
4040

4141
override fun customizeMiddleware(ctx: ProtocolGenerator.GenerationContext, resolved: List<ProtocolMiddleware>) =
42-
resolved + flexibleChecksumsResponseMiddleware + configBusinessMetrics
42+
resolved + flexibleChecksumsResponseMiddleware + responseChecksumValidationBusinessMetric
43+
}
4344

44-
private val configBusinessMetrics = object : ProtocolMiddleware {
45-
override val name: String = "responseChecksumValidationBusinessMetric"
45+
/**
46+
* Emits business metric based on `responseChecksumValidation` client config
47+
*/
48+
private val responseChecksumValidationBusinessMetric = object : ProtocolMiddleware {
49+
override val name: String = "responseChecksumValidationBusinessMetric"
4650

47-
override fun render(ctx: ProtocolGenerator.GenerationContext, op: OperationShape, writer: KotlinWriter) {
48-
writer.withBlock("when(config.responseChecksumValidation) {", "}") {
49-
writer.write(
50-
"#T.WHEN_SUPPORTED -> op.context.#T(#T.FLEXIBLE_CHECKSUMS_RES_WHEN_SUPPORTED)",
51-
RuntimeTypes.SmithyClient.Config.HttpChecksumConfigOption,
52-
RuntimeTypes.Core.BusinessMetrics.emitBusinessMetric,
53-
RuntimeTypes.Core.BusinessMetrics.SmithyBusinessMetric,
54-
)
55-
writer.write(
56-
"#T.WHEN_REQUIRED -> op.context.#T(#T.FLEXIBLE_CHECKSUMS_RES_WHEN_REQUIRED)",
57-
RuntimeTypes.SmithyClient.Config.HttpChecksumConfigOption,
58-
RuntimeTypes.Core.BusinessMetrics.emitBusinessMetric,
59-
RuntimeTypes.Core.BusinessMetrics.SmithyBusinessMetric,
60-
)
61-
}
51+
override fun render(ctx: ProtocolGenerator.GenerationContext, op: OperationShape, writer: KotlinWriter) {
52+
writer.withBlock("when(config.responseChecksumValidation) {", "}") {
53+
// Supported
54+
writer.write(
55+
"#T.WHEN_SUPPORTED -> op.context.#T(#T.FLEXIBLE_CHECKSUMS_RES_WHEN_SUPPORTED)",
56+
RuntimeTypes.SmithyClient.Config.HttpChecksumConfigOption,
57+
RuntimeTypes.Core.BusinessMetrics.emitBusinessMetric,
58+
RuntimeTypes.Core.BusinessMetrics.SmithyBusinessMetric,
59+
)
60+
// Required
61+
writer.write(
62+
"#T.WHEN_REQUIRED -> op.context.#T(#T.FLEXIBLE_CHECKSUMS_RES_WHEN_REQUIRED)",
63+
RuntimeTypes.SmithyClient.Config.HttpChecksumConfigOption,
64+
RuntimeTypes.Core.BusinessMetrics.emitBusinessMetric,
65+
RuntimeTypes.Core.BusinessMetrics.SmithyBusinessMetric,
66+
)
6267
}
6368
}
69+
}
6470

65-
private val flexibleChecksumsResponseMiddleware = object : ProtocolMiddleware {
66-
override val name: String = "FlexibleChecksumsResponse"
67-
68-
override fun isEnabledFor(ctx: ProtocolGenerator.GenerationContext, op: OperationShape): Boolean {
69-
val httpChecksumTrait = op.getTrait<HttpChecksumTrait>()
70-
val input = op.input.getOrNull()?.let { ctx.model.expectShape<StructureShape>(it) }
71+
/**
72+
* Adds interceptor to handle flexible checksum response validation
73+
*/
74+
private val flexibleChecksumsResponseMiddleware = object : ProtocolMiddleware {
75+
override val name: String = "flexibleChecksumsResponseMiddleware"
7176

72-
return (httpChecksumTrait != null) &&
73-
(httpChecksumTrait.requestValidationModeMember?.getOrNull() != null) &&
74-
(input?.memberNames?.any { it == httpChecksumTrait.requestValidationModeMember.get() } == true)
75-
}
77+
override fun isEnabledFor(ctx: ProtocolGenerator.GenerationContext, op: OperationShape): Boolean {
78+
val httpChecksumTrait = op.getTrait<HttpChecksumTrait>()
79+
val inputShape = op.input.getOrNull()?.let { ctx.model.expectShape<StructureShape>(it) }
7680

77-
override fun render(ctx: ProtocolGenerator.GenerationContext, op: OperationShape, writer: KotlinWriter) {
78-
val inputSymbol = ctx.symbolProvider.toSymbol(ctx.model.expectShape(op.inputShape))
81+
return (httpChecksumTrait != null) &&
82+
(httpChecksumTrait.requestValidationModeMember?.getOrNull() != null) &&
83+
(inputShape?.memberNames?.any { it == httpChecksumTrait.requestValidationModeMember.get() } == true)
84+
}
7985

80-
val httpChecksumTrait = op.getTrait<HttpChecksumTrait>()!!
81-
val requestValidationModeMember = ctx.model.expectShape<StructureShape>(op.input.get())
82-
.members()
83-
.first { it.memberName == httpChecksumTrait.requestValidationModeMember.get() }
84-
val requestValidationModeMemberName = ctx.symbolProvider.toMemberName(requestValidationModeMember)
86+
override fun render(ctx: ProtocolGenerator.GenerationContext, op: OperationShape, writer: KotlinWriter) {
87+
val inputSymbol = ctx.symbolProvider.toSymbol(ctx.model.expectShape(op.inputShape))
88+
val httpChecksumTrait = op.getTrait<HttpChecksumTrait>()!!
89+
val requestValidationModeMember = ctx.model.expectShape<StructureShape>(op.input.get())
90+
.members()
91+
.first { it.memberName == httpChecksumTrait.requestValidationModeMember.get() }
92+
val requestValidationModeMemberName = ctx.symbolProvider.toMemberName(requestValidationModeMember)
8593

86-
writer.withBlock(
87-
"op.interceptors.add(#T<#T>(",
88-
"))",
89-
RuntimeTypes.HttpClient.Interceptors.FlexibleChecksumsResponseInterceptor,
90-
inputSymbol,
91-
) {
92-
writer.write("input.#L?.value == \"ENABLED\",", requestValidationModeMemberName)
93-
writer.write("config.responseChecksumValidation,")
94-
}
94+
writer.withBlock( // TODO: ADD DIFFERENT INTERCEPTORS DEPENDING ON IF THE SERVICE HAS COMPOSITE CHECKSUMS !
95+
"op.interceptors.add(#T<#T>(",
96+
"))",
97+
RuntimeTypes.HttpClient.Interceptors.FlexibleChecksumsResponseInterceptor,
98+
inputSymbol,
99+
) {
100+
writer.write("input.#L?.value == \"ENABLED\",", requestValidationModeMemberName)
101+
writer.write("config.responseChecksumValidation,")
95102
}
96103
}
97104
}

codegen/aws-sdk-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/customization/s3/express/S3ExpressIntegration.kt

Lines changed: 13 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import software.amazon.smithy.kotlin.codegen.rendering.protocol.ProtocolGenerato
1616
import software.amazon.smithy.kotlin.codegen.rendering.protocol.ProtocolMiddleware
1717
import software.amazon.smithy.kotlin.codegen.rendering.util.ConfigProperty
1818
import software.amazon.smithy.kotlin.codegen.rendering.util.ConfigPropertyType
19-
import software.amazon.smithy.kotlin.codegen.utils.getOrNull
2019
import software.amazon.smithy.model.Model
2120
import software.amazon.smithy.model.shapes.*
2221
import software.amazon.smithy.model.traits.*
@@ -26,7 +25,7 @@ import software.amazon.smithy.model.transform.ModelTransformer
2625
* An integration which handles codegen for S3 Express, such as:
2726
* 1. Configure auth scheme by applying a synthetic shape and trait
2827
* 2. Add ExpressClient and Bucket to execution context
29-
* 3. Disable all checksums for s3:UploadPart
28+
* 3. Configuring the default checksum algorithm
3029
*/
3130
class S3ExpressIntegration : KotlinIntegration {
3231
companion object {
@@ -97,7 +96,7 @@ class S3ExpressIntegration : KotlinIntegration {
9796
resolved + listOf(
9897
addClientToExecutionContext,
9998
addBucketToExecutionContext,
100-
uploadPartDisableChecksum,
99+
s3ExpressDefaultChecksumAlgorithm,
101100
)
102101

103102
private val s3AttributesSymbol = buildSymbol {
@@ -130,33 +129,23 @@ class S3ExpressIntegration : KotlinIntegration {
130129
}
131130

132131
/**
133-
* Disable all checksums for s3:UploadPart
132+
* Re-configures the default checksum algorithm for S3 Express.
134133
*/
135-
private val uploadPartDisableChecksum = object : ProtocolMiddleware {
136-
override val name: String = "UploadPartDisableChecksum"
134+
private val s3ExpressDefaultChecksumAlgorithm = object : ProtocolMiddleware {
135+
override val name: String = "s3ExpressDefaultChecksumAlgorithm"
136+
override val order: Byte = -1 // After setting the modeled default (-2) and before calculating the checksum (0)
137137

138138
override fun isEnabledFor(ctx: ProtocolGenerator.GenerationContext, op: OperationShape): Boolean =
139-
op.isS3UploadPart && op.hasTrait<HttpChecksumTrait>()
139+
op.hasTrait<HttpChecksumTrait>() || op.hasTrait<HttpChecksumRequiredTrait>()
140140

141141
override fun render(ctx: ProtocolGenerator.GenerationContext, op: OperationShape, writer: KotlinWriter) {
142-
val httpChecksumTrait = op.getTrait<HttpChecksumTrait>()!!
143-
144-
val requestAlgorithmMemberName = httpChecksumTrait.requestAlgorithmMember?.getOrNull()?.let {
145-
val requestAlgorithmMemberShape = ctx.model.expectShape<StructureShape>(op.input.get())
146-
.members()
147-
.first { it.memberName == httpChecksumTrait.requestAlgorithmMember.get() }
148-
ctx.symbolProvider.toMemberName(requestAlgorithmMemberShape)
149-
}
150-
151-
val interceptorSymbol = buildSymbol {
152-
namespace = "aws.sdk.kotlin.services.s3.express"
153-
name = "S3ExpressDisableChecksumInterceptor"
154-
}
155-
writer.addImport(interceptorSymbol)
156142
writer.write(
157-
"op.interceptors.add(#T(input.#L?.value != null))",
158-
interceptorSymbol,
159-
requestAlgorithmMemberName,
143+
"op.interceptors.add(#T(#L))",
144+
buildSymbol {
145+
namespace = "aws.sdk.kotlin.services.s3.express"
146+
name = "S3ExpressDefaultChecksumAlgorithm"
147+
},
148+
op.isS3UploadPart
160149
)
161150
}
162151
}

0 commit comments

Comments
 (0)