pub const MAX_LOCAL_REPORT_BYTES: u64 = 64 * 1024 * 1024;
pub const MAX_BATCH_INPUT_BYTES: usize = 1024 * 1024 * 1024;
pub enum CappedRead {
Bytes(Vec<u8>),
TooLarge(u64),
}
pub fn read_capped(path: &std::path::Path, max: u64) -> std::io::Result<CappedRead> {
use std::io::Read as _;
let file = std::fs::File::open(path)?;
let len = file.metadata()?.len();
if len > max {
return Ok(CappedRead::TooLarge(len));
}
let mut bytes = Vec::new();
file.take(max + 1).read_to_end(&mut bytes)?;
if bytes.len() as u64 > max {
return Ok(CappedRead::TooLarge(bytes.len() as u64));
}
Ok(CappedRead::Bytes(bytes))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_file_under_the_cap_is_read_whole() {
let dir = tempfile::tempdir().expect("tempdir");
let path = dir.path().join("report.json");
std::fs::write(&path, b"{}").expect("write");
assert!(matches!(read_capped(&path, 2), Ok(CappedRead::Bytes(bytes)) if bytes == b"{}"));
}
#[test]
fn a_file_over_the_cap_reports_its_size() {
let dir = tempfile::tempdir().expect("tempdir");
let path = dir.path().join("report.json");
std::fs::write(&path, b"{\"a\":1}").expect("write");
assert!(matches!(read_capped(&path, 3), Ok(CappedRead::TooLarge(7))));
}
#[cfg(unix)]
#[test]
fn a_file_whose_metadata_lies_is_still_bounded() {
let read = read_capped(std::path::Path::new("/dev/zero"), 16);
assert!(matches!(read, Ok(CappedRead::TooLarge(17))));
}
}