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

Client silently ignoring http method #851

Closed
sellmair opened this issue Jan 6, 2019 · 2 comments
Closed

Client silently ignoring http method #851

sellmair opened this issue Jan 6, 2019 · 2 comments
Assignees
Labels
ux User Experience issue

Comments

@sellmair
Copy link

sellmair commented Jan 6, 2019

Ktor Version

1.1.1

Ktor Engine Used(client or server and name)

Netty, Client

JVM Version, Operating System and Relevant Context

Android, Multiplatform

Feedback

Declaration of client

HttpClient {
            install(JsonFeature) {
                serializer = KotlinxSerializer()
            }

            defaultRequest {
                accept(ContentType.Application.Json)
                contentType(ContentType.Application.Json)
                url {
                    port = instance(Http.Tags.PORT)
                    host = instance(Http.Tags.HOST)
                    protocol = URLProtocol.HTTP
                }
            }
        }

Declaration of request:

     val call = client.call {
            method = HttpMethod.Get
            url { path("registration", "available", handle.value) }
        }

Results in

2019-01-06 18:04:23.959 10001-10001/io.sellmair.link E/AndroidRuntime: FATAL EXCEPTION: main
    Process: io.sellmair.link, PID: 10001
    kotlinx.serialization.SerializationException: Can't locate argument-less serializer for class io.ktor.client.utils.EmptyContent. For generic classes, such as lists, please provide serializer explicitly.
        at kotlinx.serialization.PlatformUtilsKt.serializer(PlatformUtils.kt:28)
        at io.ktor.client.features.json.serializer.KotlinxSerializer.lookupSerializerByData(KotlinxSerializer.kt:91)
        at io.ktor.client.features.json.serializer.KotlinxSerializer.write(KotlinxSerializer.kt:67)
        at io.ktor.client.features.json.JsonFeature$Feature$install$1.invokeSuspend(JsonFeature.kt:56)
        at io.ktor.client.features.json.JsonFeature$Feature$install$1.invoke(Unknown Source:12)
        at io.ktor.util.pipeline.SuspendFunctionGun.loop(PipelineContext.kt:278)
        at io.ktor.util.pipeline.SuspendFunctionGun.access$loop(PipelineContext.kt:63)
        at io.ktor.util.pipeline.SuspendFunctionGun.proceed(PipelineContext.kt:137)
        at io.ktor.util.pipeline.SuspendFunctionGun.execute(PipelineContext.kt:157)
        at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:24)
        at io.ktor.client.HttpClient.execute(HttpClient.kt:151)
        at io.ktor.client.call.HttpClientCallKt.call(HttpClientCall.kt:80)
        at io.sellmair.link.backend.registration.internal.ApiRegistrationService.isHandleAvailable(ApiRegistrationService.kt:27)
        at io.sellmair.link.backend.registration.internal.OwnerRegistrationFunctions$setHandle$1.invokeSuspend(OwnerRegistrationFunctions.kt:51)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:32)
        at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:233)
        at android.os.Handler.handleCallback(Handler.java:873)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6669)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

Declaration of request with body

       val call = client.call {
            method = HttpMethod.Get
            body = ""
            url { path("registration", "available", handle.value) }
        }

Still sends a post request to the server.
Ktor server side logging:

18:06:44.554 [nettyCallPool-4-2] DEBUG ktor.application - Unhandled: POST - /registration/available/b
@e5l
Copy link
Member

e5l commented Jan 7, 2019

Hi @sellmair, it looks like the side effect from HttpUrlConnection: the request type automatically changes to post depends on body configuration.

Could you reproduce it with OkHttp engine?

@e5l e5l self-assigned this Jan 7, 2019
@e5l e5l added the ux User Experience issue label Jan 10, 2019
@wollnyst
Copy link
Contributor

I noticed a similar effect which could explain the Exception, but the post change:

The JsonFeature only takes into account the Content-Type of the request, whether it should serialize the payload or not.
If the payload is already instance of OutgoingContent (like EmptyContent) this does not make any sense and will fail with the exception above. (see here)

I think it's totally valid to have another guard to check the payload instance here. Something like:

if (payload is OutgoingContent) {
  return@intercept
}

Not sure if this solves your problem, I have written the following workaround

class IgnoreOutgoingContentJsonSerializer(private val delegate: JsonSerializer) : JsonSerializer by delegate {
    override fun write(data: Any): OutgoingContent {
        if (data is OutgoingContent) {
            return data
        }
        return delegate.write(data)
    }
}

fun JsonSerializer.ignoreOutgoingContent() = IgnoreOutgoingContentJsonSerializer(this)

val client = HttpClient(OkHttp) {
    install(JsonFeature) {
        serializer = KotlinxSerializer().ignoreOutgoingContent()
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ux User Experience issue
Projects
None yet
Development

No branches or pull requests

3 participants