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