1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
use super::help::bug_report;
use crate::http::header::HeaderValue;
use crate::Status;
use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS};
use std::convert::{TryFrom, TryInto};
use std::fmt::{self, Display, Formatter};
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"),
}
}
}