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