1
0
mirror of https://github.com/fafhrd91/actix-web synced 2024-12-18 01:43:58 +01:00

add ContentDisposition::attachment constructor (#2867)

This commit is contained in:
Rob Ede 2022-09-13 01:19:25 +01:00 committed by GitHub
parent 40f7ab38d2
commit 909461087c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 26 additions and 2 deletions

View File

@ -1,6 +1,10 @@
# Changelog # Changelog
## Unreleased - 2022-xx-xx ## Unreleased - 2022-xx-xx
### Added
- Add `ContentDisposition::attachment` constructor. [#2867]
[#2867]: https://github.com/actix/actix-web/pull/2867
## 4.2.1 - 2022-09-12 ## 4.2.1 - 2022-09-12

View File

@ -79,7 +79,7 @@ impl<'a> From<&'a str> for DispositionType {
/// assert!(param.is_filename()); /// assert!(param.is_filename());
/// assert_eq!(param.as_filename().unwrap(), "sample.txt"); /// assert_eq!(param.as_filename().unwrap(), "sample.txt");
/// ``` /// ```
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
#[allow(clippy::large_enum_variant)] #[allow(clippy::large_enum_variant)]
pub enum DispositionParam { pub enum DispositionParam {
/// For [`DispositionType::FormData`] (i.e. *multipart/form-data*), the name of an field from /// For [`DispositionType::FormData`] (i.e. *multipart/form-data*), the name of an field from
@ -302,7 +302,7 @@ impl DispositionParam {
/// change to match local file system conventions if applicable, and do not use directory path /// change to match local file system conventions if applicable, and do not use directory path
/// information that may be present. /// information that may be present.
/// See [RFC 2183 §2.3](https://datatracker.ietf.org/doc/html/rfc2183#section-2.3). /// See [RFC 2183 §2.3](https://datatracker.ietf.org/doc/html/rfc2183#section-2.3).
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct ContentDisposition { pub struct ContentDisposition {
/// The disposition type /// The disposition type
pub disposition: DispositionType, pub disposition: DispositionType,
@ -312,16 +312,36 @@ pub struct ContentDisposition {
} }
impl ContentDisposition { impl ContentDisposition {
/// Constructs a Content-Disposition header suitable for downloads.
///
/// # Examples
/// ```
/// use actix_web::http::header::{ContentDisposition, TryIntoHeaderValue as _};
///
/// let cd = ContentDisposition::attachment("files.zip");
///
/// let cd_val = cd.try_into_value().unwrap();
/// assert_eq!(cd_val, "attachment; filename=\"files.zip\"");
/// ```
pub fn attachment(filename: impl Into<String>) -> Self {
Self {
disposition: DispositionType::Attachment,
parameters: vec![DispositionParam::Filename(filename.into())],
}
}
/// Parse a raw Content-Disposition header value. /// Parse a raw Content-Disposition header value.
pub fn from_raw(hv: &header::HeaderValue) -> Result<Self, crate::error::ParseError> { pub fn from_raw(hv: &header::HeaderValue) -> Result<Self, crate::error::ParseError> {
// `header::from_one_raw_str` invokes `hv.to_str` which assumes `hv` contains only visible // `header::from_one_raw_str` invokes `hv.to_str` which assumes `hv` contains only visible
// ASCII characters. So `hv.as_bytes` is necessary here. // ASCII characters. So `hv.as_bytes` is necessary here.
let hv = String::from_utf8(hv.as_bytes().to_vec()) let hv = String::from_utf8(hv.as_bytes().to_vec())
.map_err(|_| crate::error::ParseError::Header)?; .map_err(|_| crate::error::ParseError::Header)?;
let (disp_type, mut left) = split_once_and_trim(hv.as_str().trim(), ';'); let (disp_type, mut left) = split_once_and_trim(hv.as_str().trim(), ';');
if disp_type.is_empty() { if disp_type.is_empty() {
return Err(crate::error::ParseError::Header); return Err(crate::error::ParseError::Header);
} }
let mut cd = ContentDisposition { let mut cd = ContentDisposition {
disposition: disp_type.into(), disposition: disp_type.into(),
parameters: Vec::new(), parameters: Vec::new(),