1use content_security_policy::Destination;
6use headers::{Error, Header, HeaderMap};
7use http::{HeaderName, HeaderValue};
8use net_traits::fetch::headers::get_decode_and_split_header_name;
9use net_traits::request::RequestMode;
10
11static SEC_FETCH_DEST: HeaderName = HeaderName::from_static("sec-fetch-dest");
12
13static SEC_FETCH_MODE: HeaderName = HeaderName::from_static("sec-fetch-mode");
14
15static SEC_FETCH_SITE: HeaderName = HeaderName::from_static("sec-fetch-site");
16
17static SEC_FETCH_USER: HeaderName = HeaderName::from_static("sec-fetch-user");
18
19pub fn determine_nosniff(headers: &HeaderMap) -> bool {
21 let values = get_decode_and_split_header_name("x-content-type-options", headers);
22
23 match values {
24 None => false,
25 Some(values) => !values.is_empty() && values[0].eq_ignore_ascii_case("nosniff"),
26 }
27}
28
29pub struct SecFetchDest(pub Destination);
31
32pub enum SecFetchMode {
37 SameOrigin,
38 Cors,
39 NoCors,
40 Navigate,
41 WebSocket,
42}
43
44pub struct SecFetchUser;
46
47#[derive(Eq, PartialEq)]
49pub enum SecFetchSite {
50 None,
51 SameOrigin,
52 SameSite,
53 CrossSite,
54}
55
56impl Header for SecFetchDest {
57 fn name() -> &'static HeaderName {
58 &SEC_FETCH_DEST
59 }
60
61 fn decode<'i, I>(_: &mut I) -> Result<Self, Error>
62 where
63 Self: Sized,
64 I: Iterator<Item = &'i HeaderValue>,
65 {
66 Err(Error::invalid())
68 }
69
70 fn encode<E>(&self, values: &mut E)
71 where
72 E: Extend<HeaderValue>,
73 {
74 let value = HeaderValue::from_static(destination_as_str(self.0));
75 values.extend(std::iter::once(value));
76 }
77}
78
79impl From<Destination> for SecFetchDest {
80 fn from(value: Destination) -> Self {
81 Self(value)
82 }
83}
84
85impl Header for SecFetchMode {
86 fn name() -> &'static HeaderName {
87 &SEC_FETCH_MODE
88 }
89
90 fn decode<'i, I>(_: &mut I) -> Result<Self, Error>
91 where
92 Self: Sized,
93 I: Iterator<Item = &'i HeaderValue>,
94 {
95 Err(Error::invalid())
97 }
98
99 fn encode<E>(&self, values: &mut E)
100 where
101 E: Extend<HeaderValue>,
102 {
103 let value = HeaderValue::from_static(self.as_str());
104 values.extend(std::iter::once(value));
105 }
106}
107
108impl<'a> From<&'a RequestMode> for SecFetchMode {
109 fn from(value: &'a RequestMode) -> Self {
110 match value {
111 RequestMode::SameOrigin => Self::SameOrigin,
112 RequestMode::CorsMode => Self::Cors,
113 RequestMode::NoCors => Self::NoCors,
114 RequestMode::Navigate => Self::Navigate,
115 RequestMode::WebSocket { .. } => Self::WebSocket,
116 }
117 }
118}
119
120impl Header for SecFetchSite {
121 fn name() -> &'static HeaderName {
122 &SEC_FETCH_SITE
123 }
124
125 fn decode<'i, I>(_: &mut I) -> Result<Self, Error>
126 where
127 Self: Sized,
128 I: Iterator<Item = &'i HeaderValue>,
129 {
130 Err(Error::invalid())
132 }
133
134 fn encode<E>(&self, values: &mut E)
135 where
136 E: Extend<HeaderValue>,
137 {
138 let s = match self {
139 Self::None => "none",
140 Self::SameSite => "same-site",
141 Self::CrossSite => "cross-site",
142 Self::SameOrigin => "same-origin",
143 };
144 let value = HeaderValue::from_static(s);
145 values.extend(std::iter::once(value));
146 }
147}
148
149impl Header for SecFetchUser {
150 fn name() -> &'static HeaderName {
151 &SEC_FETCH_USER
152 }
153
154 fn decode<'i, I>(_: &mut I) -> Result<Self, Error>
155 where
156 Self: Sized,
157 I: Iterator<Item = &'i HeaderValue>,
158 {
159 Err(Error::invalid())
161 }
162
163 fn encode<E>(&self, values: &mut E)
164 where
165 E: Extend<HeaderValue>,
166 {
167 let value = HeaderValue::from_static("?1");
168 values.extend(std::iter::once(value));
169 }
170}
171
172const fn destination_as_str(destination: Destination) -> &'static str {
173 match destination {
174 Destination::None => "empty",
175 Destination::Audio => "audio",
176 Destination::AudioWorklet => "audioworklet",
177 Destination::Document => "document",
178 Destination::Embed => "embed",
179 Destination::Font => "font",
180 Destination::Frame => "frame",
181 Destination::IFrame => "iframe",
182 Destination::Image => "image",
183 Destination::Json => "json",
184 Destination::Manifest => "manifest",
185 Destination::Object => "object",
186 Destination::PaintWorklet => "paintworklet",
187 Destination::Report => "report",
188 Destination::Script => "script",
189 Destination::ServiceWorker => "serviceworker",
190 Destination::SharedWorker => "sharedworker",
191 Destination::Style => "style",
192 Destination::Track => "track",
193 Destination::Video => "video",
194 Destination::WebIdentity => "webidentity",
195 Destination::Worker => "worker",
196 Destination::Xslt => "xslt",
197 }
198}
199
200impl SecFetchMode {
201 fn as_str(&self) -> &'static str {
203 match self {
204 Self::SameOrigin => "same-origin",
205 Self::Cors => "cors",
206 Self::NoCors => "no-cors",
207 Self::Navigate => "navigate",
208 Self::WebSocket => "websocket",
209 }
210 }
211}