Closed SebastianAigner closed 3 years ago
I'm having the same problem with ktor 0.9.4 with Netty
Some details on the issue: The problem only happens for me when I first call receiveParameters & later call receiveMultipart Here is a simple example:
val data = call.receiveParameters()
val multipart = call.receiveMultipart()
multipart.forEachPart { println(it.name) }
Some details on the issue: The problem only happens for me when I first call receiveParameters & later call receiveMultipart Here is a simple example:
val data = call.receiveParameters() val multipart = call.receiveMultipart() multipart.forEachPart { println(it.name) }
Same problem calling first "call.receiveParameters()"
@SebastianAigner You send incorrect multipart request.
Curl handling boundary itself. And when you set manually -H 'content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW'
curl add one more additional boundary, and header Content-Type
in request looks like
Content-Type: multipart/form-data; boundary=WebKitFormBoundary7MA4YWxkTrZu0gW; boundary=------------------------8b5ba40884633a0e
With double boundary. It is invalid multipart. You can see this using -v
flag in curl.
Currently in 1.0.0-rc1 ktor throws java.io.IOException: Multipart preamble/prologue limit of 8192 bytes exceeded
for this case.
Official docs example (https://ktor.io/servers/uploads.html) throws same exception.
val multipart = call.receiveMultipart()
multipart.forEachPart { part ->
when (part) {
is PartData.FormItem -> {
if (part.name == "title") {
title = part.value
}
}
is PartData.FileItem -> {
val ext = File(part.originalFileName).extension
val file = File(uploadDir, "upload-${System.currentTimeMillis()}-${session.userId.hashCode()}-${title.hashCode()}.$ext")
part.streamProvider().use { input -> file.outputStream().buffered().use { output -> input.copyToSuspend(output) } }
videoFile = file
}
}
part.dispose()
}
suspend fun InputStream.copyToSuspend(
out: OutputStream,
bufferSize: Int = DEFAULT_BUFFER_SIZE,
yieldSize: Int = 4 * 1024 * 1024,
dispatcher: CoroutineDispatcher = Dispatchers.IO
): Long {
return withContext(dispatcher) {
val buffer = ByteArray(bufferSize)
var bytesCopied = 0L
var bytesAfterYield = 0L
while (true) {
val bytes = read(buffer).takeIf { it >= 0 } ?: break
out.write(buffer, 0, bytes)
if (bytesAfterYield >= yieldSize) {
yield()
bytesAfterYield %= yieldSize
}
bytesCopied += bytes
bytesAfterYield += bytes
}
return@withContext bytesCopied
}
}
HTML form:
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file"/>
<button type="submit">Upload</button>
</form>
Looks like Ktor is not very actively maintained framework :(
Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.
I received this error and I fixed it by not running multipart inside a coroutineScope ; withContext. I don't know why this is but it worked.
Problem description: When receiving an empty multipart-form request on a POST route, the request handler throws an IOException, preventing graceful handling or the display of an error message. Instead, a 500 error message is returned.
Minimum working example:
Send a request with an empty multipart body to see the issue:
Error Message: