in ktor-http/ktor-http-cio/common/src/io/ktor/http/cio/ChunkedTransferEncoding.kt [57:107]
public suspend fun decodeChunked(input: ByteReadChannel, out: ByteWriteChannel, contentLength: Long) {
val chunkSizeBuffer = ChunkSizeBufferPool.borrow()
var totalBytesCopied = 0L
try {
while (true) {
chunkSizeBuffer.clear()
if (!input.readUTF8LineTo(chunkSizeBuffer, MAX_CHUNK_SIZE_LENGTH)) {
throw EOFException("Chunked stream has ended unexpectedly: no chunk size")
} else if (chunkSizeBuffer.isEmpty()) {
throw EOFException("Invalid chunk size: empty")
}
val chunkSize =
if (chunkSizeBuffer.length == 1 && chunkSizeBuffer[0] == '0') 0
else chunkSizeBuffer.parseHexLong()
if (contentLength != -1L && chunkSize > (contentLength - totalBytesCopied)) {
input.cancel()
throw ParserException("Invalid chunk: chunk-encoded content is larger than expected $contentLength")
}
if (chunkSize > 0) {
input.copyTo(out, chunkSize)
out.flush()
totalBytesCopied += chunkSize
}
chunkSizeBuffer.clear()
if (!input.readUTF8LineTo(chunkSizeBuffer, 2)) {
throw EOFException("Invalid chunk: content block of size $chunkSize ended unexpectedly")
}
if (chunkSizeBuffer.isNotEmpty()) {
throw EOFException("Invalid chunk: content block should end with CR+LF")
}
if (chunkSize == 0L) break
}
if (contentLength != -1L && totalBytesCopied != contentLength) {
input.cancel()
throw EOFException("Corrupted chunk-encoded content: steam ended before the expected number of bytes ($contentLength) were decoded.")
}
} catch (t: Throwable) {
out.close(t)
throw t
} finally {
ChunkSizeBufferPool.recycle(chunkSizeBuffer)
out.close()
}
}