use crate::constants; use actix_multipart::form::MultipartForm; use actix_multipart::form::tempfile::TempFile; use actix_web::dev::Payload; use actix_web::{Error, FromRequest, HttpRequest}; use mime_guess::Mime; use std::io::Read; use std::str::FromStr; #[derive(Debug, MultipartForm)] struct FileUploadForm { #[multipart(rename = "file")] file: TempFile, } pub struct FileExtractor { pub buff: Vec, pub mime: Mime, pub name: Option, } impl FileExtractor { pub fn name(&self) -> String { match &self.name { None => { let ext = self.mime.suffix().map(|s| s.as_str()).unwrap_or("bin"); format!("file.{ext}") } Some(f) => f.to_string(), } } } impl FromRequest for FileExtractor { type Error = Error; type Future = futures_util::future::LocalBoxFuture<'static, Result>; fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future { let form = MultipartForm::::from_request(req, payload); Box::pin(async move { let mut form = form.await?; if form.file.size > constants::MAX_UPLOAD_FILE_SIZE { return Err(actix_web::error::ErrorPayloadTooLarge( "Uploaded file is too large!", )); } let mut buff = Vec::with_capacity(form.file.size); form.file.file.read_to_end(&mut buff)?; let mime = match form .file .content_type .clone() .or_else(|| Mime::from_str(form.file.file_name.as_deref().unwrap_or("")).ok()) { Some(s) => s, None => { return Err(actix_web::error::ErrorBadRequest( "Mimetype was not specified!!", )); } }; Ok(Self { mime, buff, name: form.file.file_name.clone(), }) }) } }