https://kotlinlang.org logo
#ktor
Title
# ktor
r

Robin T

03/12/2024, 8:33 AM
I dont know if this is a bug or if Im using it incorrectly. I try to read from multipart form file items like this:
Copy code
when (val fileItem = call.receiveMultipart().readAllParts().single()) {
                is PartData.FileItem -> {
                    fileItem.provider().use {
                        it.readByte()
                    }
                }
                else -> error("")
            }
But
it.readByte()
is returning -1. Also,
it.canRead()
is returning false. However, if I first call
it.tryPeek()
then I am able to call readBytes. and
it.canRead()
is returning true again. Does this have something to do with the chunkbuffer-pool not being setup for read yet?
a

Aleksei Tirman [JB]

03/12/2024, 8:33 AM
is there only one part?
r

Robin T

03/12/2024, 8:34 AM
Yes, for now there is only one part
It does work to call fileItem.streamProvider().readAllBytes() but this is not what I want to do.. I need to cancel the stream after X bytes
a

Aleksei Tirman [JB]

03/12/2024, 8:39 AM
Unfortunately, I cannot reproduce the problem using your code and by sending a single file part.
r

Robin T

03/12/2024, 8:40 AM
Hmm, strange.. Does this look horrible?
Copy code
client.submitFormWithBinaryData(
                    "/mellomlagring/fil",
                    formData {
                        append("document", Resource.read("/resources/images/bilde.jpg"),
                            Headers.build {
                                append(HttpHeaders.ContentDisposition, "filename=bilde.jpg")
                                append(HttpHeaders.ContentType, "image/jpeg")
                            })
                    },
                )
a

Aleksei Tirman [JB]

03/12/2024, 8:41 AM
Are you able to reproduce the problem using Postman, curl or Insomnia?
r

Robin T

03/12/2024, 9:09 AM
Yes.
Copy code
fun main() {
    embeddedServer(Netty, port = 8080, module = {
        install(ContentNegotiation) { jackson {} }

        routing {
            post("/byte") {
                when (val fileItem = call.receiveMultipart().readAllParts().single()) {
                    is PartData.FileItem -> {
                        fileItem.provider().use {
                            // it.tryPeek() // uncomment to read byte
                            when (it.canRead()) {
                                true -> call.respond(it.readByte())
                                false -> call.respond(HttpStatusCode.UnprocessableEntity, "cant read stream")
                            }
                        }
                    }

                    else -> call.respond(HttpStatusCode.BadRequest, "File not found")
                }
            }
        }
    }).start(wait = true)
}
Intellij HTTP client:
Copy code
POST  <http://0.0.0.0:8080/byte>
Content-Type: multipart/form-data; boundary=boundary

--boundary
Content-Disposition: form-data; name="document"; filename="bilde.jpg"

< ./bilde.jpg
Setup: JDK 21 ktor 2.3.9 Kotlin 1.9.23
Copy code
dependencies {
    implementation("io.ktor:ktor-server-core:$ktorVersion")
    implementation("io.ktor:ktor-server-netty:$ktorVersion")
    implementation("io.ktor:ktor-server-content-negotiation:$ktorVersion")
    implementation("io.ktor:ktor-serialization-jackson:$ktorVersion")
}
Hmm. After debug some more, it looks lik
.jpg
starts with -1 Example:
Copy code
object Resource {
    fun read(path: String): ByteArray = requireNotNull(this::class.java.getResource(path)).readBytes()
}
Copy code
Resource.read("/resources/images/Cat03.jpg") # first byte is -1
Ref:

https://en.m.wikipedia.org/wiki/File:Cat03.jpg

Nvm, canRead is still false with a .png that does not start with -1