clawhdf5-remote: a 200 covering the requested range is the whole file

The first request asks for bytes=0-1048575. RFC 9110 lets a server answer
200 when the range covers the whole representation, so a file under
1 MiB on a server that does support ranges could be refused as 'does not
support range requests'. A 200 whose Content-Length (or, without one, its
body, read at most that far) is within the range asked for is now kept as
the whole file and read from memory; a longer one is still refused unless
allow_full_download is set.

Test: a 9968-byte file served with 200 opens in one request with the
transcript of File::open (it was refused before); with a 4096-byte first
request it is still refused.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
osobh
2026-09-26 18:32:15 -05:00
co-authored by Claude Opus 5.5
parent 680c90b3a8
commit 61e34927dc
2 changed files with 50 additions and 5 deletions
+23
View File
@@ -777,3 +777,26 @@ fn redirects_are_followed_safely() {
let e = open_url_with(&front.url("/s.h5"), &opts).unwrap_err();
assert!(matches!(e, Error::Remote(RemoteError::Redirect(_))), "{e}");
}
/// A server may answer the first request (bytes 0 to 1 MiB - 1) with 200
/// when that covers the whole file: a body no longer than the range asked
/// for is accepted as the whole file, in one request.
#[test]
fn a_200_covering_the_requested_range_is_the_whole_file() {
let root = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
let tall = root.join("../clawhdf5/tests/fixtures/tall.h5");
let bytes = std::fs::read(&tall).unwrap();
assert!(bytes.len() < 1 << 20);
let server = Server::start(vec![("/t.h5".into(), bytes.clone())]);
server.shared.ignore_range.store(true, Ordering::SeqCst);
let storage = storage_for_url(&server.url("/t.h5"), &quick()).unwrap();
let f = File::open_storage(storage).unwrap();
assert_eq!(f.contiguous_bytes(), Some(&bytes[..]));
assert_eq!(transcript(&f), transcript(&File::open(&tall).unwrap()));
assert_eq!(server.requests(), 1);
// Larger than the range asked for: still refused.
let mut opts = quick().http;
opts.first_request = 4096;
let e = HttpStorage::open(&server.url("/t.h5"), opts).unwrap_err();
assert!(matches!(e, RemoteError::RangeNotSupported(_)), "{e}");
}