Не удается загрузить файл на сервер ktor с помощью клиента ktor

Я настроил сервер в соответствии с документами и пытаюсь загрузить файл используя код из этого вопроса:

val parts: List<PartData> = formData {
    append(
        "image",
        InputProvider { ins.asInput() },
        Headers.build {
            this[HttpHeaders.ContentType] = "image/png"
            this[HttpHeaders.ContentDisposition] = "filename=$name"
        }
    )
}
return HttpClient(Apache) {
    install(Logging) {
        logger = Logger.DEFAULT
        level = LogLevel.ALL
    }
}.submitFormWithBinaryData(formData = parts) {
    url("$baseUrl/images")
}

Если я использую его как есть (без запроса Content-Type), тогда сервер выходит из строя: заголовок Content-Type требуется для многостраничной обработки.

Если я пытаюсь добавить заголовок, клиент терпит неудачу: Content-Type заголовка контролируется движком и не может быть установлен явно.

Тогда на самом деле происходит что-то странное.

Согласно журналам клиента, он отправляет тип контента:

REQUEST: http://localhost:8090/images
METHOD: HttpMethod(value=POST)
COMMON HEADERS
-> Accept: */*
-> Accept-Charset: UTF-8
CONTENT HEADERS
BODY Content-Type: multipart/form-data; boundary=-675255df42a752ee167beaab-5799548c6088f411-a7e8dc449d68ab028c44d80-42b
BODY START
[request body omitted]
...

Но на стороне сервера заголовки совершенно разные:

Accept-Charset [UTF-8]
Accept [*/*]
User-Agent [Ktor client]
Transfer-Encoding [chunked]
Host [localhost:8090]
Connection [Keep-Alive]

С другой стороны, я могу успешно загрузить файл с помощью okhttp (и заголовки действительно совпадают):

val logging = HttpLoggingInterceptor(object : HttpLoggingInterceptor.Logger {
    override fun log(message: String ) {
        println(message)
    }
})
logging.level = HttpLoggingInterceptor.Level.BODY
val client = OkHttpClient.Builder()
    .addInterceptor(logging)
    .build()
val file = File("image.png")
val part: MultipartBody.Part = MultipartBody.Part.Companion.createFormData(
    "image",
    "image.png",
    file.asRequestBody("image/png".toMediaTypeOrNull())
)
val request = Request.Builder()
    .url("http://localhost:8090/images")
    .post(MultipartBody.Builder().addPart(part).build())
    .build()
val res = client.newCall(request).execute()
res.body

Это ошибка в ktor client или я что-то упустил?

редактировать:

И клиентская, и серверная версии - 1.4.1. Соответствующие части зависимостей градиента:

    implementation("io.ktor:ktor-server-core:${ktor_version}")
    implementation("io.ktor:ktor-server-netty:${ktor_version}")
    implementation("io.ktor:ktor-jackson:$ktor_version")
    implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.8")

    ...

    implementation("io.ktor:ktor-client-core:$ktor_version")
    implementation("io.ktor:ktor-client-cio:$ktor_version")
    implementation("io.ktor:ktor-client-jackson:$ktor_version")
    implementation("io.ktor:ktor-client-logging:$ktor_version")
    implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.10.2")

маршрут:

object ImagesRouter {

    fun Routing.images(imagesModule: ImagesModule) {
        route("images") {
            get("/{id}") {
                // ...
            }

            post {
                val multipart = call.receiveMultipart() // fails here   
                // ...             
            }
        }
    }

}

person Aleksey Zhidkov    schedule 19.12.2020    source источник
comment
Посмотрите, можно ли это связать: youtrack.jetbrains.com/issue/KTOR-1129   -  person shadowsheep    schedule 21.12.2020
comment
Ваш образец отлично работает, когда я делаю запрос к https://httpbin.org/post с заголовком Content-Type и без него. Я проверял это с помощью Ktor 1.3.2, 1.4.1 и 1.5.0. Не могли бы вы предоставить дополнительную информацию о версии Ktor и зависимостях вашего проекта?   -  person Aleksei Tirman    schedule 22.12.2020
comment
@shadowsheep спасибо, но я добавил ведение журнала после того, как столкнулся с проблемой   -  person Aleksey Zhidkov    schedule 22.12.2020
comment
@AlekseiTirman Я добавил версии и зависимости. На этой неделе я попробую создать минимальный репродуктор   -  person Aleksey Zhidkov    schedule 22.12.2020
comment
О, я сократил минимальный пример точно до воспроизводящего в youtrack.jetbrains.com/issue/KTOR-1129, спасибо ...   -  person Aleksey Zhidkov    schedule 22.12.2020