From 7bca1f7d8de013212fd35aff9f2f89162a023f40 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Sat, 20 Jul 2019 11:43:49 +0600 Subject: [PATCH] Allow to disable Content-Disposition header #686 --- actix-files/CHANGES.md | 5 +++++ actix-files/src/lib.rs | 44 ++++++++++++++++++++++++++++++++++++---- actix-files/src/named.rs | 43 ++++++++++++++++++++++++++------------- 3 files changed, 74 insertions(+), 18 deletions(-) diff --git a/actix-files/CHANGES.md b/actix-files/CHANGES.md index 2f98e15c..916d579f 100644 --- a/actix-files/CHANGES.md +++ b/actix-files/CHANGES.md @@ -1,5 +1,10 @@ # Changes +## [0.1.4] - 2019-07-20 + +* Allow to disable `Content-Disposition` header #686 + + ## [0.1.3] - 2019-06-28 * Do not set `Content-Length` header, let actix-http set it #930 diff --git a/actix-files/src/lib.rs b/actix-files/src/lib.rs index cf07153f..2eab6405 100644 --- a/actix-files/src/lib.rs +++ b/actix-files/src/lib.rs @@ -314,23 +314,32 @@ impl Files { } #[inline] - ///Specifies whether to use ETag or not. + /// Specifies whether to use ETag or not. /// - ///Default is true. + /// Default is true. pub fn use_etag(mut self, value: bool) -> Self { self.file_flags.set(named::Flags::ETAG, value); self } #[inline] - ///Specifies whether to use Last-Modified or not. + /// Specifies whether to use Last-Modified or not. /// - ///Default is true. + /// Default is true. pub fn use_last_modified(mut self, value: bool) -> Self { self.file_flags.set(named::Flags::LAST_MD, value); self } + /// Disable `Content-Disposition` header. + /// + /// By default Content-Disposition` header is enabled. + #[inline] + pub fn disable_content_disposition(mut self) -> Self { + self.file_flags.remove(named::Flags::CONTENT_DISPOSITION); + self + } + /// Sets default handler which is used when no matched file could be found. pub fn default_handler(mut self, f: F) -> Self where @@ -638,6 +647,33 @@ mod tests { ); } + #[test] + fn test_named_file_content_disposition() { + assert!(NamedFile::open("test--").is_err()); + let mut file = NamedFile::open("Cargo.toml").unwrap(); + { + file.file(); + let _f: &File = &file; + } + { + let _f: &mut File = &mut file; + } + + let req = TestRequest::default().to_http_request(); + let resp = file.respond_to(&req).unwrap(); + assert_eq!( + resp.headers().get(header::CONTENT_DISPOSITION).unwrap(), + "inline; filename=\"Cargo.toml\"" + ); + + let file = NamedFile::open("Cargo.toml") + .unwrap() + .disable_content_disposition(); + let req = TestRequest::default().to_http_request(); + let resp = file.respond_to(&req).unwrap(); + assert!(resp.headers().get(header::CONTENT_DISPOSITION).is_none()); + } + #[test] fn test_named_file_set_content_type() { let mut file = NamedFile::open("Cargo.toml") diff --git a/actix-files/src/named.rs b/actix-files/src/named.rs index 3273a4d6..4c80e1d9 100644 --- a/actix-files/src/named.rs +++ b/actix-files/src/named.rs @@ -23,9 +23,10 @@ use crate::range::HttpRange; use crate::ChunkedReadFile; bitflags! { - pub(crate) struct Flags: u32 { + pub(crate) struct Flags: u8 { const ETAG = 0b0000_0001; const LAST_MD = 0b0000_0010; + const CONTENT_DISPOSITION = 0b0000_0100; } } @@ -40,13 +41,13 @@ impl Default for Flags { pub struct NamedFile { path: PathBuf, file: File, + modified: Option, + pub(crate) md: Metadata, + pub(crate) flags: Flags, + pub(crate) status_code: StatusCode, pub(crate) content_type: mime::Mime, pub(crate) content_disposition: header::ContentDisposition, - pub(crate) md: Metadata, - modified: Option, pub(crate) encoding: Option, - pub(crate) status_code: StatusCode, - pub(crate) flags: Flags, } impl NamedFile { @@ -172,11 +173,21 @@ impl NamedFile { /// sent to the peer. By default the disposition is `inline` for text, /// image, and video content types, and `attachment` otherwise, and /// the filename is taken from the path provided in the `open` method - /// after converting it to UTF-8 using + /// after converting it to UTF-8 using. /// [to_string_lossy](https://doc.rust-lang.org/std/ffi/struct.OsStr.html#method.to_string_lossy). #[inline] pub fn set_content_disposition(mut self, cd: header::ContentDisposition) -> Self { self.content_disposition = cd; + self.flags.insert(Flags::CONTENT_DISPOSITION); + self + } + + /// Disable `Content-Disposition` header. + /// + /// By default Content-Disposition` header is enabled. + #[inline] + pub fn disable_content_disposition(mut self) -> Self { + self.flags.remove(Flags::CONTENT_DISPOSITION); self } @@ -294,10 +305,12 @@ impl Responder for NamedFile { if self.status_code != StatusCode::OK { let mut resp = HttpResponse::build(self.status_code); resp.set(header::ContentType(self.content_type.clone())) - .header( - header::CONTENT_DISPOSITION, - self.content_disposition.to_string(), - ); + .if_true(self.flags.contains(Flags::CONTENT_DISPOSITION), |res| { + res.header( + header::CONTENT_DISPOSITION, + self.content_disposition.to_string(), + ); + }); if let Some(current_encoding) = self.encoding { resp.encoding(current_encoding); } @@ -368,10 +381,12 @@ impl Responder for NamedFile { let mut resp = HttpResponse::build(self.status_code); resp.set(header::ContentType(self.content_type.clone())) - .header( - header::CONTENT_DISPOSITION, - self.content_disposition.to_string(), - ); + .if_true(self.flags.contains(Flags::CONTENT_DISPOSITION), |res| { + res.header( + header::CONTENT_DISPOSITION, + self.content_disposition.to_string(), + ); + }); // default compressing if let Some(current_encoding) = self.encoding { resp.encoding(current_encoding);