1use std::fmt;
8use std::fmt::{Display, Formatter};
9use std::str::FromStr;
10
11use ion::conversions::FromValue;
12use ion::{Context, Error, ErrorKind, FromValue, Result, Traceable, Value};
13use mozjs::jsapi::JSObject;
14use mozjs::jsval::JSVal;
15use url::Url;
16
17use crate::globals::fetch::body::FetchBody;
18use crate::globals::fetch::header::HeadersInit;
19
20#[derive(Clone, Default, Debug, Traceable)]
21pub enum Referrer {
22 #[expect(clippy::enum_variant_names)]
23 NoReferrer,
24 #[default]
25 Client,
26 Url(#[trace(no_trace)] Url),
27}
28
29impl FromStr for Referrer {
30 type Err = Error;
31
32 fn from_str(referrer: &str) -> Result<Referrer> {
33 if referrer.is_empty() {
34 Ok(Referrer::NoReferrer)
35 } else {
36 let url = Url::parse(referrer).map_err(|e| Error::new(e.to_string(), ErrorKind::Type))?;
37
38 if url.scheme() == "about" && url.path() == "client" {
39 Ok(Referrer::Client)
40 } else {
41 Ok(Referrer::Url(url))
42 }
43 }
44 }
45}
46
47impl Display for Referrer {
48 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
49 match self {
50 Referrer::NoReferrer => f.write_str("no-referrer"),
51 Referrer::Client => f.write_str("about:client"),
52 Referrer::Url(url) => Display::fmt(url, f),
53 }
54 }
55}
56
57impl<'cx> FromValue<'cx> for Referrer {
58 type Config = ();
59
60 fn from_value(cx: &'cx Context, value: &Value, strict: bool, _: ()) -> Result<Referrer> {
61 let referrer = String::from_value(cx, value, strict, ())?;
62 Referrer::from_str(&referrer)
63 }
64}
65
66#[derive(Copy, Clone, Default, Debug, Traceable)]
67pub enum ReferrerPolicy {
68 #[default]
69 None,
70 NoReferrer,
71 NoReferrerWhenDowngrade,
72 Origin,
73 OriginWhenCrossOrigin,
74 SameOrigin,
75 StrictOrigin,
76 StrictOriginWhenCrossOrigin,
77 UnsafeUrl,
78}
79
80impl FromStr for ReferrerPolicy {
81 type Err = Error;
82
83 fn from_str(policy: &str) -> Result<ReferrerPolicy> {
84 use ReferrerPolicy as RP;
85 match policy {
86 "" => Ok(RP::None),
87 "no-referrer" => Ok(RP::NoReferrer),
88 "no-referrer-when-downgrade" => Ok(RP::NoReferrerWhenDowngrade),
89 "origin" => Ok(RP::Origin),
90 "origin-when-cross-origin" => Ok(RP::OriginWhenCrossOrigin),
91 "same-origin" => Ok(RP::SameOrigin),
92 "strict-origin" => Ok(RP::StrictOrigin),
93 "strict-origin-when-cross-origin" => Ok(RP::StrictOriginWhenCrossOrigin),
94 "unsafe-url" => Ok(RP::UnsafeUrl),
95 _ => Err(Error::new(
96 "Invalid value for Enumeration ReferrerPolicy",
97 ErrorKind::Type,
98 )),
99 }
100 }
101}
102
103impl Display for ReferrerPolicy {
104 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
105 let str = match self {
106 ReferrerPolicy::None => "",
107 ReferrerPolicy::NoReferrer => "no-referrer",
108 ReferrerPolicy::NoReferrerWhenDowngrade => "no-referrer-when-downgrade",
109 ReferrerPolicy::Origin => "origin",
110 ReferrerPolicy::OriginWhenCrossOrigin => "origin-when-cross-origin",
111 ReferrerPolicy::SameOrigin => "same-origin",
112 ReferrerPolicy::StrictOrigin => "strict-origin",
113 ReferrerPolicy::StrictOriginWhenCrossOrigin => "strict-origin-when-cross-origin",
114 ReferrerPolicy::UnsafeUrl => "unsafe-url",
115 };
116 f.write_str(str)
117 }
118}
119
120impl<'cx> FromValue<'cx> for ReferrerPolicy {
121 type Config = ();
122
123 fn from_value(cx: &'cx Context, value: &Value, _: bool, _: ()) -> Result<ReferrerPolicy> {
124 let policy = String::from_value(cx, value, true, ())?;
125 ReferrerPolicy::from_str(&policy)
126 }
127}
128
129#[derive(Copy, Clone, Debug, Default, PartialEq, Traceable)]
130pub enum RequestMode {
131 SameOrigin,
132 Cors,
133 #[default]
134 NoCors,
135 Navigate,
136 #[expect(dead_code)]
137 Websocket,
138}
139
140impl FromStr for RequestMode {
141 type Err = Error;
142
143 fn from_str(mode: &str) -> Result<RequestMode> {
144 use RequestMode as RM;
145 match mode {
146 "same-origin" => Ok(RM::SameOrigin),
147 "cors" => Ok(RM::Cors),
148 "no-cors" => Ok(RM::NoCors),
149 "navigate" => Ok(RM::Navigate),
150 _ => Err(Error::new("Invalid value for Enumeration RequestMode", ErrorKind::Type)),
151 }
152 }
153}
154
155impl Display for RequestMode {
156 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
157 let str = match self {
158 RequestMode::SameOrigin => "same-origin",
159 RequestMode::Cors => "cors",
160 RequestMode::NoCors => "no-cors",
161 RequestMode::Navigate => "navigate",
162 RequestMode::Websocket => "websocket",
163 };
164 f.write_str(str)
165 }
166}
167
168impl<'cx> FromValue<'cx> for RequestMode {
169 type Config = ();
170
171 fn from_value(cx: &'cx Context, value: &Value, _: bool, _: ()) -> Result<RequestMode> {
172 let mode = String::from_value(cx, value, true, ())?;
173 RequestMode::from_str(&mode)
174 }
175}
176
177#[derive(Copy, Clone, Debug, Default, PartialEq, Traceable)]
178pub enum RequestCredentials {
179 Omit,
180 #[default]
181 SameOrigin,
182 Include,
183}
184
185impl FromStr for RequestCredentials {
186 type Err = Error;
187
188 fn from_str(credentials: &str) -> Result<RequestCredentials> {
189 use RequestCredentials as RC;
190 match credentials {
191 "omit" => Ok(RC::Omit),
192 "same-origin" => Ok(RC::SameOrigin),
193 "include" => Ok(RC::Include),
194 _ => Err(Error::new(
195 "Invalid value for Enumeration RequestCredentials",
196 ErrorKind::Type,
197 )),
198 }
199 }
200}
201
202impl Display for RequestCredentials {
203 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
204 let str = match self {
205 RequestCredentials::Omit => "omit",
206 RequestCredentials::SameOrigin => "same-origin",
207 RequestCredentials::Include => "include",
208 };
209 f.write_str(str)
210 }
211}
212
213impl<'cx> FromValue<'cx> for RequestCredentials {
214 type Config = ();
215
216 fn from_value(cx: &'cx Context, value: &Value, _: bool, _: ()) -> Result<RequestCredentials> {
217 let mode = String::from_value(cx, value, true, ())?;
218 RequestCredentials::from_str(&mode)
219 }
220}
221
222#[derive(Copy, Clone, Debug, Default, PartialEq, Traceable)]
223pub enum RequestCache {
224 #[default]
225 Default,
226 NoStore,
227 Reload,
228 NoCache,
229 ForceCache,
230 OnlyIfCached,
231}
232
233impl FromStr for RequestCache {
234 type Err = Error;
235
236 fn from_str(credentials: &str) -> Result<RequestCache> {
237 use RequestCache as RC;
238 match credentials {
239 "default" => Ok(RC::Default),
240 "no-store" => Ok(RC::NoStore),
241 "reload" => Ok(RC::Reload),
242 "no-cache" => Ok(RC::NoCache),
243 "force-cache" => Ok(RC::ForceCache),
244 "only-if-cached" => Ok(RC::OnlyIfCached),
245 _ => Err(Error::new(
246 "Invalid value for Enumeration RequestCache",
247 ErrorKind::Type,
248 )),
249 }
250 }
251}
252
253impl Display for RequestCache {
254 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
255 let str = match self {
256 RequestCache::Default => "default",
257 RequestCache::NoStore => "no-store",
258 RequestCache::Reload => "reload",
259 RequestCache::NoCache => "no-cache",
260 RequestCache::ForceCache => "force-cache",
261 RequestCache::OnlyIfCached => "only-if-cached",
262 };
263 f.write_str(str)
264 }
265}
266
267impl<'cx> FromValue<'cx> for RequestCache {
268 type Config = ();
269
270 fn from_value(cx: &'cx Context, value: &Value, _: bool, _: ()) -> Result<RequestCache> {
271 let mode = String::from_value(cx, value, true, ())?;
272 RequestCache::from_str(&mode)
273 }
274}
275
276#[derive(Copy, Clone, Debug, Default, PartialEq, Traceable)]
277pub enum RequestRedirect {
278 #[default]
279 Follow,
280 Error,
281 Manual,
282}
283
284impl FromStr for RequestRedirect {
285 type Err = Error;
286
287 fn from_str(redirect: &str) -> Result<RequestRedirect> {
288 use RequestRedirect as RR;
289 match redirect {
290 "follow" => Ok(RR::Follow),
291 "error" => Ok(RR::Error),
292 "manual" => Ok(RR::Manual),
293 _ => Err(Error::new(
294 "Invalid value for Enumeration RequestRedirect",
295 ErrorKind::Type,
296 )),
297 }
298 }
299}
300
301impl Display for RequestRedirect {
302 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
303 let str = match self {
304 RequestRedirect::Follow => "follow",
305 RequestRedirect::Error => "error",
306 RequestRedirect::Manual => "manual",
307 };
308 f.write_str(str)
309 }
310}
311
312impl<'cx> FromValue<'cx> for RequestRedirect {
313 type Config = ();
314
315 fn from_value(cx: &'cx Context, value: &Value, _: bool, _: ()) -> Result<RequestRedirect> {
316 let redirect = String::from_value(cx, value, true, ())?;
317 RequestRedirect::from_str(&redirect)
318 }
319}
320
321#[derive(Copy, Clone, Debug, Default, Traceable)]
322pub enum RequestDuplex {
323 #[default]
324 Half,
325}
326
327impl FromStr for RequestDuplex {
328 type Err = Error;
329
330 fn from_str(redirect: &str) -> Result<RequestDuplex> {
331 match redirect {
332 "half" => Ok(RequestDuplex::Half),
333 _ => Err(Error::new(
334 "Invalid value for Enumeration RequestDuplex",
335 ErrorKind::Type,
336 )),
337 }
338 }
339}
340
341impl<'cx> FromValue<'cx> for RequestDuplex {
342 type Config = ();
343
344 fn from_value(cx: &'cx Context, value: &Value, _: bool, _: ()) -> Result<RequestDuplex> {
345 let redirect = String::from_value(cx, value, true, ())?;
346 RequestDuplex::from_str(&redirect)
347 }
348}
349
350#[derive(Copy, Clone, Debug, Default, Traceable)]
351pub enum RequestPriority {
352 High,
353 Low,
354 #[default]
355 Auto,
356}
357
358impl FromStr for RequestPriority {
359 type Err = Error;
360
361 fn from_str(priority: &str) -> Result<RequestPriority> {
362 use RequestPriority as RP;
363 match priority {
364 "high" => Ok(RP::High),
365 "low" => Ok(RP::Low),
366 "auto" => Ok(RP::Auto),
367 _ => Err(Error::new(
368 "Invalid value for Enumeration RequestPriority",
369 ErrorKind::Type,
370 )),
371 }
372 }
373}
374
375impl<'cx> FromValue<'cx> for RequestPriority {
376 type Config = ();
377
378 fn from_value(cx: &'cx Context, value: &Value, _: bool, _: ()) -> Result<RequestPriority> {
379 let redirect = String::from_value(cx, value, true, ())?;
380 RequestPriority::from_str(&redirect)
381 }
382}
383
384#[derive(Default, FromValue)]
385pub struct RequestInit<'cx> {
386 pub(crate) method: Option<String>,
387 pub(crate) headers: Option<HeadersInit<'cx>>,
388 pub(crate) body: Option<FetchBody>,
389
390 pub(crate) referrer: Option<Referrer>,
391 pub(crate) referrer_policy: Option<ReferrerPolicy>,
392
393 pub(crate) mode: Option<RequestMode>,
394 pub(crate) credentials: Option<RequestCredentials>,
395 pub(crate) cache: Option<RequestCache>,
396 pub(crate) redirect: Option<RequestRedirect>,
397
398 pub(crate) integrity: Option<String>,
399 pub(crate) keepalive: Option<bool>,
400 pub(crate) signal: Option<*mut JSObject>,
401
402 #[expect(dead_code)]
403 pub(crate) duplex: Option<RequestDuplex>,
404 #[expect(dead_code)]
405 #[ion(default)]
406 priority: Option<RequestPriority>,
407 pub(crate) window: Option<JSVal>,
408}