From b0443125bf7a542b0c0496dd6a056b0d4db3d0c5 Mon Sep 17 00:00:00 2001 From: Pavel Kirilin Date: Thu, 9 Nov 2023 00:46:27 +0100 Subject: [PATCH 1/2] Added content-disposition from metadata. (#144) --- Cargo.lock | 6 ++++-- Cargo.toml | 2 ++ src/info_storages/models/file_info.rs | 4 ++++ src/storages/file_storage.rs | 9 ++++++--- src/storages/s3_hybrid_storage.rs | 6 +++++- src/utils/headers.rs | 25 ++++++++++++++++++++++++- 6 files changed, 45 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 74b60fb..784183d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2067,9 +2067,9 @@ dependencies = [ [[package]] name = "mime" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "mime_guess" @@ -3191,6 +3191,8 @@ dependencies = [ "log", "md-5", "mimalloc", + "mime", + "mime_guess", "openssl", "prometheus", "rbatis", diff --git a/Cargo.toml b/Cargo.toml index 9215083..0b084af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,6 +37,8 @@ clap = { version = "4.1.8", features = ["derive", "env"] } dotenvy = { version = "0.15.6", features = ["clap"] } sentry = "0.30.0" sentry-actix = "0.30.0" +mime = "0.3.17" +mime_guess = "2.0.4" [dependencies.sha1] version = "^0.10.1" diff --git a/src/info_storages/models/file_info.rs b/src/info_storages/models/file_info.rs index d99dec1..905eba7 100644 --- a/src/info_storages/models/file_info.rs +++ b/src/info_storages/models/file_info.rs @@ -90,6 +90,10 @@ impl FileInfo { } } + pub fn get_filename(&self) -> &str { + self.metadata.get("filename").unwrap_or(&self.id) + } + pub async fn json(&self) -> RustusResult { let info_clone = self.clone(); tokio::task::spawn_blocking(move || { diff --git a/src/storages/file_storage.rs b/src/storages/file_storage.rs index 0427833..b386b41 100644 --- a/src/storages/file_storage.rs +++ b/src/storages/file_storage.rs @@ -1,4 +1,4 @@ -use std::{io::Write, path::PathBuf}; +use std::{fs::File, io::Write, path::PathBuf}; use actix_files::NamedFile; use actix_web::{HttpRequest, HttpResponse}; @@ -76,8 +76,11 @@ impl Storage for FileStorage { request: &HttpRequest, ) -> RustusResult { if let Some(path) = &file_info.path { - Ok(NamedFile::open_async(path) - .await + let file = File::open(path).map_err(|err| { + error!("{:?}", err); + RustusError::FileNotFound + })?; + Ok(NamedFile::from_file(file, file_info.get_filename()) .map_err(|err| { error!("{:?}", err); RustusError::FileNotFound diff --git a/src/storages/s3_hybrid_storage.rs b/src/storages/s3_hybrid_storage.rs index 17a2cf1..7c6139f 100644 --- a/src/storages/s3_hybrid_storage.rs +++ b/src/storages/s3_hybrid_storage.rs @@ -3,10 +3,12 @@ use std::{collections::HashMap, path::PathBuf}; use crate::{ errors::{RustusError, RustusResult}, info_storages::FileInfo, + utils::headers::generate_disposition, }; use super::Storage; use crate::{storages::file_storage::FileStorage, utils::dir_struct::substr_time}; + use actix_web::{HttpRequest, HttpResponse, HttpResponseBuilder}; use async_trait::async_trait; use bytes::Bytes; @@ -136,7 +138,9 @@ impl Storage for S3HybridStorage { let s3_request = Reqwest::new(&self.bucket, &key, command); let s3_response = s3_request.response().await?; let mut response = HttpResponseBuilder::new(actix_web::http::StatusCode::OK); - Ok(response.streaming(s3_response.bytes_stream())) + Ok(response + .insert_header(generate_disposition(file_info.get_filename())) + .streaming(s3_response.bytes_stream())) } async fn add_bytes(&self, file_info: &FileInfo, bytes: Bytes) -> RustusResult<()> { diff --git a/src/utils/headers.rs b/src/utils/headers.rs index 1bec0b8..5a2a268 100644 --- a/src/utils/headers.rs +++ b/src/utils/headers.rs @@ -1,6 +1,9 @@ use std::str::FromStr; -use actix_web::HttpRequest; +use actix_web::{ + http::header::{ContentDisposition, DispositionParam, DispositionType}, + HttpRequest, +}; /// Parse header's value. /// @@ -42,6 +45,26 @@ pub fn check_header(request: &HttpRequest, header_name: &str, expr: fn(&str) -> .unwrap_or(false) } +/// This function generates content disposition +/// based on file name. +pub fn generate_disposition(filename: &str) -> ContentDisposition { + let mime_type = mime_guess::from_path(filename).first_or_octet_stream(); + let disposition = match mime_type.type_() { + mime::IMAGE | mime::TEXT | mime::AUDIO | mime::VIDEO => DispositionType::Inline, + mime::APPLICATION => match mime_type.subtype() { + mime::JAVASCRIPT | mime::JSON => DispositionType::Inline, + name if name == "wasm" => DispositionType::Inline, + _ => DispositionType::Attachment, + }, + _ => DispositionType::Attachment, + }; + + ContentDisposition { + disposition, + parameters: vec![DispositionParam::Filename(String::from(filename))], + } +} + #[cfg(test)] mod tests { use super::{check_header, parse_header}; From 2112d8f37c54ac943f91eea129ef417252c37c93 Mon Sep 17 00:00:00 2001 From: Pavel Kirilin Date: Thu, 9 Nov 2023 00:47:48 +0100 Subject: [PATCH 2/2] Version bumped to 0.7.6. Signed-off-by: Pavel Kirilin --- Cargo.lock | 2 +- Cargo.toml | 2 +- deploy/helm/Chart.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 784183d..ad03003 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3164,7 +3164,7 @@ dependencies = [ [[package]] name = "rustus" -version = "0.7.5" +version = "0.7.6" dependencies = [ "actix-cors", "actix-files", diff --git a/Cargo.toml b/Cargo.toml index 0b084af..82d27f0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustus" -version = "0.7.5" +version = "0.7.6" edition = "2021" description = "TUS protocol implementation written in Rust." keywords = ["tus", "server", "actix-web"] diff --git a/deploy/helm/Chart.yaml b/deploy/helm/Chart.yaml index 7e58f96..ad39168 100644 --- a/deploy/helm/Chart.yaml +++ b/deploy/helm/Chart.yaml @@ -22,7 +22,7 @@ version: 0.2.0 # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "0.6.1" +appVersion: "0.7.6" dependencies: