sn-fetch PoC: range probe, weighted planner, parallel segments, reassembly + sha256

This commit is contained in:
2026-09-24 13:53:35 +02:00
parent 3cb2890425
commit 9a61452931
18 changed files with 3290 additions and 6 deletions
+66
View File
@@ -0,0 +1,66 @@
//! Probing: find out whether a server supports HTTP range requests and
//! how large the object is, before planning a segmented download.
use reqwest::header::{ACCEPT_RANGES, CONTENT_LENGTH};
use reqwest::StatusCode;
use crate::error::FetchError;
use crate::types::{FileSize, RangeSupport, TargetUrl};
/// What a HEAD request (plus fallback range probe) told us about the target.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ProbeInfo {
pub range_support: RangeSupport,
pub content_length: Option<FileSize>,
}
/// Probe the target: HEAD first; if the `Accept-Ranges` header is absent
/// or inconclusive, fall back to a 1-byte GET with a `Range` header and
/// check for `206 Partial Content`.
pub async fn probe(client: &reqwest::Client, url: &TargetUrl) -> Result<ProbeInfo, FetchError> {
let head = client
.head(url.inner().clone())
.send()
.await?
.error_for_status()?;
let content_length = head
.headers()
.get(CONTENT_LENGTH)
.and_then(|v| v.to_str().ok())
.and_then(|v| v.parse::<u64>().ok());
let advertised = match head
.headers()
.get(ACCEPT_RANGES)
.and_then(|v| v.to_str().ok())
.map(str::trim)
{
Some("bytes") => Some(RangeSupport::Supported),
Some("none") => Some(RangeSupport::Unsupported),
_ => None,
};
let range_support = match advertised {
Some(support) => support,
// HEAD was inconclusive: ask directly with a 1-byte range.
None => {
let resp = client
.get(url.inner().clone())
.header(reqwest::header::RANGE, "bytes=0-0")
.send()
.await?;
match resp.status() {
StatusCode::PARTIAL_CONTENT => RangeSupport::Supported,
StatusCode::OK => RangeSupport::Unsupported,
_ => RangeSupport::Unknown,
}
}
};
Ok(ProbeInfo {
range_support,
content_length: content_length.and_then(|len| FileSize::try_new(len).ok()),
})
}