question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Multipart upload fail when using on ktor

See original GitHub issue

Similar with(https://github.com/ChuckerTeam/chucker/issues/110) ktor + okhttp client(1.5.0/1.5.2) and multipart upload with chucker(3.4.0):

I/System.out: File exists: IMG_20210329_084101.jpg, size=31660
I/i.k.c.HttpClient.log: [DefaultDispatcher-worker-1] REQUEST: https://*.*/blabla
I/i.k.c.HttpClient.log: [DefaultDispatcher-worker-1] METHOD: HttpMethod(value=PUT)
I/i.k.c.HttpClient.log: [DefaultDispatcher-worker-1] COMMON HEADERS
I/i.k.c.HttpClient.log: [DefaultDispatcher-worker-1] -> Accept: application/json
I/i.k.c.HttpClient.log: [DefaultDispatcher-worker-1] -> Accept-Charset: UTF-8
I/i.k.c.HttpClient.log: [DefaultDispatcher-worker-1] -> Authorization: blabla
I/i.k.c.HttpClient.log: [DefaultDispatcher-worker-1] -> Cache-Control: private
I/i.k.c.HttpClient.log: [DefaultDispatcher-worker-1] CONTENT HEADERS
I/i.k.c.HttpClient.log: [DefaultDispatcher-worker-1] -> Content-Length: 32085
I/i.k.c.HttpClient.log: [DefaultDispatcher-worker-1] -> Content-Type: multipart/form-data; boundary=-681f0d6a310571652db4fcd412f01206-38c3e46b45ddb43479b39dfc-30c76d864e3
I/i.k.c.HttpClient.log: [DefaultDispatcher-worker-1] BODY Content-Type: multipart/form-data; boundary=-681f0d6a310571652db4fcd412f01206-38c3e46b45ddb43479b39dfc-30c76d864e3
I/i.k.c.HttpClient.log: [OkHttp https://*.*/...] BODY START
I/i.k.c.HttpClient.log: [OkHttp https://*.*/...] [request body omitted]
I/i.k.c.HttpClient.log: [OkHttp https://*.*/...] BODY END
I/i.k.c.HttpClient.log: [DefaultDispatcher-worker-3] REQUEST https://*.*/blabla failed with exception: java.net.ProtocolException: unexpected end of stream

 Caused by: java.net.ProtocolException: unexpected end of stream
	at okhttp3.internal.connection.Exchange$RequestBodySink.close(Exchange.kt:239)
	at okio.RealBufferedSink.close(RealBufferedSink.kt:268)
	at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.kt:60)
	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
	at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:34)
	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
	at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:82)
	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
	at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83)
	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
	at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:76)
	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
	at com.chuckerteam.chucker.api.ChuckerInterceptor.intercept(ChuckerInterceptor.kt:114)
	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
	at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:197)
	at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:502)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
	at java.lang.Thread.run(Thread.java:923)

without chucker ok:

I/System.out: File exists: IMG_20210329_084101.jpg, size=31660
I/i.k.c.HttpClient.log: [DefaultDispatcher-worker-1] REQUEST: https://*.*/blabla
I/i.k.c.HttpClient.log: [DefaultDispatcher-worker-1] METHOD: HttpMethod(value=PUT)
I/i.k.c.HttpClient.log: [DefaultDispatcher-worker-1] COMMON HEADERS
I/i.k.c.HttpClient.log: [DefaultDispatcher-worker-1] -> Accept: application/json
I/i.k.c.HttpClient.log: [DefaultDispatcher-worker-1] -> Accept-Charset: UTF-8
I/i.k.c.HttpClient.log: [DefaultDispatcher-worker-1] -> Authorization: blabla
I/i.k.c.HttpClient.log: [DefaultDispatcher-worker-1] -> Cache-Control: private
I/i.k.c.HttpClient.log: [DefaultDispatcher-worker-1] CONTENT HEADERS
I/i.k.c.HttpClient.log: [DefaultDispatcher-worker-1] -> Content-Length: 32085
I/i.k.c.HttpClient.log: [DefaultDispatcher-worker-1] -> Content-Type: multipart/form-data; boundary=6538ee3e2b1702c55849d34-6c66f14c702565c15406a4a4-7b253755310821926b054
I/i.k.c.HttpClient.log: [DefaultDispatcher-worker-1] BODY Content-Type: multipart/form-data; boundary=6538ee3e2b1702c55849d34-6c66f14c702565c15406a4a4-7b253755310821926b054
I/i.k.c.HttpClient.log: [OkHttp https://*.*/...] BODY START
I/i.k.c.HttpClient.log: [OkHttp https://*.*/...] [request body omitted]
I/i.k.c.HttpClient.log: [OkHttp https://*.*/...] BODY END
I/i.k.c.HttpClient.log: [DefaultDispatcher-worker-1] RESPONSE: 200 OK
I/i.k.c.HttpClient.log: [DefaultDispatcher-worker-1] METHOD: HttpMethod(value=PUT)
I/i.k.c.HttpClient.log: [DefaultDispatcher-worker-1] FROM: https://*.*/blabla

method for upload:

suspend fun attachFile(
        context: Context,
        uri: Uri,
        fileName: String,
        fileSizeByte: Long
    ) {
        client.request<HttpResponse> {
            apiUrl("blabla")
            method = HttpMethod.Put
            body = MultiPartFormDataContent(
                formData {
                    appendInput(
                        key = "encode-base64-scan",
                        headers = Headers.build {
                            append(HttpHeaders.ContentLength, fileSizeByte)
                            append(HttpHeaders.ContentDisposition, "filename=${fileName}")
                        },
                        size = fileSizeByte
                    ) {
                        buildPacket {
                            context.contentResolver.openInputStream(uri)!!.use {
                                writeFully(it.readBytes())
                            }
                        }
                    }
                }
            )
        }
    }

https://github.com/ChuckerTeam/chucker/blob/3.x/library/src/main/java/com/chuckerteam/chucker/api/ChuckerInterceptor.kt#L114

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:5 (3 by maintainers)

github_iconTop GitHub Comments

2reactions
MiSikoracommented, Apr 10, 2021

@olegsvs

This is a bug in KTOR. Implementation of RequestBody has issues.

https://github.com/ktorio/ktor/blob/e425a2885f8e4ff0158c38c6595f2f2169fa3c9a/ktor-client/ktor-client-okhttp/jvm/src/io/ktor/client/engine/okhttp/StreamRequestBody.kt

It should either override isOneShot() function and return true from it, or lambda passed as block should allow multiple reads from the source.

First solution won’t make it work with Chucker because there is a bug that I mentioned that was fixed in e412626. Second solution would make it work with Chucker out-of-the-box.

0reactions
jonamirehcommented, Jul 13, 2022

I’ve opened KTOR-4637 to address this issue, recommending the first solution from @MiSikora

Read more comments on GitHub >

github_iconTop Results From Across the Web

Error uploading Multipart to MongoDB using Ktor
I'm trying to upload a JPEG to MongoDB using Ktor and Kotlin but keep getting an error: java.io.FileNotFoundException: /document/image:32: ...
Read more >
Ktor 1.4.1 fails to upload file (submit form) when logging level ...
Ktor 1.4.1 fails to upload file (submit form) when logging level = LogLevel.BODY. I am using ktor 1.4.1 in my multiplatform project to...
Read more >
[Solved]-Error uploading Multipart to MongoDB using Ktor-kotlin
I found a solution to my problem. To make a post with Uri possible is it necessary to create a temporary file in...
Read more >
Handling requests - Ktor
Inside a route handler, you can get access to a request using the ... The sample below shows how to use ByteReadChannel to...
Read more >
Ktor - File Upload and Download - Ryan Harrison
To handle this in Ktor, you can get hold of the multipart data through receiveMultipart and then loop over each part as required....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found