headers_ext/common/
referrer_policy.rs1use {HeaderValue};
2
3#[derive(Clone, Debug, PartialEq, Eq, Hash, Header)]
34pub struct ReferrerPolicy(Policy);
35
36#[derive(Clone, Debug, PartialEq, Eq, Hash)]
37enum Policy {
38 NoReferrer,
39 NoReferrerWhenDowngrade,
40 SameOrigin,
41 Origin,
42 OriginWhenCrossOrigin,
43 UnsafeUrl,
44 StrictOrigin,
45 StrictOriginWhenCrossOrigin,
46}
47
48impl ReferrerPolicy {
49 pub const NO_REFERRER: Self = ReferrerPolicy(Policy::NoReferrer);
51
52 pub const NO_REFERRER_WHEN_DOWNGRADE: Self = ReferrerPolicy(Policy::NoReferrerWhenDowngrade);
54
55 pub const SAME_ORIGIN: Self = ReferrerPolicy(Policy::SameOrigin);
57
58 pub const ORIGIN: Self = ReferrerPolicy(Policy::Origin);
60
61 pub const ORIGIN_WHEN_CROSS_ORIGIN: Self = ReferrerPolicy(Policy::OriginWhenCrossOrigin);
63
64 pub const UNSAFE_URL: Self = ReferrerPolicy(Policy::UnsafeUrl);
66
67 pub const STRICT_ORIGIN: Self = ReferrerPolicy(Policy::StrictOrigin);
69
70 pub const STRICT_ORIGIN_WHEN_CROSS_ORIGIN: Self = ReferrerPolicy(Policy::StrictOriginWhenCrossOrigin);
72}
73
74impl ::util::TryFromValues for Policy {
75 fn try_from_values<'i, I>(values: &mut I) -> Result<Self, ::Error>
76 where
77 I: Iterator<Item = &'i HeaderValue>,
78 {
79 let mut known = None;
82 for s in csv(values) {
83 known = Some(match s {
84 "no-referrer" | "never" => Policy::NoReferrer,
85 "no-referrer-when-downgrade" | "default" => Policy::NoReferrerWhenDowngrade,
86 "same-origin" => Policy::SameOrigin,
87 "origin" => Policy::Origin,
88 "origin-when-cross-origin" => Policy::OriginWhenCrossOrigin,
89 "strict-origin" => Policy::StrictOrigin,
90 "strict-origin-when-cross-origin" => Policy::StrictOriginWhenCrossOrigin,
91 "unsafe-url" | "always" => Policy::UnsafeUrl,
92 _ => continue,
93 });
94 }
95
96 known
97 .ok_or_else(::Error::invalid)
98 }
99}
100
101impl<'a> From<&'a Policy> for HeaderValue {
102 fn from(policy: &'a Policy) -> HeaderValue {
103 HeaderValue::from_static(match *policy {
104 Policy::NoReferrer => "no-referrer",
105 Policy::NoReferrerWhenDowngrade => "no-referrer-when-downgrade",
106 Policy::SameOrigin => "same-origin",
107 Policy::Origin => "origin",
108 Policy::OriginWhenCrossOrigin => "origin-when-cross-origin",
109 Policy::StrictOrigin => "strict-origin",
110 Policy::StrictOriginWhenCrossOrigin => "strict-origin-when-cross-origin",
111 Policy::UnsafeUrl => "unsafe-url",
112 })
113 }
114}
115
116fn csv<'i, I>(values: I) -> impl Iterator<Item=&'i str>
117where
118 I: Iterator<Item = &'i HeaderValue>,
119{
120 values
121 .flat_map(|value| {
122 value
123 .to_str()
124 .into_iter()
125 .flat_map(|string| {
126 string
127 .split(',')
128 .filter_map(|x| match x.trim() {
129 "" => None,
130 y => Some(y),
131 })
132 })
133 })
134}
135
136#[cfg(test)]
137mod tests {
138 use super::ReferrerPolicy;
139 use super::super::test_decode;
140
141 #[test]
142 fn decode_as_last_policy() {
143 assert_eq!(
144 test_decode::<ReferrerPolicy>(&["same-origin, origin"]),
145 Some(ReferrerPolicy::ORIGIN),
146 );
147
148 assert_eq!(
149 test_decode::<ReferrerPolicy>(&["origin", "same-origin"]),
150 Some(ReferrerPolicy::SAME_ORIGIN),
151 );
152 }
153
154 #[test]
155 fn decode_as_last_known() {
156 assert_eq!(
157 test_decode::<ReferrerPolicy>(&["origin, nope, nope, nope"]),
158 Some(ReferrerPolicy::ORIGIN),
159 );
160
161 assert_eq!(
162 test_decode::<ReferrerPolicy>(&["nope, origin, nope, nope"]),
163 Some(ReferrerPolicy::ORIGIN),
164 );
165
166 assert_eq!(
167 test_decode::<ReferrerPolicy>(&["nope, origin", "nope, nope"]),
168 Some(ReferrerPolicy::ORIGIN),
169 );
170
171 assert_eq!(
172 test_decode::<ReferrerPolicy>(&["nope", "origin", "nope, nope"]),
173 Some(ReferrerPolicy::ORIGIN),
174 );
175 }
176
177 #[test]
178 fn decode_unknown() {
179 assert_eq!(
180 test_decode::<ReferrerPolicy>(&["nope"]),
181 None,
182 );
183 }
184
185 #[test]
186 fn matching() {
187 let rp = ReferrerPolicy::ORIGIN;
188
189 match rp {
190 ReferrerPolicy::ORIGIN => (),
191 _ => panic!("matched wrong"),
192 }
193 }
194}