diff --git a/aws-runtime/auth/common/src/aws/sdk/kotlin/runtime/auth/Presigner.kt b/aws-runtime/auth/common/src/aws/sdk/kotlin/runtime/auth/Presigner.kt index ca8d555e8ea..6cc306eede3 100644 --- a/aws-runtime/auth/common/src/aws/sdk/kotlin/runtime/auth/Presigner.kt +++ b/aws-runtime/auth/common/src/aws/sdk/kotlin/runtime/auth/Presigner.kt @@ -5,16 +5,20 @@ import aws.sdk.kotlin.crt.auth.signing.AwsSignedBodyHeaderType import aws.sdk.kotlin.crt.auth.signing.AwsSignedBodyValue import aws.sdk.kotlin.crt.auth.signing.AwsSigner import aws.sdk.kotlin.crt.auth.signing.AwsSigningConfig -import aws.sdk.kotlin.crt.http.HttpRequest +import aws.sdk.kotlin.runtime.crt.path +import aws.sdk.kotlin.runtime.crt.queryParameters import aws.sdk.kotlin.runtime.crt.toCrtHeaders import aws.sdk.kotlin.runtime.crt.toSdkHeaders import aws.sdk.kotlin.runtime.endpoint.EndpointResolver import aws.smithy.kotlin.runtime.http.Headers +import aws.smithy.kotlin.runtime.http.HttpBody import aws.smithy.kotlin.runtime.http.HttpMethod import aws.smithy.kotlin.runtime.http.Protocol import aws.smithy.kotlin.runtime.http.QueryParameters import aws.smithy.kotlin.runtime.http.Url +import aws.smithy.kotlin.runtime.http.request.HttpRequest import aws.smithy.kotlin.runtime.util.InternalApi +import aws.sdk.kotlin.crt.http.HttpRequest as CrtHttpRequest /** * The service configuration details for a presigned request @@ -63,26 +67,14 @@ public data class PresignedRequestConfig( public val additionalHeaders: Headers = Headers.Empty ) -/** - * Properties of an HTTP request that has been presigned - * @property method HTTP method to use when initiating the request - * @property url HTTP url of the presigned request - * @property headers Headers that must be sent with the request - */ -public data class PresignedRequest( - val method: HttpMethod, - val url: String, - val headers: Headers -) - /** * Generate a presigned request given the service and operation configurations. * @param serviceConfig The service configuration to use in signing the request * @param requestConfig The presign configuration to use in signing the request - * @return a [PresignedRequest] that can be executed by any HTTP client within the specified duration. + * @return a [HttpRequest] that can be executed by any HTTP client within the specified duration. */ @InternalApi -public suspend fun createPresignedRequest(serviceConfig: ServicePresignConfig, requestConfig: PresignedRequestConfig): PresignedRequest { +public suspend fun createPresignedRequest(serviceConfig: ServicePresignConfig, requestConfig: PresignedRequestConfig): HttpRequest { val crtCredentials = serviceConfig.credentialsProvider.getCredentials().toCrt() val endpoint = serviceConfig.endpointResolver.resolve(serviceConfig.serviceId, serviceConfig.region) @@ -96,22 +88,28 @@ public suspend fun createPresignedRequest(serviceConfig: ServicePresignConfig, r expirationInSeconds = requestConfig.durationSeconds } - val url = Url(Protocol.HTTPS, endpoint.hostname, path = requestConfig.path, parameters = requestConfig.queryString) + val unsignedUrl = Url(Protocol.HTTPS, endpoint.hostname, path = requestConfig.path, parameters = requestConfig.queryString) - val headers = aws.sdk.kotlin.crt.http.Headers.build { - append("Host", endpoint.hostname) - appendAll(requestConfig.additionalHeaders.toCrtHeaders()) - } - val request = HttpRequest( + val request = CrtHttpRequest( requestConfig.method.name, - url.encodedPath, - headers + unsignedUrl.encodedPath, + aws.sdk.kotlin.crt.http.Headers.build { + append("Host", endpoint.hostname) + appendAll(requestConfig.additionalHeaders.toCrtHeaders()) + } ) val signedRequest = AwsSigner.signRequest(request, signingConfig) - return PresignedRequest( - requestConfig.method, - "${endpoint.protocol}://${endpoint.hostname}${signedRequest.encodedPath}", - signedRequest.headers.toSdkHeaders() + return HttpRequest( + method = HttpMethod.parse(signedRequest.method), + url = Url( + scheme = Protocol.HTTPS, + host = endpoint.hostname, + path = signedRequest.path(), + parameters = signedRequest.queryParameters() ?: QueryParameters.Empty, + encodeParameters = false + ), + headers = signedRequest.headers.toSdkHeaders(), + body = HttpBody.Empty ) } diff --git a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsRuntimeTypes.kt b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsRuntimeTypes.kt index bbee4da2cf3..725e90432d3 100644 --- a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsRuntimeTypes.kt +++ b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsRuntimeTypes.kt @@ -43,7 +43,6 @@ object AwsRuntimeTypes { val CredentialsProvider = runtimeSymbol("CredentialsProvider", AwsKotlinDependency.AWS_AUTH) val createPresignedRequest = runtimeSymbol("createPresignedRequest", AwsKotlinDependency.AWS_AUTH) val DefaultChainCredentialsProvider = runtimeSymbol("DefaultChainCredentialsProvider", AwsKotlinDependency.AWS_AUTH) - val PresignedRequest = runtimeSymbol("PresignedRequest", AwsKotlinDependency.AWS_AUTH) val PresignedRequestConfig = runtimeSymbol("PresignedRequestConfig", AwsKotlinDependency.AWS_AUTH) val ServicePresignConfig = runtimeSymbol("ServicePresignConfig", AwsKotlinDependency.AWS_AUTH) val SigningLocation = runtimeSymbol("SigningLocation", AwsKotlinDependency.AWS_AUTH) diff --git a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/PresignerGenerator.kt b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/PresignerGenerator.kt index 11df4121dea..fd9a4a014d5 100644 --- a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/PresignerGenerator.kt +++ b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/PresignerGenerator.kt @@ -75,11 +75,11 @@ class PresignerGenerator : KotlinIntegration { // Symbols which should be imported private val presignerRuntimeSymbols = setOf( // smithy-kotlin types + RuntimeTypes.Http.Request.HttpRequest, RuntimeTypes.Core.ExecutionContext, // AWS types AwsRuntimeTypes.Auth.CredentialsProvider, AwsRuntimeTypes.Auth.DefaultChainCredentialsProvider, - AwsRuntimeTypes.Auth.PresignedRequest, AwsRuntimeTypes.Auth.PresignedRequestConfig, AwsRuntimeTypes.Auth.ServicePresignConfig, AwsRuntimeTypes.Auth.SigningLocation, @@ -327,10 +327,10 @@ class PresignerGenerator : KotlinIntegration { write("Presign a [$requestTypeName] using a [$serviceClientTypeName].") write("@param serviceClient the client providing properties used to generate the presigned request.") write("@param durationSeconds the amount of time from signing for which the request is valid, with seconds granularity.") - write("@return The [PresignedRequest] that can be invoked within the specified time window.") + write("@return The [HttpRequest] that can be invoked within the specified time window.") } // FIXME ~ Replace or add additional function, swap ULong type for kotlin.time.Duration when type becomes stable - writer.withBlock("suspend fun $requestTypeName.presign(serviceClient: $serviceClientTypeName, durationSeconds: ULong): PresignedRequest {", "}\n") { + writer.withBlock("suspend fun $requestTypeName.presign(serviceClient: $serviceClientTypeName, durationSeconds: ULong): HttpRequest {", "}\n") { withBlock("val serviceClientConfig = $presignConfigTypeName {", "}") { write("credentialsProvider = serviceClient.config.credentialsProvider ?: DefaultChainCredentialsProvider()") write("endpointResolver = serviceClient.config.endpointResolver ?: DefaultEndpointResolver()") @@ -345,10 +345,10 @@ class PresignerGenerator : KotlinIntegration { write("Presign a [$requestTypeName] using a [ServicePresignConfig].") write("@param serviceClientConfig the client configuration used to generate the presigned request") write("@param durationSeconds the amount of time from signing for which the request is valid, with seconds granularity.") - write("@return The [PresignedRequest] that can be invoked within the specified time window.") + write("@return The [HttpRequest] that can be invoked within the specified time window.") } // FIXME ~ Replace or add additional function, swap ULong type for kotlin.time.Duration when type becomes stable - writer.withBlock("suspend fun $requestTypeName.presign(serviceClientConfig: ServicePresignConfig, durationSeconds: ULong): PresignedRequest {", "}\n") { + writer.withBlock("suspend fun $requestTypeName.presign(serviceClientConfig: ServicePresignConfig, durationSeconds: ULong): HttpRequest {", "}\n") { write("return createPresignedRequest(serviceClientConfig, $requestConfigFnName(this, durationSeconds))") } } diff --git a/codegen/smithy-aws-kotlin-codegen/src/test/kotlin/aws/sdk/kotlin/codegen/PresignerGeneratorTest.kt b/codegen/smithy-aws-kotlin-codegen/src/test/kotlin/aws/sdk/kotlin/codegen/PresignerGeneratorTest.kt index 476fe494225..c52a4039a65 100644 --- a/codegen/smithy-aws-kotlin-codegen/src/test/kotlin/aws/sdk/kotlin/codegen/PresignerGeneratorTest.kt +++ b/codegen/smithy-aws-kotlin-codegen/src/test/kotlin/aws/sdk/kotlin/codegen/PresignerGeneratorTest.kt @@ -89,7 +89,6 @@ class PresignerGeneratorTest { import aws.sdk.kotlin.runtime.ClientException import aws.sdk.kotlin.runtime.auth.CredentialsProvider import aws.sdk.kotlin.runtime.auth.DefaultChainCredentialsProvider - import aws.sdk.kotlin.runtime.auth.PresignedRequest import aws.sdk.kotlin.runtime.auth.PresignedRequestConfig import aws.sdk.kotlin.runtime.auth.ServicePresignConfig import aws.sdk.kotlin.runtime.auth.SigningLocation @@ -97,6 +96,7 @@ class PresignerGeneratorTest { import aws.sdk.kotlin.runtime.endpoint.EndpointResolver import aws.smithy.kotlin.runtime.client.ExecutionContext import aws.smithy.kotlin.runtime.http.QueryParameters + import aws.smithy.kotlin.runtime.http.request.HttpRequest import smithy.kotlin.traits.internal.DefaultEndpointResolver import smithy.kotlin.traits.model.GetFooRequest import smithy.kotlin.traits.model.PostFooRequest @@ -109,9 +109,9 @@ class PresignerGeneratorTest { * Presign a [GetFooRequest] using a [ServicePresignConfig]. * @param serviceClientConfig the client configuration used to generate the presigned request * @param durationSeconds the amount of time from signing for which the request is valid, with seconds granularity. - * @return The [PresignedRequest] that can be invoked within the specified time window. + * @return The [HttpRequest] that can be invoked within the specified time window. */ - suspend fun GetFooRequest.presign(serviceClientConfig: ServicePresignConfig, durationSeconds: ULong): PresignedRequest { + suspend fun GetFooRequest.presign(serviceClientConfig: ServicePresignConfig, durationSeconds: ULong): HttpRequest { return createPresignedRequest(serviceClientConfig, getFooPresignConfig(this, durationSeconds)) } @@ -119,9 +119,9 @@ class PresignerGeneratorTest { * Presign a [GetFooRequest] using a [TestClient]. * @param serviceClient the client providing properties used to generate the presigned request. * @param durationSeconds the amount of time from signing for which the request is valid, with seconds granularity. - * @return The [PresignedRequest] that can be invoked within the specified time window. + * @return The [HttpRequest] that can be invoked within the specified time window. */ - suspend fun GetFooRequest.presign(serviceClient: TestClient, durationSeconds: ULong): PresignedRequest { + suspend fun GetFooRequest.presign(serviceClient: TestClient, durationSeconds: ULong): HttpRequest { val serviceClientConfig = TestPresignConfig { credentialsProvider = serviceClient.config.credentialsProvider ?: DefaultChainCredentialsProvider() endpointResolver = serviceClient.config.endpointResolver ?: DefaultEndpointResolver() @@ -147,9 +147,9 @@ class PresignerGeneratorTest { * Presign a [PostFooRequest] using a [ServicePresignConfig]. * @param serviceClientConfig the client configuration used to generate the presigned request * @param durationSeconds the amount of time from signing for which the request is valid, with seconds granularity. - * @return The [PresignedRequest] that can be invoked within the specified time window. + * @return The [HttpRequest] that can be invoked within the specified time window. */ - suspend fun PostFooRequest.presign(serviceClientConfig: ServicePresignConfig, durationSeconds: ULong): PresignedRequest { + suspend fun PostFooRequest.presign(serviceClientConfig: ServicePresignConfig, durationSeconds: ULong): HttpRequest { return createPresignedRequest(serviceClientConfig, postFooPresignConfig(this, durationSeconds)) } @@ -157,9 +157,9 @@ class PresignerGeneratorTest { * Presign a [PostFooRequest] using a [TestClient]. * @param serviceClient the client providing properties used to generate the presigned request. * @param durationSeconds the amount of time from signing for which the request is valid, with seconds granularity. - * @return The [PresignedRequest] that can be invoked within the specified time window. + * @return The [HttpRequest] that can be invoked within the specified time window. */ - suspend fun PostFooRequest.presign(serviceClient: TestClient, durationSeconds: ULong): PresignedRequest { + suspend fun PostFooRequest.presign(serviceClient: TestClient, durationSeconds: ULong): HttpRequest { val serviceClientConfig = TestPresignConfig { credentialsProvider = serviceClient.config.credentialsProvider ?: DefaultChainCredentialsProvider() endpointResolver = serviceClient.config.endpointResolver ?: DefaultEndpointResolver() @@ -185,9 +185,9 @@ class PresignerGeneratorTest { * Presign a [PutFooRequest] using a [ServicePresignConfig]. * @param serviceClientConfig the client configuration used to generate the presigned request * @param durationSeconds the amount of time from signing for which the request is valid, with seconds granularity. - * @return The [PresignedRequest] that can be invoked within the specified time window. + * @return The [HttpRequest] that can be invoked within the specified time window. */ - suspend fun PutFooRequest.presign(serviceClientConfig: ServicePresignConfig, durationSeconds: ULong): PresignedRequest { + suspend fun PutFooRequest.presign(serviceClientConfig: ServicePresignConfig, durationSeconds: ULong): HttpRequest { return createPresignedRequest(serviceClientConfig, putFooPresignConfig(this, durationSeconds)) } @@ -195,9 +195,9 @@ class PresignerGeneratorTest { * Presign a [PutFooRequest] using a [TestClient]. * @param serviceClient the client providing properties used to generate the presigned request. * @param durationSeconds the amount of time from signing for which the request is valid, with seconds granularity. - * @return The [PresignedRequest] that can be invoked within the specified time window. + * @return The [HttpRequest] that can be invoked within the specified time window. */ - suspend fun PutFooRequest.presign(serviceClient: TestClient, durationSeconds: ULong): PresignedRequest { + suspend fun PutFooRequest.presign(serviceClient: TestClient, durationSeconds: ULong): HttpRequest { val serviceClientConfig = TestPresignConfig { credentialsProvider = serviceClient.config.credentialsProvider ?: DefaultChainCredentialsProvider() endpointResolver = serviceClient.config.endpointResolver ?: DefaultEndpointResolver() diff --git a/services/polly/common/test/aws/sdk/kotlin/services/polly/PollyTest.kt b/services/polly/common/test/aws/sdk/kotlin/services/polly/PollyTest.kt index 526642ef8bf..31df18bc4aa 100644 --- a/services/polly/common/test/aws/sdk/kotlin/services/polly/PollyTest.kt +++ b/services/polly/common/test/aws/sdk/kotlin/services/polly/PollyTest.kt @@ -6,7 +6,6 @@ import aws.sdk.kotlin.services.polly.model.OutputFormat import aws.sdk.kotlin.services.polly.model.SynthesizeSpeechRequest import aws.sdk.kotlin.services.polly.model.VoiceId import aws.smithy.kotlin.runtime.http.HttpMethod -import aws.smithy.kotlin.runtime.http.Url import org.junit.jupiter.api.Test import kotlin.test.assertEquals import kotlin.test.assertTrue @@ -34,9 +33,8 @@ class PollyPresignerTest { assertEquals(HttpMethod.GET, presignedRequest.method) assertTrue(presignedRequest.headers.entries().size == 1) assertEquals("polly.us-east-2.amazonaws.com", presignedRequest.headers["Host"]) - val parsedUrl = Url.parse(presignedRequest.url) - assertEquals("/v1/speech", parsedUrl.path) + assertEquals("/v1/speech", presignedRequest.url.path) val expectedQueryParameters = setOf("OutputFormat", "Text", "VoiceId", "X-Amz-Algorithm", "X-Amz-Credential", "X-Amz-Date", "X-Amz-SignedHeaders", "X-Amz-Expires", "X-Amz-Signature") - assertEquals(expectedQueryParameters, parsedUrl.parameters.entries().map { it.key }.toSet()) + assertEquals(expectedQueryParameters, presignedRequest.url.parameters.entries().map { it.key }.toSet()) } }