I have an issue where a request is generating an e...
# ktor
j
I have an issue where a request is generating an exception io.ktor.utils.io.charsets.MalformedInputException: Input length = 1, In the request handler i am doing call.receiveParameters() which i think is where the issue is coming from. However my issue is how can i capture the raw request as this is happening in the wild and i want to capture the body in a log so i can investigate?
r
hi, what version of Ktor do you use?
j
1.5
r
do you have the stacktrace?
j
io.ktor.utils.io.charsets.MalformedInputException: Input length = 1     at io.ktor.utils.io.charsets.CharsetJVMKt.throwExceptionWrapped(CharsetJVM.kt:323)     at io.ktor.utils.io.charsets.CharsetJVMKt.decodeImplSlow(CharsetJVM.kt:289)     at io.ktor.utils.io.charsets.CharsetJVMKt.decodeExactBytes(CharsetJVM.kt:254)     at io.ktor.utils.io.core.StringsKt.readTextExactBytes(Strings.kt:297)     at io.ktor.utils.io.core.StringsKt.readTextExactBytes$default(Strings.kt:296)     at io.ktor.utils.io.core.AbstractInput.readText(AbstractInput.kt:470)     at io.ktor.utils.io.core.AbstractInput.readText$default(AbstractInput.kt:467)     at io.ktor.http.cio.CIOMultipartDataBase.partToData(CIOMultipartData.kt:77)     at io.ktor.http.cio.CIOMultipartDataBase$partToData$1.invokeSuspend(CIOMultipartData.kt)     at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)     at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)     at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164)     at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:472)     at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:500)     at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)     at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)     at io.ktor.server.netty.EventLoopGroupProxy$Companion$create$factory$1$1.run(NettyApplicationEngine.kt:227)     at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)     at java.base/java.lang.Thread.run(Thread.java:832)
r
Looking at the stacktrace, most likely someone sends not valid request that can’t be transformed to the string. In that case, the only thing you can do is to receive body as
ByteArray
and try to parse it to
Parameters
manually. If it fails you can log it (and maybe create an issue in Ktor if there is an error in transformation).
j
so as it stands if the call.recieveParameters() throws an error i have already consumed the channel, so i would always need to receive it as a byte array, is there a helper function for me to attempt to turn that into a parameters?
r
You can use
DoubleReceive
feature to first try to receive
Parameters
and then
ByteArray
if it fails
x-form-urlencoded
(i believe you use this content type) is just a string of
key=value
tuples separated with
&
and url encoded. So just convert byte array to string and then url decode it. If it succeeds, please file an issue to ktor
j
it seems to be throwing this now:
io.ktor.features.RequestReceiveAlreadyFailedException: Request body consumption was failed     at io.ktor.features.DoubleReceive$Feature$install$1.invokeSuspend(DoubleReceive.kt:62)     at io.ktor.features.DoubleReceive$Feature$install$1.invoke(DoubleReceive.kt)     at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:243)     at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:113)     at io.ktor.util.pipeline.SuspendFunctionGun.execute(SuspendFunctionGun.kt:133)     at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:79)     at io.ktor.request.ApplicationReceiveFunctionsKt.receive(ApplicationReceiveFunctions.kt:116)     at privasea.Privasea$$special$$inlined$with$lambda$2$3.invokeSuspend(Privasea.kt:316)     at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)     at io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith(SuspendFunctionGun.kt:191)     at io.ktor.util.pipeline.SuspendFunctionGun.access$resumeRootWith(SuspendFunctionGun.kt:15)     at io.ktor.util.pipeline.SuspendFunctionGun$continuation$1.resumeWith(SuspendFunctionGun.kt:86)     at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)     at io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith(SuspendFunctionGun.kt:191)     at io.ktor.util.pipeline.SuspendFunctionGun.access$resumeRootWith(SuspendFunctionGun.kt:15)     at io.ktor.util.pipeline.SuspendFunctionGun$continuation$1.resumeWith(SuspendFunctionGun.kt:86)     at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)     at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)     at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164)     at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:472)     at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:500)     at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)     at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)     at io.ktor.server.netty.EventLoopGroupProxy$Companion$create$factory$1$1.run(NettyApplicationEngine.kt:227)     at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)     at java.base/java.lang.Thread.run(Thread.java:832) Caused by: io.ktor.utils.io.charsets.MalformedInputException: Input length = 1     at io.ktor.utils.io.charsets.CharsetJVMKt.throwExceptionWrapped(CharsetJVM.kt:323)     at io.ktor.utils.io.charsets.CharsetJVMKt.decodeImplSlow(CharsetJVM.kt:289)     at io.ktor.utils.io.charsets.CharsetJVMKt.decodeExactBytes(CharsetJVM.kt:254)     at io.ktor.utils.io.core.StringsKt.readTextExactBytes(Strings.kt:297)     at io.ktor.utils.io.core.StringsKt.readTextExactBytes$default(Strings.kt:296)     at io.ktor.utils.io.core.AbstractInput.readText(AbstractInput.kt:470)     at io.ktor.utils.io.core.AbstractInput.readText$default(AbstractInput.kt:467)     at io.ktor.http.cio.CIOMultipartDataBase.partToData(CIOMultipartData.kt:77)     at io.ktor.http.cio.CIOMultipartDataBase$partToData$1.invokeSuspend(CIOMultipartData.kt)     at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)     ... 9 more
r
Oh, ok, sorry for misleading you. Yes, if original consumption failed,
DoubleReceive
feature will not help.
j
is there an alternative to log the request?
r
As a bit hacky workaround, you can try to first read
ByteArray
and save it locally, then try to read
Parameters
. If
Parameters
fails, you already have the saved data. Do you find it ok as temp solution to try to understand what is wrong with the request?
j
excellent i can now see the request many thanks!
👍 1
274 Views