Skip to content

Commit d665873

Browse files
committed
PR feedback
1 parent 4a162de commit d665873

File tree

20 files changed

+356
-181
lines changed

20 files changed

+356
-181
lines changed

aws-runtime/aws-config/api/aws-config.api

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -262,12 +262,9 @@ public final class aws/sdk/kotlin/runtime/config/AwsSdkSettingKt {
262262
public static final fun resolveEndpointUrl (Laws/sdk/kotlin/runtime/config/AwsSdkSetting;Laws/smithy/kotlin/runtime/util/PlatformProvider;Ljava/lang/String;Ljava/lang/String;)Laws/smithy/kotlin/runtime/net/url/Url;
263263
}
264264

265-
public final class aws/sdk/kotlin/runtime/config/checksums/ResolveRequestChecksumCalculationKt {
265+
public final class aws/sdk/kotlin/runtime/config/checksums/ResolveFlexibleChecksumsConfigKt {
266266
public static final fun resolveRequestChecksumCalculation (Laws/smithy/kotlin/runtime/util/PlatformProvider;Laws/smithy/kotlin/runtime/util/LazyAsyncValue;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
267267
public static synthetic fun resolveRequestChecksumCalculation$default (Laws/smithy/kotlin/runtime/util/PlatformProvider;Laws/smithy/kotlin/runtime/util/LazyAsyncValue;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
268-
}
269-
270-
public final class aws/sdk/kotlin/runtime/config/checksums/ResolveResponseChecksumValidationKt {
271268
public static final fun resolveResponseChecksumValidation (Laws/smithy/kotlin/runtime/util/PlatformProvider;Laws/smithy/kotlin/runtime/util/LazyAsyncValue;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
272269
public static synthetic fun resolveResponseChecksumValidation$default (Laws/smithy/kotlin/runtime/util/PlatformProvider;Laws/smithy/kotlin/runtime/util/LazyAsyncValue;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
273270
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package aws.sdk.kotlin.runtime.config.checksums
2+
3+
import aws.sdk.kotlin.runtime.ConfigurationException
4+
import aws.sdk.kotlin.runtime.InternalSdkApi
5+
import aws.sdk.kotlin.runtime.config.AwsSdkSetting
6+
import aws.sdk.kotlin.runtime.config.profile.AwsProfile
7+
import aws.sdk.kotlin.runtime.config.profile.requestChecksumCalculation
8+
import aws.sdk.kotlin.runtime.config.profile.responseChecksumValidation
9+
import aws.smithy.kotlin.runtime.client.config.HttpChecksumConfigOption
10+
import aws.smithy.kotlin.runtime.config.resolve
11+
import aws.smithy.kotlin.runtime.util.LazyAsyncValue
12+
import aws.smithy.kotlin.runtime.util.PlatformProvider
13+
14+
/**
15+
* Attempts to resolve requestChecksumCalculation from the specified sources.
16+
* @return requestChecksumCalculation setting if found, the default value if not.
17+
*/
18+
@InternalSdkApi
19+
public suspend fun resolveRequestChecksumCalculation(platform: PlatformProvider = PlatformProvider.System, profile: LazyAsyncValue<AwsProfile>): HttpChecksumConfigOption {
20+
val unparsedString = AwsSdkSetting.AwsRequestChecksumCalculation.resolve(platform) ?: profile.get().requestChecksumCalculation
21+
return parseHttpChecksumConfigOption(unparsedString, "requestChecksumCalculation")
22+
}
23+
24+
/**
25+
* Attempts to resolve responseChecksumValidation from the specified sources.
26+
* @return responseChecksumValidation setting if found, the default value if not.
27+
*/
28+
@InternalSdkApi
29+
public suspend fun resolveResponseChecksumValidation(platform: PlatformProvider = PlatformProvider.System, profile: LazyAsyncValue<AwsProfile>): HttpChecksumConfigOption {
30+
val unparsedString = AwsSdkSetting.AwsResponseChecksumValidation.resolve(platform) ?: profile.get().responseChecksumValidation
31+
return parseHttpChecksumConfigOption(unparsedString, "responseChecksumValidation")
32+
}
33+
34+
private fun parseHttpChecksumConfigOption(unparsedString: String?, configOption: String): HttpChecksumConfigOption =
35+
when (unparsedString?.uppercase()) {
36+
null -> HttpChecksumConfigOption.WHEN_SUPPORTED
37+
"WHEN_SUPPORTED" -> HttpChecksumConfigOption.WHEN_SUPPORTED
38+
"WHEN_REQUIRED" -> HttpChecksumConfigOption.WHEN_REQUIRED
39+
else -> throw ConfigurationException(
40+
"'$unparsedString' is not a valid value for $configOption. Valid values are: ${HttpChecksumConfigOption.entries}",
41+
)
42+
}

aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/config/checksums/ResolveRequestChecksumCalculation.kt

Lines changed: 0 additions & 29 deletions
This file was deleted.

aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/config/checksums/ResolveResponseChecksumValidation.kt

Lines changed: 0 additions & 29 deletions
This file was deleted.

aws-runtime/aws-http/api/aws-http.api

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,29 @@ public final class aws/sdk/kotlin/runtime/http/interceptors/BusinessMetricsInter
196196
public fun readBeforeTransmit (Laws/smithy/kotlin/runtime/client/ProtocolRequestInterceptorContext;)V
197197
}
198198

199+
public final class aws/sdk/kotlin/runtime/http/interceptors/S3CompositeChecksumsInterceptor : aws/smithy/kotlin/runtime/client/Interceptor {
200+
public fun <init> ()V
201+
public fun modifyBeforeAttemptCompletion-gIAlu-s (Laws/smithy/kotlin/runtime/client/ResponseInterceptorContext;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
202+
public fun modifyBeforeCompletion-gIAlu-s (Laws/smithy/kotlin/runtime/client/ResponseInterceptorContext;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
203+
public fun modifyBeforeDeserialization (Laws/smithy/kotlin/runtime/client/ProtocolResponseInterceptorContext;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
204+
public fun modifyBeforeRetryLoop (Laws/smithy/kotlin/runtime/client/ProtocolRequestInterceptorContext;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
205+
public fun modifyBeforeSerialization (Laws/smithy/kotlin/runtime/client/RequestInterceptorContext;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
206+
public fun modifyBeforeSigning (Laws/smithy/kotlin/runtime/client/ProtocolRequestInterceptorContext;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
207+
public fun modifyBeforeTransmit (Laws/smithy/kotlin/runtime/client/ProtocolRequestInterceptorContext;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
208+
public fun readAfterAttempt (Laws/smithy/kotlin/runtime/client/ResponseInterceptorContext;)V
209+
public fun readAfterDeserialization (Laws/smithy/kotlin/runtime/client/ResponseInterceptorContext;)V
210+
public fun readAfterExecution (Laws/smithy/kotlin/runtime/client/ResponseInterceptorContext;)V
211+
public fun readAfterSerialization (Laws/smithy/kotlin/runtime/client/ProtocolRequestInterceptorContext;)V
212+
public fun readAfterSigning (Laws/smithy/kotlin/runtime/client/ProtocolRequestInterceptorContext;)V
213+
public fun readAfterTransmit (Laws/smithy/kotlin/runtime/client/ProtocolResponseInterceptorContext;)V
214+
public fun readBeforeAttempt (Laws/smithy/kotlin/runtime/client/ProtocolRequestInterceptorContext;)V
215+
public fun readBeforeDeserialization (Laws/smithy/kotlin/runtime/client/ProtocolResponseInterceptorContext;)V
216+
public fun readBeforeExecution (Laws/smithy/kotlin/runtime/client/RequestInterceptorContext;)V
217+
public fun readBeforeSerialization (Laws/smithy/kotlin/runtime/client/RequestInterceptorContext;)V
218+
public fun readBeforeSigning (Laws/smithy/kotlin/runtime/client/ProtocolRequestInterceptorContext;)V
219+
public fun readBeforeTransmit (Laws/smithy/kotlin/runtime/client/ProtocolRequestInterceptorContext;)V
220+
}
221+
199222
public final class aws/sdk/kotlin/runtime/http/interceptors/UnsupportedSigningAlgorithmInterceptor : aws/smithy/kotlin/runtime/client/Interceptor {
200223
public fun <init> ()V
201224
public fun modifyBeforeAttemptCompletion-gIAlu-s (Laws/smithy/kotlin/runtime/client/ResponseInterceptorContext;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package aws.sdk.kotlin.runtime.http.interceptors
2+
3+
import aws.smithy.kotlin.runtime.client.ProtocolResponseInterceptorContext
4+
import aws.smithy.kotlin.runtime.http.HeadersBuilder
5+
import aws.smithy.kotlin.runtime.http.interceptors.HttpInterceptor
6+
import aws.smithy.kotlin.runtime.http.request.HttpRequest
7+
import aws.smithy.kotlin.runtime.http.response.HttpResponse
8+
import aws.smithy.kotlin.runtime.http.response.toBuilder
9+
import aws.smithy.kotlin.runtime.telemetry.logging.Logger
10+
import aws.smithy.kotlin.runtime.telemetry.logging.logger
11+
import kotlin.coroutines.coroutineContext
12+
13+
private const val CHECKSUM_HEADER_PREFIX = "x-amz-checksum-"
14+
15+
/**
16+
* Removes any checksum headers that contain composite checksums from an S3 response.
17+
*/
18+
public class S3CompositeChecksumsInterceptor : HttpInterceptor {
19+
override suspend fun modifyBeforeDeserialization(context: ProtocolResponseInterceptorContext<Any, HttpRequest, HttpResponse>): HttpResponse {
20+
val response = context.protocolResponse.toBuilder()
21+
val logger = coroutineContext.logger<S3CompositeChecksumsInterceptor>()
22+
23+
response.headers.removeCompositeChecksums(logger)
24+
25+
return response.build()
26+
}
27+
}
28+
29+
/**
30+
* Removes any checksum headers that contain composite checksums.
31+
*/
32+
internal fun HeadersBuilder.removeCompositeChecksums(logger: Logger): Unit =
33+
names().forEach { header ->
34+
if (header.startsWith(CHECKSUM_HEADER_PREFIX, ignoreCase = true) && get(header)!!.isCompositeChecksum()) {
35+
logger.warn { "S3 returned a composite checksum, composite checksums are not supported, removing checksum" }
36+
remove(header)
37+
}
38+
}
39+
40+
/**
41+
* Verifies if a checksum is composite.
42+
*/
43+
private fun String.isCompositeChecksum(): Boolean {
44+
// Ends with "-#" where "#" is a number
45+
val regex = Regex("-(\\d)+$")
46+
return regex.containsMatchIn(this)
47+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package aws.sdk.kotlin.runtime.http.interceptors
2+
3+
import aws.smithy.kotlin.runtime.http.HeadersBuilder
4+
import aws.smithy.kotlin.runtime.telemetry.logging.logger
5+
import kotlinx.coroutines.test.runTest
6+
import kotlin.coroutines.coroutineContext
7+
import kotlin.test.Test
8+
import kotlin.test.assertFalse
9+
import kotlin.test.assertTrue
10+
11+
class S3CompositeChecksumsInterceptorTest {
12+
@Test
13+
fun compositeChecksumRemoval() = runTest {
14+
val headers = HeadersBuilder()
15+
16+
headers.append("x-amz-checksum-crc32", "foo-1")
17+
headers.append("x-amz-checksum-sha256", "bar")
18+
19+
assertTrue(
20+
headers.contains("x-amz-checksum-crc32"),
21+
)
22+
assertTrue(
23+
headers.contains("x-amz-checksum-sha256"),
24+
)
25+
26+
headers.removeCompositeChecksums(coroutineContext.logger<S3CompositeChecksumsInterceptor>())
27+
28+
assertFalse(
29+
headers.contains("x-amz-checksum-crc32"),
30+
)
31+
assertTrue(
32+
headers.contains("x-amz-checksum-sha256"),
33+
)
34+
}
35+
}

codegen/aws-sdk-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsRuntimeTypes.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ object AwsRuntimeTypes {
6262
val UnsupportedSigningAlgorithmInterceptor = symbol("UnsupportedSigningAlgorithmInterceptor")
6363
val BusinessMetricsInterceptor = symbol("BusinessMetricsInterceptor")
6464
val AwsBusinessMetric = symbol("AwsBusinessMetric")
65+
val S3CompositeChecksumsInterceptor = symbol("S3CompositeChecksumsInterceptor")
6566
}
6667

6768
object Retries {

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

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,6 @@ import software.amazon.smithy.model.Model
1818
import software.amazon.smithy.model.shapes.OperationShape
1919
import software.amazon.smithy.model.shapes.StructureShape
2020

21-
/**
22-
* AWS services that can return composite checksums in their responses
23-
*/
24-
private val compositeChecksumServices = setOf(
25-
"s3",
26-
)
27-
2821
/**
2922
* Adds a middleware which validates checksums returned in responses if the user has opted-in.
3023
*/
@@ -98,7 +91,6 @@ class FlexibleChecksumsResponse : KotlinIntegration {
9891
) {
9992
writer.write("input.#L?.value == \"ENABLED\",", requestValidationModeMemberName)
10093
writer.write("config.responseChecksumValidation,")
101-
writer.write("#L", compositeChecksumServices.contains(ctx.settings.sdkId))
10294
}
10395
}
10496
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package aws.sdk.kotlin.codegen.customization.flexiblechecksums.s3
2+
3+
import aws.sdk.kotlin.codegen.AwsRuntimeTypes.Http.Interceptors.S3CompositeChecksumsInterceptor
4+
import aws.sdk.kotlin.codegen.customization.s3.isS3
5+
import software.amazon.smithy.aws.traits.HttpChecksumTrait
6+
import software.amazon.smithy.kotlin.codegen.KotlinSettings
7+
import software.amazon.smithy.kotlin.codegen.core.KotlinWriter
8+
import software.amazon.smithy.kotlin.codegen.integration.KotlinIntegration
9+
import software.amazon.smithy.kotlin.codegen.model.expectShape
10+
import software.amazon.smithy.kotlin.codegen.model.hasTrait
11+
import software.amazon.smithy.kotlin.codegen.rendering.protocol.ProtocolGenerator
12+
import software.amazon.smithy.kotlin.codegen.rendering.protocol.ProtocolMiddleware
13+
import software.amazon.smithy.model.Model
14+
import software.amazon.smithy.model.shapes.OperationShape
15+
import software.amazon.smithy.model.shapes.ServiceShape
16+
17+
/**
18+
* Removes composite checksums returned by S3 so that flexible checksums won't validate them.
19+
* Composite checksums are used for multipart uploads and end with "-#" where "#" is a number.
20+
*/
21+
class S3CompositeChecksumsIntegration : KotlinIntegration {
22+
override val order: Byte
23+
get() = -128
24+
25+
override fun enabledForService(model: Model, settings: KotlinSettings): Boolean =
26+
model.expectShape<ServiceShape>(settings.service).isS3
27+
28+
override fun customizeMiddleware(ctx: ProtocolGenerator.GenerationContext, resolved: List<ProtocolMiddleware>) =
29+
resolved + s3CompositeChecksumsMiddleware
30+
}
31+
32+
/**
33+
* Adds [S3CompositeChecksumsInterceptor] to interceptors when operation has flexible checksums.
34+
*/
35+
private val s3CompositeChecksumsMiddleware = object : ProtocolMiddleware {
36+
override val name: String = "S3CompositeChecksumsMiddleware"
37+
38+
override fun isEnabledFor(ctx: ProtocolGenerator.GenerationContext, op: OperationShape): Boolean =
39+
op.hasTrait<HttpChecksumTrait>()
40+
41+
override fun render(ctx: ProtocolGenerator.GenerationContext, op: OperationShape, writer: KotlinWriter) {
42+
writer.write("op.interceptors.add(#T())", S3CompositeChecksumsInterceptor)
43+
}
44+
}

0 commit comments

Comments
 (0)