Skip to content

Commit 1157f26

Browse files
committed
Fix composite checksums
1 parent d74c949 commit 1157f26

File tree

3 files changed

+32
-22
lines changed

3 files changed

+32
-22
lines changed

runtime/auth/aws-signing-common/common/src/aws/smithy/kotlin/runtime/auth/awssigning/AwsSigningConfig.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ public class AwsSigningConfig(builder: Builder) {
174174

175175
/**
176176
* Determines the checksum to add to the canonical request query parameters before signing.
177+
* The first element of the pair represents the checksum name, the second represents the checksum value.
177178
*/
178179
public val checksum: Pair<String, String>? = builder.checksum
179180

runtime/protocol/http-client/common/src/aws/smithy/kotlin/runtime/http/interceptors/FlexibleChecksumsResponseInterceptor.kt

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -44,38 +44,33 @@ internal val CHECKSUM_HEADER_VALIDATION_PRIORITY_LIST: List<String> = listOf(
4444
* @param responseChecksumValidation Configuration option that determines when checksum validation should be done.
4545
*/
4646
@InternalApi
47-
public class FlexibleChecksumsResponseInterceptor<I>(
47+
public open class FlexibleChecksumsResponseInterceptor(
4848
private val responseValidationRequired: Boolean,
4949
private val responseChecksumValidation: HttpChecksumConfigOption?,
5050
) : HttpInterceptor {
51-
52-
// FIXME: Remove in next minor version bump
53-
@Deprecated("Old constructor is no longer used but it's kept for backwards compatibility")
54-
public constructor(
55-
shouldValidateResponseChecksumInitializer: (input: I) -> Boolean,
56-
) : this(
57-
false,
58-
HttpChecksumConfigOption.WHEN_REQUIRED,
59-
)
60-
6151
@InternalApi
6252
public companion object {
6353
// The name of the checksum header which was validated. If `null`, validation was not performed.
6454
public val ChecksumHeaderValidated: AttributeKey<String> = AttributeKey("ChecksumHeaderValidated")
6555
}
6656

6757
override suspend fun modifyBeforeDeserialization(context: ProtocolResponseInterceptorContext<Any, HttpRequest, HttpResponse>): HttpResponse {
68-
val logger = coroutineContext.logger<FlexibleChecksumsResponseInterceptor<I>>()
58+
val logger = coroutineContext.logger<FlexibleChecksumsResponseInterceptor>()
6959

70-
val forcedToVerifyChecksum = responseValidationRequired || responseChecksumValidation == HttpChecksumConfigOption.WHEN_SUPPORTED
71-
if (!forcedToVerifyChecksum) return context.protocolResponse
60+
val configuredToVerifyChecksum = responseValidationRequired || responseChecksumValidation == HttpChecksumConfigOption.WHEN_SUPPORTED
61+
if (!configuredToVerifyChecksum) return context.protocolResponse
7262

7363
val checksumHeader = CHECKSUM_HEADER_VALIDATION_PRIORITY_LIST
7464
.firstOrNull { context.protocolResponse.headers.contains(it) } ?: run {
75-
logger.warn { "Checksum validation was requested but the response headers didn't contain a valid checksum." }
65+
logger.warn { "Checksum validation was requested but the response headers didn't contain a valid checksum." }
66+
return context.protocolResponse
67+
}
68+
69+
val serviceChecksumValue = context.protocolResponse.headers[checksumHeader]!!
70+
if (ignoreChecksum(serviceChecksumValue)) {
71+
logger.warn { "Checksum detected but validation was skipped." }
7672
return context.protocolResponse
7773
}
78-
val serviceChecksumValue = context.protocolResponse.headers[checksumHeader]!!
7974

8075
context.executionContext[ChecksumHeaderValidated] = checksumHeader
8176

@@ -111,6 +106,11 @@ public class FlexibleChecksumsResponseInterceptor<I>(
111106
else -> throw IllegalStateException("HTTP body type '$bodyType' is not supported for flexible checksums.")
112107
}
113108
}
109+
110+
/**
111+
* Additional check on the checksum itself to see if it should be validated
112+
*/
113+
public open fun ignoreChecksum(checksum: String): Boolean = false
114114
}
115115

116116
public class ChecksumMismatchException(message: String?) : ClientException(message)

runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/hashing/HashFunction.kt

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,20 +73,29 @@ public fun String.toHashFunction(): HashFunction? = when (this.lowercase()) {
7373
}
7474

7575
/**
76-
* Return the [HashFunction] which is represented by this string, or an exception if none match.
76+
* @return The [HashFunction] which is represented by this string, or an exception if none match.
7777
*/
7878
@InternalApi
7979
public fun String.toHashFunctionOrThrow(): HashFunction =
8080
toHashFunction() ?: throw ClientException("Checksum algorithm is not supported: $this")
8181

8282
/**
83-
* @return if the [HashFunction] is supported by flexible checksums
83+
* @return If the [HashFunction] is supported by flexible checksums
8484
*/
8585
@InternalApi
86-
public val HashFunction.isSupportedForFlexibleChecksums: Boolean get() = when (this) {
87-
is Crc32, is Crc32c, is Sha256, is Sha1 -> true
88-
else -> false
89-
}
86+
public val HashFunction.isSupportedForFlexibleChecksums: Boolean get() =
87+
algorithmsSupportedForFlexibleChecksums.contains(this::class.simpleName)
88+
89+
/**
90+
* The class names of checksum algorithms supported for flexible checksums
91+
*/
92+
// This is shown to users in exception messages to let them know which algorithms are supported
93+
public val algorithmsSupportedForFlexibleChecksums: Set<String> = setOf(
94+
"Crc32",
95+
"Crc32c",
96+
"Sha1",
97+
"Sha256",
98+
)
9099

91100
/**
92101
* @return The checksum algorithm header used depending on the checksum algorithm name

0 commit comments

Comments
 (0)