Merge pull request #135 from amir1376/fix/close-connection-when-response-is-not-2xx

close connection if download response is not successful
This commit is contained in:
AmirHossein Abdolmotallebi 2024-10-24 11:09:55 +03:30 committed by GitHub
commit 62a8bb73c4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -53,7 +53,7 @@ class PartDownloader(
val part: Part, val part: Part,
val client: DownloaderClient, val client: DownloaderClient,
val speedLimiters: List<Throttler>, val speedLimiters: List<Throttler>,
val strictMode:Boolean, val strictMode: Boolean,
private val partSplitLock: Any, private val partSplitLock: Any,
) { ) {
class ShouldNotHappened(msg: String?) : RuntimeException(msg) class ShouldNotHappened(msg: String?) : RuntimeException(msg)
@ -66,7 +66,16 @@ class PartDownloader(
): Connection { ): Connection {
val connect = client.connect(credentials, from, to) val connect = client.connect(credentials, from, to)
// make sure this is a 2xx response // make sure this is a 2xx response
connect.responseInfo.expectSuccess() kotlin.runCatching {
connect.responseInfo.expectSuccess()
}
.onFailure {
// close connection before throwing exception
kotlin.runCatching {
connect.closeable.close()
}
}
.getOrThrow()
val source = speedLimiters.fold<Throttler, Source>(connect.source) { acc, throttler -> val source = speedLimiters.fold<Throttler, Source>(connect.source) { acc, throttler ->
throttler.source(acc) throttler.source(acc)
} }
@ -132,7 +141,8 @@ class PartDownloader(
iCantRetryAnymore( iCantRetryAnymore(
PartTooManyErrorException( PartTooManyErrorException(
part, part,
lastException?:Exception("BUG : if you see me please report it to the developer! when we encounter error so it have to be a least one last exception"), lastException
?: Exception("BUG : if you see me please report it to the developer! when we encounter error so it have to be a least one last exception"),
) )
) )
} }
@ -144,7 +154,7 @@ class PartDownloader(
} catch (e: Exception) { } catch (e: Exception) {
tries++ tries++
onCanceled(e) onCanceled(e)
when(canRetry(e)){ when (canRetry(e)) {
CanRetryResult.Yes -> continue CanRetryResult.Yes -> continue
CanRetryResult.No -> {} CanRetryResult.No -> {}
CanRetryResult.NoAndStopDownloadJob -> iCantRetryAnymore(e) CanRetryResult.NoAndStopDownloadJob -> iCantRetryAnymore(e)
@ -160,7 +170,7 @@ class PartDownloader(
when (status) { when (status) {
is PartDownloadStatus.Canceled -> { is PartDownloadStatus.Canceled -> {
tries++ tries++
when(canRetry(status.e)){ when (canRetry(status.e)) {
CanRetryResult.Yes -> continue CanRetryResult.Yes -> continue
CanRetryResult.No -> {} CanRetryResult.No -> {}
CanRetryResult.NoAndStopDownloadJob -> iCantRetryAnymore(status.e) CanRetryResult.NoAndStopDownloadJob -> iCantRetryAnymore(status.e)
@ -187,10 +197,10 @@ class PartDownloader(
} }
} }
private sealed interface CanRetryResult{ private sealed interface CanRetryResult {
data object Yes:CanRetryResult data object Yes : CanRetryResult
data object No:CanRetryResult data object No : CanRetryResult
data object NoAndStopDownloadJob:CanRetryResult data object NoAndStopDownloadJob : CanRetryResult
} }
private fun canRetry(e: Throwable): CanRetryResult { private fun canRetry(e: Throwable): CanRetryResult {
@ -198,13 +208,15 @@ class PartDownloader(
ExceptionUtils.isNormalCancellation(e) -> { ExceptionUtils.isNormalCancellation(e) -> {
CanRetryResult.No CanRetryResult.No
} }
e is DownloadValidationException -> if (e.isCritical()){
e is DownloadValidationException -> if (e.isCritical()) {
//download validation occurs, and also it is critical, //download validation occurs, and also it is critical,
//so we can't proceed any further //so we can't proceed any further
CanRetryResult.NoAndStopDownloadJob CanRetryResult.NoAndStopDownloadJob
}else{ } else {
CanRetryResult.Yes CanRetryResult.Yes
} }
else -> { else -> {
CanRetryResult.Yes CanRetryResult.Yes
} }
@ -252,7 +264,7 @@ class PartDownloader(
} }
} }
if (contentLength != partCopy.remainingLength) { if (contentLength != partCopy.remainingLength) {
if (strictMode){ if (strictMode) {
conn.closeable.close() conn.closeable.close()
throw ServerPartIsNotTheSameAsWeExpectException( throw ServerPartIsNotTheSameAsWeExpectException(
start = partCopy.current, start = partCopy.current,
@ -411,12 +423,12 @@ suspend fun PartDownloader.awaitFinishOrError(): PartDownloadStatus {
when (it) { when (it) {
PartDownloadStatus.Completed, PartDownloadStatus.Completed,
is PartDownloadStatus.Canceled, is PartDownloadStatus.Canceled,
-> true -> true
PartDownloadStatus.ReceivingData, PartDownloadStatus.ReceivingData,
PartDownloadStatus.SendGet, PartDownloadStatus.SendGet,
PartDownloadStatus.IDLE, PartDownloadStatus.IDLE,
-> false -> false
} }
}.first() }.first()
} }
@ -427,12 +439,12 @@ suspend fun PartDownloader.awaitToEnsureDataBeingTransferred(): Boolean {
when (it) { when (it) {
PartDownloadStatus.Completed, PartDownloadStatus.Completed,
PartDownloadStatus.ReceivingData, PartDownloadStatus.ReceivingData,
-> true -> true
is PartDownloadStatus.Canceled, is PartDownloadStatus.Canceled,
PartDownloadStatus.SendGet, PartDownloadStatus.SendGet,
PartDownloadStatus.IDLE, PartDownloadStatus.IDLE,
-> false -> false
} }
}.first().let { }.first().let {
when (it) { when (it) {
@ -441,7 +453,7 @@ suspend fun PartDownloader.awaitToEnsureDataBeingTransferred(): Boolean {
PartDownloadStatus.ReceivingData -> true PartDownloadStatus.ReceivingData -> true
PartDownloadStatus.SendGet, PartDownloadStatus.SendGet,
PartDownloadStatus.IDLE, PartDownloadStatus.IDLE,
-> error("should not happen") -> error("should not happen")
} }
} }
isThatOk isThatOk
@ -454,11 +466,11 @@ suspend fun PartDownloader.awaitIdle() {
is PartDownloadStatus.Canceled, is PartDownloadStatus.Canceled,
PartDownloadStatus.Completed, PartDownloadStatus.Completed,
PartDownloadStatus.IDLE, PartDownloadStatus.IDLE,
-> true -> true
PartDownloadStatus.SendGet, PartDownloadStatus.SendGet,
PartDownloadStatus.ReceivingData, PartDownloadStatus.ReceivingData,
-> false -> false
} }
}.first() }.first()
} }