use std::convert::{TryFrom, TryInto};
use std::fmt::{self, Display, Formatter};
use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS};
use super::help::bug_report;
use crate::http::header::HeaderValue;
use crate::Status;
const HTTP_VALUE: &AsciiSet = &CONTROLS
.add(b' ')
.add(b'"')
.add(b'%')
.add(b'\'')
.add(b'(')
.add(b')')
.add(b'*')
.add(b',')
.add(b'/')
.add(b':')
.add(b';')
.add(b'<')
.add(b'-')
.add(b'>')
.add(b'?')
.add(b'[')
.add(b'\\')
.add(b']')
.add(b'{')
.add(b'}');
#[derive(Clone, Debug, PartialEq)]
pub enum DispositionType {
Inline,
Attachment,
}
pub struct ContentDisposition {
typ: DispositionType,
encoded_filename: Option<String>,
}
impl ContentDisposition {
#[inline]
pub(crate) fn new(typ: DispositionType, filename: Option<&str>) -> Self {
Self {
typ,
encoded_filename: filename
.map(|name| utf8_percent_encode(name, HTTP_VALUE).to_string()),
}
}
}
impl TryFrom<ContentDisposition> for HeaderValue {
type Error = Status;
#[inline]
fn try_from(value: ContentDisposition) -> Result<Self, Self::Error> {
value
.to_string()
.try_into()
.map_err(|err| bug_report(format!("{}\nNot a valid header value", err)))
}
}
impl Display for ContentDisposition {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match &self.encoded_filename {
None => f.write_fmt(format_args!("{}", self.typ)),
Some(name) => f.write_fmt(format_args!(
"{}; filename={}; filename*=UTF-8''{}",
self.typ, name, name
)),
}
}
}
impl Display for DispositionType {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
DispositionType::Inline => f.write_str("inline"),
DispositionType::Attachment => f.write_str("attachment"),
}
}
}