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

SES list-contacts action not working with kotlin library #758

Closed
peterehik-px opened this issue Nov 18, 2022 · 4 comments
Closed

SES list-contacts action not working with kotlin library #758

peterehik-px opened this issue Nov 18, 2022 · 4 comments
Assignees
Labels
bug This issue is a bug.

Comments

@peterehik-px
Copy link

peterehik-px commented Nov 18, 2022

Describe the bug

listContactsPaginated request uses okhttpclient to call out to ses endpoint with a GET request. However it passes a request body which is not allowed by okhttp clients. Here's an open issue from okhttp.

Expected behavior

I expect that when I call this endpoint, I get the result of the amazon ses ListContact action

Current behavior

This is the error that gets thrown.

Exception in thread "main" java.lang.IllegalStateException: unexpected HTTP body for method GET
        at aws.smithy.kotlin.runtime.http.engine.okhttp.OkHttpUtilsKt.toOkHttpRequest(OkHttpUtils.kt:64)
        at aws.smithy.kotlin.runtime.http.engine.okhttp.OkHttpEngine.roundTrip(OkHttpEngine.kt:40)
        at aws.smithy.kotlin.runtime.http.SdkHttpClient$executeWithCallContext$2.invokeSuspend(SdkHttpClient.kt:54)
        at aws.smithy.kotlin.runtime.http.SdkHttpClient$executeWithCallContext$2.invoke(SdkHttpClient.kt)
        at aws.smithy.kotlin.runtime.http.SdkHttpClient$executeWithCallContext$2.invoke(SdkHttpClient.kt)
        at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:89)
        at kotlinx.coroutines.BuildersKt__Builders_commonKt.withContext(Builders.common.kt:169)
        at kotlinx.coroutines.BuildersKt.withContext(Unknown Source)
        at aws.smithy.kotlin.runtime.http.SdkHttpClient.executeWithCallContext(SdkHttpClient.kt:53)
        at aws.smithy.kotlin.runtime.http.SdkHttpClient.call(SdkHttpClient.kt:46)
        at aws.smithy.kotlin.runtime.http.SdkHttpClient.call(SdkHttpClient.kt:38)
        at aws.smithy.kotlin.runtime.http.operation.SdkOperationExecutionKt.httpTraceMiddleware(SdkOperationExecution.kt:187)
        at aws.smithy.kotlin.runtime.http.operation.SdkOperationExecutionKt.access$httpTraceMiddleware(SdkOperationExecution.kt:1)
        at aws.smithy.kotlin.runtime.http.operation.SdkOperationExecutionKt$decorate$1.invoke(SdkOperationExecution.kt:76)
        at aws.smithy.kotlin.runtime.http.operation.SdkOperationExecutionKt$decorate$1.invoke(SdkOperationExecution.kt:76)
        at aws.smithy.kotlin.runtime.io.middleware.MiddlewareLambda.handle(Middleware.kt:30)
        at aws.smithy.kotlin.runtime.io.middleware.DecoratedHandler.call(Middleware.kt:40)
        at aws.smithy.kotlin.runtime.http.operation.HttpCallMiddleware.handle(SdkOperationExecution.kt:167)
        at aws.smithy.kotlin.runtime.http.operation.HttpCallMiddleware.handle(SdkOperationExecution.kt:158)
        at aws.smithy.kotlin.runtime.io.middleware.DecoratedHandler.call(Middleware.kt:40)
        at aws.smithy.kotlin.runtime.io.middleware.Phase.handle(Phase.kt:64)
        at aws.smithy.kotlin.runtime.io.middleware.DecoratedHandler.call(Middleware.kt:40)
        at aws.smithy.kotlin.runtime.http.operation.DeserializeHandler.call(SdkOperationExecution.kt:146)
        at aws.smithy.kotlin.runtime.http.operation.DeserializeHandler.call(SdkOperationExecution.kt:135)
        at aws.smithy.kotlin.runtime.http.operation.FinalizeHandler.call(SdkOperationExecution.kt:132)
        at aws.smithy.kotlin.runtime.http.operation.FinalizeHandler.call(SdkOperationExecution.kt:129)
        at aws.smithy.kotlin.runtime.io.middleware.ModifyRequestMiddleware.handle(ModifyRequest.kt:24)
        at aws.smithy.kotlin.runtime.io.middleware.ModifyRequestMiddleware$handle$1.invokeSuspend(ModifyRequest.kt)

Steps to Reproduce

val unsubscribedContacts = sesClient.listContactsPaginated {
            contactListName = "xxx"
            filter = aws.sdk.kotlin.services.sesv2.model.ListContactsFilter {
                filteredStatus = aws.sdk.kotlin.services.sesv2.model.SubscriptionStatus.OptOut
            }
        }

Possible Solution

The problem is in this class, notice where it creates a request body:

internal class ListContactsOperationSerializer: HttpSerialize<ListContactsRequest> {
    override suspend fun serialize(context: ExecutionContext, input: ListContactsRequest): HttpRequestBuilder {
        val builder = HttpRequestBuilder()
        builder.method = HttpMethod.GET
        builder.url {
            val pathSegments = listOf(
                "v2",
                "email",
                "contact-lists",
                "${input.contactListName}".encodeLabel(),
                "contacts",
            )
            path = pathSegments.joinToString(separator = "/", prefix = "/")
            parameters {
                if (input.nextToken != null) append("NextToken", input.nextToken)
                if (input.pageSize != null) append("PageSize", "${input.pageSize}")
            }
        }
        val payload = serializeListContactsOperationBody(context, input)
        builder.body = ByteArrayContent(payload)
        if (builder.body !is HttpBody.Empty) {
            builder.headers.setMissing("Content-Type", "application/json")
        }
        return builder
    }
}

so it either needs to use a post request but that means making an update to the ses v2 api, which shouldn't be a problem or somehow pass in the request as url parameters or let's just not use okhttp. The java version of this method also has an outstanding issue that still persists in the latest version

Context

No response

AWS Kotlin SDK version used

0.17.12-beta

Platform (JVM/JS/Native)

openjdk 17.0.4

Operating System and version

osx

@peterehik-px peterehik-px added bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels Nov 18, 2022
@ianbotsf ianbotsf removed the needs-triage This issue or PR still needs to be triaged. label Nov 18, 2022
@ianbotsf
Copy link
Contributor

Hi @peterehik-px, thanks for the bug report. I've reproduced this on my end. We'll research solutions internally for resolving this when using OkHttp but, in the meantime, you can workaround the issue by selecting the CRT client engine instead of OkHttp.

Add the following dependency to your build.gradle.kts file:

implementation("aws.smithy.kotlin:http-client-engine-crt:0.12.13")

And then specify the httpClientEngine when instantiating your SES client:

val sesClient = SesV2Client.fromEnvironment {
    httpClientEngine = CrtHttpEngine { }
}

@ianbotsf
Copy link
Contributor

ianbotsf commented Nov 18, 2022

A review of other services indicates that GETs with bodies are present in the following APIs:

@ianbotsf
Copy link
Contributor

We had a conversation with the OkHttp maintainers and they aren't inclined to support GET requests with bodies at this time.

We'll work with service teams (e.g., SESv2, EFS, Lightsail, etc.) to get new endpoints/models where possible so that those API calls which require bodies no longer use GET. These updates may take a while so the short-term fix remains to use the CRT HTTP engine when needed.

@github-actions
Copy link

⚠️COMMENT VISIBILITY WARNING⚠️

Comments on closed issues are hard for our team to see.
If you need more assistance, please either tag a team member or open a new issue that references this one.
If you wish to keep having a conversation with other community members under this issue feel free to do so.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug This issue is a bug.
Projects
None yet
Development

No branches or pull requests

2 participants