Hello guys I'm trying to make an api call with kto...
# ktor
r
Hello guys I'm trying to make an api call with ktor client in my kmm project here's the curl from the ios device log
curl "<https://httpbin.org/post>" -X POST -H "Accept: application/json" -H "Accept-Charset: UTF-8" -H "Content-Type: multipart/form-data; boundary=29d61685-228ec613-44759624-46d5b594-3563b24e-4de1ab26749622364911b1e3-" -H "Content-Length: 491" -H "User-Agent: Ktor client" -d "--29d61685-228ec613-44759624-46d5b594-3563b24e-4de1ab26749622364911b1e3-
Content-Disposition: form-data; name=store_img_profile; filename=image_file.jpg
Content-Type: image/jpg
Content-Length: 210
file:///Users/mac/Library/Developer/CoreSimulator/Devices/121666D6-FC09-4296-B9A2-50FC86B6E9FE/data/Containers/Data/Application/5218EFEE-1666-4829-B16D-E346D65E6923/tmp/1D30F36C-3B12-4E42-95E7-8F849D9FA580.jpeg
--29d61685-228ec613-44759624-46d5b594-3563b24e-4de1ab26749622364911b1e3---
"
it's working fine on postman, and it's succeeding on android, but in ios it's returning timeout I have tried to upgrade the ktor version to
Copy code
3.0.0-rc-1
but still the same behaviour what could be the issue here
a
Can you share the code where Ktor client is used?
r
sure
Copy code
HttpClient.submitFormWithBinaryData(
                    url = url,
                    formData = formData {
                        append("\"store_img_profile\"", body, Headers.build {
                            append(HttpHeaders.ContentType, "image/jpeg")
                            append(HttpHeaders.ContentDisposition, "filename=\"image_file.jpeg\"")
                        })
                    }
                )
m
Can you try an image with a really small size on iOS? Also, can we see the logs for the request just before the timeout?
r
How can we see the logs of the request before the timeout, I don’t know if that’s possible in iOS ?
m
Are running the code in Xcode? If you are, then you can see the logs in Xcode log output.
r
No I’m running it on android studio not Xcode
a
Can you check if a simple GET request works? How do you determine that the request times out?
r
Yes the same http client is working fine with simple get and post requests It’s time out because I have it 1 min timeout and it waits for 1 min and then fail with no response or error code
Something I noticed that if you tried this curl in postman it will timeout too until you uncheck the content-length field I don’t know how to delete this filed from the request when firing it from iOS device
a
Can you share the endpoint URL?
m
I was able to reach out, it seems that the timeout issue is independent of Ktor. The backend service loads indefinitely when the Content-Length attribute is greater than the actual payload image size. The same issue happened on PostMan when an incorrect Content-Length was specified. Ideally the Content-Length is calculated and appended to the request headers, so I’m a bit unsure as to why the request on iOS seemed to specify an incorrect Content-Length. A look at the logs would better explain this issue.
r
@Aleksei Tirman [JB] yes I’m using this one to test
a
Do you get a timeout when sending the multipart request without files? Can you share the code where HttpClient is configured and where the
body
variable is populated?
r
no I do send file
Copy code
val httpClientPrivate = httpClientBuilder {
    expectSuccess = true
    install(ContentNegotiation) {
        json(Json {
            ignoreUnknownKeys = true
            explicitNulls = false
        })
    }

    defaultRequest {
        url {
            url("<https://httpbin.org/post>")
            header(HttpHeaders.ContentType, "application/json")
        }
    }
    install(HttpTimeout) {
        requestTimeoutMillis = 3000
        connectTimeoutMillis = 3000
        socketTimeoutMillis =  3000
    }

    install(Logging) {
        logger = object : Logger {
            override fun log(message: String) {
                logRequest(message)
            }
        }
        level = LogLevel.ALL
    }

    HttpResponseValidator {
        validateResponse { response ->
            if (!response.status.isSuccess()) {
                val failureReason = when (response.status) {
                    HttpStatusCode.BadRequest -> BAD_REQUEST
                    HttpStatusCode.Unauthorized -> UNAUTHORIZED
                    HttpStatusCode.Forbidden -> "${response.status.value} $FORBIDDEN"
                    HttpStatusCode.NotFound -> NOT_FOUND
                    HttpStatusCode.RequestTimeout -> TIMEOUT
                    in HttpStatusCode.InternalServerError..HttpStatusCode.GatewayTimeout -> "${response.status.value} $SERVER_ERROR"

                    else -> NETWORK_ERROR
                }

                throw HttpExceptions(
                    response = response,
                    failureReason = failureReason,
                    cachedResponseText = response.bodyAsText(),
                )
            }
        }
    }
}
even if i sent binaryArrayof(0) it's the same response