runtime/globals/fetch/request/
options.rs

1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 */
6
7use 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}