wasmtime_wasi_http/p3/mod.rs
1//! Experimental, unstable and incomplete implementation of wasip3 version of `wasi:http`.
2//!
3//! This module is under heavy development.
4//! It is not compliant with semver and is not ready
5//! for production use.
6//!
7//! Bug and security fixes limited to wasip3 will not be given patch releases.
8//!
9//! Documentation of this module may be incorrect or out-of-sync with the implementation.
10
11pub mod bindings;
12mod body;
13mod conv;
14mod helpers;
15mod host;
16mod proxy;
17mod request;
18mod response;
19
20pub use request::Request;
21pub use response::Response;
22
23/// The default value configured for [`WasiHttpHooks::p3_outgoing_body_chunk_size`].
24///
25/// [`WasiHttpHooks::p3_outgoing_body_chunk_size`]: crate::WasiHttpHooks::p3_outgoing_body_chunk_size
26pub const DEFAULT_OUTGOING_BODY_CHUNK_SIZE: usize = 1024 * 1024;
27
28use crate::{FieldMapError, WasiHttp, WasiHttpView};
29use bindings::http::{client, types};
30use core::ops::Deref;
31use std::sync::Arc;
32use wasmtime::component::Linker;
33use wasmtime_wasi::TrappableError;
34
35pub(crate) type HttpResult<T> = Result<T, HttpError>;
36pub(crate) type HttpError = TrappableError<types::ErrorCode>;
37
38pub(crate) type HeaderResult<T> = Result<T, HeaderError>;
39pub(crate) type HeaderError = TrappableError<types::HeaderError>;
40
41impl From<FieldMapError> for HeaderError {
42 fn from(e: FieldMapError) -> Self {
43 match e {
44 FieldMapError::Immutable => types::HeaderError::Immutable.into(),
45 FieldMapError::InvalidHeaderName | FieldMapError::InvalidHeaderValue => {
46 types::HeaderError::InvalidSyntax.into()
47 }
48 FieldMapError::TooManyFields | FieldMapError::TotalSizeTooBig => {
49 types::HeaderError::SizeExceeded.into()
50 }
51 FieldMapError::Forbidden => types::HeaderError::Forbidden.into(),
52 }
53 }
54}
55
56pub(crate) type RequestOptionsResult<T> = Result<T, RequestOptionsError>;
57pub(crate) type RequestOptionsError = TrappableError<types::RequestOptionsError>;
58
59/// Add all interfaces from this module into the `linker` provided.
60///
61/// This function will add all interfaces implemented by this module to the
62/// [`Linker`], which corresponds to the `wasi:http/imports` world supported by
63/// this module.
64///
65/// # Example
66///
67/// ```
68/// use wasmtime::{Engine, Result, Store, Config};
69/// use wasmtime::component::{Linker, ResourceTable};
70/// use wasmtime_wasi_http::{WasiHttpCtx, WasiHttpCtxView, WasiHttpView};
71///
72/// fn main() -> Result<()> {
73/// let mut config = Config::new();
74/// config.wasm_component_model_async(true);
75/// let engine = Engine::new(&config)?;
76///
77/// let mut linker = Linker::<MyState>::new(&engine);
78/// wasmtime_wasi_http::p3::add_to_linker(&mut linker)?;
79/// // ... add any further functionality to `linker` if desired ...
80///
81/// let mut store = Store::new(
82/// &engine,
83/// MyState::default(),
84/// );
85///
86/// // ... use `linker` to instantiate within `store` ...
87///
88/// Ok(())
89/// }
90///
91/// #[derive(Default)]
92/// struct MyState {
93/// http: WasiHttpCtx,
94/// table: ResourceTable,
95/// }
96///
97/// impl WasiHttpView for MyState {
98/// fn http(&mut self) -> WasiHttpCtxView<'_> {
99/// WasiHttpCtxView {
100/// ctx: &mut self.http,
101/// table: &mut self.table,
102/// hooks: Default::default(),
103/// }
104/// }
105/// }
106/// ```
107pub fn add_to_linker<T>(linker: &mut Linker<T>) -> wasmtime::Result<()>
108where
109 T: WasiHttpView + 'static,
110{
111 client::add_to_linker::<_, WasiHttp>(linker, T::http)?;
112 types::add_to_linker::<_, WasiHttp>(linker, T::http)?;
113 Ok(())
114}
115
116/// An [Arc], which may be immutable.
117///
118/// In `wasi:http` resources like `fields` or `request-options` may be
119/// mutable or immutable. This construct is used to model them efficiently.
120pub enum MaybeMutable<T> {
121 /// Clone-on-write, mutable [Arc]
122 Mutable(Arc<T>),
123 /// Immutable [Arc]
124 Immutable(Arc<T>),
125}
126
127impl<T> From<MaybeMutable<T>> for Arc<T> {
128 fn from(v: MaybeMutable<T>) -> Self {
129 v.into_arc()
130 }
131}
132
133impl<T> Deref for MaybeMutable<T> {
134 type Target = Arc<T>;
135
136 fn deref(&self) -> &Self::Target {
137 match self {
138 Self::Mutable(v) | Self::Immutable(v) => v,
139 }
140 }
141}
142
143impl<T> MaybeMutable<T> {
144 /// Construct a mutable [`MaybeMutable`].
145 pub fn new_mutable(v: impl Into<Arc<T>>) -> Self {
146 Self::Mutable(v.into())
147 }
148
149 /// Construct a mutable [`MaybeMutable`] filling it with default `T`.
150 pub fn new_mutable_default() -> Self
151 where
152 T: Default,
153 {
154 Self::new_mutable(T::default())
155 }
156
157 /// Construct an immutable [`MaybeMutable`].
158 pub fn new_immutable(v: impl Into<Arc<T>>) -> Self {
159 Self::Immutable(v.into())
160 }
161
162 /// Unwrap [`MaybeMutable`] into [`Arc`].
163 pub fn into_arc(self) -> Arc<T> {
164 match self {
165 Self::Mutable(v) | Self::Immutable(v) => v,
166 }
167 }
168
169 /// If this [`MaybeMutable`] is [`Mutable`](MaybeMutable::Mutable),
170 /// return a mutable reference to it, otherwise return `None`.
171 ///
172 /// Internally, this will use [`Arc::make_mut`] and will clone the underlying
173 /// value, if multiple strong references to the inner [`Arc`] exist.
174 pub fn get_mut(&mut self) -> Option<&mut T>
175 where
176 T: Clone,
177 {
178 match self {
179 Self::Mutable(v) => Some(Arc::make_mut(v)),
180 Self::Immutable(..) => None,
181 }
182 }
183}