use std::{fs, path::PathBuf}; use crate::{ handling::response::{ResponseBody, Status}, utils::mime::Mime, }; #[derive(Debug)] /// Struct to handle files on the server side. /// Validates paths ignores actions like `..` pub struct NamedFile { /// The length of the file in bytes, format: [usize] pub content_len: usize, /// The Mime Type of the file as a [Mime] pub content_type: Mime, /// The content of the file as a [`Vec<u8>`] pub content: Vec<u8>, } impl ResponseBody for NamedFile { fn get_data(&self) -> Vec<u8> { self.content.clone() } fn get_mime(&self) -> Mime { self.content_type } fn get_len(&self) -> usize { self.content_len } } impl NamedFile { /// Reads in a file as a [NamedFile]. Ignores seqences like `..` /// /// # Panics /// /// Panics if a [PathBuf] can't be convertet to a [str] /// /// # Errors /// /// Can give a [Status::NotFound] if it can't find the file /// /// This function will return an error if . pub fn open(path: PathBuf) -> Result<NamedFile, Status> { let path = proove_path(path); let data = fs::read(&path); let data = match data { Ok(dat) => dat, Err(_) => { return Err(Status::NotFound); } }; Ok(NamedFile { content_len: data.len(), content_type: Mime::from_filename(path.to_str().unwrap()), content: data, }) } } /// Validates a path so that seqences like `//` and `..` are omitted /// /// # Panics /// /// Panics if it can't convert a [PathBuf] to a [str] fn proove_path(path: PathBuf) -> PathBuf { PathBuf::from( path.to_str() .unwrap() .split('/') .filter(|&val| val != ".." && !val.is_empty()) .collect::<Vec<&str>>() .join("/"), ) }