@ -1,3 +1,4 @@
use super ::clocks ::host ::{ monotonic_clock , wall_clock } ;
use crate ::preview2 ::{
clocks ::{ self , HostMonotonicClock , HostWallClock } ,
filesystem ::{ Dir , TableFsExt } ,
@ -6,8 +7,7 @@ use crate::preview2::{
DirPerms , FilePerms , Table ,
} ;
use cap_rand ::{ Rng , RngCore , SeedableRng } ;
use super ::clocks ::host ::{ monotonic_clock , wall_clock } ;
use std ::mem ;
pub struct WasiCtxBuilder {
stdin : Box < dyn HostInputStream > ,
@ -22,9 +22,29 @@ pub struct WasiCtxBuilder {
insecure_random_seed : u128 ,
wall_clock : Box < dyn HostWallClock + Send + Sync > ,
monotonic_clock : Box < dyn HostMonotonicClock + Send + Sync > ,
built : bool ,
}
impl WasiCtxBuilder {
/// Creates a builder for a new context with default parameters set.
///
/// The current defaults are:
///
/// * stdin is closed
/// * stdout and stderr eat all input but it doesn't go anywhere
/// * no env vars
/// * no arguments
/// * no preopens
/// * clocks use the host implementation of wall/monotonic clocks
/// * RNGs are all initialized with random state and suitable generator
/// quality to satisfy the requirements of WASI APIs.
///
/// These defaults can all be updated via the various builder configuration
/// methods below.
///
/// Note that each builder can only be used once to produce a [`WasiCtx`].
/// Invoking the [`build`](WasiCtxBuilder::build) method will panic on the
/// second attempt.
pub fn new ( ) -> Self {
// For the insecure random API, use `SmallRng`, which is fast. It's
// also insecure, but that's the deal here.
@ -47,129 +67,130 @@ impl WasiCtxBuilder {
insecure_random_seed ,
wall_clock : wall_clock ( ) ,
monotonic_clock : monotonic_clock ( ) ,
built : false ,
}
}
pub fn set_s tdin ( mut self , stdin : impl HostInputStream + 'static ) -> Self {
pub fn stdin ( & mut self , stdin : impl HostInputStream + 'static ) -> & mut Self {
self . stdin = Box ::new ( stdin ) ;
self
}
pub fn set_s tdout ( mut self , stdout : impl HostOutputStream + 'static ) -> Self {
pub fn stdout ( & mut self , stdout : impl HostOutputStream + 'static ) -> & mut Self {
self . stdout = Box ::new ( stdout ) ;
self
}
pub fn set_s tderr ( mut self , stderr : impl HostOutputStream + 'static ) -> Self {
pub fn stderr ( & mut self , stderr : impl HostOutputStream + 'static ) -> & mut Self {
self . stderr = Box ::new ( stderr ) ;
self
}
pub fn inherit_stdin ( self ) -> Self {
self . set_s tdin ( stdio ::stdin ( ) )
pub fn inherit_stdin ( & mut self ) -> & mut Self {
self . stdin ( stdio ::stdin ( ) )
}
pub fn inherit_stdout ( self ) -> Self {
self . set_s tdout ( stdio ::stdout ( ) )
pub fn inherit_stdout ( & mut self ) -> & mut Self {
self . stdout ( stdio ::stdout ( ) )
}
pub fn inherit_stderr ( self ) -> Self {
self . set_s tderr ( stdio ::stderr ( ) )
pub fn inherit_stderr ( & mut self ) -> & mut Self {
self . stderr ( stdio ::stderr ( ) )
}
pub fn inherit_stdio ( self ) -> Self {
pub fn inherit_stdio ( & mut self ) -> & mut Self {
self . inherit_stdin ( ) . inherit_stdout ( ) . inherit_stderr ( )
}
pub fn set_ env( mut self , env : & [ ( impl AsRef < str > , impl AsRef < str > ) ] ) -> Self {
self . env = env
. iter ( )
. map ( | ( k , v ) | ( k . as_ref ( ) . to_owned ( ) , v . as_ref ( ) . to_owned ( ) ) )
. collect ( ) ;
pub fn envs ( & mut self , env : & [ ( impl AsRef < str > , impl AsRef < str > ) ] ) -> & mut Self {
self . env . extend (
env . iter ( )
. map ( | ( k , v ) | ( k . as_ref ( ) . to_owned ( ) , v . as_ref ( ) . to_owned ( ) ) ) ,
) ;
self
}
pub fn push_ env( mut self , k : impl AsRef < str > , v : impl AsRef < str > ) -> Self {
pub fn env ( & mut self , k : impl AsRef < str > , v : impl AsRef < str > ) -> & mut Self {
self . env
. push ( ( k . as_ref ( ) . to_owned ( ) , v . as_ref ( ) . to_owned ( ) ) ) ;
self
}
pub fn set_ args( mut self , args : & [ impl AsRef < str > ] ) -> Self {
self . args = args . iter ( ) . map ( | a | a . as_ref ( ) . to_owned ( ) ) . collect ( ) ;
pub fn args ( & mut self , args : & [ impl AsRef < str > ] ) -> & mut Self {
self . args . extend ( args . iter ( ) . map ( | a | a . as_ref ( ) . to_owned ( ) ) ) ;
self
}
pub fn push_ arg( mut self , arg : impl AsRef < str > ) -> Self {
pub fn arg ( & mut self , arg : impl AsRef < str > ) -> & mut Self {
self . args . push ( arg . as_ref ( ) . to_owned ( ) ) ;
self
}
pub fn push_p reopened_dir (
mut self ,
pub fn preopened_dir (
& mut self ,
dir : cap_std ::fs ::Dir ,
perms : DirPerms ,
file_perms : FilePerms ,
path : impl AsRef < str > ,
) -> Self {
) -> & mut Self {
self . preopens
. push ( ( Dir ::new ( dir , perms , file_perms ) , path . as_ref ( ) . to_owned ( ) ) ) ;
self
}
/// Set the generator for the secure random number generator.
/// Set the generator for the secure random number generator to the custom
/// generator specified.
///
/// This initializes the random number generator using
/// [`cap_rand::thread_rng`].
pub fn set_secure_random ( mut self ) -> Self {
self . random = random ::thread_rng ( ) ;
self
}
/// Set the generator for the secure random number generator to a custom
/// generator.
///
/// This function is usually not needed; use [`set_secure_random`] to
/// install the default generator, which is intended to be sufficient for
/// most use cases.
/// Note that contexts have a default RNG configured which is a suitable
/// generator for WASI and is configured with a random seed per-context.
///
/// Guest code may rely on this random number generator to produce fresh
/// unpredictable random data in order to maintain its security invariants,
/// and ideally should use the insecure random API otherwise, so using any
/// prerecorded or otherwise predictable data may compromise security.
///
/// [`set_secure_random`]: Self::set_secure_random
pub fn set_secure_random_to_custom_generator (
mut self ,
random : impl RngCore + Send + Sync + 'static ,
) -> Self {
pub fn secure_random ( & mut self , random : impl RngCore + Send + Sync + 'static ) -> & mut Self {
self . random = Box ::new ( random ) ;
self
}
pub fn set_ insecure_random(
mut self ,
pub fn insecure_random (
& mut self ,
insecure_random : impl RngCore + Send + Sync + 'static ,
) -> Self {
) -> & mut Self {
self . insecure_random = Box ::new ( insecure_random ) ;
self
}
pub fn set_ insecure_random_seed( mut self , insecure_random_seed : u128 ) -> Self {
pub fn insecure_random_seed ( & mut self , insecure_random_seed : u128 ) -> & mut Self {
self . insecure_random_seed = insecure_random_seed ;
self
}
pub fn set_ wall_clock( mut self , clock : impl clocks ::HostWallClock + 'static ) -> Self {
pub fn wall_clock ( & mut self , clock : impl clocks ::HostWallClock + 'static ) -> & mut Self {
self . wall_clock = Box ::new ( clock ) ;
self
}
pub fn set_monotonic_clock ( mut self , clock : impl clocks ::HostMonotonicClock + 'static ) -> Self {
pub fn monotonic_clock (
& mut self ,
clock : impl clocks ::HostMonotonicClock + 'static ,
) -> & mut Self {
self . monotonic_clock = Box ::new ( clock ) ;
self
}
pub fn build ( self , table : & mut Table ) -> Result < WasiCtx , anyhow ::Error > {
/// Uses the configured context so far to construct the final `WasiCtx`.
///
/// This will insert resources into the provided `table`.
///
/// Note that each `WasiCtxBuilder` can only be used to "build" once, and
/// calling this method twice will panic.
///
/// # Panics
///
/// Panics if this method is called twice.
pub fn build ( & mut self , table : & mut Table ) -> Result < WasiCtx , anyhow ::Error > {
assert ! ( ! self . built ) ;
use anyhow ::Context ;
let Self {
stdin ,
@ -183,7 +204,9 @@ impl WasiCtxBuilder {
insecure_random_seed ,
wall_clock ,
monotonic_clock ,
} = self ;
built : _ ,
} = mem ::replace ( self , Self ::new ( ) ) ;
self . built = true ;
let stdin = table . push_input_stream ( stdin ) . context ( "stdin" ) ? ;
let stdout = table . push_output_stream ( stdout ) . context ( "stdout" ) ? ;