From 93ff08bc7e3c4af581661c158a6bfde346b9cf29 Mon Sep 17 00:00:00 2001 From: AmirHossein Abdolmotallebi Date: Wed, 4 Sep 2024 09:53:51 -0700 Subject: [PATCH] some servers send wrong content-range headers now handled correctly --- .../connection/response/ResponseInfo.kt | 10 ++-- .../response/headers/RangeHeaderExtractor.kt | 53 ++++++++++--------- 2 files changed, 36 insertions(+), 27 deletions(-) diff --git a/downloader/core/src/main/kotlin/ir/amirab/downloader/connection/response/ResponseInfo.kt b/downloader/core/src/main/kotlin/ir/amirab/downloader/connection/response/ResponseInfo.kt index e4c68ff..33d82e8 100644 --- a/downloader/core/src/main/kotlin/ir/amirab/downloader/connection/response/ResponseInfo.kt +++ b/downloader/core/src/main/kotlin/ir/amirab/downloader/connection/response/ResponseInfo.kt @@ -22,12 +22,16 @@ data class ResponseInfo( responseHeaders["content-length"]?.toLongOrNull()?.takeIf { it >= 0L } } + val contentRange by lazy { + getContentRange() + } + //total length of whole file even if it is partial content val totalLength by lazy { val responseLength = contentLength ?: return@lazy null // partial length only valid when we have content-length header if (isPartial) { - getContentRange()?.fullSize + contentRange?.fullSize ?: responseLength } else responseLength } val requiresAuth by lazy { @@ -43,8 +47,8 @@ data class ResponseInfo( } val resumeSupport by lazy { - // maybe server does not give us content-length, so we ignore resume support - isPartial && contentLength != null + // maybe server does not give us content-length or content-range, so we ignore resume support + isPartial && contentLength != null && contentRange?.fullSize!=null } val fileName: String? by lazy { diff --git a/downloader/core/src/main/kotlin/ir/amirab/downloader/connection/response/headers/RangeHeaderExtractor.kt b/downloader/core/src/main/kotlin/ir/amirab/downloader/connection/response/headers/RangeHeaderExtractor.kt index 1382f8c..63a2151 100644 --- a/downloader/core/src/main/kotlin/ir/amirab/downloader/connection/response/headers/RangeHeaderExtractor.kt +++ b/downloader/core/src/main/kotlin/ir/amirab/downloader/connection/response/headers/RangeHeaderExtractor.kt @@ -7,37 +7,42 @@ data class ContentRangeValue( val fullSize: Long?, ) -fun ResponseInfo.getContentRange(): ContentRangeValue?{ - val value=responseHeaders["content-range"]?:return null - val actualValue=runCatching { +fun ResponseInfo.getContentRange(): ContentRangeValue? { + val value = responseHeaders["content-range"] ?: return null + val actualValue = runCatching { value.substring("bytes ".length) - }.getOrNull()?:return null - if (actualValue.isBlank()){ + }.getOrNull() ?: return null + if (actualValue.isBlank()) { return null } - var from:Long?=null - var to:Long?=null - var size:Long?=null - val (rangeString,sizeString)=actualValue.split("/") - if (rangeString!="*"){ - rangeString.split("-").map { - it.toLong() - }.let { - from=it[0] - to=it[1] + + val (rangeString, sizeString) = actualValue + .split("/") + .takeIf { it.size >= 2 } ?: return null + + val range = try { + if (rangeString != "*") { + rangeString.split("-").map { + it.toLong() + }.let { + it[0]..it[1] + } + } else { + null } - } - if (sizeString!="*"){ - size=sizeString.toLong() + } catch (e: Exception) { + // NumberFormatException or IndexOutOfBoundException + return null } + val size: Long? = if (sizeString != "*") { + // some servers not returning * nor integer value. + sizeString.toLongOrNull() ?: return null + } else null + return ContentRangeValue( - range = from?.let {f-> - to?.let {t-> - f..t - } - }, - fullSize=size + range = range, + fullSize = size, ) } \ No newline at end of file