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