in ktor-server/ktor-server-core/jvm/src/io/ktor/features/DoubleReceive.kt [51:107]
override fun install(pipeline: Application, configure: Configuration.() -> Unit): DoubleReceive {
val feature = DoubleReceive(Configuration().apply(configure))
pipeline.receivePipeline.intercept(ApplicationReceivePipeline.Before) { request ->
val type = request.typeInfo
require(request.type != CachedTransformationResult::class) { "CachedTransformationResult can't be received" }
val cachedResult = call.attributes.getOrNull(LastReceiveCachedResult)
when {
cachedResult == null -> call.attributes.put(LastReceiveCachedResult, RequestAlreadyConsumedResult)
cachedResult === RequestAlreadyConsumedResult -> throw RequestAlreadyConsumedException()
cachedResult is CachedTransformationResult.Failure -> throw RequestReceiveAlreadyFailedException(
cachedResult.cause
)
cachedResult is CachedTransformationResult.Success<*> && cachedResult.type == type -> {
proceedWith(ApplicationReceiveRequest(request.typeInfo, cachedResult.value))
return@intercept
}
}
var byteArray = (cachedResult as? CachedTransformationResult.Success<*>)?.value as? ByteArray
val requestValue = request.value
if (byteArray == null && feature.config.receiveEntireContent && requestValue is ByteReadChannel) {
byteArray = requestValue.toByteArray()
call.attributes.put(
LastReceiveCachedResult,
CachedTransformationResult.Success(typeOf<ByteArray>(), byteArray)
)
}
val incomingContent = byteArray?.let { ByteReadChannel(it) } ?: cachedResult ?: request.value
val finishedRequest = try {
proceedWith(ApplicationReceiveRequest(type, incomingContent))
} catch (cause: Throwable) {
call.attributes.put(LastReceiveCachedResult, CachedTransformationResult.Failure(type, cause))
throw cause
}
val transformed = finishedRequest.value
when {
transformed is CachedTransformationResult.Success<*> -> throw RequestAlreadyConsumedException()
!request.type.isInstance(transformed) -> throw CannotTransformContentToTypeException(type)
}
if (finishedRequest.reusableValue && (cachedResult == null || cachedResult !is CachedTransformationResult.Success)) {
@Suppress("UNCHECKED_CAST")
call.attributes.put(
LastReceiveCachedResult,
CachedTransformationResult.Success(type, finishedRequest.value)
)
}
}
return feature
}