Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support default checksums #1475

Open
wants to merge 70 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 68 commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
4729584
misc: add rules engine codegen tests
0marperez Nov 6, 2024
7b73088
Use snapshot version of smithy kotlin
0marperez Nov 6, 2024
dbfb973
debugging: throw exception to see what metrics are strings
0marperez Nov 6, 2024
b15358b
debugging: remove exception
0marperez Nov 6, 2024
dacc345
Don't depend on snapshot version of smithy kotlin
0marperez Nov 6, 2024
bbafc3f
Use released version
0marperez Nov 6, 2024
a79aa1e
PR feedback
0marperez Nov 6, 2024
e61efbb
Checkpoint
0marperez Nov 7, 2024
285c08b
Merge branch 'main' of https://github.com/awslabs/aws-sdk-kotlin into…
0marperez Nov 8, 2024
fbb3dd5
Checkoint 2
0marperez Nov 8, 2024
136c9db
It works now
0marperez Nov 8, 2024
cb4ab12
Clean up build scripts
0marperez Nov 9, 2024
41ad1b4
Commonize some more
0marperez Nov 9, 2024
1a2d989
Checkpoint 3
0marperez Nov 9, 2024
11c733f
Merge branch 'main' of https://github.com/awslabs/aws-sdk-kotlin into…
0marperez Nov 11, 2024
4d24a24
Remove rules engine codegen tests
0marperez Nov 11, 2024
c514cba
Setup checksums codegen tests
0marperez Nov 11, 2024
2796317
Update smithy IDL version, codegen tests pass now
0marperez Nov 11, 2024
6d53243
Setup dummy unit tests
0marperez Nov 11, 2024
40cfb17
Basic setup for client config tests
0marperez Nov 11, 2024
410c085
Added requestChecksumCalculation config option
0marperez Nov 11, 2024
472fae9
RequestChecksum not required client config tests
0marperez Nov 11, 2024
e9bf8e5
RequestChecksum required client config tests
0marperez Nov 11, 2024
5133a60
Added responseChecksumValidation
0marperez Nov 11, 2024
4ce5da7
TODO ResponseChecksumValidation tests
0marperez Nov 11, 2024
da31deb
Added ResponseChecksumValidation codegen tests
0marperez Nov 12, 2024
6037580
Quick self review
0marperez Nov 12, 2024
2f6e10b
Self review V2
0marperez Nov 12, 2024
d085dec
Add todos for business metrics
0marperez Nov 12, 2024
0bafdcc
Unit tests pass
0marperez Nov 25, 2024
fc84b61
E2E tests pass
0marperez Nov 26, 2024
0f6fa65
Self review
0marperez Nov 27, 2024
c76aefe
trigger ci
0marperez Nov 27, 2024
3476242
Fix smoke tests
0marperez Dec 1, 2024
b21ec41
Don't specify gradle version in smoke tests
0marperez Dec 1, 2024
dd2792f
Correctly print enum entries in error message
0marperez Dec 1, 2024
779cd3a
Remove test ordering from S3ChecksumTest
0marperez Dec 1, 2024
6674dc7
Merge branch 'main' of https://github.com/awslabs/aws-sdk-kotlin into…
0marperez Dec 1, 2024
a3a2e09
Add copyright headers to checksum codegen tests
0marperez Dec 1, 2024
c80b55c
Update buildSrc package setup
0marperez Dec 1, 2024
5e2855c
Fix codegen tests not having packages
0marperez Dec 1, 2024
0405b20
Fix event stream codegen test templates
0marperez Dec 1, 2024
eb338f4
Save test reports for failing JVM CI checks
0marperez Dec 1, 2024
a2fb7fb
Track smithy kotlin changes
0marperez Dec 3, 2024
093ed72
Merge branch 'main' of https://github.com/awslabs/aws-sdk-kotlin into…
0marperez Dec 4, 2024
d498e30
Fix jvmTest JVM compatibility
0marperez Dec 4, 2024
b534927
Drop support for http body dot bytes response checksums
0marperez Dec 4, 2024
2761bf9
Left FIXME to use random buckets in motorcade E2E tests
0marperez Dec 4, 2024
5328641
Refactor/fix S3 express integrations
0marperez Dec 6, 2024
ad30f70
Clean up S3 integrations and e2e tests
0marperez Dec 9, 2024
4a162de
s3 express no checksums in upload part test
0marperez Dec 9, 2024
d665873
PR feedback
0marperez Dec 11, 2024
1aefe66
Use head bucket
0marperez Dec 11, 2024
55bdcb8
Presigned URL checksums
0marperez Dec 13, 2024
44894e6
Ktlint
0marperez Dec 13, 2024
ad8d1ad
Trigger CI
0marperez Dec 13, 2024
d398801
Merge branch 'main' of https://github.com/awslabs/aws-sdk-kotlin into…
0marperez Dec 13, 2024
3c259ef
PR feeback checkpoint
0marperez Dec 13, 2024
0029768
Trigger CI
0marperez Dec 13, 2024
427daf3
Refactor checksum interceptors
0marperez Dec 18, 2024
41ad742
Fix composite checksums
0marperez Dec 19, 2024
5c6c0bf
Make it compile
0marperez Dec 19, 2024
4d915c6
Fix smithy model template
0marperez Dec 19, 2024
609226c
Fix model smithy template again?
0marperez Dec 19, 2024
80ba070
Fix model again
0marperez Dec 19, 2024
94dfc93
Merge branch 'main' of https://github.com/awslabs/aws-sdk-kotlin into…
0marperez Dec 19, 2024
77f6ea5
Refactor rules engine codegen tests
0marperez Dec 19, 2024
4b61347
Run CI (empty commit)
0marperez Dec 19, 2024
756f66d
PR feedback
0marperez Dec 23, 2024
3ed4d91
Change JVM version
0marperez Dec 24, 2024
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
6 changes: 6 additions & 0 deletions .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ jobs:
pwd
ls -lsa
./gradlew -Ptest.java.version=${{ matrix.java-version }} jvmTest --stacktrace
- name: Save Test Reports
if: failure()
uses: actions/upload-artifact@v3
with:
name: test-reports
path: '**/build/reports'
Comment on lines +43 to +48
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment: Good catch!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are these test reports used for?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not 100% sure why but sometimes the logs from failed CI tests are not very useful. In those cases you can just get a test report from the build and see which test cases failed and exception messages. Other CI checks have this as well


all-platforms:
runs-on: ${{ matrix.os }}
Expand Down
11 changes: 11 additions & 0 deletions aws-runtime/aws-config/api/aws-config.api
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,9 @@ public final class aws/sdk/kotlin/runtime/config/AwsSdkSetting {
public final fun getAwsMaxAttempts ()Laws/smithy/kotlin/runtime/config/EnvironmentSetting;
public final fun getAwsProfile ()Laws/smithy/kotlin/runtime/config/EnvironmentSetting;
public final fun getAwsRegion ()Laws/smithy/kotlin/runtime/config/EnvironmentSetting;
public final fun getAwsRequestChecksumCalculation ()Laws/smithy/kotlin/runtime/config/EnvironmentSetting;
public final fun getAwsRequestMinCompressionSizeBytes ()Laws/smithy/kotlin/runtime/config/EnvironmentSetting;
public final fun getAwsResponseChecksumValidation ()Laws/smithy/kotlin/runtime/config/EnvironmentSetting;
public final fun getAwsRetryMode ()Laws/smithy/kotlin/runtime/config/EnvironmentSetting;
public final fun getAwsRoleArn ()Laws/smithy/kotlin/runtime/config/EnvironmentSetting;
public final fun getAwsRoleSessionName ()Laws/smithy/kotlin/runtime/config/EnvironmentSetting;
Expand All @@ -260,6 +262,13 @@ public final class aws/sdk/kotlin/runtime/config/AwsSdkSettingKt {
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;
}

public final class aws/sdk/kotlin/runtime/config/checksums/ResolveFlexibleChecksumsConfigKt {
public static final fun resolveRequestChecksumCalculation (Laws/smithy/kotlin/runtime/util/PlatformProvider;Laws/smithy/kotlin/runtime/util/LazyAsyncValue;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
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;
public static final fun resolveResponseChecksumValidation (Laws/smithy/kotlin/runtime/util/PlatformProvider;Laws/smithy/kotlin/runtime/util/LazyAsyncValue;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
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;
}

public final class aws/sdk/kotlin/runtime/config/compression/RequestCompressionResolversKt {
public static final fun resolveDisableRequestCompression (Laws/smithy/kotlin/runtime/util/PlatformProvider;Laws/smithy/kotlin/runtime/util/LazyAsyncValue;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static synthetic fun resolveDisableRequestCompression$default (Laws/smithy/kotlin/runtime/util/PlatformProvider;Laws/smithy/kotlin/runtime/util/LazyAsyncValue;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
Expand Down Expand Up @@ -467,7 +476,9 @@ public final class aws/sdk/kotlin/runtime/config/profile/AwsProfileKt {
public static synthetic fun getLongOrNull$default (Laws/sdk/kotlin/runtime/config/profile/ConfigSection;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Ljava/lang/Long;
public static final fun getMaxAttempts (Laws/sdk/kotlin/runtime/config/profile/ConfigSection;)Ljava/lang/Integer;
public static final fun getRegion (Laws/sdk/kotlin/runtime/config/profile/ConfigSection;)Ljava/lang/String;
public static final fun getRequestChecksumCalculation (Laws/sdk/kotlin/runtime/config/profile/ConfigSection;)Ljava/lang/String;
public static final fun getRequestMinCompressionSizeBytes (Laws/sdk/kotlin/runtime/config/profile/ConfigSection;)Ljava/lang/Long;
public static final fun getResponseChecksumValidation (Laws/sdk/kotlin/runtime/config/profile/ConfigSection;)Ljava/lang/String;
public static final fun getRetryMode (Laws/sdk/kotlin/runtime/config/profile/ConfigSection;)Laws/smithy/kotlin/runtime/client/config/RetryMode;
public static final fun getRoleArn (Laws/sdk/kotlin/runtime/config/profile/ConfigSection;)Ljava/lang/String;
public static final fun getSdkUserAgentAppId (Laws/sdk/kotlin/runtime/config/profile/ConfigSection;)Ljava/lang/String;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
package aws.sdk.kotlin.runtime.config

import aws.sdk.kotlin.runtime.client.AwsSdkClientConfig
import aws.sdk.kotlin.runtime.config.checksums.resolveRequestChecksumCalculation
import aws.sdk.kotlin.runtime.config.checksums.resolveResponseChecksumValidation
import aws.sdk.kotlin.runtime.config.compression.resolveDisableRequestCompression
import aws.sdk.kotlin.runtime.config.compression.resolveRequestMinCompressionSizeBytes
import aws.sdk.kotlin.runtime.config.endpoints.resolveUseDualStack
Expand All @@ -22,6 +24,7 @@ import aws.smithy.kotlin.runtime.auth.awscredentials.SigV4aClientConfig
import aws.smithy.kotlin.runtime.client.*
import aws.smithy.kotlin.runtime.client.config.ClientSettings
import aws.smithy.kotlin.runtime.client.config.CompressionClientConfig
import aws.smithy.kotlin.runtime.client.config.HttpChecksumClientConfig
import aws.smithy.kotlin.runtime.config.resolve
import aws.smithy.kotlin.runtime.telemetry.TelemetryConfig
import aws.smithy.kotlin.runtime.telemetry.TelemetryProvider
Expand Down Expand Up @@ -94,6 +97,14 @@ public abstract class AbstractAwsSdkClientFactory<
config.sigV4aSigningRegionSet ?: resolveSigV4aSigningRegionSet(platform, profile)
}

if (config is HttpChecksumClientConfig.Builder) {
config.requestChecksumCalculation =
config.requestChecksumCalculation ?: resolveRequestChecksumCalculation(platform, profile)

config.responseChecksumValidation =
config.responseChecksumValidation ?: resolveResponseChecksumValidation(platform, profile)
}

finalizeConfig(builder)
finalizeEnvironmentalConfig(builder, sharedConfig, profile)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,18 @@ public object AwsSdkSetting {
*/
public val AwsSigV4aSigningRegionSet: EnvironmentSetting<String> =
strEnvSetting("aws.sigV4aSigningRegionSet", "AWS_SIGV4A_SIGNING_REGION_SET")

/**
* Configures request checksum calculation
*/
public val AwsRequestChecksumCalculation: EnvironmentSetting<String> =
strEnvSetting("aws.requestChecksumCalculation", "AWS_REQUEST_CHECKSUM_CALCULATION")

/**
* Configures response checksum validation
*/
public val AwsResponseChecksumValidation: EnvironmentSetting<String> =
strEnvSetting("aws.responseChecksumValidation", "AWS_RESPONSE_CHECKSUM_VALIDATION")
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package aws.sdk.kotlin.runtime.config.checksums

import aws.sdk.kotlin.runtime.ConfigurationException
import aws.sdk.kotlin.runtime.InternalSdkApi
import aws.sdk.kotlin.runtime.config.AwsSdkSetting
import aws.sdk.kotlin.runtime.config.profile.AwsProfile
import aws.sdk.kotlin.runtime.config.profile.requestChecksumCalculation
import aws.sdk.kotlin.runtime.config.profile.responseChecksumValidation
import aws.smithy.kotlin.runtime.client.config.HttpChecksumConfigOption
import aws.smithy.kotlin.runtime.config.resolve
import aws.smithy.kotlin.runtime.util.LazyAsyncValue
import aws.smithy.kotlin.runtime.util.PlatformProvider

/**
* Attempts to resolve requestChecksumCalculation from the specified sources.
* @return requestChecksumCalculation setting if found, the default value if not.
*/
@InternalSdkApi
public suspend fun resolveRequestChecksumCalculation(platform: PlatformProvider = PlatformProvider.System, profile: LazyAsyncValue<AwsProfile>): HttpChecksumConfigOption {
val unparsedString = AwsSdkSetting.AwsRequestChecksumCalculation.resolve(platform) ?: profile.get().requestChecksumCalculation
return parseHttpChecksumConfigOption(unparsedString, "requestChecksumCalculation")
}

/**
* Attempts to resolve responseChecksumValidation from the specified sources.
* @return responseChecksumValidation setting if found, the default value if not.
*/
@InternalSdkApi
public suspend fun resolveResponseChecksumValidation(platform: PlatformProvider = PlatformProvider.System, profile: LazyAsyncValue<AwsProfile>): HttpChecksumConfigOption {
val unparsedString = AwsSdkSetting.AwsResponseChecksumValidation.resolve(platform) ?: profile.get().responseChecksumValidation
return parseHttpChecksumConfigOption(unparsedString, "responseChecksumValidation")
}

private fun parseHttpChecksumConfigOption(unparsedString: String?, configOption: String): HttpChecksumConfigOption =
when (unparsedString?.uppercase()) {
null -> HttpChecksumConfigOption.WHEN_SUPPORTED
"WHEN_SUPPORTED" -> HttpChecksumConfigOption.WHEN_SUPPORTED
"WHEN_REQUIRED" -> HttpChecksumConfigOption.WHEN_REQUIRED
else -> throw ConfigurationException(
"'$unparsedString' is not a valid value for $configOption. Valid values are: ${HttpChecksumConfigOption.entries}",
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,20 @@ public val AwsProfile.requestMinCompressionSizeBytes: Long?
public val AwsProfile.sigV4aSigningRegionSet: String?
get() = getOrNull("sigv4a_signing_region_set")

/**
* Configures request checksum calculation
*/
@InternalSdkApi
public val AwsProfile.requestChecksumCalculation: String?
get() = getOrNull("request_checksum_calculation")

/**
* Configures response checksum validation
*/
@InternalSdkApi
public val AwsProfile.responseChecksumValidation: String?
get() = getOrNull("response_checksum_validation")

/**
* Parse a config value as a boolean, ignoring case.
*/
Expand Down
5 changes: 5 additions & 0 deletions aws-runtime/aws-http/api/aws-http.api
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,11 @@ public final class aws/sdk/kotlin/runtime/http/interceptors/BusinessMetricsInter
public fun readBeforeTransmit (Laws/smithy/kotlin/runtime/client/ProtocolRequestInterceptorContext;)V
}

public final class aws/sdk/kotlin/runtime/http/interceptors/S3FlexibleChecksumResponseInterceptor : aws/smithy/kotlin/runtime/http/interceptors/FlexibleChecksumsResponseInterceptor {
public fun <init> (ZLaws/smithy/kotlin/runtime/client/config/HttpChecksumConfigOption;)V
public fun ignoreChecksum (Ljava/lang/String;)Z
}

public final class aws/sdk/kotlin/runtime/http/interceptors/UnsupportedSigningAlgorithmInterceptor : aws/smithy/kotlin/runtime/client/Interceptor {
public fun <init> ()V
public fun modifyBeforeAttemptCompletion-gIAlu-s (Laws/smithy/kotlin/runtime/client/ResponseInterceptorContext;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
Expand Down
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

correctness: This file should go in services/s3/common/src/aws/sdk/kotlin/services/s3/internal with all the other S3-specific interceptors

Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package aws.sdk.kotlin.runtime.http.interceptors

import aws.smithy.kotlin.runtime.client.config.HttpChecksumConfigOption
import aws.smithy.kotlin.runtime.http.interceptors.FlexibleChecksumsResponseInterceptor

/**
* S3 variant of the flexible checksum interceptor where composite checksums are not validated
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit/docs: ... of the [FlexibleChecksumsResponseInterceptor]...

*/
public class S3FlexibleChecksumResponseInterceptor(
responseValidationRequired: Boolean,
responseChecksumValidation: HttpChecksumConfigOption?,
) : FlexibleChecksumsResponseInterceptor(
responseValidationRequired,
responseChecksumValidation,
) {
override fun ignoreChecksum(checksum: String): Boolean =
checksum.isCompositeChecksum()
}

/**
* Verifies if a checksum is composite.
*/
private fun String.isCompositeChecksum(): Boolean {
// Ends with "-#" where "#" is a number
val regex = Regex("-(\\d)+$")
return regex.containsMatchIn(this)
}
7 changes: 7 additions & 0 deletions buildSrc/build.gradle.kts
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need to exist? buildSrc is treated as an included build which means every subproject will have these config options applied.

It seems odd to need this just for codegen tests

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's the best way I could find to share a data class between subprojects, do you know of alternatives that would work better? I might've missed them

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can make a new project that both of those subprojects depend on

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still a work in progress, I don't want to block the review because of this. I think worst case scenario we can come back and refactor this without it being a breaking change

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
plugins {
alias(libs.plugins.kotlin.jvm)
}

repositories {
mavenCentral()
}
7 changes: 7 additions & 0 deletions buildSrc/settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
dependencyResolutionManagement {
versionCatalogs {
create("libs") {
from(files("../gradle/libs.versions.toml"))
}
}
}
19 changes: 19 additions & 0 deletions buildSrc/src/main/kotlin/aws/sdk/kotlin/shared/CodegenTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package aws.sdk.kotlin.shared

/**
* An AWS SDK for Kotlin codegen test
*/
data class CodegenTest(
val name: String,
val model: Model,
val serviceShapeId: String,
val protocolName: String? = null,
)

/**
* A smithy model file
*/
data class Model(
val fileName: String,
val path: String = "src/commonTest/resources/",
)
1 change: 1 addition & 0 deletions codegen/aws-sdk-codegen/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ dependencies {
api(libs.smithy.protocol.test.traits)
implementation(libs.smithy.aws.endpoints)
implementation(libs.smithy.smoke.test.traits)
implementation(libs.smithy.kotlin.runtime.core)

testImplementation(libs.junit.jupiter)
testImplementation(libs.junit.jupiter.params)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ object AwsRuntimeTypes {
val UnsupportedSigningAlgorithmInterceptor = symbol("UnsupportedSigningAlgorithmInterceptor")
val BusinessMetricsInterceptor = symbol("BusinessMetricsInterceptor")
val AwsBusinessMetric = symbol("AwsBusinessMetric")
val S3FlexibleChecksumResponseInterceptor = symbol("S3FlexibleChecksumResponseInterceptor")
}

object Retries {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,31 @@
package aws.sdk.kotlin.codegen

import aws.sdk.kotlin.codegen.model.traits.Presignable
import aws.smithy.kotlin.runtime.hashing.algorithmsSupportedForFlexibleChecksums
import software.amazon.smithy.aws.traits.HttpChecksumTrait
import software.amazon.smithy.aws.traits.auth.SigV4Trait
import software.amazon.smithy.aws.traits.protocols.AwsQueryTrait
import software.amazon.smithy.codegen.core.Symbol
import software.amazon.smithy.kotlin.codegen.core.*
import software.amazon.smithy.kotlin.codegen.core.RuntimeTypes.Core.Hashing.isSupportedForFlexibleChecksums
import software.amazon.smithy.kotlin.codegen.core.RuntimeTypes.Core.Hashing.toHashFunctionOrThrow
import software.amazon.smithy.kotlin.codegen.core.RuntimeTypes.Core.Text.Encoding.encodeBase64String
import software.amazon.smithy.kotlin.codegen.core.RuntimeTypes.Core.Utils.runBlocking
import software.amazon.smithy.kotlin.codegen.core.RuntimeTypes.Http.HttpBody
import software.amazon.smithy.kotlin.codegen.core.RuntimeTypes.Http.readAll
import software.amazon.smithy.kotlin.codegen.core.RuntimeTypes.KotlinCoroutines.coroutineContext
import software.amazon.smithy.kotlin.codegen.core.RuntimeTypes.Observability.TelemetryApi.warn
import software.amazon.smithy.kotlin.codegen.integration.KotlinIntegration
import software.amazon.smithy.kotlin.codegen.integration.SectionId
import software.amazon.smithy.kotlin.codegen.integration.SectionKey
import software.amazon.smithy.kotlin.codegen.lang.KotlinTypes
import software.amazon.smithy.kotlin.codegen.model.buildSymbol
import software.amazon.smithy.kotlin.codegen.model.expectShape
import software.amazon.smithy.kotlin.codegen.model.getTrait
import software.amazon.smithy.kotlin.codegen.model.*
import software.amazon.smithy.kotlin.codegen.model.knowledge.AwsSignatureVersion4
import software.amazon.smithy.kotlin.codegen.rendering.endpoints.EndpointResolverAdapterGenerator
import software.amazon.smithy.kotlin.codegen.rendering.protocol.HttpBindingProtocolGenerator
import software.amazon.smithy.kotlin.codegen.rendering.protocol.HttpBindingResolver
import software.amazon.smithy.kotlin.codegen.rendering.serde.serializerName
import software.amazon.smithy.kotlin.codegen.utils.getOrNull
import software.amazon.smithy.model.knowledge.TopDownIndex
import software.amazon.smithy.model.shapes.OperationShape
import software.amazon.smithy.model.shapes.ServiceShape
Expand Down Expand Up @@ -149,6 +158,7 @@ class PresignerGenerator : KotlinIntegration {
requestSymbol,
serializerSymbol,
contextMap,
op,
)
}
}
Expand Down Expand Up @@ -193,6 +203,7 @@ class PresignerGenerator : KotlinIntegration {
requestSymbol: Symbol,
serializerSymbol: Symbol,
contextMap: Map<SectionKey<*>, Any>,
op: OperationShape,
) = writer.apply {
dokka {
write("Presign a [#T] using the configuration of this [#T].", requestSymbol, serviceSymbol)
Expand Down Expand Up @@ -265,6 +276,45 @@ class PresignerGenerator : KotlinIntegration {
)
}

checksumAlgorithmMember(op, ctx)?.let { checksumAlgorithmMember ->
withBlock("input.#L?.value?.let { checksumAlgorithmName ->", "}", checksumAlgorithmMember) {
withBlock("when (unsignedRequest.body) {", "}") {
withBlock("is #1T.Bytes, is #1T.Empty -> {", "}", HttpBody) {
write("val checksumAlgorithm = checksumAlgorithmName.#T()", toHashFunctionOrThrow)
withInlineBlock(
"if (checksumAlgorithm.#T) {",
"}",
isSupportedForFlexibleChecksums,
) {
withBlock("#T {", "}", runBlocking) {
withBlock("checksumAlgorithm.update(", ")") {
write("unsignedRequest.body.#T() ?: byteArrayOf()", readAll)
}
}
write(
"checksum = #S.lowercase() to checksumAlgorithm.digest().#T()",
"x-amz-checksum-\${checksumAlgorithmName}",
encodeBase64String,
)
}
withBlock(" else {", "}") {
withBlock("#T {", "}", runBlocking) {
write("class Presigner")
write(
"#T.#T<Presigner> { #S }",
coroutineContext,
warn,
"The requested checksum algorithm (\${checksumAlgorithmName}) is not supported for pre-signed URL checksums, sending request without checksum. " +
"Supported checksums for pre-signed URLs: $algorithmsSupportedForFlexibleChecksums",
)
}
}
}
write("else -> throw IllegalStateException(#S)", "HTTP body type unsupported for pre-signed URL checksums.")
}
}
}

declareSection(SigningConfigCustomizationSection)

write("configBlock()")
Expand All @@ -287,4 +337,24 @@ class PresignerGenerator : KotlinIntegration {
* > "my-object/example/photo.user". This is an incorrect path for that object.
*/
private fun normalizeUriPath(service: ServiceShape) = service.sdkId != "S3"

/**
* Gets the checksum algorithm member if configured on a request, otherwise null
*/
private fun checksumAlgorithmMember(
operationShape: OperationShape,
ctx: CodegenContext,
): String? {
operationShape.getTrait<HttpChecksumTrait>()?.let { httpChecksumTrait ->
httpChecksumTrait.requestAlgorithmMember.getOrNull()?.let { requestAlgorithmMember ->
val memberShape = ctx.model
.expectShape<StructureShape>(operationShape.input.get())
.members()
.first { it.memberName == requestAlgorithmMember }

return ctx.symbolProvider.toMemberName(memberShape)
}
}
return null
}
}
Loading
Loading