1pub use crate::resource_policy::{Credentials, Initiator, ResourcePolicy, ResourceScope};
4pub use bytes::Bytes;
5pub use http::{self, HeaderMap, HeaderValue, Method};
6use serde::{
7 Serialize,
8 ser::{SerializeSeq, SerializeTuple},
9};
10use std::sync::{Arc, Mutex};
11use std::{ops::Deref, path::PathBuf};
12pub use url::Url;
13
14pub trait CookieJar: Send + Sync + 'static {
17 fn cookies_header(&self, url: &Url) -> Option<HeaderValue>;
19
20 fn store_from_response(&self, url: &Url, headers: &HeaderMap);
22}
23
24pub trait NetProvider: Send + Sync + 'static {
28 fn fetch(&self, doc_id: usize, request: Request, handler: Box<dyn NetHandler>);
29
30 fn for_child_document(&self, _url: Url) -> Option<Arc<dyn NetProvider>> {
32 None
33 }
34
35 fn resource_initiator(&self) -> Initiator {
37 Initiator::Unknown
38 }
39
40 fn is_noop(&self) -> bool {
46 false
47 }
48}
49
50pub trait NetHandler: Send + Sync + 'static {
53 fn bytes(self: Box<Self>, resolved_url: String, bytes: Bytes);
54}
55
56pub trait NetWaker: Send + Sync + 'static {
59 fn wake(&self, client_id: usize);
60}
61
62impl<F: Fn(usize) + Send + Sync + 'static> NetWaker for F {
63 fn wake(&self, doc_id: usize) {
64 self(doc_id)
65 }
66}
67
68#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
70pub enum RequestDestination {
71 #[default]
72 Empty,
73 Document,
74 Iframe,
75 Style,
76 Script,
77 Image,
78 Font,
79 Audio,
80 Video,
81 Track,
82 Manifest,
83}
84
85impl RequestDestination {
86 pub fn as_str(self) -> &'static str {
87 match self {
88 Self::Empty => "empty",
89 Self::Document => "document",
90 Self::Iframe => "iframe",
91 Self::Style => "style",
92 Self::Script => "script",
93 Self::Image => "image",
94 Self::Font => "font",
95 Self::Audio => "audio",
96 Self::Video => "video",
97 Self::Track => "track",
98 Self::Manifest => "manifest",
99 }
100 }
101}
102
103#[non_exhaustive]
104#[derive(Debug, Clone)]
105pub struct Request {
107 pub url: Url,
108 pub method: Method,
109 pub content_type: Option<String>,
110 pub headers: HeaderMap,
111 pub body: Body,
112 pub signal: Option<AbortSignal>,
113 pub destination: RequestDestination,
114 pub initiator: Initiator,
116 pub credentials: Credentials,
117}
118impl Request {
119 pub fn get(url: Url) -> Self {
121 Self {
122 url,
123 method: Method::GET,
124 content_type: None,
125 headers: HeaderMap::new(),
126 body: Body::Empty,
127 signal: None,
128 destination: RequestDestination::default(),
129 initiator: Initiator::default(),
130 credentials: Credentials::default(),
131 }
132 }
133
134 pub fn initiator(mut self, initiator: Initiator) -> Self {
135 self.initiator = initiator;
136 self
137 }
138
139 pub fn destination(mut self, d: RequestDestination) -> Self {
140 self.destination = d;
141 self
142 }
143
144 pub fn signal(mut self, signal: AbortSignal) -> Self {
145 self.signal = Some(signal);
146 self
147 }
148}
149
150#[derive(Debug, Clone)]
151pub enum Body {
152 Bytes(Bytes),
153 Form(FormData),
154 Empty,
155}
156
157#[derive(Debug, Clone, PartialEq, Default)]
159pub struct FormData(pub Vec<Entry>);
160impl FormData {
161 pub fn new() -> Self {
163 FormData(Vec::new())
164 }
165}
166impl Serialize for FormData {
167 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
168 where
169 S: serde::Serializer,
170 {
171 let mut seq_serializer = serializer.serialize_seq(Some(self.len()))?;
172 for entry in &self.0 {
173 seq_serializer.serialize_element(entry)?;
174 }
175 seq_serializer.end()
176 }
177}
178impl Deref for FormData {
179 type Target = Vec<Entry>;
180
181 fn deref(&self) -> &Self::Target {
182 &self.0
183 }
184}
185
186#[derive(Debug, Clone, PartialEq)]
188pub struct Entry {
189 pub name: String,
190 pub value: EntryValue,
191}
192impl Serialize for Entry {
193 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
194 where
195 S: serde::Serializer,
196 {
197 let mut serializer = serializer.serialize_tuple(2)?;
198 serializer.serialize_element(&self.name)?;
199 match &self.value {
200 EntryValue::String(s) => serializer.serialize_element(s)?,
201 EntryValue::File(p) => serializer.serialize_element(p.to_str().unwrap_or_default())?,
202 EntryValue::EmptyFile => serializer.serialize_element("")?,
203 }
204 serializer.end()
205 }
206}
207
208#[derive(Debug, Clone, PartialEq)]
209pub enum EntryValue {
210 String(String),
211 File(PathBuf),
212 EmptyFile,
213}
214impl AsRef<str> for EntryValue {
215 fn as_ref(&self) -> &str {
216 match self {
217 EntryValue::String(s) => s,
218 EntryValue::File(p) => p.to_str().unwrap_or_default(),
219 EntryValue::EmptyFile => "",
220 }
221 }
222}
223
224impl From<&str> for EntryValue {
225 fn from(value: &str) -> Self {
226 EntryValue::String(value.to_string())
227 }
228}
229impl From<PathBuf> for EntryValue {
230 fn from(value: PathBuf) -> Self {
231 EntryValue::File(value)
232 }
233}
234
235#[derive(Default)]
237pub struct DummyNetProvider;
238impl NetProvider for DummyNetProvider {
239 fn fetch(&self, _doc_id: usize, _request: Request, _handler: Box<dyn NetHandler>) {}
240 fn is_noop(&self) -> bool {
241 true
242 }
243}
244
245#[derive(Debug, Default)]
251pub struct AbortController {
252 pub signal: AbortSignal,
253}
254
255impl AbortController {
256 pub fn abort(self) {
262 let waiters = {
263 let mut state = self
264 .signal
265 .0
266 .lock()
267 .unwrap_or_else(|error| error.into_inner());
268 state.aborted = true;
269 std::mem::take(&mut state.waiters)
270 };
271 for (_, waker) in waiters {
272 waker.wake();
273 }
274 }
275}
276
277#[derive(Debug, Default, Clone)]
282pub struct AbortSignal(Arc<Mutex<AbortState>>);
283
284#[derive(Debug, Default)]
285struct AbortState {
286 aborted: bool,
287 next: u64,
288 waiters: std::collections::BTreeMap<u64, std::task::Waker>,
289}
290
291pub struct AbortWaiter {
295 signal: AbortSignal,
296 id: u64,
297}
298
299impl std::future::Future for AbortWaiter {
300 type Output = ();
301
302 fn poll(
303 self: std::pin::Pin<&mut Self>,
304 cx: &mut std::task::Context<'_>,
305 ) -> std::task::Poll<()> {
306 let mut state = self
307 .signal
308 .0
309 .lock()
310 .unwrap_or_else(|error| error.into_inner());
311 if state.aborted {
312 std::task::Poll::Ready(())
313 } else {
314 state.waiters.insert(self.id, cx.waker().clone());
315 std::task::Poll::Pending
316 }
317 }
318}
319
320impl Drop for AbortWaiter {
321 fn drop(&mut self) {
322 self.signal
323 .0
324 .lock()
325 .unwrap_or_else(|error| error.into_inner())
326 .waiters
327 .remove(&self.id);
328 }
329}
330
331impl AbortSignal {
332 pub fn aborted(&self) -> bool {
335 self.0
336 .lock()
337 .unwrap_or_else(|error| error.into_inner())
338 .aborted
339 }
340
341 pub fn cancelled(&self) -> AbortWaiter {
346 let mut state = self.0.lock().unwrap_or_else(|error| error.into_inner());
347 let id = state.next;
348 state.next = state
349 .next
350 .checked_add(1)
351 .expect("abort waiter identifier exhausted");
352 AbortWaiter {
353 signal: self.clone(),
354 id,
355 }
356 }
357}