Skip to main content

apace_traits/
net.rs

1//! Abstractions of networking so that custom networking implementations can be provided
2
3pub use bytes::Bytes;
4pub use http::{self, HeaderMap, Method};
5use serde::{
6    Serialize,
7    ser::{SerializeSeq, SerializeTuple},
8};
9use std::sync::{
10    Arc,
11    atomic::{AtomicBool, Ordering},
12};
13use std::{ops::Deref, path::PathBuf};
14pub use url::Url;
15pub type NetReady<'a> =
16    std::pin::Pin<Box<dyn std::future::Future<Output = Result<(), String>> + Send + 'a>>;
17
18/// A type that fetches resources for a Document.
19///
20/// This may be over the network via http(s), via the filesystem, or some other method.
21pub trait NetProvider: Send + Sync + 'static {
22    fn fetch(&self, doc_id: usize, request: Request, handler: Box<dyn NetHandler>);
23
24    /// Cancel a resource whose last document consumer disappeared. Providers
25    /// must revoke late publication as well as stop I/O where possible.
26    fn cancel(&self, _doc_id: usize, _url: &str) {}
27
28    /// Permanently release all requests for this document.
29    fn close(&self, _doc_id: usize) {}
30
31    /// Whether this provider is a no-op (e.g. `DummyNetProvider`) that will never
32    /// deliver resources. When true, callers must NOT register resources as
33    /// "pending critical" — doing so blocks painting forever, since the
34    /// completion callback never fires. Used by integrations that feed a
35    /// pre-rendered DOM and perform no sub-fetches (e.g. aginxbrowser).
36    fn is_noop(&self) -> bool {
37        false
38    }
39}
40
41/// A type that parses raw bytes from a network request into a Data and then calls
42/// the NetCallack with the result.
43pub trait NetHandler: Send + Sync + 'static {
44    /// Await before parsing/decoding. Drop this future when cancelling I/O.
45    fn prepare<'a>(&'a mut self, _url: &'a str, _bytes: &'a Bytes) -> NetReady<'a> {
46        Box::pin(std::future::ready(Ok(())))
47    }
48    fn bytes(self: Box<Self>, resolved_url: String, bytes: Bytes);
49
50    /// Complete a failed request. The document implementation clears blocking
51    /// state on failure too; never leave a failed stylesheet pending forever.
52    fn error(self: Box<Self>, resolved_url: String, _error: String) {
53        self.bytes(resolved_url, Bytes::new());
54    }
55}
56
57/// A callback which gets called every time a network request completes
58// Q: Should we use std::task::Waker for this?
59pub trait NetWaker: Send + Sync + 'static {
60    fn wake(&self, client_id: usize);
61}
62
63impl<F: Fn(usize) + Send + Sync + 'static> NetWaker for F {
64    fn wake(&self, doc_id: usize) {
65        self(doc_id)
66    }
67}
68
69#[non_exhaustive]
70#[derive(Debug, Clone)]
71/// A request type loosely representing <https://fetch.spec.whatwg.org/#requests>
72pub struct Request {
73    pub url: Url,
74    pub method: Method,
75    pub content_type: Option<String>,
76    pub headers: HeaderMap,
77    pub body: Body,
78    pub signal: Option<AbortSignal>,
79}
80impl Request {
81    /// A get request to the specified Url and an empty body
82    pub fn get(url: Url) -> Self {
83        Self {
84            url,
85            method: Method::GET,
86            content_type: None,
87            headers: HeaderMap::new(),
88            body: Body::Empty,
89            signal: None,
90        }
91    }
92
93    pub fn signal(mut self, signal: AbortSignal) -> Self {
94        self.signal = Some(signal);
95        self
96    }
97}
98
99#[derive(Debug, Clone)]
100pub enum Body {
101    Bytes(Bytes),
102    Form(FormData),
103    Empty,
104}
105
106/// A list of form entries used for form submission
107#[derive(Debug, Clone, PartialEq, Default)]
108pub struct FormData(pub Vec<Entry>);
109impl FormData {
110    /// Creates a new empty FormData
111    pub fn new() -> Self {
112        FormData(Vec::new())
113    }
114}
115impl Serialize for FormData {
116    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
117    where
118        S: serde::Serializer,
119    {
120        let mut seq_serializer = serializer.serialize_seq(Some(self.len()))?;
121        for entry in &self.0 {
122            seq_serializer.serialize_element(entry)?;
123        }
124        seq_serializer.end()
125    }
126}
127impl Deref for FormData {
128    type Target = Vec<Entry>;
129
130    fn deref(&self) -> &Self::Target {
131        &self.0
132    }
133}
134
135/// A single form entry consisting of a name and value
136#[derive(Debug, Clone, PartialEq)]
137pub struct Entry {
138    pub name: String,
139    pub value: EntryValue,
140}
141impl Serialize for Entry {
142    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
143    where
144        S: serde::Serializer,
145    {
146        let mut serializer = serializer.serialize_tuple(2)?;
147        serializer.serialize_element(&self.name)?;
148        match &self.value {
149            EntryValue::String(s) => serializer.serialize_element(s)?,
150            EntryValue::File(p) => serializer.serialize_element(p.to_str().unwrap_or_default())?,
151            EntryValue::EmptyFile => serializer.serialize_element("")?,
152        }
153        serializer.end()
154    }
155}
156
157#[derive(Debug, Clone, PartialEq)]
158pub enum EntryValue {
159    String(String),
160    File(PathBuf),
161    EmptyFile,
162}
163impl AsRef<str> for EntryValue {
164    fn as_ref(&self) -> &str {
165        match self {
166            EntryValue::String(s) => s,
167            EntryValue::File(p) => p.to_str().unwrap_or_default(),
168            EntryValue::EmptyFile => "",
169        }
170    }
171}
172
173impl From<&str> for EntryValue {
174    fn from(value: &str) -> Self {
175        EntryValue::String(value.to_string())
176    }
177}
178impl From<PathBuf> for EntryValue {
179    fn from(value: PathBuf) -> Self {
180        EntryValue::File(value)
181    }
182}
183
184/// A default noop NetProvider
185#[derive(Default)]
186pub struct DummyNetProvider;
187impl NetProvider for DummyNetProvider {
188    fn fetch(&self, _doc_id: usize, _request: Request, _handler: Box<dyn NetHandler>) {}
189    fn is_noop(&self) -> bool {
190        true
191    }
192}
193
194/// The AbortController interface represents a controller object that
195/// allows you to abort one or more Web requests as and when desired.
196///
197/// <https://developer.mozilla.org/en-US/docs/Web/API/AbortController>
198#[derive(Debug, Default)]
199pub struct AbortController {
200    pub signal: AbortSignal,
201}
202
203impl AbortController {
204    /// The abort() method of the AbortController interface aborts
205    /// an asynchronous operation before it has completed.
206    /// This is able to abort fetch requests.
207    ///
208    /// <https://developer.mozilla.org/en-US/docs/Web/API/AbortController/abort>
209    pub fn abort(self) {
210        self.signal.0.store(true, Ordering::SeqCst);
211    }
212}
213
214/// The AbortSignal interface represents a signal object that allows you to
215/// communicate with an asynchronous operation (such as a fetch request) and
216/// abort it if required via an AbortController object.
217///
218/// <https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal>
219#[derive(Debug, Default, Clone)]
220pub struct AbortSignal(Arc<AtomicBool>);
221
222impl AbortSignal {
223    /// The aborted read-only property returns a value that indicates whether
224    /// the asynchronous operations the signal is communicating with are
225    /// aborted (true) or not (false).
226    ///
227    /// <https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/aborted>
228    pub fn aborted(&self) -> bool {
229        self.0.load(Ordering::SeqCst)
230    }
231}