From dbbfd5dc7cdcfb70bbf2cc2d53ca6caa6cfda0b7 Mon Sep 17 00:00:00 2001 From: NimBold Date: Mon, 29 Jun 2026 22:13:26 +0330 Subject: [PATCH] fix(download): automatically degrade to single connection when server rejects chunked range bounds When a server (like fuckingfast.co) ignores the upper bound of a range request (returning bytes=start-end/total), aria2 aborts with 'Invalid range header'. This patch treats that error as transient and mutates the download payload to force connections=1 before re-enqueuing. This ensures aria2 issues an open-ended range request (bytes=start-) on the retry, seamlessly resuming the download. --- src-tauri/src/queue.rs | 10 +++++++++- src-tauri/src/retry.rs | 4 +++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src-tauri/src/queue.rs b/src-tauri/src/queue.rs index f2a2a7c..7be17e6 100644 --- a/src-tauri/src/queue.rs +++ b/src-tauri/src/queue.rs @@ -492,6 +492,8 @@ impl QueueManager { } } + log::error!("aria2 download {} failed: {}", id, error); + self.clear_aria2_retry_state(id).await; self.forget_aria2_gid(id).await; self.emit_failed(id, error); @@ -630,7 +632,13 @@ impl QueueManager { .await; return; } - let payload = payload.unwrap(); + let mut payload = payload.unwrap(); + + if error.to_ascii_lowercase().contains("invalid range header") { + log::warn!("Server does not support chunked ranges. Degrading {} to single connection.", id); + payload.connections = Some(1); + self.aria2_payloads.lock().await.insert(id.clone(), payload.clone()); + } let this = Arc::clone(self); let stale_gid = gid.to_string(); diff --git a/src-tauri/src/retry.rs b/src-tauri/src/retry.rs index 5ccfbc3..a8e24cf 100644 --- a/src-tauri/src/retry.rs +++ b/src-tauri/src/retry.rs @@ -102,7 +102,7 @@ pub fn is_transient_network_error(message: &str) -> bool { let m = message.to_ascii_lowercase(); - const TRANSIENT: [&str; 34] = [ + const TRANSIENT: [&str; 35] = [ // reqwest / hyper / OS socket-layer "timed out", "timeout", @@ -141,6 +141,7 @@ pub fn is_transient_network_error(message: &str) -> bool { // aria2c log phrasing "connection was closed", "timeout.", + "invalid range header", ]; TRANSIENT.iter().any(|t| m.contains(t)) } @@ -278,6 +279,7 @@ mod tests { assert!(is_transient_network_error("network is unreachable")); assert!(is_transient_network_error("The response status is not successful. status=503")); assert!(is_transient_network_error("The response status is not successful. status=502")); + assert!(is_transient_network_error("Invalid range header. Request: 106954752-361758719/383882118, Response: 106954752-383882117/383882118")); } // --- transient classification: negative cases -------------------------