use std::io;
use std::io::Read;
use std::path::Path;
pub(crate) const MAX_FILE_BYTES: u64 = 16 * 1024 * 1024;
pub(crate) fn read_to_string_capped(path: impl AsRef<Path>) -> io::Result<String> {
read_to_string_capped_with(path.as_ref(), MAX_FILE_BYTES)
}
fn read_to_string_capped_with(path: &Path, max: u64) -> io::Result<String> {
let file = std::fs::File::open(path)?;
let mut buf = String::new();
let read = file.take(max + 1).read_to_string(&mut buf)?;
if read as u64 > max {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("{} is larger than the {max} byte limit", path.display()),
));
}
Ok(buf)
}
#[cfg(test)]
mod tests {
use super::read_to_string_capped_with;
#[test]
fn reads_file_within_limit() {
let dir = tempfile::tempdir().expect("tempdir");
let f = dir.path().join("ok");
std::fs::write(&f, b"hello").expect("write");
assert_eq!(read_to_string_capped_with(&f, 16).unwrap(), "hello");
}
#[test]
fn rejects_file_over_limit() {
let dir = tempfile::tempdir().expect("tempdir");
let f = dir.path().join("big");
std::fs::write(&f, vec![b'x'; 32]).expect("write");
let err = read_to_string_capped_with(&f, 16).unwrap_err();
assert_eq!(err.kind(), std::io::ErrorKind::InvalidData);
}
#[test]
fn missing_file_is_error() {
assert!(read_to_string_capped_with(std::path::Path::new("/no/such/file"), 16).is_err());
}
}