net: retry flaky archive fetches and pin index downloads via by-hash

Busy mirrors and CDNs routinely break bulk fetches: pooled keep-alive
connections get closed remotely ('error sending request'), downloads are
cut short (surfacing as bogus checksum mismatches), and index generations
momentarily drift from the Release file fetched moments before.

- shared client: short idle-pool timeout and TCP keepalive, and a
  bounded-retry GET helper now used for index, Release, keyring and
  Launchpad fetches (previously reqwest::get, which has no timeouts)
- downloads: retry the whole download, and check the content length so
  truncation is reported as such instead of a checksum mismatch
- sources index: on a checksum mismatch against the Release file, retry
  pinned to the exact listed generation via Debian's by-hash mechanism;
  body-read errors are retried and reported per component instead of
  aborting the whole lookup
This commit is contained in:
2026-09-17 15:18:14 +02:00
parent afedde1f2b
commit 3ed95725e4
4 changed files with 213 additions and 36 deletions
+4 -4
View File
@@ -137,7 +137,7 @@ impl ChecksumKind {
}
/// Human-readable algorithm name, for error messages
fn name(self) -> &'static str {
pub fn name(self) -> &'static str {
match self {
ChecksumKind::Md5 => "MD5",
ChecksumKind::Sha1 => "SHA-1",
@@ -782,7 +782,7 @@ pub async fn verify_suite(
/// GET a URL, returning None on any HTTP error, non-success status, or body
/// read failure (Release files are probed, so absence is a normal outcome)
async fn fetch_optional(url: &str) -> Option<Vec<u8>> {
match reqwest::get(url).await {
match crate::distro_info::http_get_retried(url).await {
Ok(response) if response.status().is_success() => match response.bytes().await {
Ok(bytes) => return Some(bytes.to_vec()),
Err(e) => debug!("Reading the body of '{url}' failed: {e}"),
@@ -811,7 +811,7 @@ async fn fetch_keyring_cached(url: &str) -> Result<Vec<u8>, Box<dyn Error + Send
return Ok(cached.clone());
}
let response = reqwest::get(url).await?;
let response = crate::distro_info::http_get_retried(url).await?;
if !response.status().is_success() {
return Err(format!(
"downloading keyring from '{url}' failed with HTTP {}",
@@ -887,7 +887,7 @@ pub async fn ppa_keyring_bytes(
}
let api_url = format!("https://api.launchpad.net/1.0/~{owner}/+archive/ubuntu/{name}");
let response = reqwest::get(&api_url).await?;
let response = crate::distro_info::http_get_retried(&api_url).await?;
if !response.status().is_success() {
return Err(format!(
"querying the Launchpad API for the signing key of PPA \