clawhdf5-remote, h5rs: never allocate a length the server only claims
h5rs check URL read the whole file with one read_at(0, len), len being whatever Content-Range said. BlockCache listed every block index of the span and preallocated len bytes: a server claiming 2^62 bytes for a 10 KB file made h5rs abort (memory allocation of 35184372088832 bytes failed). - BlockCache: a read spanning more than the budget (or eight max_requests) is fetched piece by piece and not kept, its output growing only as data arrives; read_ranges falls back to that per range; prefetch is clamped to the budget. - New clawhdf5_remote::download(storage, max_bytes): refuses a claimed length above the limit (RemoteError::TooLarge) before any request, then reads in 64 MiB steps. New RemoteError::Backend for read errors. - h5rs check downloads through it, with --max-download N (default 1 GiB). Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
@@ -248,8 +248,10 @@ impl H5 {
|
||||
|
||||
/// [`H5::open_arg`], with a remote file downloaded whole into memory
|
||||
/// first — for `check`, which validates every byte of the file anyway
|
||||
/// and parses it as one slice ([`H5::data`]).
|
||||
pub fn open_arg_whole(arg: &str) -> Result<H5> {
|
||||
/// and parses it as one slice ([`H5::data`]). A remote file longer
|
||||
/// than `max_download` bytes is refused before anything is read: its
|
||||
/// length is only what the server claims.
|
||||
pub fn open_arg_whole(arg: &str, max_download: u64) -> Result<H5> {
|
||||
let h5 = H5::open_arg(arg)?;
|
||||
if h5.file.contiguous_bytes().is_some() {
|
||||
return Ok(h5);
|
||||
@@ -259,12 +261,8 @@ impl H5 {
|
||||
let storage =
|
||||
clawhdf5_remote::storage_for_url(arg, &clawhdf5_remote::Options::default())
|
||||
.map_err(|e| Error::new(format!("{arg}: {e}")))?;
|
||||
let len = usize::try_from(storage.len())
|
||||
.map_err(|_| Error::new(format!("{arg}: too large to download")))?;
|
||||
let bytes = storage
|
||||
.read_at(0, len)
|
||||
.map_err(|e| Error::new(format!("{arg}: {e}")))?
|
||||
.into_owned();
|
||||
let bytes = clawhdf5_remote::download(&*storage, max_download)
|
||||
.map_err(|e| Error::new(format!("{arg}: {e}")))?;
|
||||
let size = bytes.len() as u64;
|
||||
let file = File::from_bytes(bytes).map_err(|e| {
|
||||
Error::new(format!("{arg}: not an HDF5 file this tool can open: {e}"))
|
||||
@@ -272,7 +270,10 @@ impl H5 {
|
||||
Ok(H5::new(PathBuf::from(arg), file, size))
|
||||
}
|
||||
#[cfg(not(feature = "remote"))]
|
||||
unreachable!("open_arg refuses URLs without the remote feature")
|
||||
{
|
||||
let _ = max_download;
|
||||
unreachable!("open_arg refuses URLs without the remote feature")
|
||||
}
|
||||
}
|
||||
|
||||
/// The file's bytes from the superblock on: what every address indexes.
|
||||
|
||||
Reference in New Issue
Block a user